From bb14cfee749df06e29940a49d8d908c6ace0c3e9 Mon Sep 17 00:00:00 2001 From: Akash Satheesan Date: Sat, 5 Jun 2021 00:08:01 +0530 Subject: [PATCH 01/45] Squashed 'lib/vscode/' changes from cfa2e218100..2064d4c301c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2064d4c301c fix issue reporter unit tests d99a697eb52 Fix #125503 b098b10a77e Merge branch 'notebook/dev' into main a57e41b7a43 notebooks: more accurately detect old style of renderers c8a447f93b8 Fix #125507 ae4124aa7e1 Fix #122570 2bcdb95e7df update distro 89d750cd687 add restricted mode to created issues (#125537) 5f7166fd915 Put run menu above output container, Fix #125188 d9cf45e0dba Fix #125526 ab0bd774c91 Pass profiles, defaultProfile, isWorkspaceTrusted from renderer to shared process (#125450) 061403c7458 Switches to new RemoteHub authority separator 0e6d07052c8 remove untrustedWorkspace search for now 1c5b5a632f9 Hide "Customize Notebooks" in getting started behind setting f843c51bca8 Update lock file 2456872bcaa Bump distro 12547c1de87 remove virtual workspace information from banner (#125512) 6de86dcd840 update notebook layout default values. 0f0abb3dc87 trust vfs (#125523) 8d87a664274 Bump es build bcdfe884a3c Fix window reload with an empty remote window a0bc15ff6fc Close Remote Connection shows up in local windows fe1eafc80c0 Merge pull request #125498 from microsoft/hediet/fix-125034 5eb636f22fc Renames InlineSuggestionActions back to InlineCompletionsActions. e8ad99de2b3 Merge branch 'main' into hediet/fix-125034 dcf62e3a1e4 Merge pull request #125501 from microsoft/hediet/add-accept-action fe6fc208e9d Puts EditorOption.inlineSuggest to the right spot. c6777d5c6c9 Reverts menu rename. c5bbe0a35ea Merge pull request #125484 from microsoft/hediet/fix-125478 20cb29b076b Fixes #125430: Add a lock around the extension registry. 383ae36449b restricted mode hover: added a link to manage trust. For #125408 1a8285a9654 Adds accept action to inline suggestion hover. Fixes #125472. 2ba1dcb0c9c Removes setting ghostTextExpanded. Fixes #125037. 3300006ee17 * Renames command ids, context keys and command titles to Inline Suggestion. * Renames menu item, makes it proposed API. f8c061e73d7 restricted trust status bar item should use rich hover. Fixes #125408 620434543f5 * renames editor.suggest.showSuggestionPreview to editor.suggest.preview * renames editor.suggest.showInlineCompletions to editor.inlineSuggest.enabled 4b0c17e1808 fixes #115535 93e61e267ca fix compile error 54dd1429b64 startup timings uses now `exit` and not `quit`, fyi @bpasero 922f866a282 run menu: more precise context keys f207b383071 inline `NotebookExecuteHandler` type fa1694c8afb Merge pull request #125465 from microsoft/menubarFix 5efc2e7abcd :lipstick: 7954c27d2d9 Fixes #125478. f99e1c358f0 fixes issue with asExternalUri API 8163cfd8c54 Make sure we layout editors in sideBySideEditor after they are created (#125445) 387e2f39ebb Properly complete notebook profile step 11f86fefb46 Track opening notebook separately from showing notebook GS page a2ef11ff553 fixes context keys with menubar fd2ed91612c Fix wrong CKS on output toolbar Fix #125109 f95fb77f22a Fix cellstatusbar layout issues from "visibleAfterExecute" Fix #125403 0acf7df100e Fix showCellStatusbar default #125403 a244a4ccc65 improve messaging with remote 5d58be33080 switch to a switch for localization edge cases ae0e8f04468 uppercase h in localization 885ac7f1c11 fixes #125406 b519331a06b fix #125458. 4c12628b2b5 fix #125234. 0c7e7cf21d6 disable notebook layout getting started. 4cae6713714 fix #125452. 72d325b4bc9 fix #125027 df59dc8470a don't show status bar entry until files are opened d3db92b7a2e Fine tune image styles. Fix #122680 72a67899410 add settings links to improve understanding of workspace trust c9e683d6c78 fix #124405 827398db432 fix #125444. f004a398e0b Fix #125313 b26e1aba58c Remove hashes from override 41b1406d3a8 Revert parts of "Fix #125395" Re-enables GitHub extension in untrusted workspaces eab8d0403f2 Revert "Fixes #125350: disallow in untrusted ws" 0006964091a Change cell type contextkey to markup Fix #125378 5ea26044187 Fix #124531 0a5d652bdfd Fixes #125332. f73f263c6bf Needed localization changes for converting xlfs to json (#125442) 0f0f066b392 Remove codespaces walkthrough from Getting Started 96004bc2c97 icon hover: add pointer for element hovers 11debc38469 Merge branch 'notebook/dev' into main b80011a819c Fix #124049 fd430418a01 Refine `CellInfo` type (#125351) b2cc8487aed Flip positioning of steps and media in narrow layouts. Closes #125246 5966e9dfec0 Check to see if there are any artifacts that haven't been published (#125428) a56ef182474 notebooks: fix default selection of untrusted renderer 788e39aad86 #125395 Improve the prompt 062401745a2 Switch loglevel to trace 73de22af596 Close #119722 be1cf4bddb5 Focus contributed profile terminals after creation 60651a0c4de Fix #125030 8f9eedf0019 Merge branch 'main' into notebook/dev 01c6fb557d0 Fix #125395 41163014f8c :lipstick: 490cef7c075 Revoking trust in the remote scenario will reload the window 3f8672be8a4 fixes #124051 6d66648c51b Add snippets for ports attributes to settings helper Fixes #125081 e43c3957f64 rename onDidChangeNotebookAssociation to onDidChangeSelectedNotebooks 732769073a2 Workspace trust - add --disable-workspace-trust flag (#124998) 499e4948c7d Fix typo 41f117753ed debug: update js-debug 20df87725d3 fix build again 15aca96cd5c build - unblock lauching 8b4bc01166a Removes RemoteHub 0f2f7c7f04b Update notebook getting started images b2a64b1379c Merge pull request #125352 from microsoft/tyriar/migrate 515b7125255 revert a change fa19cd28adb fix build errors 6f0ce2e7508 Fix #125250 884b1e7a0d0 Fix "Trying to add a disposable to a DisposableStore that has already been disposed of." ref #125354 c8b7aaf2c29 Merge pull request #125340 from microsoft/merogge/onExit 7fd324944d3 Fix selected notebook profile highlights 99665d0b4ac Merge cell statusbar settings Fix #125173 2974dcbd985 Fix bugs causing walkthoughs to not open on install ab1c9202003 Try setting gettingStarted as default editor (#125321) ebde979a485 fix cell top/bottom border always active. 7dacb10b591 fix #125339. e6aaf493989 Move notebook getting started walkthrough to its own section f473e3dc9f8 fixes #125047 6cc80fea815 fix #125338. 66917f41795 fix #125334. 2356d7c5b76 fix init layout interrupted by editor group resize. a2a61127667 Hide execute actions from markdown toolbar Fix #125336 0f8c499d101 Migrate profile setting and fallback properly 272208523b5 register the extension request handler once workspace is resolved fixes #125342 4c57cf40313 fix #125175. bbc4995eca7 fix #125176. 195477a0e96 remove unused import 68e862e1d62 skip flaky window test. 9bd7cbd1403 notebook.insertToolbarLocation 769e7080f4b Fixes #125350: disallow in untrusted ws ae2f0b39e63 Fix #122741 8f3a47cc88c add singleTerminal argument 6ef81b30370 add safeDisposeTerminal to terminal service b295408c303 tweak wording fa8a7a84a13 Merge branch 'main' into merogge/onExit 895dbf4dfd0 fix #125069 60dd761211b update the layout based on treatment. 26cd18321bd remove backwards compatible tests. d215fc72380 Fallback to active editor if no webview is focused c5a4158a651 fixes #125247 3d0d203bb02 fix #124849 509906cd916 Merge branch 'notebook/dev' into main 4d4f0b528a2 fixes #125319 093b03bb39e fix #124854 Co-Authored-By: Daniel Imms 941a603ccd0 Revert "Try fix getting started as default crashing integration tests" 0206b2ee43f Try fix getting started as default crashing integration tests d0ba023c71e Fix #122680 48fcde4048c Fix #123476 0543065c41a Don't commit inline completions on tab when "tabMovesFocus" is active. e2ad6d2c9a8 Merge pull request #125126 from microsoft/hediet/make-hover-unselectable b49731160d3 Add henning to my-endgame notebook 1fee13180b7 Vertically center notebook profile list 09a3fa687a9 Resets context keys properly when editor is disposed. c324c61ad57 add closing tags e92e3d1a9ea Reset context keys when Ghost Text Controller is disposed. ec5bf6733ca Fixes "Ctrl+Z doesn't retrigger inline suggestions" 26ff863e3d4 Merge pull request #125221 from jeanp413/fix-125035 ce8d2e86028 make IHoverDelegate.placement optional 32e6054985c Adds more documentation to the proposed inline completion API. Fixes #125267. 20be2c8eaa2 icon label hover: allow element placement. Fixes #125090 232412ff87b adopt terminalTabList 60a36219813 Revert "icon label hover: allow element placement. FIxes #125090" 4aa9f8271b8 Merge pull request #125292 from microsoft/tyriar/themeicon 8223d3d5c7f Fix #125156 0a32357e6d7 Fix filter.filterQuery initialization 3099c6f1c1b ios: trigger list/tree/table context menus 3a388466b85 tree viewer hover delegate: command handing now comes from hover service 1d471214fb3 icon label hover: allow element placement. FIxes #125090 0ee6895a6b8 Convert vscode ThemeIcon to internal type e040c0881f7 Workspace trust - calculate trust before extension host starts (#125283) ea339694fc7 fixes #125272 727caa7f238 Merge branch 'main' into notebook/dev e0131062c84 bail on standard start when workspace isn't trusted 0bf73ff15ab make sash work better on ios 9764a02c5d3 sash: use DomEmitter df709ddd3d5 Fix otherPortsAttributes protocol not updating correctly Fixes #125079 ef0fb8afb89 Revert "use associatedResource instead of untitledResource, https://github.com/microsoft/vscode/issues/125028" 073c4ffd7da remove deprecated notebook-namespace, notebooks is the future a24c1495208 Merge pull request #125281 from microsoft/hediet/allow-inline-completion-array 2e53913b637 Separator in remote indicator can appear/disappear. Fixes #122309 d71e5718c90 Fix ctrl+click to open link in ports view Fixes #125076 f32b38aa216 Allows to directly return an array of inline completions instead of an InlineCompletionList. b5bdc48d553 use vscode.notebooks not vscode.notebook 3d2309d4e74 Set icon for custom pty terminals e537c47c63c Fix double extension terminal profile creation a3337d01bb0 more api polish 17da5e37217 use associatedResource instead of untitledResource, https://github.com/microsoft/vscode/issues/125028 7051f7db889 Sort content of XLF files 109c9d9486b adopt viewType everywhere and drop support for it, fixes https://github.com/microsoft/vscode/issues/125163 b1e613481bb fix https://github.com/microsoft/vscode/issues/125163 9796ac82c3f (re)move NotebookCellOutput#id into proposal, also remove ctor overload that allows to set id a14600c325f editor trust - limit trust validation in `openEditors` to the places we want 39e7fd6a779 Merge pull request #125128 from microsoft/alex/ghost-text a1e7ce9cde2 tackle more todos, change ctor of NotebookCellData 0c3646199aa editors trust - support opening diffs into new window (#124618) 592ae5a1f53 editors trust - make sure diff editors bring up trust dialog too a286059b90d macOS - workaround fullscreen window regression (#125122) 82acbe807f2 updated todo search file ac05ae7b6f0 move file'ish things into workspace namespace e57462fd1f6 dnd - only add file system resources (for #125187) 0b6e70302f8 remove deprecated API dfc47c79571 rename notebookViewType context key to notebookType 542655758b4 fix https://github.com/microsoft/vscode/issues/125138 f2d6da27d01 make sure appendOutputItems and replaceOutputItems return something ee87b2bd432 missing adopting for end-call d487b379bae Merge branch 'main' into notebook/dev 7865b99b44e Fixes #125035 febc20e8d39 safari - disable clipboard error notification e7b9f3a1a40 Show a confirmation notification when installing/uninstalling shell commands (fix #125145) 217f1a2f60a Workspace trust - extension enablement (#125179) b154a3d3043 skip view column test. 322c81122dd Add "move cell up/down" to the cell context menu when drag and drop is disabled a90729cb6f0 show notebook profile the first time when a notebook is opened. c55d8a0e16c select notebook layout action. b2da4119928 Add undo/redo per cell for jupyter profile. 7aa8c5ec4a7 Fix profile contribution schema 2d97edd98f2 Update QuickPick api doc (#124485) 8df0f068588 Group startTime and endTime into a single object ef28d1663d9 Inline parameters to execution task start and end 5c6ae4fc5ac Update NotebookCellStatusBarItem constructor 872bbcc8c1c Update provideCellStatusBarItems 28bf10376c3 Add 'notebookLayout' tag to suggestions 4dd5ccb1566 Make registerWalkthrough public d2561813a8d Merge branch 'notebook/dev' into main dc9dc66109d tweak fix ac7bb556e8f Disable "consolidated run button" in Jupyter profile 4449461cae4 fix #125121 a296485f007 fix #125045 8e86a3c6b16 Enable consolidated run button by default, now that Jupyter has caught up 515c64f05e6 fix #125125 5e27fb3ba85 Fix to make @recommended:languages search work 84196c8b8d3 fix: update colors 950ad4ffec5 colors: add support for exporting colors 2c503281922 Add import to pull notebook getting started content into build 9bd78a8bf53 notebooks: restore renderer messaging generic 088e0d282ee Revert "fix #125137" d6d3091cbd3 fix #125137 c7f8b301938 Revert "fix #125137" 67e64a8fc86 Merge pull request #125083 from microsoft/ben/69349 80a899d8d67 fix #125040 aeecc7c03ff notebook: messaging api polish 4df863a28da Remove extra notebook images 092a2242ce5 fix #125137 2e8e888989a editors - more tests for capabilities b743bf63de1 fix #125124 d6d9200832a notebook: fix mimetype switcher not working between custom renderers ebcbe001591 update todo search file 6dbbcc2eee7 fix compile issues... e8d8e53752a update/tackle todos 6fe84c402bb Merge pull request #125106 from microsoft/joh/api/noMetadataType 553893e940a Merge pull request #125104 from microsoft/joh/api/noItemMetadata 632f2156f2e remote indicator: remove vscode-vfs workaround 5a49e6a283e Focuses the editor after showing next/previous inline completion. 1bab611b73b Sets user-select: none to the hover actions so they cannot be selected anymore. 103d3edfdc0 Fix text replace case operation false positive Fix #123483 a3bad5878ef Add a protocol property to tunnels that corresponds to the attributes for that tunnel and is reflected in the UI. bd8a0fb3d76 Fix #124779 0115c74d4af update todo@api search file 8dd2e53e247 bump versions a476c9d4f08 fixes #124850 0580a6bae45 Settings: remove notification that changes are saved (fix #69349) 545b931b96b remove dedicated types for notebook and cell metadata b1457fa4b6d remove NotebookCellOutputItem#metadata e7b775adebf Revert "fixes #115535" ae86512bf07 Fix automatic task timing Fixes #125044 6a02e8333c1 small jsdoc and todo tweaks 952e39f9d2d fixes #125026 d163f3f3d45 tooltip text grabbing broken. Fixes #124457 e9d05647b3b update distro 122df438a80 Run OSS Tool 89157c1a87a notebooks - tweak description for untitled files 1e446dfadf5 Don't hide suggest widget when expanding ghost text ab80101db2d Revert "Fix regression with extension enablement" 24e1234559d [json/css/html] update services a8a57c3fc67 Merge pull request #124288 from huszkacs/bug/issues_with_backspace a4e1a259a2b Fix tests that were not updated 91b7e6027ad Move vscode.newWindow & vscode.removeFromRecentlyOpened out of apiCommands. For #110583 2ae32273fd2 update my-endgame notebook 0a1046ada41 Merge branch 'notebook/dev' into main 2f253fcc220 more todos 4093effb9b0 Merge pull request #124964 from microsoft/alex/ghost-text 79048992ef1 Adds leftTrim function, fixes bug in inlineCompletionToGhostText. b1da1fbc8c4 Merge pull request #124972 from microsoft/hediet/fix-negative-overwriteAfter 3a259a7a6ae The replaced text does only need to be a prefix of the insert text after removing all leading whitespace. 1176faf27f2 Fix #119265 78c865d70d4 polish remote menu control actions 4ebf68103e6 readonly [] over ReadonlyArray... 67a85487125 Expose the inline completions provider in the monaco editor. 1eef15f0d54 more todos for notebook API... 552d457b718 updated code search file f700cab7c36 :lipstick: 2031df26538 rename hasExecutionOrder to supportsExecutionOrder f2fb2b8cbe3 rename viewType to notebookType, https://github.com/microsoft/vscode/issues/122922 ae17cc95591 Improve autocompletion for statusBar/remoteIndicator contribution point. Fixes #122566 efcf0eea9bc Remove default support from vscode-translations-import b55d4384260 Fix regression with extension enablement b7be98705fd Update descriptions 220f89ba3c6 jsdoc and todos 1e57955c798 Remove handling of Default inno setup file e1928efbb63 notebook API finalization part1 cc8ff11f574 Fix recursion exit condition in variable resolver 2e026cf7c28 more API todos 0fde806bf85 Add limited support for variables that resolve to other variables Fixes microsoft/vscode-remote-release#5007 355df0eccb6 move renderer script and IPC into proposed and merge with general renderer IPC, https://github.com/microsoft/vscode/issues/123601 da851abcd6f jsdoc :lipstick: 8d244362832 remove resolved todo 83d5e2bda06 rename namespace to notebooks, https://github.com/microsoft/vscode/issues/122922 594fc814bca update untitled hint to work, use the correct setting name f68ee48c524 Fixes #124742 by ensuring that overwriteAfter is not negative. edf85f1711d fixes #122402 3b407e0b6c1 move onDidChangeNotebookCellExecutionState into proposed, https://github.com/microsoft/vscode/issues/124970 e9579534bb2 Only trigger session when typing, not when the model context changes. 6832b7ec4b0 Disables rendering visible whitespace due to feedback. This makes ghost text less real. 7cd53df7d72 Swaps previous and next inline completion actions in the hover menu. 427f48b8d17 Add prebuild commands dea978dd1c1 custom hover for remote indicator 8d41153ffc5 support custom hover on status bar entries d4161177d98 don't use console.trace for all... 692fb8ab211 print trace for potential cycle, https://github.com/microsoft/vscode/issues/124723#issuecomment-850674813 f55a5243a43 don't use console.trace for all... 910d70bb88d print trace for potential cycle, https://github.com/microsoft/vscode/issues/124723#issuecomment-850674813 8b04a825b49 Merge branch 'main' into notebook/dev 94f47f44c98 Merge branch 'main' into alex/ghost-text d776f0c1eba Fixes border color. Renames to ghostTextBorder/Foreground. 85f9447b720 Call adjustWhitespace on snippet. db1bd650dcc Don't compute ghost text that is not supported. Thus, no space is reserved for unsupported ghost text. 4f3d865a6b4 refactor for cleaner initialization (#124904) ccb0a8c2d93 Revert change in default due to build failures 6737ea008ff Change executionState to state 6949856b195 Remove API todo 038bac01c41 jsdoc for notebook cell statusbar API 667e3dd844a Tune getting startred color picker bb5b6afdce4 Remove "primary" in favor of alway opening the first applicable walkthrough 6adfa8b3135 Enable getting started as default startup editor b2f203113c1 editors - more alignments across editor inputs ada71479023 Open getting started the first time a notebook is opened 08eedafbd60 Finish getting started content b0862e99074 Don't include our loader in notebooks (#124864) 26b9218d64f Merge branch 'josola-edit-devcontainer-readme-markdown' into main ad52b3f4583 Fix merge conflicts 09d1935b4cd Correct dev container info in README 1605d16ee3d Refresh dev container content d7a79f0393f Add notebook profiles to Getting Started 887ff91a14a Merge branch 'notebook/dev' into main 5e7cd998762 Bump TS build version e3354e26eff Whitespace characters are near invisible in High Contrast theme (Fixes #124612) bb4e83a19a8 Improve hover stability and handle case where mouse is directly over inline ghosted text aada268951a update distro 5fe858a229c Workspace trust explainer in getting started f568f5aec3a Avoid scaling down SVGs in Getting Started eb65a93f4bb Include import ref to markdown so it gets included in bundle bbc7af71930 fixes #115535 3772aeec10b Typo 24143e91320 Merge pull request #124828 from microsoft/alex/ghost-text 868b84ceb99 fixes #124850 f509e7552a9 update classifier 676340ffad9 Get expected service worker version from renderer instead of main.js 3bfa3455a6b Fix incorrect reference when 404 on webview resource 445dc50f737 Use unique id for releaseNotes webview 1380c0c5e0b Remove unused code for rewriting endpoint 8058ab1a966 Disable consolidated run button by default 15616f8d936 refactor codeExchangeProxy to use same route and use it for refresh token as well a6f4d96b826 Fix #124049 44a24280846 editors - unset preferred mode/contents before attempting to resolve c784a74b8ba send Output metadata, not just OutputItem metadata, to renderer ea02f214c74 Merge remote-tracking branch 'origin/main' into alex/ghost-text dca2b9e2db8 Show hover over multiline ghost text ab1cf30d883 add api-todo code search file affbf49ccca Introduce `HoverAnchor` to allow hovering on something other than a range 4202ab071a6 rename NotebookCellOutput#outputs to #items b16b45fecb8 Tweaks the effect of showSuggestionPreview and introduces showInlineCompletions. Explicitly triggering inline completions will now work even if settings are disabled. d2854fd7877 fix #124842 d9f1e27aeb9 more API todos 394a1ce2dbc Merge pull request #124752 from microsoft/tyriar/term_trust 2f0a9160d0a more jsdoc, also more API-todos... 9eb940e243f Remove padding left (#124823) 42af32d16a0 do not use shadow dom for editor context menu for iOS 6c10a5334ee add jsdoc placeholder everywhere e7776ccdcc3 Setting for specifiying the local host for port forwarding Fixes #124581 e15f4026511 Add `mightBeForeignElement` detail for `CONTENT_TEXT` mouse target types a2d1bd0d158 Adds menu 'editor/inlineCompletions/actions' that extensions can contribute to. 098dfd56e3c Changes shortcuts of next/previous inline completion to Alt + Open/Close Square Bracket. 00de32d013a Keep track of the span node used for hit testing 8e54aed67b7 Remove `IHoverPart.equals` ccfda77c8e6 Reorder participants to improve stability 77bc8745b29 jsdoc for NotebookController 71fafe39464 update jsdoc for `NotebookCellExecution` 541a5d4fa70 smoke: trust dialog should appear in 5 seconds, and we can ignore if it doesn't 5b642616ef3 Use loading + spin codicon for task terminals status Part of https://github.com/microsoft/vscode/issues/121659 04e09dacdfd refine output modifications of NotebookCellExecution 3a857fc436d editors - add tests for capability change events 004f6609f8c Fix problems with port protocol 903e219ccb8 files - need to track individual readonly stats everywhere (#124524) 466dd4e490e files - provide access to stat object from not modified error 872fac207ee Merge branch 'main' into notebook/dev d5c73cc952d fix https://github.com/microsoft/vscode/issues/123570 3ac57c71329 Fix NPEs caused by extension that is not in the marketplace df03e4caadc Removed unused MarkdownString. e5f70e8e2a2 fix smoke tests (#124814) 47d3d743cad set max zoom to 8 (#124769) b2da15ea2d8 Merge pull request #124745 from microsoft/alex/ghost-text a9c54044e50 Refactors inline completions model. ccedcbdf5ec Do not accept suggestion on tab if indentation is suggested. a2944c32ea9 Fixes rendering of whitespace in the inline decoration. 8a3f351eb9c Use explicit context when the user cycles through suggestions. 1fa3397c48c fix post-merge hickup a97ebdbabc8 Merge branch 'main' into notebook/dev 8715d80695f fixes #124809 7a767570e85 editors - more tweaks to dnd behaviour 07ff28c58d2 Dont center markdown content 3ea0bf8fbca Implement run button with extra actions, and "run above"/"run below" actions 970858ef6dd Add first pass of color theme selection markdown content 29cad8fb5e6 Merge pull request #124754 from microsoft/tyriar/profile_api e0c8a76b7ad don't sort scope list. Fixes Microsoft/vscode-pull-request-github#2751 c1448f3161e Remove ansi escapes from localized string 9eeb092206f Re-enable skipped test 9b609ab1e11 Clean up profile provider api e8758933d80 Disallow custom profiles as default e037348d272 Support launching contributed profiles from dropdown 280e0070733 Add undocumented always syntax only TS server mode 866ecdd45a0 Merge branch 'notebook/dev' into main 1c3cc87bccb Add an `InlineCompletionsHoverParticipant` 7ce379e3f2b Merge branch 'main' into tyriar/term_trust d9e043161fb Bump sw version 73ff24e451d Fix de/encoding for rewritten vscode-resoruce uris b8f11107f72 Use @types/vscode-webview decb1ab6a89 update left aligned plus button margin. 484b04df64b fix #124774 902bb43b3b1 testing: move back to proposed 31aef10814f testing: hotkey for opening output peek 14a013e7f3c Support contributed profiles in dropdown dd61b26f33a enable workspace trust by default #wt 5338cc32da7 fix build. 4403b9010e5 Tweak remote workspace trust calculation e3d4313714f support editor options override. 384f42bca76 Tweak wording, fix #124724 0dd52e2d77f Update distro b157bc7e5c3 Support for @recommended:languages search (#124546) 9224159b004 Migrate users from shell -> profile settings (#124615) d2a0bfb2866 editors - log error when opening fails 61f3ac6e07b support context keys in menu bar (#124726) 0de0faecee5 fix https://github.com/microsoft/vscode/issues/122376 f523f65f398 Add a `description` field to decorations to be able to find leaks 4c5a061df61 rename NotebookKernelPreload to NotebookRendererScript 9ef57b5c216 remove NotebookCellOutputItem#value, https://github.com/microsoft/vscode/issues/123884 4ad3265cbed Support workspace trust in terminal a56fe2b397e use isVirtualWorkspace ed611d0ec39 Minor tweaks 4edb0110f6b Small tweaks 7bd0337d940 Move parts of the triggering logic into the widget 2508b33f0d3 Wait for listen when making tunnels 7a83e5aa627 workbench API: assumeGalleryExtensionsAreAddressable e94e8ed3998 Show default profile on top of term dropdown 693677c8a24 babel.config.json language mode should be 'jsonc'. Fixes #124683 cd501b2e5bb Merge pull request #124741 from jeanp413/fix-124735 9dd89100b49 Improve editor DND to work with untyped resource editor inputs (#124749) 14a4548e4ab editors - use preferred content only once da1193950a1 some jsdoc for NotebookCellExecution 30074591eea editors - input :lipstick: 55d91bbed87 editors dnd - more :lipstick: 9d907212baf rename NotebookCellExecutionTask to NotebookCellExecution 5d534b94f83 dart: fix language configuration location d0d80ec337f fix build 23fb4207373 Merge branch 'main' into notebook/dev 0637663fcfe fix isNoCorsEnvironment 9095b835bbf editors dnd - fix dirty contents in files diff c870d75473c editors dnd - enable diff editor transfer 70418f0aced editors dnd - fix untitled transfer bba59424f56 Merge branch 'main' into ben/better-dnd 367a0b809ab editors dnd - towards allowing any untyped editor input 6ba7093a8a1 Fix window/folder/workspace terminology for status bar entry and banner 9638534dd51 Fixes #124735 c1d4497a31e Merge pull request #124664 from microsoft/aeschli/dart 1082913dd01 fix config default value. 433c801dcc3 editors dnd - some more cleanup cbbdb17b80d editors dnd - rework to allow to set contents to untyped editors b5b059d2e2b fix typo in files.ts (#124693) 5eec3c86e3c smoke test - disable experiments 85d8f223c70 Remove keymaps from getting started walkthrough 02968bc2503 Call post message to all parent clients 1fd2b4ed1e3 Rename keys and support full context key expressions for check offs 14b31425b90 Fix #124531 bfb94c85fa3 fix build. c95af9ae460 fix build. 8519a42c5f6 notebook options respond to view type specific cell toolbar position. e3c8ff57849 try showing the banner only after some files have been opened 561b8364008 testing: fix hidden tests not being un-hidable ade83f05895 update context based on outputs. 574696980c9 notebooks: update state of messaging spec internally c4fda24034a testing: fix terminal being shown inappropriately, use beaker 0feee9edefc Remove `instanceof` check 641c2b175ca Merge pull request #124707 from microsoft/alex/ghost-text e0a52df1695 Merge branch 'notebook/dev' into main c3d63c1a1b2 fixes #124692 8e9405e7a9b Keep the `ColorPickerModel` alive between repaints in the `ColorHover` 35b43a410b0 Help TS understand the code ebdd548be22 fixes #124702 c538781d780 add notification if tsserver logs are left on for more than 7 days (#124149) 363e8f25f6f bump distro 244b48af73d testing: additional actions and better theming for peek a5bbc53e882 Extract more color picker related logic to `ColorHoverParticipant` 4e6fe2dc51e Extract pieces of the Color Picker logic to a new `ColorHoverParticipant` fd7c71a2eea :lipstick: c88d5756213 update compact view default value. 1e6b6cb6843 Pick up TS 4.3 final 6a12866c3e9 :lipstick: 1abeaf97753 Workspace trust - remote workspace (#124617) a430e8f9692 Fix settings dropdown hover style Fix #124207 b6acb191fac Fixes #124665. 99bcc8e2458 Show clear outputs only when there is kernel. 9252be4f90a distro 21bf10d4977 Removed unused member. 54ebd819176 distro f1a5d40aa75 refactor getCallbackEnvironment to return authority by default 5eddbd9d207 Properly support splitting ext profiles 08cf3df7457 Pass object instead of unwrapped args for term create d7779916566 move buildExtensionMedia to lib 62e8b545f7a missing build 51a5caf3f23 Simplify terminal creation bf5f7dd5ec1 Get split terminals working d1ed9c8bf35 Adds proposed API for window.getInlineCompletionItemController(...).onDidShowCompletionItem. 3ff91e7621b Merge remote-tracking branch 'origin/main' into tyriar/profile_api 7f21b1af485 Revert "Allow extensions to create multiple sessions from the same provider (#124640)" (#124705) 4583ef442b0 Fixes bug that "show previous inline completion" actually shows the next one. 8f0589da177 Set suggestionPreviewExpanded to true by default. 9464d14f317 Make notebook renderer activate potentially async (#124647) 5eb64c54ca4 Modified markdown preview nested list styling (#124445) 23e1f261dc8 Remove `HoverPartInfo` 84bc432011c Add `IHoverPart.owner` 31a59b5970d bump distro e6a1cc38437 Update commands.json e29194ad0d3 Activation event, register api 6a7c700a12d file working copies - do not throw from ctor anymore when schemes are unexpected bfccdcb9581 disable fullscreen on ios 764d8fdc3dd test: add test for event Relay (#119070) a7ab347c2b3 remove old notification d662cc56549 remove old license notification c704e43d5dc Check that the /build/ folder compiles 0e3459b0b9f expose Grid.onDidScroll 0a4bfb31c90 fix naming a628237458f Web: "Open Folder" on empty workspace does nothing 4cda850edf5 disable welcome editor in smoke tests (fix #124674) 0688745e82e Color.Format.Css.format does not return null, so the return type can be made more strict. (#124568) dff33d73244 use actual object 0d44b63c1c1 fixes #124407 9cba86888c9 update node version in optimize 0a7a69f1908 fix build compilation 9eb4eff77b8 some more jsdoc, https://github.com/microsoft/vscode/issues/124357 d63a69abf3d some enforcement of unique mime types in the extension host, https://github.com/microsoft/vscode/issues/124357 24ca9e0d7c7 Merge pull request #124654 from ValidMelvin/main a961587ecf7 dart as built-in language 98dc73a3296 unnecessary space in in julia cgmanifest c97189d9d06 some more :lipstsick: and simplifications a48d92d0fd8 only pick the first occurrence of an item per mimetype, ignore others, https://github.com/microsoft/vscode/issues/124357 18b6620bc39 fixes #123543 c2cc9b11afe Update README.md 14f61093f43 fixes #124507 69259e84a0a some :lipstick: for https://github.com/microsoft/vscode/issues/124357 44b470c99ff fixes #124576 47d00215aff editors - cleanup untyped editor interfaces for text capabilities 04f585a580a cleanup interfaces e12f21f498d Merge pull request #124549 from DonJayamanne/createNb 5e146d257b5 Update classifier.json d0884f4a1ec webview - clear group listener when it gets disposed fe1547c251b Merge pull request #124621 from microsoft/roblou/diffNotificationMessage 5cc9ec944d8 sandbox - bring in iframe based webview service 3084319750b Get rid of classes for workbench editor options (#124589) b82b90c1000 editor options - more :lipstick: before merge a18ea9c9ec2 Allow extensions to create multiple sessions from the same provider (#124640) 21162bfb68c Shift execution count label down just a bit 68efd480d0e Explicitly convert properties to strings before uploading ad41b3a12b5 Mark a few more props as readonly 0a7061ed002 ReadonlyArray -> readonly arr[] 24a23a8ea05 Mark array params in vscode.d.ts readonly (#124599) 7d50ce2061e fix tests 2521499104b testing: add clear test button to peek view title 57af60a7b7f testing: initial test message split view 473cfe28bfa Revert "Revert "Merge branch 'main' of https://github.com/microsoft/vscode into main"" 8822790908b Merge pull request #124622 from microsoft/gettingstarted/navigateToStep 7c01395da16 Revert "Merge branch 'main' of https://github.com/microsoft/vscode into main" 7a976501eb3 Merge branch 'main' of https://github.com/microsoft/vscode into main 22576768342 Applied new style to first getting started walkthrough 8ccc1243fc0 Fix notebook unit test b0f67df65d7 Fix build bb19c28fe2c Getting started layout polish 2d9aa1868ae Fix broken @tag in settings editor Better fix for #124520 0b2d890624c fixes #124619 #wt 20ce9d57629 fix weird border rendering on windows. b4f4839da5e fix integration test 6bcd590a706 Merge branch 'notebook/dev' into main e1731e91048 fix build f378cff1a8e dropAndDrop -> dragAndDrop 032920fa2ee vfs -> virtualfs 72c4bd69c04 remote menu: sort entries of current remote first 757fd91f040 Hide TestReolver.newWindow when in virtual workspace cf2a866b7dd test resolver: supports untrusted workspaces 68ba0141fbd fixed notebook focus indicator margin 5926c50d6c4 fix missing markdown height update 33209f104db update markdown height on options change. 7fd8f828c02 fix pwsh profile test failures (#124613) 8f18f3c5ff2 oops 771446e4a21 Make showCellStatusBarAfterExecute not experimental 71cc917274f Add option to show cell statusbar after execution 3ccbe2a6b1b Fixes #124247 789a91a487d wip db6ffb43b90 fix #124583 c351b396cac Support terminal renaming inline in the tabs view (#124533) 33eb149bada Add reset to default to terminal tab color selector 18b30e5b494 Fix default shell args for debugging a8b63f564af Merge pull request #124585 from microsoft/alex/ghost-text 19c88bc3c7a editors - more EditorOptions cleanup 5254e33173d Removes unused const. af0078d44d5 editors - more EditorOptions cleanup de08dcdf276 remove folding classes first when config change. c17917e6ba4 Enable notebook renderers on web (#124557) f2b1f78ad45 editors - remove EditorOptions a21b824704b Enable notebook renderers on web (#124557) 0249ae32871 clarify that NotebookController#id should be stable, https://github.com/microsoft/vscode/issues/124535 080f8b5e35f editors - remove TextEditorOptions 8adc16d6c50 editors - remove TextOptions#create b10db1828d0 editors - remove TextOptions#from 9bdb8f88816 editors - remove TextOptions#fromEditor 593a25d41e1 editors - remove TextOptions#apply 741beb8f264 TestResolver, use 127.0.0.1, not localhost 3de3141ff56 Implements basic cycling through completions. 4d4ebbee5fc Clear inline suggestions cache on commit. f89fc476de3 Fixes colors for dark & white theme. a78bc1aa96d icon label: supportIcons implies LabelWithHighlights d4307f8d534 missing validation for top-level token color object b6551f8e4e3 Workspace trust - no need to call setWorkspaceTrust (#124566) afc2b062703 editors - start to remove typed editor options (notebooks, search) 64b0c65b8cb editors - fix cyclic dependencies 5880a6a4eeb Merge pull request #124570 from microsoft/hediet/ghost-text-expanded-by-default-setting ce8b0049619 Merge pull request #124353 from microsoft/chrmarti/localinterface 97d576cb085 editors - more cleanup of large files 43b7187c3df Force inheritEnv in ext debug terminals 0685a4af28b Default bash, zsh and fish to login shells on macOS a26ecef44b5 Add self to workbench-diagnostics 8a1de4b022a Merge pull request #124567 from microsoft/hediet/fix-after-decoration 0efc03fb168 Removes unused import. 5364a9351fd Adds option "editor.suggest.suggestionPreviewExpanded" to toggle whether suggestion previews are expanded by default. 8bd49ffd50b update distro eff82a3cef1 rename trusted types CSP from notebookOutputRenderer to just notebookRenderer ffd1f84ea9f rename notebookOutputRenderer to notebookRenderer, https://github.com/microsoft/vscode/issues/121819 fd212e712ea validation :lipstick: https://github.com/microsoft/vscode/issues/121819 52df34dcf19 Fixes invalid cursor position around after decorations. eebf8e876ab editors - extract input and side by side to own classes 42e59bd3777 more complete cell info for markup renderers e11764f8420 add ICellInfo#data to eventually replace bytes b5fc2b0a398 NotebookCellOutputItem factories allow for metadata, expose "bytes" as data property, deprecate value-property, fix converter issues, https://github.com/microsoft/vscode/issues/123884 856fb393cb4 editors - more dnd code polish towards any editor dnd f2248508a68 fix tests on windows ab793cf02ac editors - make dnd code ready to delegate serialisation to respective editors 59f5bbaf253 editors - cleanup editor descriptors and :lipstick: dee37c6e765 web - offer upload action only for editable folders e0f751f1287 editors - introduce and adopt capabilities 71d00b3b993 Merge branch 'main' into notebook/dev 0bada155580 more API todos 76523deb91e Bump browserslist from 4.16.1 to 4.16.6 (#124550) 963f30f0871 :lipstick: b1823157d54 Fall back to existing published webview commit (#119295) 286b643ecd2 chore: bump electron@12.0.9 c3c2113c368 Preserve execution summary when converting dto 8173a0e0398 Fix hang when typing incomplete @feature in settings editor Fix #124520 28803975a1a Add @feature/notebook e9f3fe9f301 rename markdown layout section. fe41fcc58d6 :lipstick: fe3cab25c5f compute position/width of output action bar. af14bf673ab remove kernel picker config in menu contribution 1da9f2d2e6a Update subscribers.json d28d8802e42 testing: add default keybindings 8b9f8595cc2 Remove unused 6cfad71ce61 notebooks: remove deprecated vscode css vars from webview 196e79256dc Add workspacePlatform context key for getting started items Closes #123824 6ed2584f390 fix unit tests. 46ef54c20e9 Merge branch 'notebook/dev' into main 8a41d85d1be notebook open layout settings. f88c007f6c6 👋 Rachel, 👋 Tyler d7ead317dca Close #122570 41d869f5514 move nb layout settings out of experiments. 79762396a06 Respect soft revert for custom editors (#115658) 78251f8e016 Update distro 7e0d8cd80ee Merge pull request #124511 from microsoft/tyriar/color_config 9993eb9d1ae testing: improve support for markdown messages b168ece8de3 markdown: add nbsp to unescaped sequences b04c9668927 Fix test resolver with trusted workspaces dbdc7a259e2 added bottom spacing for table in markdown preview (#124385) 5cbd4bc4691 Fix color of single tab status icon a8d2a3a87c5 Resolve todos 47b7320c1f4 Show tab prefix before icon is ready a31d9ca6993 Don't show icon until its resolved f7f6956554a Share profile property schema 17e82898ed1 Remove show all colors, add settings intellisense a8e7253de09 fix scroll in table widget #wt fixes #124314 2b9f22631f5 Support terminal link word wrapping (#124514) cdbf46815c6 update distro fe1af896d5d Use remote reconnection constants (#124517) 2b6564c1015 insert toolbar on the left. df3c2c48755 testing: move apis to stable b6dad5d1437 Support any theme color 3c2ffadf29c Dynamically generate terminal color css 9eaba8944ff Support colors in terminal profile setting 7a0ce574da6 Fix test output pty usage 777f09d4569 Fix safe config provider fallback to default d63078aaf04 Merge pull request #124317 from jeanp413/fix-124127 a8397d15299 Merge pull request #124480 from nrayburn-tech/fix-122348 934a4244e27 Remove overrides from editor service (#124375) b47569400a3 option to hide terminal tabs if there is only a single group fixes #122348 5319757634f Add fallback webviewExternalEndpoint in code 8f11975c47c Close #119722 d6b5df5e199 retry logic for setting password (#124390) 12fa7b04257 Increase timeout for webview focus change 4c4ec402e7e return early b314536e56a Move find file references into the search group 18296326a9a Set proper context on new cell output toolbar 28767c88f0a Close #122795 cd8bf7ba536 fix zero height output height. 7bc2019b8d5 Updating pinning test be8745ac9e0 Fixes #123228 (#123584) 6ee883bfa32 Split href before decoding instead of after 6af49913c2a title for notebook label in notebook toolbar 77ff6eb03bc Add image specific link normalizer (#124400) e9b8c129155 Add types a03daaf8506 Merge branch 'notebook/dev' into main 4ba27602740 fix #119214. 8afcdfaad8b extract complex options parsing. 9996e32bc9c testing: improvements when running a previously un-run test 6507d05310f freeze layout config. 6cda8d2373d extract configuration update f38f3bb8e78 Merge pull request #124044 from microsoft/alex/ghost-text 51aa5402d63 Allow single line decorations that are not at the end of the line 06a86116b73 Fix firstHostSegment logic 827dec3a0df Use better logic for getting scheme and avoid extra decoding for authority 44fe867eddd fix tests c23c9e448e6 Implement dragAndDrop enable setting 021071ff74a Avoid double encoding authority 22dc518a210 Remove unused type 97bbacd8087 Remove extra call to with 82d18a42fa2 testing: fix auto run triggering test multiple times 17f3a69e243 Allow toSide #119725 86cb6d6b337 Close #119725 4d53b454283 Fix local term warning in remote 5ac4f5f5be4 Fix didn't work af3fbd968c9 Make sure we decode uri path 84f5040b3db Remove unused member 91fdd52d17b Merge remote-tracking branch 'origin/main' into alex/ghost-text 8b709a2f55a testing: provide test IDs in menu contributions, rather than internal elements 231c155d31f Refactors the inline completion feature. 852b70eafed Try fix (#124384) c5da7f33a70 Fix wsl detection in profiles tests b6387e477be Tweak output toolbar position b78754e1e46 fix incorrect links (#124203) a0d7f6292e9 Remove a few instances of 'vs code' in d.ts b0683f58a5a fix #124360 9847783f62d Remove uuid from webview resource uris 79dea51e79a Rewrite webview urls to be more url-ish 8a4bf3081a8 update folding on mouse over 70c87f0db9b Fix #124240 adf68a52d56 editors - some type :lipstick: around setInput effac5be7f9 drop as-prefix for ICreateCellInfo 8f093359f07 editors - simplify some serialized editor input 8aff8020dae Improve guard against unexpected URI call 82cd4f027ad fix leaking of NotebookCellOutputTextModel and NotebookCellOutputTextModel#_onDidChange, fyi @rebornix c5b9b6c48c7 Fix missing async 5807530e3ae more jsdoc 85f518b2552 Add `RemoteAuthorityResolver.getCanonicalURI` c650993dd39 Add `ResolvedOptions.isTrusted` 49e96be2fc1 :lipstick: prefer `readonly` over `public readonly` 1087876df86 Use vendor-prefix for notebook specific mime-types, e.g application/vnd.code.notebook.stdout 045e5d2f568 Store conflicting defaults in storage service (#124366) fc0b6f5e5ab fixes #122653 8b25f922b6b builtin support image/gif mime type 61aca51a322 consolidate SVGRendererContrib and HTMLRendererContrib - both were the same... fb6f0d95fad consolidate JSONRenderer and CodeRenderer 103892d1eb4 fix code renderer layouting issues 32a06b9be2c [typescript] add limited description bbe3b2266b5 allow to signal limited functionality in virtual workspaces d65dace8ea0 Merge pull request #123351 from nrayburn-tech/fix-77239 b9f20119393 Bump distro 815f217174a jsdoc for factories, some unit tests, https://github.com/microsoft/vscode/issues/123884 8268bd46e7f :lipstick: 375a15f07e9 Merge branch 'main' into notebook/dev 996dfffd637 enforce proposed API for shortTitle proposal, https://github.com/microsoft/vscode/issues/124355 c5637229dda Merge pull request #124289 from microsoft/command/shortTitle 2b959fdadc1 Listen on local interface only (#124350) 494e827e351 expose output item bytes to renderers and provide util functions: asText, asJSON, asBytes, asBlob, fyi @connor4312, https://github.com/microsoft/vscode/issues/123884 100a70731db SVG images are not render in the tooltip (fix #123688) 949f60498ae Merge pull request #124346 from microsoft/ben/pfs-promises 063be236f34 scm do not auto focus input box on iPad f19843b0a3e editors - some :lipstick: and tests for workspace trust in openEditors 9086ecd9f08 Renames Suggestion to Completion and cleans up API a6f7aa5e4c5 handle workspace uris 73c6f34f9ec Do not recognize Debian's .install file as a shell script. Fixes #124295 90b9e04f951 try to use suffix for view type when creating untitled notebook, fyi @brettfo, https://github.com/microsoft/vscode/issues/121974 779f9876bc0 debug: properly read the debug.saveBeforeStart respecting activeEditorMode 79e642a5ddb move and simplify renderer registry bbc293839d4 declare IRenderMainframeOutput#dispose and adopt it for builtin renderer 55059ffe214 todo e6dd819bf08 first cut of "bytes only" output items 4b5db9098c2 smoke test - disable failing search test 17459a4abd1 notebooks - add test for NotebookWorkingCopyTypeIdentifier 43b51ce8e76 notebooks - fix type identifier compute 703ca68ea6b fix typo b8fe2db4392 fileworkingcopymanager2 => fileworkingcopymanager 0e58bef15cd file working copy => stored file working copy 78fbc51ad75 Close #124325 633ea857088 notebook working copy - some cleanup before refactorings d0c5675f6f2 editors - less group.openEditor usage e66c62f38a2 Generalize smoke text 89c8f919884 Add smoke test for #124146 4fd4e10e99e Fix #124146? bfb822e4cf0 fix #124284 0989449a055 Fixes #124127 2f2b6b528d0 testing: show duration for test results, handle state computation better 3e5faf69c14 Remove console.log 9e04a67d125 Switch to use vscode-webview.net as default webview endpoint acc07bd9591 Mark properties readonly bf4c7042a3a cell toolbar overlap with notebook toolbar. f29bd6f18dd Dont autofocus input on ipad Fix #122044 5b0fc94e6af fire event when trust is change in empty window #wt c1b809ef221 Fix #124307 cd27f1fcb91 update text for loose file button #wt 07a2aab8f2c Remove duplication around checking isRemote 55c2fc5604e add setting and checkbox for untrusted files #wt d3f040fe017 Fix notebook cell statusbar items duplicating. Cancel tokens on dispose, and dispose the timeout properly 894b7782cce Merge branch 'notebook/dev' into main 9627b4ea63e Emmet identify CDATA for wrap, fixes #123136 97740a7d253 Revert "Revert "Revert "Closes #122433""" ddf8cc42616 Dispose CKS 4c1474b458d debug: finalize parentSession 514d3162bc8 Persist title source and set after reconnect 604b27db1bf Fixes android screen-keyboard backspace issue. af0c01b1e36 Short title for command contribution. 18ea5ac15e6 Use isRemote instead of remote authority to determine where to load from 6f2381e33d7 Terminal tab icon API (#124004) d0cea47ae39 Merge pull request #124194 from microsoft/dev/t-andreamah/outline-reveal-editor-switch-fix dae2a9d4ebc do not auto focus on ios extensions input and keybindings 6b097212e69 Revert "Revert "Closes #122433"" bd934d89ea0 Use untyped editors for workspace trust 59abb887f6c notebook: address messaging api changes 5b17052a5b3 Fix webview tests 2270c36cff9 Use extension location instead of remote for asWebviewUri 9ffac783be4 Merge branch 'main' into dev/t-andreamah/outline-reveal-editor-switch-fix 22f7f470b69 Apply Logan's suggested changes 0b355ffc89b notebook: fix certain kernels/output not working f75152cd815 notebook: fix certain kernels/output not working ab5df442eb3 Merge pull request #123727 from microsoft/dev/t-andreamah/markdown-static-preview-scroll-state 18c254987cd Merge branch 'main' into dev/t-andreamah/markdown-static-preview-scroll-state 2ab6e9cdd26 Debounce invoking the inline suggestions provider 99be6bad750 Add a command to hide the inline suggestions 62bbbcc7bf4 Remove log 875ada9bfad experimentalUseTitleEvent -> titleMode 76154be4d4b Truncate Windows path from sequence, do title handling based on remote OS 8a6cc9cba7c Fix dynamic title for reconnected terminals 74849362b2e Render only one line of ghosted text by default 713d5861404 :lipstick: less casts 1718a6e2ac8 Hide hover on target element(s) click 224b0f22922 Fix category and max-memory option args 5ae8db2ae0e Render the suggest widget above when rendering a multi-line preview 8c194abb5e7 Do not shrink the additional lines once a shorter suggestion is displayed da4fcc266fc file working copy - avoid ugly casts aea7c1a3343 Merge pull request #124196 from microsoft/tyriar/dnd_2 e538fd90c0e Hover hover when context menu is shown 4a679df5312 Hide ghosted text when it wants to be displayed in the middle of a line e91d5475acf Merge remote-tracking branch 'origin/main' into tyriar/dnd_2 c6d2254b2fd Create a `InlineSuggestionsSession` also when showing suggestions b5a9a026068 Invalidate current suggestion based on cursor position 49339aba513 Only start a session after a content change (with debouncing) fdbcef0a842 Add `editor.suggest.showSuggestionPreview` to turn on/off inline suggestions c8410ece147 node-debug@1.44.28 234136b6c28 💄 acceptsNonWorkspaceFiles -> acceptsOutOfWorkspaceFiles 91bf9326334 fixes #123469 2cc3b168fde Do not force the instantiation of the `SuggestWidget` 1543754dcab Tweak loose file dialog warning 669b0b3f719 working copy manager - clean up some types add some new APIs on manager2 for unified access: - get(resource): working copy - workingCopies: workingcopy[] - onDidCreate: Event 3234403c5d2 Merge pull request #124191 from microsoft/aeschli/virtualWorkspacesInExtensionView 19574448d0e Fix rendering snippets 5f7cfa3a54e Introduces a GhostTextWidget model to enable data binding. a6f89f58a9e Workspace trust - empty workspace (#123811) 0c996a39b65 Implement consolidated output toolbar f583b4b3367 Merge branch 'main' into notebook/dev 29c61570a5b Revert "Closes #122433" 34180ac9bef Remove code allowing multiple ids for a command 35eafb78732 Add sort imports command e65a227c829 Test using readonly[] syntax in vscode.d.ts 1ddc623e585 Simplify logic for webview resource uris (#123740) 93be0a6fa03 Update simple service 46a1ca78249 notebook: initial renderer communication 1ecba0426a9 Make `reload webviews` support webview-views b3ed595dde7 Extract isRequestFromSafeContext 39d1a94e86f Allow loading svgs from xhr 4fbd548d72c Merge branch 'main' into dev/t-andreamah/markdown-static-preview-scroll-state 40592a274c9 fix test suite. 4fcc2720826 use custom shield dialog #wt a65d55e9c48 Strict null fixes in webview f822083cb70 Check `defaultPrevented` before showing built-in webview context menu f594bb47e59 removing more unecessary whitespace 41606da2dc0 removing unecessary spaces 920c9a3a0d5 improve banner for virtual workspace 9ee1906718d pr feedback and combining prevEditor info for preview and non-preview f433b4781a0 Pick up TS 4.3.1-rc d921cc41fc0 Update markdown grammar 1642d4cd0ad Merge groupBy and groupByNumber utils Fix #123569 c1d6e44262e Avoid listener leak warning due to reusing cancel token for many RPC calls 0d338068034 Add suiteRepeat test util 5b3cf7cc2ae Merge branch 'notebook/dev' into main c936add6013 hide kernel status bar item if it is already rendered in notebook toolbar. b8c7d75e465 Avoid illegal line numbers in case of undoing a completion at the end of the file 63348b4a395 Improve contrast de89605adfe Do not invoke provideInlineSuggestions when just moving the cursor 08f4a36de15 notebook toolbar container display none by default. 6956a38b674 Have the `InlineSuggestionsModel` listen to events directly 26194faa8be fix focus indicator default value. 2fbf0cd977e Respect the suggest widget only when there are suggestions 8c27c1f257b Update list focus highlight color in standaloned editor Refs #123703 0ec51535fa2 Rearrange actual group splits, not just instances 25bdb018483 Add theme key for terminal dnd 15f772fae32 notebook: include script url in back compat patch b79825e7c4e Clean up a3e72ce1d06 Reinit dnd observer after reattach 72b01fea379 Avoid selecting accepted text d7f6d7e735d Fix markdown cell drag indiciator having wrong position in scrolled documents de1c8ad93a9 Give clearer names and add comment 40a26850575 Fix shift for markdown cell selection only selecting current cell 3c417665643 Fix strict null errors in webview main b8a0123cfc9 Fallback to fetch if localhost resolve fails f0ef8dfd913 Add explicit null typings c63ac2f6388 Use searchParams to get id c13c6d8e468 Throw error when trying to reload/navigate within a webview 05f83d95d2b Fix issue reporter not debounce submissions (#123340) 8e87fea2f15 Support dragging to unsplit 40fbf5d915b insertToolbarPosition e071cefa4df Support creating splits in different groups f1a372c15f8 Support rearranging splits 2b30689ab00 Close #123935 25a12c75c5a use dummy uri 568bb89fadb Merge remote-tracking branch 'origin/main' into tyriar/dnd_2 5266a5fae3f Improved hover feedback 44d135e94f3 Merge branch 'main' into dev/t-andreamah/markdown-static-preview-scroll-state f4e05837d01 Remove custom height, use default from menu service #123869 134d9b187bb Closes #122433 a796ebfb8b4 update actions column width #wt f36c7a0860b Terminal dnd feedback 3804c98d6f7 fix padding for table #wt 5442f154ef6 fix issue when not connected to remote #wt 6356613d809 Update according to suggestion 49187c4e785 Replace flush with setFlushOn with loglevel info, fixes #123856 45e5c50dbfd Partially implement terminal drag and drop 283180b64b2 don't show action icons all the time wte 9716c27e068 slightly better uri for untitled notebooks, https://github.com/microsoft/vscode/issues/121974 1256b258a6f Honor the selection suggestion in the suggest widget (when it is visible) d553c21d5e0 fixes #123869 52c8fced385 focus indicator border or gutter 81c6572671c added default editor override for symbol reveal 9326ded502b show extensions limited due to virtual workspace b02acf39081 Merge pull request #123738 from microsoft/dev/mjbvz/unify-renderers-api 284c21a588e tweak terminology for wt entries 9a322a0d62a use folder terminology due to windows/linux limit dc8844925ab Part of #122996 b63ad124d2e mark untitled notebooks as dirty by default, don't hold on to untitled notebooks eagerly, https://github.com/microsoft/vscode/issues/121974 09ab8ad2029 wip eaf5a49200b status - update description of `name` property 1f912dfa3d5 Fix #123617 ff6d8771c94 fixes #124085 88d9a3aaf5c Support command links in trusted tree hovers Fixes #123723 eb5874237eb Improve task terminal status message Fixes #124062 53b58c89d44 Fix loop in port forwarding 37a11814295 do not include non configured deprecated restricted settings 53352a29540 add API to open an untitled notebook, https://github.com/microsoft/vscode/issues/121974 b7058688ad3 Fixes #124143 a0819ed4fea Add ending period to --sync faa3146a310 Add ending period fto prof-startup 159479eb5ae Allow to show status bar entries with an id and name (fix #74972) f23f011f552 untitled - clarify resolve methods 734b79dadae fix #124102 08618458110 fix ExtensionRecommendationsService test (for #124119) e5bf21393bf Additional navigation keys 99f3a3726eb Additional details in the aria label 06ee4764a4c untitled file working copy - test :lipstick: 1cc2f71a1ff untitled file working copy - tests for new unified manager 8c6db097ac7 untitled file working copy - add new manager that unifies file and untitled working copies bc37b284431 untitled file working copy - shared dispose handling 0d92cb9dd88 untitled file working copy - poperly resolve target 37fbfa61251 untitled file working copy - set visibility 5835fbc9f1d untitled file working copy - some code :lipstick: a47fc96766a untitled file working copy - fix tests 1edef157350 untitled file working copy - wire in save support 8173bd132fb untitled file working copy - add workingcopyservice#get a3ee06b3e03 untitled file working copy - extract common super type for manager 02c72e2bd64 untitled file working copy - extract reusable interfaces 44dec56af8c untitled file working copy - :lipstick: 103ba104a56 untitled file working copy - tests 9f990bbb6ec untitled file working copy - first cut manager 4173ced659c untitled file working copy - first cut 825f6c7ab84 valide URIs created via from, https://github.com/microsoft/vscode/issues/121198 b1349b64a64 update color registry names for inline values 677f2a3be12 remove excess whitespace 0e4159cb7aa fix localization key/description for debugInline colors df308a9a81b add color customizations for inline debug values a9c5e37ea0d fix #124102 c5611075cad fix ExtensionRecommendationsService test (for #124119) 501b691dd06 Additional navigation keys 6034e35043e Additional details in the aria label e878f5a3ee4 Add support for untitled file working copies (#124120) 13aff6aa7d3 untitled file working copy - test :lipstick: a48180b6e6d valide URIs created via from, https://github.com/microsoft/vscode/issues/121198 f22eb7ee29d untitled file working copy - tests for new unified manager 5f6d4786857 Merge pull request #123065 from nrayburn-tech/120936 2ecf53bf79a untitled file working copy - add new manager that unifies file and untitled working copies 32d4df9b823 untitled file working copy - shared dispose handling 3a1b950c147 Merge branch 'main' into ben/untitled 97518f5e869 Copy testRepeat helper to extension integration tests 721cdd6472b Fix data loss when renaming custom editors (#124057) bbb89b86f56 remove hover bg color on notebook toolbar icon. 8f140828107 fix mouse click double background c59f782cc7d adopt table widget for workspace trust editor 616e0fd9927 refactor: polish 4815c9e9954 fix notebook toolbar scrollbar a069768c9b6 Remove disposing of editor input in override service 0026416a7ea move showDeprecated suggest to be a CompletionOption option 2a9f02348f6 Make notebook toolbar cell visible on click (change notebook.cellToolbarVisibility default) df93e53dfb6 Merge branch 'notebook/dev' into main 4486788c81c allow the left toolbar to overflow. d501abe922d contribute actions to the toolbar. bf9f6837d14 NotebooKernelActionViewItem accepts notebook editor widget. 9063312f9c1 keep ref from cellVM to outputVM for now. 5913c5b070e Merge pull request #124125 from microsoft/tyriar/join_terminals 9b1ba3f31f0 Adds Memento.keys #87110 8b726fc9f51 update color registry names for inline values 25873bb34c4 Adds Uri.from #121198 5c4fae91762 Merge remote-tracking branch 'origin/notebook/dev' into dev/mjbvz/unify-renderers-api 79bd573d9e4 Move OpenIssueReporter api command registration out of extHostApiCommands (#124068) 73cce9a080e Fix vertical terminal margin left/right e657d422814 debug: expose parent session on DebugSessions 25967171f17 Delay workspace recommendations as remote extensions installations are ongoing For #124119 b84a8c4215a Re-enable selectionNavigation in terminal tabs 84c23ab5bd7 debug: bump node-debug2 version b3c56f52813 testing: bad rendering of inline decorations for markdown messages 2bc36bec9dc breakpoints select on stop 71f4934a0c6 use enum 21e0fab8b87 Don't show join in command palette 1243a51d59b Support join terminals 4e7029f593b workbench web api: builtinExtensionsFilter 34775b7d660 add requestOpenUris api fc76d8b6b44 fix #124113 455a8b6949b List focus colors are too dark (Fixes #123703) aee486cd293 untitled file working copy - poperly resolve target e02714b5775 Polish for some workspace reuse (#123519) daaa8a98bf3 debug: focus breakpoint on debug stop f113243a516 Close and reopen tunnel when protocol changes 960af85cd93 Reduce number of calls to get port attributes fb9d3f3e501 Fix all ports showing as user forwarded 4726abdcfa8 explorer: do not remove dotes at end of filenames before validation 026e6239be9 Merge pull request #123895 from danielgary/wmic-replacement 8f78655dbe3 untitled file working copy - set visibility 615bb082c11 Tunnel -> Port 0f5ceb2f1db Add context menu for tunnel protocol Fixes #123750 414e5dbf1f8 install additional debuggers only when at least one debugger present 1c6e481373e untitled file working copy - some code :lipstick: b0272010af8 Disable bell sound completely f3cca6236e0 remove todos about ipynb cell ids 3f6e29238c5 Show status icon in tooltip f8054f260ee Merge remote-tracking branch 'origin/main' into alex/ghost-text 2d80cb75c4b Fixes #124038: Render a `` for each `::after` decoration at end of line cdeaebbd3be Show info terminal statuses in narrow view 3467760399e Merge pull request #123867 from hediet/hediet/fix-123178-leading-ws-in-wrapped-line 71e729d1222 Merge pull request #122785 from tejasvi/patch-1 1b591be32b2 Merge remote-tracking branch 'origin/main' into pr/tejasvi/122785 49ded4d7e11 Fixes #122825: Dispose proxies when the extension host terminates 7c07550dbc5 Log errors encountered during deactivate e4159c8f892 Add protocol to portsAttributes Part of #123750 b2c32980765 untitled file working copy - fix tests b94b2d2cf01 untitled file working copy - wire in save support fe2761a026e untitled file working copy - add workingcopyservice#get 956347c4edc better logic for "notebook open/close, notebook ready when cell-document open event is fired", https://github.com/microsoft/vscode/issues/123655 191ebfabe65 Merge branch 'main' into notebook/dev 2f2f8d7b0f4 untitled file working copy - extract common super type for manager 102433ffbef untitled file working copy - extract reusable interfaces 27d250fa0da Merge branch 'main' into ben/untitled 07cf22f6814 Fix ctrl+enter in code cell editor 45aafeb326d fix #123816 fd7d84a392c Merge branch 'notebook/dev' into main d51c7f66306 add experiment global toolbar. 079be5f0fd6 remove run all cells constraint 0031e783518 Store tab list width in global storage e270ff06255 Make default horizontal tabs width 120px 1bd7c329fb2 Move tabs list size constants into const enum e0ff23866ad 💄 49870fb9fca More accessibility improvements 47c96324ba6 Banner accessibility improvements 7c4a2cb6cc6 Add args to source profile schema 2bf81674ee7 refs #123976 a3fe790a45f Explicitly flush OutputAppender #123856 2c91cc8a7d2 Clean up decorations when hiding ghosted text ac85998e016 Pipe language edit counts into CES survey (#124006) 22350f3dc54 Change the order for ghost text decorations (use a class name that sorts before) 9916815a187 Merge pull request #124039 from microsoft/tyriar/121278 74372fe5663 Fixes #124038: Render a `` for each `::after` decoration at end of line a1646e35c36 Remove try catch, clean up 6353aaac13a Share code between dispose instance and remove instance 9719ae6e725 untitled file working copy - :lipstick: 1371a8e0d49 Bulk-edit veto dialog use the correct reason 327690a3cb9 Unsplit terminals 32db232a53a Scaffold ghost text 63b6e6c51d7 untitled file working copy - tests 45769b83189 debug issues assign to Andre f2640c349b0 untitled file working copy - first cut manager 38dda41eaa0 Merge pull request #123474 from microsoft/tyriar/local_wording e8dbf0cc9a1 Improve wording, separate for remote and virtual befed354684 Merge remote-tracking branch 'origin/main' into tyriar/local_wording 509926497c8 sandbox - make CLI commands a native host thing (#123899) dc85211b159 untitled file working copy - first cut a6db2795e36 Fix elevateIfNeeded port attribute Fixes microsoft/vscode-remote-release#5065 736896527ce Improve npm trust message d4ca8b7f3a3 icon contribution: add requires (for #117437) b2273e80745 Merge remote-tracking branch 'origin/main' into main d8b70e74a88 cleanup link styling 46596757d41 fix icon contribution id validation (for #117437) 9ef2514d701 Merge branch 'main' into pr/121835 aad39f1ea63 untitled editor names :lipstick: 7320c8514c9 status bar - fix compile errors 381e7c2d0bc status bar - use secondary priority as sorting criteria (#123827) da374067139 state service - do not log expected file not found error 82767cc1d7b add aria description for workspace trust editor refs #122537 cfa977755b1 fixes #122537 5a5d1bc91f8 Add provider label in auth menus (#123922) ff59c24225a fix #123709 87476adaee7 Merge pull request #123919 from jeanp413/fix-123892 217261cf739 Mitigate #123856 055319001c6 Fixes #123892 802ba30de2e allow managing workspace trust from extension icon f3277a1e1e9 fix markdown editor position for compact view. f0e57a781af fix #123819. 12f273e3e07 fix #121056. 6d79421b349 Merge branch 'notebook/dev' into main 7b9bb17ce56 refresh styles after kernel is changed. e5c7b899cf1 compact view. d0b6c2d2276 fixes #123858 40d5e6796fb fix #123700. baccddcd459 Use Windows mode if build # is <= 19041 (#123725) dcfdc8d2e4e Merge pull request #123429 from jeanp413/file-drop-terminal-tab 18313e82b00 update markdown folding icon padding fcde284705f Merge pull request #123246 from vibhavsarraf/terminal_link_normalize_path 109f7feb3b0 Trim leading ../ or ./ from quick access query 4e79908dcff Merge remote-tracking branch 'origin/main' into pr/vibhavsarraf/123246 42b1e81d5d5 Merge remote-tracking branch 'origin/main' into pr/vibhavsarraf/123246 e5f3dd9ef82 simplify default view styles. f4691de9552 remove legacy comments. 1ccd6a07946 Merge pull request #123910 from jeanp413/fix-123891 36e2b3176ee Update distro c492f13efc4 xterm@4.13.0-beta.1 dff22a07121 Fix double border on vertical splits c33420d9872 Fixes #123891 8c0ba0b5d79 [remote menu] add command Install Additional Remote Development Extensions. Fixes #123905 6510b614c10 Consistent casing for `Install Additional ...` quick pick entries 22d7f210f79 Fix full path flashing in terminal tab 4946fee0dd1 Alt+click to split single tab f8a3cef533f debug colors: compress css selectors 828e83defca Merge pull request #123726 from suzmue/hoverText 0f7439bf2e7 Middle click to kill single tab 09b77ba6d8b added comment and removed empty lines 89b4b6c90d1 Replaced wmic call with windows-process-tree c6525283099 Remove dialog in ChangeLocalPortAction Part of microsoft/vscode-remote-release#4958 c8b4656197f Add requireLocalPort property to portsAttributes Fixes microsoft/vscode-remote-release#4958 6aec850c759 Multiroot workspaces on Windows with forward slashes are treated as relative paths. Fixes #123871 27966a2521d Merge pull request #123833 from gjsjohnmurray/fix-123831 b540874d21d Incorporate task terminal status feedback 67133f048d5 Add tooltips to task status Fixes #123730 544620b527e Fixes #123178. Sticky tabs no longer applies to leading ws in consecutively wrapped lines. 1a78b7359eb Add drag and drop controller (#123542) 2f500f0ce56 editors - wait for whenReady before accessing groups 5246162662f Fix tasks in remote Fixes #123862 6e667a66e11 Use `getOriginalUri` in editor tabs Fixes #123664 79bd687e15f [Object object]: Open Workspace Configuration File (fix #123837) 111b0dbb658 Update default image in README 7771be8b981 Fix #122622 d17d7ca46cc chore: bump electron@12.0.7 813deed41cc Fix #123820 302c638e305 Allow overriding walkthrough when clauses Fixes #120112 c3253befc05 fix #123831 handle command URL in ErrorResponse Message from debug adapter 7e037f8e8fc use details message in UI e27581cfaf0 Merge pull request #123782 from microsoft/robo/update_node_pty 839871bef23 fallback to default wt value ae6ba8f980b undo random change 17fad7e42d5 random change to pipeline 94498778fb1 cleanup b846e309fcf update classifier integrated-terminal -> terminal 0f0e5cfe91d Merge branch 'notebook/dev' into main 0099c58039c Merge branch 'main' into dev/t-andreamah/markdown-static-preview-scroll-state 13c1c37c974 fix build 17e077aab23 Update secrets doc string, fixes #115252 35917702399 related to #123762, check for windowsExec in settings e7e57aa0cf4 Ensure data event is reused f9df7b2f1a4 Merge branch 'main' into notebook/dev 8a2157f3e9c Merge branch 'main' into dev/t-andreamah/markdown-static-preview-scroll-state 9731995d946 addressed ! nit f5df5fb1970 Open normal editor when opening a non-vscode settings.json Fix #123795 5b13f40b47d Remove NotebookCellExecutionState.Idle 3dec3b3385a applied PR feedback 478ec15a800 Fix #118575 289f739c0c3 findList -> widget 6df6fd01e74 fix #123710 36e652b5aea fix #123776 005b8b8d2c9 fix #123762 7f6e9538c61 Move disable extensions section higher in bug report template, fixes #110474 a9c444a6055 🧹 9bc642fa228 files - validate readonly flag in some operations 5987414a764 Support default profile intellisense d369789eae2 chore: bump node-pty@0.11.0-beta7 2cdbfe3724a Add exception label color for multithreaded fc181acc00d Support profile icon intellisense 1957af4f99b Support overrideName in default terminals 8be52b214e0 Update distro c185bff4005 Merge pull request #123729 from microsoft/tyriar/getprofilesexthost 006be3ffb69 chore: bump node-pty@0.11.0-beta6 9a002ccef2a Fix windows profiles test 5d95c01ec10 Remove getDefaultShellAndArgs from tasks da1df62ee5b Don't go to ext host for task default shell/args 303519568eb Log actual vs expected profile names in test fd07b80c45e Reduce profile throttle time to 2 seconds f25ff2a5c3b Clarify profiles ready barrier 66d817c3cc4 Simplify resolving of text 10ad00891da Bring back TerminalSettingId usage in platform d7b70a6fdb4 Remove workspaceFolder from profiles, included in var resolver now 2373db009ee Replace configuredProfilesOnly with includeDetectedProfiles fb991820c94 Revert accidental change to git.png 09d22f9bbb3 Remote ext host ready from terminal service c3bdf6c825d Removing logs/comments e1dba2ac020 Merge remote-tracking branch 'origin/main' into tyriar/getprofilesexthost c4f3f8f9bea Change in the optional Custom Editor makes the raw file open (#123057) e02dfbbcab7 workspace trust - remove async from showing editor pane 23dc403a178 [Insiders] Throwing error when a file is edited and saved from a diff view (fix #123756) 659175fa39b Fix up merge issues ea39e2b66ae Allow text search providers to give messages with links that trigger researching. (#123213) 66fa5c41b3a First cut at unifying notebook renderers apis 0988e056b2d use mode terminology in viewlet 2b8d74c4a82 Make metadata/internalMetadata non-optional e10e3f417e4 Clarify deprecation message 4c63cdf2fa5 doneOn => completionEvents implement onLink, onEvent, onCommand, extensionInstalled, stepSelected ref #122570 1f2077f7e63 improvements to unsupported workspace ext filter dfb8c467ca8 Separate extension metadata from execution metadata Fix #123235 21bb657ce24 :lipstick: 87f053cea66 cell toolbar positions 6d70e727d08 Set default profile in exthost from renderer 1fb3175fb27 Merge pull request #123728 from microsoft/merogge/rightClick d2894562d57 fixing issue with static scroll alongside text editor ada851cc72b separate markdown and code cell margins 963eff6d063 Update distro 1816095148f Get remote profiles working 9d3f61bbb74 fix #123694 27dfcd4677b use editorErrorFg 6673ba9c464 use button theme colors for selected trust state dd54e2b24a9 Wait for profiles before creating first terminal ee4510b4bf7 Merge branch 'main' into dev/t-andreamah/markdown-static-preview-scroll-state 18950181eba scroll state persists while toggling between static preview and text 939204bb3a6 remove check for .debug-call-stack-title 34e17a20c7a update call stack label in css c5a8e59db78 update notebook contributions. a41b51ab3f2 update notebook contributions. dd7102dfaee update distro a37ee2baf1d Merge branch 'notebook/dev' into main ae751048e4a Enable changing color of terminal tab icons (#123596) d1dfa8dd2b8 Fix setting hover text for stopped event 11a8c4b4bc7 Merge the notebookMarkupRenderer contribution point into the renderers contribition point 09bd8496616 Remove todo comment b61721e94d6 trying sync editor input api 3def280fba0 update kernel view item when affinity or binding changes bfe88ab4641 Revert "workaround #123676" d4625bda3c9 wt enabled e555768cd74 remove old extension point for notebookProvider 9e199766c8a Revert "wt enabled" 2ea518ea37e testing: improve current test filter and welcome experience a823e975ba8 testing: use stop instead of cancel icon 6e1d69258a6 testing: fix button size 1ee54f7ff0a wt enabled a2f7ad10ca5 Try better fix for loading mixed local/remote notebook resources (#123638) 2e2dc159451 Get profiles detecting on pty host (local) 2f2ca2ea192 more trace logging, https://github.com/microsoft/vscode/issues/123700 dd924d774ff Remove leftover trusted metadata references c6beaef489d added logging for https://github.com/microsoft/vscode/issues/123700 e1009bfdcf5 wip 2f282bbefb2 Log which extension creates what controller when, https://github.com/microsoft/vscode/issues/122409#issuecomment-833448914 d1b73271581 kernel action view item shows icon _and_ label 22fc27d4cf7 Closes #123674 dbc2166e56b Fix #123360 a53919b8e92 Fixes microsoft/monaco-editor#2466 1f76da28f6a Fixes microsoft/monaco-editor#2355 20d4467d997 Better handling of escaped @ in monarch (microsoft/monaco-editor#2424) 39ee13c839b Add JSError renderer, experiment with NotebookCellOutputItem#error-factory function, https://github.com/microsoft/vscode/issues/120063 37a12c9b084 Merge pull request #121557 from ValeraS/fix/safari-media-query 2abf8d37792 Introduce `addMatchMediaChangeListener` with support for Safari 13.x 8daeff32527 Fix imports c148a2fd919 Fix layering 6c476279f16 Resolve variables on renderer 95dee5b5baa Fixes microsoft/monaco-editor#2345: Add support for browsers that cannot parse regular expressions used for the SnakeCaseAction 0a2f87623d5 Restore behavior of `BrowserWindow.setupOpenHandlers` (see microsoft/monaco-editor#2474) 579cf91f0a0 Fixes microsoft/monaco-editor#2474: Use 'noopener' when calling window.open 80308b93d9d Fix typo 51803eabffd Expose `ITextModel.isAttachedToEditor()` and `ITextModel.onDidChangeAttached` 5ac3eaeaf6a Fixes microsoft/monaco-editor#2396: Add an option to opt out of the usage of shadow dom inside the editor 608d03bf72b Fixes microsoft/monaco-editor#2409 fd529498f0e Typos in tunnelView string Part of microsoft/vscode-remote-release#4958 d13f5feb43d fix npe 3146c54bf38 Use dialog for change local port mismatch Part of microsoft/vscode-remote-release#4958 f9dc6969605 browser url service: hook up to opener service 1379ca20335 extension url handler: fix missing gallery baa0a2890e7 web api: expose uriScheme and openUri 3c6377db030 Cannot drop a *. ply file into the window (fix #123496) 84abba8754d Clean up 31e3f5d16d9 Merge remote-tracking branch 'origin/main' into tyriar/getprofilesexthost 64e707842e6 workaround for https://github.com/microsoft/vscode/issues/123667 9553ccbe6ed workaround #123676 096d9cde615 fix https://github.com/microsoft/vscode/issues/123665 b5702a305a8 mark 'text/x-javascript' as always secure because we only render it 12808be8383 Merge pull request #123293 from hediet/hediet/fix-wrapping-left-navigation d8e2bee4b46 First cut of special action view item for kernel picker command d81e6f58b20 tests - cover working copy backup discards on shutdown behaviour a13da59f955 Fix #123621 76c56905934 tests - avoid real text editor in tests 0a14a26cd39 rename latestExecutionSummary to executionSummary 793a123a815 Allow FileSystemProvider to stat a file as readonly (#73122) (#111237) 0b3618c6e99 fix integration test a396872d66e Merge branch 'main' into notebook/dev d785c83fb95 Make unsupported check case-insensitive 1e8d96dcc17 Dataloss when closing Code before it fully restored with dirty files (fix #123636) 08b559fd96c Refactor markup renderer in backlayWebview to be more generic cb8a322e5cd cell editor bg color should not affect toolbar. caad0a943f6 compute markdown indicator height d026aff522c file working copy - fallback to backup when saving from destroy 84c4dfbdc95 Don't expand arguments 5c22e55a745 Disable broken smoke test #123621 b847eb35e7e Add remote-authority to webview uri 5537a8a9c48 dispose notebook options. ddf02aee487 compute webview options. 3cdf41aa1c6 compute editor padding. 927e791753c Fix Initial Scroll Position on Markdown Dynamic Preview (#123613) 662cdc5e847 move cell toolbar location setting into notebook options. db0cea611b8 fix cell toolbar position for hidden. 36e8f2b3019 extensions: don't use named regex groups to avoid build err 46a57578347 add cell status bar configuration handling in notebook options. 04398f16e80 ViewContext for notebook options and event dispatcher. 3439958ed11 bump distro 3ef8ea56b62 extensions: allow date-based engines constraint 32525336620 compute editor width. 28cc8e8aab0 extract common layout calculation code. 65aa0c2630a :lipstick: 55888553df9 use stylesheet text content other than insertRule as the DOM node might not be attached yet. d4e6b16a634 move layout constants to notebook options. 05d4a5c56d5 skip test. eb6e048ca39 Merge branch 'notebook/dev' into main 6dac1365fc9 Notebook cell editor background color. bf24ab16e0a refs #123521 ec4babc1987 Alt click + terminal button to split (#123531) 7259955ce31 Do not invoke `resolveWithInteraction` over terminal settings (#123590) 5f3466a21e8 Change grunt, gulp and jake task auto detection to be off by default (#123588) 4151b62cfa0 update seti contribution guide c24aad5bf2d Fix issue with extension enablement 86bc05155f8 update seti theme 900a028d27b Extension enablement fix 000e064e618 Bump hosted-git-info from 2.8.8 to 2.8.9 in /test/smoke (#123481) 9b422e7fa54 Task terminal status tweak Part of #121659 78c2627b938 destroy working copy manager when view type is removed b58a33aba77 Merge branch 'main' into notebook/dev 69108a528a6 better isNotebookCellOutputItem-check c144a884d1e file working copy - let dispose unregister working copies (#123555) 62df795920e working copy - add has(identifier) a0ce27feda8 Update spdlog, use lazy initialization in extension host (#123033) 27af37c2d31 :lipstick: working copy backup discards 016c6c89709 Update distro ec9025be0a2 Include useShellEnvironment in shell dto 7ad261890f4 :lipstick: 4963e05b0d5 Remove loading icon from task status Part of#121659 f07201bf559 close notebook editor when extension goes, e.g extension host restart, https://github.com/microsoft/vscode/issues/123563 2a39f1f6391 Add terminal statuses for tasks Part of #121659 50d78f15850 Simplify transition code 1e810cafb74 The default Monokai highlight color is displayed incorrectly. Fixes #123044 04491348e0c Merge branch 'main' into notebook/dev e73447e4363 Move banner theme colors 7722872fa1a simpler onDidChangeDiagnostics-event c99b670267b make sure to invoke onLastListenerRemove when disposing an Emitter, https://github.com/microsoft/vscode/issues/123487#issuecomment-837160646 e5ae100f2ce fix state tests 07299c900bc :lipstick: 4ed31ca457f introduce DomEmitter 5eff4500bd4 more jsdoc f41b6e6d813 Add active editor to editor tabs and use in variable resolver (#123450) 102b3b410ef fix tests b6a7db06de6 Workspace trust - restricted mode banner (#123110) 812217d43bc fix compile errors (our watch task is not reliable?) 42730e3c66e state service :lipstick: a37e34a9c9e rename extension point to "notebooks", fix default value, https://github.com/microsoft/vscode/issues/121819 87452fe2b93 state - rewrite state main persistence d5ab22d7dbd test that no RPC leaks via NotebookController e1a01761fdb more :lipstick: for docs e1ac8a6223c add openNotebookDocument, onDidOpen-, and onDidCloseNotebookDocument to finaliztion list 4177014a1cc Revert "Put authority into webview resource uri" beeaa3675cb Remove only 9f0fe65c77e [Getting Started] Allow for localized markdown files Closes #123538 3d978d4ddef Put authority into webview resource uri d60cbb0eae2 Pick up latest TS nightly for extension 368c86c3f66 Don't hide tabs view until the mouse leaves it (#123500) 6c9f17152ca save tabs width in vertical and horizontal terminal panel positions (#123516) 4eef854ab47 Revert "Move bing settings to its own stage (#123504)" (#123523) ae998a9261a Merge remote-tracking branch 'origin/notebook/dev' into main e70eb682c51 Only use --login for bash/zsh on macOS 2bcb8dfb641 add workspace trust required editor (#123181) 0b810457658 fire activeInstanceChanged when active instance is set and more migration from terminalTab -> terminalGroup (#123339) 36416c8236f Merge pull request #123502 from microsoft/tyriar/layout 07e7ecbb991 Fix integration tests 62c97558865 Move bing settings to its own stage (#123504) 387012dab49 Remove container from instance ctor 39c4261bc50 Clean up 5b58db6d75a Add hide option 99b3724c1ee Fix #119620 1d1b902c11a Improved terminal layout fbb11a9bf7b Fix #122621 254c7dc359f Syntax token inspector doesn't show font-style changes caused by semantic highlighting. Fixes #123299 05d22c68531 [html] duplicated onDocumentRangeFormatting handler (#122994) e0065d42594 state service - harden the save code to try to prevent issues 8e6f4a3185c Fix markdown cell context key service warning. Previously the CKS was leaking 1199d1ae0ff jsdoc tweaks https://github.com/microsoft/vscode/issues/122647 75640e9788d remove unused function, https://github.com/microsoft/vscode/issues/122647 0449a18b7bb cache layout calls to grid views e0bf13685ce grid: latch view.onDidChange events 559dae41ad2 jsdoc 61129b2897d file upload :lipstick: fbe3d1eeb91 Make PortAttributes API a class Part of #115616 08c9a930424 Improve local shell wording 0148fdfc35f Much more aggressive setting conversion 3015e285e4d web - upload up to 20 files in parallle to speed things up 8c630ac16e6 Move split terminal back to terminalActions a1e4f1b91c5 validate NotebookCellData before passing it to renderer 8de5c819a1e Add test for C# grammar but Part of https://github.com/microsoft/vscode/issues/123333 66eb516dc3a Revert C# grammar Part of https://github.com/microsoft/vscode/issues/123333 6ac37fcd3ce implicit kernel selection upon: hover, notebook change, cell change, https://github.com/microsoft/vscode/issues/122647 d90709f3ee7 Auto detect scoop git bash paths 2fae6ffacd4 Do port finding when there's a tunnel provider Fixes https://github.com/microsoft/vscode-remote-release/issues/4923 2fc3214ba42 Fixes #123083: Localization: starts with 'DE' locale and verifies title and viewlets text is in German a399a894df0 let getMatchingKernel return selected and suggested kernels, https://github.com/microsoft/vscode/issues/122647 0a4d4563b8e Fixes #105730. Word wrapping did not work well with left/right cursor movement if there is a selection. 27fe7f9dfb0 Revert "Add an "always" options to port source setting" 04ef7cb9855 Merge pull request #123294 from hediet/hediet/fix-link-detection-121438 5d1370af495 file editors - move the input to the editor (`browser`) 06fa8b8543a API :lipstick: for NotebookCellData 4bcf463bc04 explorer - have "Download..." first a02047d7068 remove notebook selector because it isn't needed anymore 4089f9c660d :lipstick: use {}-syntax instead of Record, https://github.com/microsoft/vscode/issues/122495 38a62d50f64 Removes 《, 》, “ and ” as well, as there are urls using these characters. 7ea5b137eaf rename cell kind Markdown to Markup, https://github.com/microsoft/vscode/issues/105933 133ae5ecee8 explorer - consolidate upload/download code and provide a "Upload..." action (web) 2a824d80cc2 editors - adopt working copy handler for files dc8155a3bee editors - adopt working copy handler for untitled 7a004c69735 Bump hosted-git-info from 2.8.8 to 2.8.9 (#123320) d3092241f6b code editor - move untitled hint contribution b9c5d61dfe7 Merge branch 'main' into notebook/dev 7bec90ca469 editor group - inline `doOpenEditor` 94ab53c9b52 adopt working copy editor handler and remove custom editor input factory (#123308) 62090020c19 Add support for file drop on a terminal tab Fixes #123348 54d33cf14cf fix diff editor reload on content editing. 5979135dbe7 Fix #123342 1831d545071 Workspace trust transition participants (#122727) f75ade6e431 Add showDeprecated option to suggest, filters out deprecated options b55b12fac63 Handle onDrop within TerminalInstance (#123329) c113cc74d66 Adopt @ link inside mode.ts (#123198) 029a54d087b Fix #122680 4f444950637 Fix cell statusbaritem tabindex d97beb35889 Fix focus mode switching flakiness Fix #122594 2ee59df71eb always create the artifact file b987317d1a0 Rename onDidChangeNotebookCellExecutionState a945921fccb update artifact name a92c3660b29 Keep process explorer window on top, fixes #120391 4a76f0b19a6 registerNotebookCellStatusBarItemProvider should use viewType instead of NotebookSelector Fix #122347 403723c4f97 allow focusing links in custom dialogs refs #122537 d61f87f2926 handle multiple retries in publish stage 36d9ef55640 more diff tests. 4eb5f7a7e91 Fix merge conflict 0d522390b5c Error if trying to create a markdown preview that already exists 450e5d164e4 Lookup the proper keybinding for the placeholder hint. Need to consider the notebookViewType for the jupyter-contributed keybindings, fake the focus-related keys, and also use the real editor context to get jupyter's keybinding config key Fix #122768 cd43111c9fd Don't send execution requests to running cells. This is only a basic best effort 532aada25c7 fixes #122655 536dde711fa fixes #122527 4978a1891e9 Implement GitHub Enterprise authn provider (#115940) 0f64d3a2e52 🧹 7553f47bde7 Fix #117185 - TB Icon Colours dont match the UI debug bar colours e2fe4434916 Merge branch 'notebook/dev' into main 3f431d4a857 notebook: make markdown cell initialization idempotent 04227b12669 fix #123062 110c966887a :lipstick: 0568de16a80 support multiple cell ranges. 3110c52a6e3 handle shift+enter in core. f8d610486a1 Update Codicons: Add `inspect` https://github.com/microsoft/vscode-codicons/commit/40014cd4f4415cd8aca14c50370c32346473cf6f 76334a9c60e Fix #119395, Can't report new issues when authentication providers are disabled 65553d9d7ce increase width threshold f8a40e817c0 Hide the inline actions when the width is below a certain threshold (79 pixels) 54ce4a405ec server-ready: support debugWithEdge as well as debugWithChrome 244eccdbcc0 fixes #122520 0925af498c2 Adopt EditorOverrideService for split editor #121668 900f30989d4 Merge pull request #123208 from microsoft/rebornix/verticalSeparator cfa8113ce21 WIP to move fetching profile out of exthost 82b21cc193a References view color theme issues (Fixes #123151) 996b769ca59 simplify changes fde9e2fc15c Add cancel button to manage trusted extensions quickpick, fixes #113347 a19565da7df Merge pull request #122991 from hediet/hediet/fix-99629 41a9866f4bf working copy - add a working copy editor handler for complex notebooks 5b73c885890 remove isIpad flag, use a more generic isIOS eefa92fbfb2 Fix #123297 60f2c697776 fixes #121206 ff75a560bc9 Put constants into enum. 5e3593cb164 Fix #123279 81643c948f8 HTML, CSS, JSON language servers don't provide the documentFormattingProvider capability. Fixes #122994 dbed1fbe954 fixes #122390 5cd98b957f2 update distro b41265718bf update to latest `vscode-oniguruma` and `vscode-textmate` 0afd2e6baff Merge branch 'main' into notebook/dev 25d1c0b0eba Use virtual workspace scheme in path service 2ba93b3fec0 Fix bug with respecting user setting 0ce5dec0373 Render terminal dropdown on right element when updating baca9094a0d Merge pull request #123290 from microsoft/tyriar/123128 006591a7cfa Allow default profile at workspace scope 0a39585f6a2 Bring back select/reveal active tab on instance change 98892391922 bootstrap code :lipstick: 26379b1044f Fix tests 52b3b661c23 Remove logs c6810e61bd6 Select a fallback profile as an existing profile if possible cc213fc26cf Merge branch 'main' into notebook/dev 0f477167269 some jsdoc for NotebookCell, esp for https://github.com/microsoft/vscode/issues/123269 2f53a7d8507 Have defaultProfile show up in terminal dropdown 84671392320 hide breadcrumbs at start, https://github.com/microsoft/vscode/issues/112630#issuecomment-834363944 1ab76005d32 even more strict assertions in flaky integration tests 0adef5350d0 Wait for task info before running auto tasks Fixes #123214 f7f1dbd5bec :lipstick: 6cde59f25bc Fixes #121438 by removing special case for certain bracket that would terminate detection. 6938a38d7a0 add unit test for cancellation and interrupt 8b139231bd3 Merge branch 'main' into notebook/dev 1949fb9706e fix notebook unit tests using willRemove event fa378cd02a7 move NotebookCellExecutionTask into extHostNotebookKernels, fyi @roblourens ea727e90223 output should be readonly c3e1f133cfb Tasks should use remote info when remote + empty workspace Fixes #123252 f9b5f8f624c :lipstick: b1777536686 check that a cell is still "alive" and only iff so start executing it, fixes https://github.com/microsoft/vscode/issues/123269 429fba9524d fixes #122048 95150d4443d Remove duplicated editor actions c948b662f52 fix https://github.com/microsoft/vscode/issues/123268 dbdcdecdaa3 skipped/failing test for https://github.com/microsoft/vscode/issues/123270 b2341b9cc6d run saveAllFilesAndCloseAll in setup and teardown and don't have it in each and every test, avoid usage of 'vscode.openWith'-command and prefer `showNotebookDocument`-API 5dcc4222997 Avoid having two contributions or two actions with the same id 9903550fa02 Clear maps in `dispose()` 6723972e12b fixes #121989 8ff1d4b609c Merge pull request #123112 from hediet/hediet/fix-121125 b66a9f6308e Merge pull request #123019 from hediet/hediet/fix-89888 d3ae5b9efd1 fixes #123036 7d5b672eb7c working copy - introduce generic resource working copy that can track orphaned state 6764639ce6c store extension identifier with NotebookProviderInfo 6bee0f2f3fe fix bad yml name f096c36412f Bump underscore from 1.8.3 to 1.12.1 (#123206) f24916fe995 Bump lodash from 4.17.19 to 4.17.21 in /build (#123211) d71fe81f53d Bump lodash from 4.17.19 to 4.17.21 (#123212) 2bd63c22600 Merge branch 'main' into notebook/dev 7e8942adb59 resource editor input - add tests a2ddfc3aef5 editors - introduce a `AbstractTextResourceEditorInput` for some label sharing cc3fe5a64ee fix #96715 590bbc440e2 fix #123116 (#123196) e85bcc786c4 fix #123156 e3b7e6a6c19 remove excess whitespace 5458e39c0c2 fix #123203 and fix #123117 f6996f99621 Force shell env for tasks c39a320028b Merge pull request #123197 from microsoft/tyriar/shellenv efbdc9ae739 Clean up 492262f847a Fix #122741: Change vertical positions of the walkthrough titles and close-icons to center (#122782) 1488e25b243 :lipstick: 40321932fc1 Render KaTeX errors in notebooks 96b553a1257 Fix #122463 f06159fb887 Revert "Defer awaiting the service worker until we actually write content into the webview" 34b6e934ca2 Workbench statusbar cell counter should show total cell count 1aeaf80520f Cleanup - don't use execute action for putting markdown cells back in preview mode. Instead, created a separate ctrl+enter keybinding for markdown cells 1528a24e49a Fix #122792 8496edcf549 Fix markdown cells being re-rendering too much a7e19890f4c Fix #122091 722b90c52a0 Fix #122799 68486256a55 Set access control header on service worker resource responses 0bae48f6c10 Enable markdown notebook extensions in untrusted workspaces 8c186e8f4a7 Enable notebook markdown-extensions in virtualWorkspaces acc74c75cbe Adding documentation 639b8f38945 Ensure terminal icons don't flicker when launching 49c1abb0f6d Fix #122812 e32c6b6e998 Fix #122813 feb93d830ad Support vertical separator for primary groups in toolbar. 7085e50f920 Fix #118050 f25ffb76edd Fix stopping load indicator when updateOpen completes 896a2a3562d Delete dupe cell statusbar provider 5f7422b6bba Add release stage back (#123204) 1aed1ca43bb Allow "revert file" to revert search config too 0023a96cf1c Adopt @ link in few places internally 4b2a11c5914 Fix reusePriorSearchConfiguration 074b02d04b7 Use shell environment based on setting 48ea4ea5f12 Adopt @ link in a few more places da7f681e9f3 Defer awaiting the service worker until we actually write content into the webview 294cc7e86bc Use arguments instead of string replacement in the preload script f280f4c63ef Merge pull request #97272 from relmify/more-sort-order-options d45ac504624 Remove unused 0caa2af4d14 Remove unneccesary matches 7b4ef1e65f0 Remember instance of check 3a72f1646ea debug.saveBeforeStart should be overridable by language 160544d5857 Fix text to search flip flopping 376e5fb6b49 Merge branch 'notebook/dev' into main 438c9b2d3a5 fix #121359. 97a7fab6c23 Improve utility function names 7d9a31bc7f0 exclusive => default Ref #121668 65611f1c22c Remove extra newline 6f7d8dbffbb Remove unused 9f32d376b02 Properyl dipsoe of unused editor input c6b3d1db0e4 Finish fixt for #120221 bd110cc0d4b [Search Editor] Adopt new editorOverrideService Ref #121668 88c1322a82a Fix webview views not updating correctly on scroll (#122887) 74fdb8ec085 testing: refactor actions to allow multiple running, contributions 64bd1fc65ae testing: make uri optional fd625405232 testing: avoid jumping number ca1145af4b7 WIP fix for tasks/shell env 0493df76f2b combine publishing of blobs 8991a1f97dc Switch priority of shell/shellArgs and defaultProfile setting 769afaf981c fix #123040 3a04ad79e49 Merge pull request #123130 from hediet/hediet/simple-editor-context 3d221ca3499 Better fallback logic f5b2c93911a Allow to pass `NotebookRegistrationData` when registering serializer or content provider, https://github.com/microsoft/vscode/issues/122733 a31b7b7ea8c Fix #123074 039b1d86ed5 Fix remove recent task from task quick access Fixes #122972 b6ac0e96d6c Remove hanging import 40e094c9901 Fixes #89459 by introducing SimpleEditorContext. 56a024e9e65 use assertType, add isICellRange-util f3bb41a804b Reduce editor association setting verbosity. (#123017) 093a5592cc1 Merge branch 'main' into notebook/dev 2c4f3cb9a54 fixes #123041 b7009c5b546 Add close option to several tasks Part of #112230 46a2b705831 Add an "always" options to port source setting Fixes microsoft/vscode-remote-release#4923 233a3bd7365 make sure EditorEditTask modifies the wanted model, https://github.com/microsoft/vscode/issues/122883 9a3bfc1ea1a add leak test scaffolding 9d56906e786 editors - move decorateFileEditorLabel to common place d7b9d8786c7 editors - make closing a non-resolved editor on file deletes work with any editor 6ee77a8126e Fixes #121125. 7f04fddf4a9 Merge branch 'main' into notebook/dev 192ae339e67 suggest detals widget leaks sashes, https://github.com/microsoft/vscode/issues/122668 2000f36fdef remove memoize.clear c2a303c6934 Fixes #89888. 8c5490ff59f sandbox - more lifting of extensions related management contributions 81ef603d0df sandbox - move some files to electron-sandbox that are ready 9f8431f7fcc Allow rapid render in sandbox (#122828) (#122830) fecca7b8d8f :lipstick: shutdown wording from backup tracker e9410109bf1 Merge branch 'main' into notebook/dev 2a5ba048303 :lipstick: comment 8e00999cf8b fix #123024. 0c83aaf20a3 fix localization key/description for debugInline colors 249bf465aef add color customizations for inline debug values fe23c2041f8 Merge pull request #122893 from microsoft/misolori/quick-pick-list-update 052fb6dd7fe re-add web d502a9d08db fix #122227 54a3d676b00 fixes #122598 bae81bfb738 match notification button styling fixes #122522 20a2938f3a0 pass in accesstoken into build 774e94e0aae Merge pull request #123013 from microsoft/misolori/notebook-toolbar-visiblity b5049877696 Try to block print keyboard shortcut in webviews 6d964f3154e Add explicit menu item order for webview context menu a3cddc8bc53 Fix some potential leaks related to using memoize 771a79a1cde show trustReq exts when an untrusted workspace 0eef643ce54 Fix compiling issues dc0030109b6 notebook: use initializeMarkdownPreview to avoid flickering 7c226ae1558 notebook: reload backLayerWebView when kernels change 78871c971fd Add basic copy/paste/cut context menu actions to webviews 71303fc0418 Remove custom latex css rules 2dd77412ac6 :lipstick: 17c4d6d2506 more #122668. 0aa308a705d Merge branch 'main' into misolori/notebook-toolbar-visiblity a07fdad4673 rev distro again 7f5eba22e0e rev distro 40444c3f2e5 Initial move to a Publish stage (#122886) 65a0ac67fb6 Update nb symbol highlighting for new dom structure d4dd93f3291 Make code in comparers.ts a bit more concise 97f53bb675b un-ref CellDragAndDrop. 8e97328e9a0 Add missing _register and unref on dispose. b396623ac03 rev distro 9c462604843 Prevent listeners circular ref each other @jrieken ee927cc1b89 Merge branch 'notebook/dev' into main cb31884fe7e rev distro c80a39136e5 first attempt 6367aaed066 Fix potentially unsafe cast 13d81db2500 Don't insert link element into the markdown cell preview body 0b1926db8a2 update distro ab5eff8589e use square not curly brackets ad576d73db5 Revert "Update spdlog, affects #121513" d09e71dc220 Update Codicons: fix refresh icon https://github.com/microsoft/vscode-codicons/commit/54745ba98510f372bd7dd1098cf5b43ab49d95f7 90a7d2bcbbc removed duplicates from the python tags (#122952) 42db18b5db3 update terminalService 58bcb641806 update distro 2d2de1920ba Update spdlog, affects #121513 45b0eded088 Add checks for notebook.cellToolbarVisibility 9ff7c93a9b4 Persist terminal tab icons and titles on window reload (#123010) f7ffe364a77 Merge branch 'main' into more-sort-order-options 9864cf242b9 Fix #122362 dcf5e7d23bb Update logic for toolbar visibility on click 9eef5ba58cd Add setting to toggle notebook toolbar visibility 2cf38034a3e Pick up new TS nightly b872f0323b8 Fixed picker label logic b7f72eeb181 Fix execution duration left over after clearing output b95b73b7b07 Bumps RemoteHub version 3759ecf9249 Only run upload-vscode-configuration when publishing 57b227b75a9 fix compile errors 9be6a2476e3 Combine build ext and build ext media tasks 7a1b3a84043 clear breadcrumbs when closing last editor, https://github.com/microsoft/vscode/issues/122668 e8c4f472246 Allow multiselect and multidelete in ports view Fixes #121780 04a3fb2d17c Improve creation of launch.json JSON scheme 993e71e89bf unset notebook widget from borrowable references, https://github.com/microsoft/vscode/issues/122668 dbb9eb455e1 Make port auto forwarding more sequential a8a71273d92 more :lipstick: 196c2bdac21 :lipstick: c55873ce16f remove stickys 2ec395d4934 dispose all emitters of resizable, https://github.com/microsoft/vscode/issues/122668 fbaf532211f fix another notebook widget leakage, https://github.com/microsoft/vscode/issues/122668 77ac0e55806 fix notebook editors that leak via duplicated contributions b238ac8c963 fix leaking execute menu e71b3379ff5 file input - lift some code up that is only specific to files 23a6935a255 slim-down NotebookProviderInfo f29ef0d7893 Adds link to unicode emoji spec. c98cc5cf81b dispose working copy manager when disposing serializer, fyi @bpasero b023cacd25d push a workaround for #122990 64b687b2488 Fixes #99629 by detecting emoji sequences and emoji modifiers on left delete. 5f697ad80d8 hot exit - turn progress on shutdown to a modal dialog (#122774) 77b2a5fcfca api todos d5ff9bcb459 fix region comments 8b2f0222be6 Make state service async (#122977) d930085326b remove vscode.notebook.createNotebookCellExecutionTask 9313b5897ea perf :lipstick: 3ff84bb5497 automatically convert notebook range to its internal type, https://github.com/microsoft/vscode/issues/122877 2fe990d12d3 throw error when creating an execution task for a notebook that the controller isn't associated to, https://github.com/microsoft/vscode/issues/122877 2c91a75e214 Merge branch 'main' into notebook/dev 8a41ae1d932 less openWith-command, more editor asserting, https://github.com/microsoft/vscode/issues/122851 9ddbdf449b5 get context menu to work for selected tab cdf318e1e21 Remove usages of deprecated assert methods. Have to deal with null proto objects vs normal proto objects #118667 95119a7c95a Don't trust some notebook output types in an untrusted workspace Fix #118584 58adf722d1a trust the workspace file directly ebe08a2e52b Fix #122277 - Trusted domains getRemotes call errors in virtual folder 6902f8bfaf2 Select the active terminal - not the focused one and allow right clicking to apply context menu (#122958) 6d8142e1eeb Dont override parent's instantiation service, use our own scoped one when creating query editor widget Closes #120699 48541b605fa Revert "Fix #120699" ede88300ee2 Revert "fix search editor (#120699)" d631beda227 Merge branch 'notebook/dev' into main ff1ba308e91 respect vscode open cell text document with selection. 85a007833a1 Scope standalone quick pick focused highlight c22fad1fa4d Fix php autoindent with ]) Fix #122899 68dbd890088 Remove typo 80a30a30e3f Support standalone editor quick pick changes a5f23477a7b Add codicons in custom quick pick color inheritance 5a41e931eab Remove unnecessary character from ces survey url 7a728f2bcaf Make sure we actually update the local resource roots c9d63cee5e4 Merge pull request #116621 from shskwmt/fix/116335 656e1e60867 More deprecated assertion cleanup af69dc26ca2 notEqual -> notStrictEqual 358b28f3932 QuickPick now fires the `onDidChangeValue` when setting value manually (#122948) d6393457912 notebooks: improve renderer message passing 025fcaf6114 remove old asserts from git tests 775ef547073 Remove assert.equal from custom editor tests aa255d73ae6 Simplify condition 2b81396e0a1 109216 Sanitize Process Environment before spawning terminal instance 2a42ce696d0 Remove textarea listener, element is enough d1604866c06 Remove duplicate listeners 80f1382ba20 Fix merge issues 72aa675fc9b Update API tests to strict equal cf2eeb87acc initialize pty host log level (#122943) cbfef516512 Fix #122367 e1e76e273dc Merge branch 'main' into fix/116335 c2a8d684664 show modal only if window is focused fixes #122450 1469a9840ff Update deprecated html language features 135142e497b Update deprecated typescript tests e44bd2d93d1 Removed deprecated assert from css-language-features 08e090781b9 Merge pull request #115276 from habibkarim/hbibkrim/114898_terminal_name_change_event b4749e01396 rename externalTerminal contrib 376161b9158 Fix 122637 a23b8594e0b select environment quick pick polish 48720a300f5 Fix whitespace 6384c5e73a5 Remove imagePreview.border 7bfc8c16ddb get desktop externalTerminal menu entry working again 95c2bc66532 Use the scoped context key service for notebook editor context keys Fix #122701 8e5b3b5aff8 Merge branch 'main' into hbibkrim/114898_terminal_name_change_event c201f0c8539 Remove any from xterm theme method 153d77c61ea Merge pull request #122929 from microsoft/tyriar/message_finalize fce6c54d377 Update focus highlight color on light theme c48d374e680 fix #118405 088f35f7029 terminalTab -> terminalGroup (#122891) 840d3dce67e Removed unused telemetry. 6bf0a308706 Open split terminal when all tasks are in the same one Fixes #122868 51dbb570e9b tests for https://github.com/microsoft/vscode/issues/122927 729f4c8b6f3 Remove shell environment patching from shared process (fix #121947) (#122846) 706348fff8b invoke notebook serialize with data that's to be persisted only, https://github.com/microsoft/vscode/issues/122927 85eee460c27 [json] update service a44f7ebb9a4 Merge pull request #122919 from hediet/hediet/fix-122914 a4cd92ead09 Merge pull request #122873 from microsoft/tyriar/tab_list 14e5e4272f0 Merge branch 'main' into tyriar/tab_list 337fc09b091 structure notebooks API along planned finalization, https://github.com/microsoft/vscode/issues/122922 69373b78334 Finalize TerminalOptions.message API 31fed906143 Merge pull request #122926 from microsoft/tyriar/public 3768c69aae3 Extract nested functions. 6033b61c5af Remove explicit public from platform terminal 153ed1f000d Fix compile a0000c4c8dc Remove explicit public from contrib/terminal 48010db276a Merge pull request #122918 from microsoft/tyriar/lint 7a92985cde8 Add "close" presentation option to tasks Fixes #112230 2498273ab62 Relax const rule 4fde14b9ef2 Use pascal case for term enums 81734d23502 Change casing of terminal command id enum f249c1db605 use showNotebookDocument instead of command, maybe https://github.com/microsoft/vscode/issues/122851 3410dd1729f Fixes #122914. a6a9f771adf Lint progress 0fa9d367196 Add some eslint rules to terminal 655fe7546f2 Fix port theme color typo 39d180d6624 Initial implementation of drag and drop api (#122239) 22096649910 sandbox - remove terminal related simple services 9ea9623a8a0 fix smoketest df15c8e832a Update grammars 80e5d07b89b Update distro 1f597772c5d Merge pull request #122897 from microsoft/tyriar/inheritEnv e2954beb4b0 Remove `--no-sandbox` (#122909) b1ce0eda2dd Merge pull request #122796 from jeanp413/fix-122255 bce4d71f648 chore: bump node@14.x in devDependencies (#122905) 6d4aeb99bdb Merge pull request #122895 from mjbvz/fix-122585 35e54152614 Fix context on LabelTunnelAction (#122856) 8d4d6ea4bef Finish removing terminal from electron-browser 4868dd3bd8e :chore: more action2 adoptions a29dc73f31a Merge branch 'main' into notebook/dev 885e1631a5a Remove native delete from terminal native contribution 17ef2c7feee Add getWslPath to pty service f09dc09c3bd Remove native dependency on shell setting registration 2b520498625 Move electron profile resolver service to sandbox 4485a0cfd08 Remove electron-browser instance service c2f8abb4d2d Remove onRequestDefaultShellAndArgs 9a0f4994fd9 api for may e536fb6ca4d at a way to confirm a suggested kernel, https://github.com/microsoft/vscode/issues/122647 87acf5fc1a8 only load preloads when kernel is selected 538b91fe420 Update distro 58a2d5bc265 Rename getShellEnvironment to getEnvironment 1df6bc65735 fix search editor (#120699) 3ef66a464b1 Remove inheritEnv, don't use shell env 25cb0d2fca1 Fix first line being replaced in suggestion label 5b74ae11070 Add listFocusHighlightForeground 5a6992a681e Update quick pick focused state de4e9067e80 externalTerminal renderer -> main process (#122871) f19a2c969bf Allow searching with a ./ path in a workspace folder that has a slash in its name Fix #99512 bc04b1c04bf Update md grammar 2e0644918d3 Spelling f8cf85a6cc7 Fix build abd1df11b6d testing: improve display of line numbers and markdown messages in diff peek 52c93f9932f peek: use title instead of aria-label so truncated text is visible 9b74e6cfb24 peek: fix text not truncating in peekview title 31a7a50b939 Fix NotebookMetadata tests baa45af0995 Name all notebook action classes ffe6e299943 Remove notebook.trust command 65c6a0a543c Pick up TS 4.3 nightly 6c10fb43716 Remove 'trusted' notebook document See #118584 for more 9aac6ab8f61 Use @ link in vscode.d.ts 248cbc49cf8 Update TS version for building VS Code 7bdc6e43649 search: fix bad crlf normalization for negated character classes 039a3043f1f search: fix bad crlf normalization for negated character classes faed865e2fc Fix #120699 022483ae8c3 allow trust editor to shrink better fixes #122523 a1e2329a505 fix scroll bar in trust editor refs #122523 480d8376a2e remove padding trust editor refs #122523 7d22e3b4148 fixes #122302 9ca1b435932 fixes #120923 1288d9a3ef9 Fix #122700 8d9c7734ec4 Merge branch 'notebook/dev' into main 29b9648b3e9 Emmet fix #122231 81085f43129 :lipstick: ad0fe629ca4 Remove a11y service 9467b1c5060 Remove comment b38e8177862 Convert some references to tree/widget with list a26f02fa51f Convert tabs to use list instead of tree 486072c4a01 remove unused import e523a23caec fixes #120946 2598778977f Merge pull request #122866 from microsoft/tyriar/122034 9da2c37be01 Fix compile 31cda6eb850 Update all usages of full setting to use const aa2f7cc14b5 Move terminal settings into const enum d4ec6516679 Don't put settings menu in shadow root, on iPad Fix #108824 967020ff380 Change the configure default picker (#122863) ae2eb51f16f Add simple override tests, part of #121792 90c7f8e10de fix #122668 514871273b2 notebook: convert NotebookKernelPreload to a class 62736de465c Block windows/iframes from preventing the unload (#122835) 448b9eccb90 Make loading spinning icon square (Fixes #117859) 39a8f3c1740 fix #121216 d465e988f1e Register .mak extension for the Make language (#122614) 5bf5c77800d Menu migration (#122599) c554dccf10a fs - preserve previous error when moving to trash throws 3d4eb8ae206 Merge pull request #122823 from microsoft/merogge/aria 1ce98bb0604 :up: distro 973d66f55a0 windows - :up: dependencies (remote) 08401f046a8 :up: web dependencies (jschardet) fe8d6320604 :up: remote dependencies (jschardet, graceful-fs) 2126be63311 :chore: - adopt some action2 over deprecated workbench actions 31781a45da6 :up: windows-mutex@0.4.1 73688e7b408 :up: windows-foreground-love@0.4.0 8a49aa7fecc :up: jschardet@3.0.0 b8419bb8854 :up: graceful-fs@4.2.6 89731c82053 Remove shell environment patching in the renderer (fix #108804) 16baed2dd41 :chore: - adopt some Electron 12 API 317a9388d4d ux - convert some notifications to dialogs 28f8afb97f4 electron - stop delaying the quit method artifically 51ed283cc5b :chore: some code cleanup b0334d2c19b fixes #122834 66c3c135b37 compare with - stop using editor override hack bc6fd0a8abc web - stop using window.localStorage e475cf038bc state service - allow multiple setItems at once 678330a9ecf Expand capabilities of canSetWorkspaceTrust a2995117ec7 move constructor to one line 28a1bae2160 fix #122332 dc8bd9cd7e5 Merge pull request #121941 from plankp/main 174c9e46e22 ThemeMainService: update window background color dfb22d172fb Only disable onbeforeunload if using iframe based webviews 3edce10f204 Cleanup modal property from proposed api 119055dec70 Remove workspace trust soft notification code from core 44b97e05b7b Merge branch 'lszomoru/extensionSupportCompletionProvider' b7b095cdf65 Cleanup code 2aa0f0f4285 Fixes #122255 bc41da329f3 Improve docs for TextEditor.setDecorations c8bd5b211ac Enable infer function return type for 4.3+ 8d1d9bc1b6c Add Reload Window to disconnected remote indicator menu github/codespaces#2659 ee24dbfc6c5 Document new behavior of postMesage on VS Code 1.57+ 18a986bef59 Fixing array buffer serialization 1cce707eb8e Merge branch 'notebook/dev' into main 7da0243ca95 fix #120284 6196ad1d144 fix navigate previous on start. 55067ece9a4 extract notebook find model and support content update research. fix #112748. c63564b5318 fix #122589 88089f2ddd3 Remove debug attr dee149aebe8 Try to block webviews from cancelling unloads ede914800c6 don't escape quick input validation message (#120593) 059f2cf45ff Ensure that notebook cell URIs work (#122746) 2285f879348 Fix incorrect active editor matching b68a820544f Clear cell error state when clearing all outputs Fix #122645 c7ef33f67e5 update my-work to May b17b808870d add 'notebookKernelSelected' context 2f5fb0fe0cc Merge branch 'joh/next' into main b34cff7e054 Update package.json 8f8634b7747 :lipstick: don't use object as map bc52e4d9867 more inlay... a1e69b746f9 rename InlineHint to InlayHint, make it InlayHint only and keep OverlayHint as a future, separate feature, remove hover message db5cb92a746 fix: use addListener instead of addEventListener to observe media query lists 0bc066daef8 Add extension support completion provider to core 7d2da4ea7c7 Add pattern matching 'in' 0c42da9368e Fix welcome view links no hover color d0c8b51a838 Merge branch 'main' into hbibkrim/114898_terminal_name_change_event 9437d13aa6e Add comment explaining Process->Api event change 4f6732316ea Bring emitTitle back 67514727319 Merge remote-tracking branch 'origin/main' into pr/habibkarim/115276 9d931d32eed Merge branch 'main' into fix/116335 1587c81b3a2 Send a file path text to the dropped terminal area 5330f361d52 Remove unused import c0d886c8cc9 Remove hasReceivedResponseFromRemoteExtHost check 3db5cd54e18 Implement Pseudoterminal.onDidChangeName 28a74470d78 Implement onDidChangeTerminalName #114898 965a3d2df0f Compare case insensitive extensions for unicode 7d816342ab1 Merge branch 'master' into more-sort-order-options e008e146ab2 Merge branch 'master' into more-sort-order-options c8e7f52d076 One public getter for sort order configuration 4a8f0088fed Fix merge issue 6e0e9770c91 Merge branch 'master' into more-sort-order-options 6294cfd2f18 Add Explorer Sort Order Lexicographic Options 8458f3f9f70 Rename `Numeric` compare functions to `Mixed`. 69577a4504e Add unused SortOrderOption setting for discussion. REVERT: cfa2e218100 Make sure we actually update the local resource roots (#122957) REVERT: 206524cbf6f Merge pull request #122941 from microsoft/roblou/fix122701 REVERT: 0ce07162f07 Use the scoped context key service for notebook editor context keys Fix #122701 REVERT: 4fbe56e36b3 Merge pull request #122933 from microsoft/aeschli/122466 REVERT: 32a743d2af9 [JSON] Schema not found error on opening package.json. For #122279 REVERT: 0676e9a727e Fix port theme color typo (#122915) REVERT: 85f8ebf1687 Fix context on LabelTunnelAction (#122856) REVERT: 5913f53cab5 Block windows/iframes from preventing the unload (#122835) (#122869) REVERT: acd78c82ac6 Ensure that notebook cell URIs work (#122747) REVERT: 4e185d89863 Merge pull request #122764 from microsoft/roblou/fix122407 REVERT: 7eb7814b56c Try to block webviews from cancelling unloads (#122758) REVERT: 25092105030 Hardcode keybinding string to fix #122407 REVERT: b084e6f4a73 Fix currently active indicator preventing editor switching (#122742) REVERT: bc2373aaa54 Merge pull request #122732 from microsoft/r156_tabs REVERT: d7a86f269a8 Disable tabs by default git-subtree-dir: lib/vscode git-subtree-split: 2064d4c301c394b60b0bc5c344735050b7d61c3d --- .devcontainer/README.md | 101 + .../cache/.gitignore | 0 .../cache/before-cache.sh | 0 .../cache/build-cache-image.sh | 0 .../cache/cache-diff.sh | 0 .../cache/cache.Dockerfile | 0 .../cache/restore-diff.sh | 0 .../devcontainer.json | 18 +- .../prepare.sh | 0 .dockerignore | 3 - .editorconfig | 11 +- lib/vscode/.eslintignore => .eslintignore | 4 - lib/vscode/.eslintrc.json => .eslintrc.json | 6 +- .eslintrc.yaml | 46 - .gitattributes | 11 +- .github/CODEOWNERS | 3 - .github/ISSUE_TEMPLATE/bug-report.md | 74 - .../ISSUE_TEMPLATE/bug_report.md | 11 +- .github/ISSUE_TEMPLATE/config.yml | 7 +- .github/ISSUE_TEMPLATE/doc.md | 7 - .github/ISSUE_TEMPLATE/extension-request.md | 18 - .github/ISSUE_TEMPLATE/feature-request.md | 13 - .../ISSUE_TEMPLATE/feature_request.md | 0 .../pull_request_template.md | 6 - .../PULL_REQUEST_TEMPLATE/release_template.md | 18 - {lib/vscode/.github => .github}/calendar.yml | 0 .../.github => .github}/classifier.json | 21 +- .github/codeql-config.yml | 4 - {lib/vscode/.github => .github}/commands.json | 14 +- {lib/vscode/.github => .github}/commands.yml | 0 .github/dependabot.yml | 27 - .../.github => .github}/endgame/insiders.yml | 0 {lib/vscode/.github => .github}/insiders.yml | 0 .github/lock.yml | 37 - .../pull_request_template.md | 0 .github/ranger.yml | 45 - .../vscode/.github => .github}/similarity.yml | 0 .../.github => .github}/subscribers.json | 3 +- .../workflows/author-verified.yml | 0 .../workflows/build-chat.yml | 0 .github/workflows/ci.yaml | 466 - .../.github => .github}/workflows/ci.yml | 3 + .github/workflows/codeql-analysis.yml | 33 - .../.github => .github}/workflows/codeql.yml | 0 .../workflows/deep-classifier-monitor.yml | 0 .../workflows/deep-classifier-runner.yml | 0 .../workflows/deep-classifier-scraper.yml | 0 .../workflows/devcontainer-cache.yml | 0 .../workflows/english-please.yml | 0 .../workflows/feature-request.yml | 0 .../workflows/latest-release-monitor.yml | 0 .../.github => .github}/workflows/locker.yml | 0 .../workflows/needs-more-info-closer.yml | 0 .../workflows/no-yarn-lock-changes.yml | 0 .../workflows/on-comment.yml | 0 .../workflows/on-label.yml | 0 .../.github => .github}/workflows/on-open.yml | 0 .github/workflows/publish.yaml | 53 - .../workflows/release-pipeline-labeler.yml | 0 .../workflows/rich-navigation.yml | 0 .../workflows/test-plan-item-validator.yml | 0 .gitignore | 36 +- lib/vscode/.mailmap => .mailmap | 0 lib/vscode/.mention-bot => .mention-bot | 0 .prettierrc.yaml | 4 - .stylelintrc.yaml | 2 - .tours/contributing.tour | 151 - .tours/start-development.tour | 26 - .../cglicenses.schema.json | 0 .../cgmanifest.schema.json | 0 .../.vscode => .vscode}/extensions.json | 0 {lib/vscode/.vscode => .vscode}/launch.json | 0 .../notebooks/api.github-issues | 18 +- .../notebooks/endgame.github-issues | 2 +- .../notebooks/grooming-delta.github-issues | 0 .../notebooks/grooming.github-issues | 0 .../notebooks/inbox.github-issues | 0 .../notebooks/my-endgame.github-issues | 4 +- .../notebooks/my-work.github-issues | 57 +- .../notebooks/papercuts.github-issues | 0 .../notebooks/verification.github-issues | 0 .../searches/TrustedTypes.code-search | 0 .../searches/ts36031.code-search | 0 {lib/vscode/.vscode => .vscode}/settings.json | 0 .../.vscode => .vscode}/shared.code-snippets | 0 {lib/vscode/.vscode => .vscode}/tasks.json | 53 +- lib/vscode/.yarnrc => .yarnrc | 2 +- lib/vscode/CONTRIBUTING.md => CONTRIBUTING.md | 0 LICENSE.txt | 27 +- README.md | 96 +- lib/vscode/SECURITY.md => SECURITY.md | 0 ThirdPartyNotices.txt | 2880 ++- {lib/vscode/build => build}/.cachesalt | 0 {lib/vscode/build => build}/.gitattributes | 0 {lib/vscode/build => build}/.moduleignore | 0 {lib/vscode/build => build}/.webignore | 0 .../common/computeNodeModulesCacheKey.js | 0 .../common/computeNodeModulesCacheKey.ts | 0 build/azure-pipelines/common/createAsset.js | 197 + .../azure-pipelines/common/createAsset.ts | 121 +- .../azure-pipelines/common/createBuild.js | 0 .../azure-pipelines/common/createBuild.ts | 0 .../common/extract-telemetry.sh | 0 .../common/installPlaywright.js | 0 .../common/installPlaywright.ts | 0 .../azure-pipelines/common/listNodeModules.js | 0 .../azure-pipelines/common/listNodeModules.ts | 0 .../azure-pipelines/common/publish-webview.js | 0 .../azure-pipelines/common/publish-webview.sh | 0 .../azure-pipelines/common/publish-webview.ts | 0 .../azure-pipelines/common/releaseBuild.js | 0 .../azure-pipelines/common/releaseBuild.ts | 0 .../azure-pipelines/common/retry.js | 0 .../azure-pipelines/common/retry.ts | 0 .../common/telemetry-config.json | 0 .../darwin/app-entitlements.plist | 0 .../darwin/helper-gpu-entitlements.plist | 0 .../darwin/helper-renderer-entitlements.plist | 0 .../darwin/product-build-darwin-sign.yml | 26 +- .../darwin/product-build-darwin.yml | 29 +- .../azure-pipelines/distro-build.yml | 0 .../azure-pipelines/exploration-build.yml | 0 .../azure-pipelines/linux/.gitignore | 0 .../linux/alpine/install-dependencies.sh | 0 .../azure-pipelines/linux/prepare-publish.sh | 11 +- .../linux/product-build-alpine.yml | 32 +- .../linux/product-build-linux.yml | 17 +- .../linux/snap-build-linux.yml | 8 +- .../azure-pipelines/linux/xvfb.init | 0 .../build => build}/azure-pipelines/mixin.js | 0 .../build => build}/azure-pipelines/mixin.ts | 0 .../azure-pipelines/product-build.yml | 51 +- .../azure-pipelines/product-compile.yml | 8 - build/azure-pipelines/product-publish.ps1 | 114 + build/azure-pipelines/product-publish.yml | 89 + .../azure-pipelines/product-release.yml | 0 .../publish-types/check-version.js | 0 .../publish-types/check-version.ts | 0 .../publish-types/publish-types.yml | 0 .../publish-types/update-types.js | 0 .../publish-types/update-types.ts | 0 .../azure-pipelines/upload-cdn.js | 0 .../azure-pipelines/upload-cdn.ts | 0 .../azure-pipelines/upload-sourcemaps.js | 0 .../azure-pipelines/upload-sourcemaps.ts | 0 .../azure-pipelines/web/product-build-web.yml | 18 +- .../win32/ESRPClient/NuGet.config | 0 .../win32/ESRPClient/packages.config | 0 .../azure-pipelines/win32/exec.ps1 | 0 .../win32/import-esrp-auth-cert.ps1 | 0 .../azure-pipelines/win32/prepare-publish.ps1 | 25 +- .../win32/product-build-win32.yml | 18 +- .../azure-pipelines/win32/retry.ps1 | 0 .../azure-pipelines/win32/sign.ps1 | 0 {lib/vscode/build => build}/builtin/.eslintrc | 0 .../build => build}/builtin/browser-main.js | 0 .../vscode/build => build}/builtin/index.html | 0 {lib/vscode/build => build}/builtin/main.js | 0 .../build => build}/builtin/package.json | 0 .../darwin/create-universal-app.js | 2 +- .../darwin/create-universal-app.ts | 0 {lib/vscode/build => build}/darwin/sign.js | 0 {lib/vscode/build => build}/darwin/sign.ts | 0 {lib/vscode/build => build}/eslint.js | 0 {lib/vscode/build => build}/filters.js | 0 .../build => build}/gulpfile.compile.js | 0 .../vscode/build => build}/gulpfile.editor.js | 0 .../build => build}/gulpfile.extensions.js | 155 +- .../build => build}/gulpfile.hygiene.js | 0 {lib/vscode/build => build}/gulpfile.js | 0 {lib/vscode/build => build}/gulpfile.reh.js | 1 - .../vscode/build => build}/gulpfile.vscode.js | 19 +- .../build => build}/gulpfile.vscode.linux.js | 0 .../build => build}/gulpfile.vscode.web.js | 0 .../build => build}/gulpfile.vscode.win32.js | 0 {lib/vscode/build => build}/hygiene.js | 0 {lib/vscode/build => build}/jsconfig.json | 0 {lib/vscode/build => build}/lib/asar.js | 0 {lib/vscode/build => build}/lib/asar.ts | 0 .../build => build}/lib/builtInExtensions.js | 4 +- .../build => build}/lib/builtInExtensions.ts | 4 +- .../lib/builtInExtensionsCG.js | 4 +- .../lib/builtInExtensionsCG.ts | 4 +- {lib/vscode/build => build}/lib/bundle.js | 0 {lib/vscode/build => build}/lib/bundle.ts | 0 .../vscode/build => build}/lib/compilation.js | 0 .../vscode/build => build}/lib/compilation.ts | 0 .../build => build}/lib/dependencies.js | 0 .../build => build}/lib/dependencies.ts | 0 {lib/vscode/build => build}/lib/electron.js | 0 {lib/vscode/build => build}/lib/electron.ts | 0 .../lib/eslint/code-import-patterns.js | 0 .../lib/eslint/code-import-patterns.ts | 0 .../lib/eslint/code-layering.js | 0 .../lib/eslint/code-layering.ts | 0 .../code-no-nls-in-standalone-editor.js | 0 .../code-no-nls-in-standalone-editor.ts | 0 .../lib/eslint/code-no-standalone-editor.js | 0 .../lib/eslint/code-no-standalone-editor.ts | 0 .../eslint/code-no-unexternalized-strings.js | 0 .../eslint/code-no-unexternalized-strings.ts | 0 .../lib/eslint/code-no-unused-expressions.js | 0 .../lib/eslint/code-no-unused-expressions.ts | 0 .../lib/eslint/code-translation-remind.js | 0 .../lib/eslint/code-translation-remind.ts | 0 .../build => build}/lib/eslint/utils.js | 0 .../build => build}/lib/eslint/utils.ts | 0 .../lib/eslint/vscode-dts-cancellation.js | 0 .../lib/eslint/vscode-dts-cancellation.ts | 0 .../lib/eslint/vscode-dts-create-func.js | 0 .../lib/eslint/vscode-dts-create-func.ts | 0 .../lib/eslint/vscode-dts-event-naming.js | 0 .../lib/eslint/vscode-dts-event-naming.ts | 0 .../lib/eslint/vscode-dts-interface-naming.js | 0 .../lib/eslint/vscode-dts-interface-naming.ts | 0 .../lib/eslint/vscode-dts-literal-or-types.js | 0 .../lib/eslint/vscode-dts-literal-or-types.ts | 0 .../lib/eslint/vscode-dts-provider-naming.js | 0 .../lib/eslint/vscode-dts-provider-naming.ts | 0 .../lib/eslint/vscode-dts-region-comments.js | 0 .../lib/eslint/vscode-dts-region-comments.ts | 0 .../lib/eslint/vscode-dts-use-thenable.js | 0 .../lib/eslint/vscode-dts-use-thenable.ts | 0 {lib/vscode/build => build}/lib/extensions.js | 132 +- {lib/vscode/build => build}/lib/extensions.ts | 139 +- {lib/vscode/build => build}/lib/git.js | 0 {lib/vscode/build => build}/lib/git.ts | 0 build/lib/i18n.js | 1163 ++ .../build => build}/lib/i18n.resources.json | 0 {lib/vscode/build => build}/lib/i18n.ts | 77 +- .../build => build}/lib/layersChecker.js | 0 .../build => build}/lib/layersChecker.ts | 0 {lib/vscode/build => build}/lib/monaco-api.js | 0 {lib/vscode/build => build}/lib/monaco-api.ts | 0 {lib/vscode/build => build}/lib/nls.js | 0 {lib/vscode/build => build}/lib/nls.ts | 0 {lib/vscode/build => build}/lib/node.js | 0 {lib/vscode/build => build}/lib/node.ts | 7 +- {lib/vscode/build => build}/lib/optimize.js | 2 +- {lib/vscode/build => build}/lib/optimize.ts | 2 +- {lib/vscode/build => build}/lib/preLaunch.js | 0 {lib/vscode/build => build}/lib/preLaunch.ts | 0 {lib/vscode/build => build}/lib/reporter.js | 0 {lib/vscode/build => build}/lib/reporter.ts | 0 .../build => build}/lib/snapshotLoader.js | 0 .../build => build}/lib/snapshotLoader.ts | 0 {lib/vscode/build => build}/lib/standalone.js | 0 {lib/vscode/build => build}/lib/standalone.ts | 0 {lib/vscode/build => build}/lib/stats.js | 0 {lib/vscode/build => build}/lib/stats.ts | 0 {lib/vscode/build => build}/lib/task.js | 0 {lib/vscode/build => build}/lib/task.ts | 0 .../build => build}/lib/test/i18n.test.js | 0 .../build => build}/lib/test/i18n.test.ts | 0 .../vscode/build => build}/lib/treeshaking.js | 7 +- .../vscode/build => build}/lib/treeshaking.ts | 10 +- .../lib/typings/cgmanifest.json | 0 .../lib/typings/event-stream.d.ts | 0 .../lib/typings/github-releases.d.ts | 0 .../build => build}/lib/typings/gulp-bom.d.ts | 0 .../lib/typings/gulp-flatmap.d.ts | 0 .../lib/typings/gulp-remote-src.d.ts | 0 .../build => build}/lib/typings/gulp-tsb.d.ts | 0 .../build => build}/lib/typings/is.d.ts | 0 .../build => build}/lib/typings/lazy.js.d.ts | 0 .../build => build}/lib/typings/vinyl.d.ts | 0 {lib/vscode/build => build}/lib/util.js | 0 {lib/vscode/build => build}/lib/util.ts | 1 - .../build => build}/lib/watch/.gitignore | 0 .../vscode/build => build}/lib/watch/index.js | 0 .../vscode/build => build}/lib/watch/index.ts | 0 .../build => build}/lib/watch/package.json | 0 .../build => build}/lib/watch/watch-win32.js | 0 .../build => build}/lib/watch/watch-win32.ts | 0 .../build => build}/lib/watch/watcher.exe | Bin .../build => build}/lib/watch/yarn.lock | 0 {lib/vscode/build => build}/monaco/LICENSE | 0 .../build => build}/monaco/README-npm.md | 0 {lib/vscode/build => build}/monaco/README.md | 0 .../monaco/ThirdPartyNotices.txt | 0 .../vscode/build => build}/monaco/esm.core.js | 0 .../build => build}/monaco/monaco.d.ts.recipe | 0 .../monaco/monaco.usage.recipe | 0 .../monaco/monaco.webpack.config.js | 0 .../build => build}/monaco/package.json | 0 .../vscode/build => build}/monaco/version.txt | 0 {lib/vscode/build => build}/npm/dirs.js | 0 .../vscode/build => build}/npm/postinstall.js | 0 {lib/vscode/build => build}/npm/preinstall.js | 0 .../npm/update-all-grammars.js | 0 .../build => build}/npm/update-distro.js | 0 build/npm/update-localization-extension.js | 101 + {lib/vscode/build => build}/package.json | 6 +- .../polyfills/vscode-extension-telemetry.js | 0 .../build => build}/polyfills/vscode-nls.js | 0 .../build => build}/tsconfig.build.json | 0 {lib/vscode/build => build}/tsconfig.json | 0 {lib/vscode/build => build}/win32/.gitignore | 0 {lib/vscode/build => build}/win32/Cargo.lock | 0 {lib/vscode/build => build}/win32/code.iss | 0 .../build => build}/win32/i18n/Default.hu.isl | 0 .../build => build}/win32/i18n/Default.ko.isl | 0 .../win32/i18n/Default.zh-cn.isl | 0 .../win32/i18n/Default.zh-tw.isl | 0 .../win32/i18n/messages.de.isl | 0 .../win32/i18n/messages.en.isl | 0 .../win32/i18n/messages.es.isl | 0 .../win32/i18n/messages.fr.isl | 0 .../win32/i18n/messages.hu.isl | 0 .../win32/i18n/messages.it.isl | 0 .../win32/i18n/messages.ja.isl | 0 .../win32/i18n/messages.ko.isl | 0 .../win32/i18n/messages.pt-br.isl | 0 .../win32/i18n/messages.ru.isl | 0 .../win32/i18n/messages.tr.isl | 0 .../win32/i18n/messages.zh-cn.isl | 0 .../win32/i18n/messages.zh-tw.isl | 0 .../build => build}/win32/inno_updater.exe | Bin .../build => build}/win32/vcruntime140.dll | Bin {lib/vscode/build => build}/yarn.lock | 39 +- lib/vscode/cglicenses.json => cglicenses.json | 45 +- lib/vscode/cgmanifest.json => cgmanifest.json | 8 +- ci/README.md | 141 - ci/build/build-code-server.sh | 45 - ci/build/build-packages.sh | 56 - ci/build/build-release.sh | 104 - ci/build/build-standalone-release.sh | 28 - ci/build/build-vscode.sh | 20 - ci/build/clean.sh | 15 - ci/build/code-server-nfpm.sh | 3 - ci/build/code-server-user.service | 11 - ci/build/code-server.sh | 36 - ci/build/code-server@.service | 12 - ci/build/nfpm.yaml | 25 - ci/build/npm-postinstall.sh | 65 - ci/build/release-github-assets.sh | 21 - ci/build/release-github-draft.sh | 50 - ci/build/release-prep.sh | 103 - ci/build/test-standalone-release.sh | 29 - ci/dev/audit.sh | 12 - ci/dev/ci.sh | 13 - ci/dev/fmt.sh | 44 - ci/dev/gen_icons.sh | 44 - ci/dev/lint.sh | 21 - ci/dev/postinstall.sh | 19 - ci/dev/test-e2e.sh | 12 - ci/dev/test-unit.sh | 15 - ci/dev/update-vscode.sh | 133 - ci/dev/watch.ts | 194 - ci/helm-chart/.helmignore | 23 - ci/helm-chart/Chart.yaml | 23 - ci/helm-chart/README.md | 117 - ci/helm-chart/templates/NOTES.txt | 25 - ci/helm-chart/templates/_helpers.tpl | 63 - ci/helm-chart/templates/deployment.yaml | 152 - ci/helm-chart/templates/ingress.yaml | 41 - ci/helm-chart/templates/pvc.yaml | 29 - ci/helm-chart/templates/secrets.yaml | 18 - ci/helm-chart/templates/service.yaml | 19 - ci/helm-chart/templates/serviceaccount.yaml | 11 - .../templates/tests/test-connection.yaml | 18 - ci/helm-chart/values.yaml | 163 - ci/lib.sh | 124 - ci/release-image/Dockerfile | 46 - ci/release-image/build.sh | 11 - ci/release-image/entrypoint.sh | 20 - ci/steps/brew-bump.sh | 13 - ci/steps/build-docker-image.sh | 14 - ci/steps/publish-npm.sh | 18 - ci/steps/push-docker-manifest.sh | 37 - docs/CODE_OF_CONDUCT.md | 79 - docs/CONTRIBUTING.md | 158 - docs/FAQ.md | 463 - docs/MAINTAINING.md | 65 - docs/SECURITY.md | 13 - docs/assets/screenshot.png | Bin 997586 -> 0 bytes docs/guide.md | 317 - docs/install.md | 225 - docs/ipad.md | 163 - docs/npm.md | 60 - docs/termux.md | 61 - docs/triage.md | 37 - .../bat/.vscodeignore | 0 .../bat/cgmanifest.json | 4 +- .../bat/language-configuration.json | 0 .../bat/package.json | 0 .../bat/package.nls.json | 0 .../bat/snippets/batchfile.code-snippets | 0 .../bat/syntaxes/batchfile.tmLanguage.json | 72 +- .../extensions => extensions}/bat/yarn.lock | 0 .../extensions => extensions}/cgmanifest.json | 0 .../clojure/.vscodeignore | 0 .../clojure/cgmanifest.json | 0 .../clojure/language-configuration.json | 0 .../clojure/package.json | 0 .../clojure/package.nls.json | 0 .../clojure/syntaxes/clojure.tmLanguage.json | 0 .../clojure/yarn.lock | 0 .../coffeescript/.vscodeignore | 0 .../coffeescript/cgmanifest.json | 0 .../coffeescript/language-configuration.json | 0 .../coffeescript/package.json | 0 .../coffeescript/package.nls.json | 0 .../snippets/coffeescript.code-snippets | 0 .../syntaxes/coffeescript.tmLanguage.json | 0 .../coffeescript/yarn.lock | 0 .../configuration-editing/.vscodeignore | 0 .../build/inline-allOf.ts | 0 .../configuration-editing/build/tsconfig.json | 0 .../extension-browser.webpack.config.js | 0 .../extension.webpack.config.js | 0 .../configuration-editing/images/icon.png | Bin .../configuration-editing/package.json | 2 +- .../configuration-editing/package.nls.json | 0 .../schemas/attachContainer.schema.json | 42 +- .../devContainer.schema.generated.json | 330 +- .../schemas/devContainer.schema.src.json | 60 +- .../src/configurationEditingMain.ts | 0 .../src/extensionsProposals.ts | 0 .../src/settingsDocumentHelper.ts | 37 +- .../src/typings/ref.d.ts | 0 .../configuration-editing/tsconfig.json | 0 .../configuration-editing/yarn.lock | 8 +- .../cpp/.vscodeignore | 0 .../cpp/build/update-grammars.js | 0 .../cpp/cgmanifest.json | 0 .../cpp/language-configuration.json | 0 .../cpp/package.json | 0 .../cpp/package.nls.json | 0 .../cpp/snippets/c.code-snippets | 0 .../cpp/snippets/cpp.code-snippets | 0 .../cpp/syntaxes/c.tmLanguage.json | 0 .../cpp.embedded.macro.tmLanguage.json | 0 .../cpp/syntaxes/cpp.tmLanguage.json | 0 .../cpp/syntaxes/cuda-cpp.tmLanguage.json | 0 .../cpp/syntaxes/platform.tmLanguage.json | 0 .../extensions => extensions}/cpp/yarn.lock | 0 .../csharp/.vscodeignore | 0 .../csharp/cgmanifest.json | 2 +- .../csharp/language-configuration.json | 0 .../csharp/package.json | 0 .../csharp/package.nls.json | 0 .../csharp/snippets/csharp.code-snippets | 0 .../csharp/syntaxes/csharp.tmLanguage.json | 276 +- .../csharp/yarn.lock | 0 .../css-language-features/.vscode/launch.json | 0 .../.vscode/settings.json | 0 .../css-language-features/.vscode/tasks.json | 0 .../css-language-features/.vscodeignore | 0 .../css-language-features/CONTRIBUTING.md | 0 .../css-language-features/README.md | 0 .../client/src/browser/cssClientMain.ts | 0 .../client/src/cssClient.ts | 0 .../client/src/customData.ts | 0 .../client/src/node/cssClientMain.ts | 0 .../client/src/node/nodeFs.ts | 0 .../client/src/requests.ts | 0 .../client/src/typings/ref.d.ts | 0 .../client/tsconfig.json | 0 .../extension-browser.webpack.config.js | 0 .../extension.webpack.config.js | 0 .../css-language-features/icons/css.png | Bin .../css-language-features/package.json | 2 +- .../css-language-features/package.nls.json | 0 .../schemas/package.schema.json | 0 .../server/.vscode/launch.json | 0 .../server/.vscode/tasks.json | 0 .../extension-browser.webpack.config.js | 0 .../server/extension.webpack.config.js | 0 .../css-language-features/server/package.json | 4 +- .../server/src/browser/cssServerMain.ts | 0 .../server/src/cssServer.ts | 0 .../server/src/customData.ts | 0 .../server/src/languageModelCache.ts | 0 .../server/src/node/cssServerMain.ts | 0 .../server/src/node/nodeFs.ts | 0 .../server/src/requests.ts | 0 .../server/src/test/completion.test.ts | 6 +- .../server/src/test/links.test.ts | 10 +- .../server/src/utils/documentContext.ts | 0 .../server/src/utils/runner.ts | 0 .../server/src/utils/strings.ts | 0 .../server/test/index.js | 0 .../server/test/linksTestFixtures/.gitignore | 0 .../node_modules/foo/package.json | 0 .../test/pathCompletionFixtures/.foo.js | 0 .../pathCompletionFixtures/about/about.css | 0 .../pathCompletionFixtures/about/about.html | 0 .../test/pathCompletionFixtures/index.html | 0 .../pathCompletionFixtures/scss/_foo.scss | 0 .../pathCompletionFixtures/scss/main.scss | 0 .../pathCompletionFixtures/src/data/foo.asar | 0 .../pathCompletionFixtures/src/feature.js | 0 .../test/pathCompletionFixtures/src/test.js | 0 .../server/tsconfig.json | 0 .../css-language-features/server/yarn.lock | 18 +- .../css-language-features/test/mocha.opts | 0 .../css-language-features/yarn.lock | 8 +- .../css/.vscode/launch.json | 0 .../css/.vscodeignore | 0 .../css/cgmanifest.json | 0 .../css/language-configuration.json | 0 .../css/package.json | 0 .../css/package.nls.json | 0 .../css/syntaxes/css.tmLanguage.json | 0 .../extensions => extensions}/css/yarn.lock | 0 .../julia => extensions/dart}/.vscodeignore | 0 extensions/dart/cgmanifest.json | 46 + extensions/dart/language-configuration.json | 29 + extensions/dart/package.json | 35 + extensions/dart/package.nls.json | 4 + extensions/dart/syntaxes/dart.tmLanguage.json | 439 + .../debug-auto-launch/.vscode/launch.json | 0 .../debug-auto-launch/.vscodeignore | 0 .../extension.webpack.config.js | 0 .../debug-auto-launch/media/icon.png | Bin .../debug-auto-launch/package.json | 2 +- .../debug-auto-launch/package.nls.json | 0 .../debug-auto-launch/src/extension.ts | 8 +- .../debug-auto-launch/src/typings/ref.d.ts | 0 .../debug-auto-launch/tsconfig.json | 0 .../debug-auto-launch}/yarn.lock | 8 +- .../debug-server-ready/.vscode/launch.json | 0 .../debug-server-ready/.vscodeignore | 0 .../extension.webpack.config.js | 0 .../debug-server-ready/media/icon.png | Bin .../debug-server-ready/package.json | 12 +- .../debug-server-ready/package.nls.json | 0 .../debug-server-ready/src/extension.ts | 24 +- .../debug-server-ready/src/typings/ref.d.ts | 0 .../debug-server-ready/tsconfig.json | 0 .../debug-server-ready}/yarn.lock | 8 +- .../docker/.vscodeignore | 0 .../docker/cgmanifest.json | 0 .../docker/language-configuration.json | 0 .../docker/package.json | 0 .../docker/package.nls.json | 0 .../docker/syntaxes/docker.tmLanguage.json | 0 .../docker/yarn.lock | 0 .../emmet/.vscode/launch.json | 0 .../emmet/.vscode/settings.json | 0 .../emmet/.vscodeignore | 0 .../emmet/CONTRIBUTING.md | 0 .../extensions => extensions}/emmet/README.md | 0 .../emmet/cgmanifest.json | 0 .../emmet/extension-browser.webpack.config.js | 0 .../emmet/extension.webpack.config.js | 0 .../emmet/images/icon.png | Bin .../emmet/package.json | 8 +- .../emmet/package.nls.json | 0 .../emmet/src/abbreviationActions.ts | 9 +- .../emmet/src/balance.ts | 0 .../emmet/src/browser/emmetBrowserMain.ts | 0 .../emmet/src/bufferStream.ts | 0 .../emmet/src/defaultCompletionProvider.ts | 0 .../emmet/src/editPoint.ts | 0 .../emmet/src/emmetCommon.ts | 0 .../emmet/src/evaluateMathExpression.ts | 0 .../emmet/src/imageSizeHelper.ts | 0 .../emmet/src/incrementDecrement.ts | 0 .../emmet/src/locateFile.ts | 0 .../emmet/src/matchTag.ts | 0 .../emmet/src/mergeLines.ts | 0 .../emmet/src/node/emmetNodeMain.ts | 0 .../emmet/src/parseDocument.ts | 0 .../emmet/src/reflectCssValue.ts | 0 .../emmet/src/removeTag.ts | 0 .../emmet/src/selectItem.ts | 0 .../emmet/src/selectItemHTML.ts | 0 .../emmet/src/selectItemStylesheet.ts | 0 .../emmet/src/splitJoinTag.ts | 0 .../emmet/src/test/abbreviationAction.test.ts | 0 .../emmet/src/test/completion.test.ts | 0 .../src/test/cssAbbreviationAction.test.ts | 0 .../test/editPointSelectItemBalance.test.ts | 0 .../src/test/evaluateMathExpression.test.ts | 0 .../emmet/src/test/incrementDecrement.test.ts | 0 .../emmet/src/test/index.ts | 0 .../src/test/partialParsingStylesheet.test.ts | 0 .../emmet/src/test/reflectCssValue.test.ts | 0 .../emmet/src/test/tagActions.test.ts | 0 .../emmet/src/test/testUtils.ts | 0 .../emmet/src/test/toggleComment.test.ts | 0 .../emmet/src/test/updateImageSize.test.ts | 0 .../src/test/wrapWithAbbreviation.test.ts | 104 +- .../emmet/src/toggleComment.ts | 0 .../emmet/src/typings/EmmetFlatNode.d.ts | 0 .../emmet/src/typings/EmmetNode.d.ts | 0 .../src/typings/emmetio__css-parser.d.ts | 0 .../src/typings/emmetio__html-matcher.d.ts | 0 .../emmet/src/typings/image-size.d.ts | 0 .../emmet/src/typings/refs.d.ts | 0 .../emmet/src/updateImageSize.ts | 0 .../emmet/src/updateTag.ts | 0 .../emmet/src/util.ts | 30 +- .../test-workspace/.vscode/settings.json | 0 .../emmet/tsconfig.json | 0 .../extensions => extensions}/emmet/yarn.lock | 14 +- .../extension-editing/.vscodeignore | 0 .../extension-browser.webpack.config.js | 0 .../extension.webpack.config.js | 0 .../extension-editing/images/icon.png | Bin .../extension-editing/package.json | 2 +- .../extension-editing/package.nls.json | 0 .../src/extensionEditingBrowserMain.ts | 0 .../src/extensionEditingMain.ts | 0 .../extension-editing/src/extensionLinter.ts | 0 .../src/packageDocumentHelper.ts | 0 .../extension-editing/src/typings/ref.d.ts | 0 .../extension-editing/tsconfig.json | 0 .../extension-editing/yarn.lock | 8 +- .../fsharp/.vscodeignore | 0 .../fsharp/cgmanifest.json | 0 .../fsharp/language-configuration.json | 0 .../fsharp/package.json | 0 .../fsharp/package.nls.json | 0 .../fsharp/snippets/fsharp.code-snippets | 0 .../fsharp/syntaxes/fsharp.tmLanguage.json | 0 .../fsharp/yarn.lock | 0 .../git/.vscodeignore | 0 .../extensions => extensions}/git/README.md | 0 .../git/build/update-emoji.js | 0 .../git/build/update-grammars.js | 0 .../git/cgmanifest.json | 0 .../git/extension.webpack.config.js | 0 .../diff.language-configuration.json | 0 .../git-commit.language-configuration.json | 0 .../git-rebase.language-configuration.json | 0 .../ignore.language-configuration.json | 0 .../git/package.json | 2 +- .../git/package.nls.json | 0 .../git/resources/emojis.json | 0 .../git/resources/icons/dark/status-added.svg | 0 .../resources/icons/dark/status-conflict.svg | 0 .../resources/icons/dark/status-copied.svg | 0 .../resources/icons/dark/status-deleted.svg | 0 .../resources/icons/dark/status-ignored.svg | 0 .../resources/icons/dark/status-modified.svg | 0 .../resources/icons/dark/status-renamed.svg | 0 .../resources/icons/dark/status-untracked.svg | 0 .../git/resources/icons/git.png | Bin .../resources/icons/light/status-added.svg | 0 .../resources/icons/light/status-conflict.svg | 0 .../resources/icons/light/status-copied.svg | 0 .../resources/icons/light/status-deleted.svg | 0 .../resources/icons/light/status-ignored.svg | 0 .../resources/icons/light/status-modified.svg | 0 .../resources/icons/light/status-renamed.svg | 0 .../icons/light/status-untracked.svg | 0 .../git/src/api/api1.ts | 0 .../git/src/api/extension.ts | 0 .../git/src/api/git.d.ts | 0 .../git/src/askpass-empty.sh | 0 .../git/src/askpass-main.ts | 0 .../git/src/askpass.sh | 0 .../git/src/askpass.ts | 0 .../git/src/autofetch.ts | 0 .../git/src/commands.ts | 0 .../git/src/decorationProvider.ts | 0 .../git/src/decorators.ts | 0 .../git/src/emoji.ts | 0 .../git/src/encoding.ts | 0 .../git/src/fileSystemProvider.ts | 0 .../extensions => extensions}/git/src/git.ts | 0 .../git/src/ipc/ipcClient.ts | 0 .../git/src/ipc/ipcServer.ts | 0 .../extensions => extensions}/git/src/log.ts | 0 .../extensions => extensions}/git/src/main.ts | 0 .../git/src/model.ts | 0 .../git/src/protocolHandler.ts | 0 .../git/src/pushError.ts | 0 .../git/src/remoteProvider.ts | 0 .../git/src/remoteSource.ts | 0 .../git/src/repository.ts | 0 .../git/src/staging.ts | 0 .../git/src/statusbar.ts | 0 .../git/src/terminal.ts | 0 .../git/src/test/git.test.ts | 72 +- .../git/src/test/index.ts | 0 .../git/src/test/smoke.test.ts | 24 +- .../git/src/timelineProvider.ts | 0 .../git/src/typings/refs.d.ts | 0 .../extensions => extensions}/git/src/uri.ts | 0 .../extensions => extensions}/git/src/util.ts | 0 .../git/src/watch.ts | 0 .../git/syntaxes/diff.tmLanguage.json | 0 .../git/syntaxes/git-commit.tmLanguage.json | 0 .../git/syntaxes/git-rebase.tmLanguage.json | 0 .../git/syntaxes/ignore.tmLanguage.json | 0 .../git/test/colorize-fixtures/COMMIT_EDITMSG | 0 .../git/test/colorize-fixtures/example.diff | 0 .../test/colorize-fixtures/git-rebase-todo | 0 .../test/colorize-results/COMMIT_EDITMSG.json | 0 .../test/colorize-results/example_diff.json | 0 .../colorize-results/git-rebase-todo.json | 0 .../git/test/mocha.opts | 0 .../git/tsconfig.json | 0 .../extensions => extensions}/git/yarn.lock | 8 +- .../github-authentication/.gitignore | 0 .../github-authentication/.vscodeignore | 0 .../github-authentication/README.md | 0 .../extension-browser.webpack.config.js | 0 .../extension.webpack.config.js | 0 .../github-authentication/images/icon.png | Bin .../github-authentication/package.json | 35 +- .../github-authentication/package.nls.json | 0 .../src/common/keychain.ts | 10 +- .../src/common/logger.ts | 0 .../github-authentication/src/common/utils.ts | 0 .../src/experimentationService.ts | 0 .../github-authentication/src/extension.ts | 28 + .../github-authentication/src/github.ts | 130 +- .../github-authentication/src/githubServer.ts | 81 +- .../src/typings/ref.d.ts | 0 .../github-authentication/tsconfig.json | 0 .../github-authentication/yarn.lock | 8 +- .../github/.vscodeignore | 0 .../github/README.md | 0 .../github/extension.webpack.config.js | 0 .../github/images/icon.png | Bin .../github/package.json | 2 +- .../github/package.nls.json | 0 .../github/src/auth.ts | 0 .../github/src/commands.ts | 0 .../github/src/credentialProvider.ts | 0 .../github/src/extension.ts | 0 .../github/src/publish.ts | 0 .../github/src/pushErrorHandler.ts | 0 .../github/src/remoteSourceProvider.ts | 0 .../github/src/typings/git.d.ts | 0 .../github/src/typings/ref.d.ts | 0 .../github/src/util.ts | 0 .../github/tsconfig.json | 0 .../github/yarn.lock | 10 +- .../go/.vscodeignore | 0 .../go/cgmanifest.json | 0 .../go/language-configuration.json | 0 .../extensions => extensions}/go/package.json | 0 .../go/package.nls.json | 0 .../go/syntaxes/go.tmLanguage.json | 0 .../extensions => extensions}/go/yarn.lock | 0 .../groovy/.vscodeignore | 0 .../groovy/cgmanifest.json | 0 .../groovy/language-configuration.json | 0 .../groovy/package.json | 0 .../groovy/package.nls.json | 0 .../groovy/snippets/groovy.code-snippets | 0 .../groovy/syntaxes/groovy.tmLanguage.json | 0 .../groovy/yarn.lock | 0 .../grunt/.vscodeignore | 0 .../extensions => extensions}/grunt/README.md | 0 .../grunt/extension.webpack.config.js | 0 .../grunt/images/grunt.png | Bin .../grunt/package.json | 6 +- .../grunt/package.nls.json | 2 +- .../grunt/src/main.ts | 0 .../grunt/src/typings/refs.d.ts | 0 .../grunt/tsconfig.json | 0 .../grunt}/yarn.lock | 8 +- .../gulp/.vscodeignore | 0 .../extensions => extensions}/gulp/README.md | 0 .../gulp/extension.webpack.config.js | 0 .../gulp/images/gulp.png | Bin .../gulp/package.json | 6 +- .../gulp/package.nls.json | 2 +- .../gulp/src/main.ts | 0 .../gulp/src/typings/refs.d.ts | 0 .../gulp/tsconfig.json | 0 .../grunt => extensions/gulp}/yarn.lock | 8 +- .../handlebars/.vscodeignore | 0 .../handlebars/cgmanifest.json | 0 .../handlebars/language-configuration.json | 0 .../handlebars/package.json | 0 .../handlebars/package.nls.json | 0 .../syntaxes/Handlebars.tmLanguage.json | 0 .../handlebars/yarn.lock | 0 .../hlsl/.vscodeignore | 0 .../hlsl/cgmanifest.json | 0 .../hlsl/language-configuration.json | 0 .../hlsl/package.json | 0 .../hlsl/package.nls.json | 0 .../hlsl/syntaxes/hlsl.tmLanguage.json | 0 .../extensions => extensions}/hlsl/yarn.lock | 0 .../.vscode/launch.json | 0 .../.vscode/settings.json | 0 .../html-language-features/.vscode/tasks.json | 0 .../html-language-features/.vscodeignore | 0 .../html-language-features/CONTRIBUTING.md | 0 .../html-language-features/README.md | 0 .../build/bundleTypeScriptLibraries.js | 0 .../html-language-features/cgmanifest.json | 0 .../client/src/browser/htmlClientMain.ts | 0 .../client/src/customData.ts | 0 .../client/src/htmlClient.ts | 0 .../client/src/htmlEmptyTagsShared.ts | 0 .../client/src/node/htmlClientMain.ts | 0 .../client/src/node/nodeFs.ts | 0 .../client/src/requests.ts | 0 .../client/src/tagClosing.ts | 0 .../client/src/typings/ref.d.ts | 0 .../client/tsconfig.json | 0 .../extension-browser.webpack.config.js | 0 .../extension.webpack.config.js | 0 .../html-language-features/icons/html.png | Bin .../html-language-features/package.json | 2 +- .../html-language-features/package.nls.json | 0 .../schemas/package.schema.json | 0 .../server/.vscode/launch.json | 0 .../server/.vscode/tasks.json | 0 .../server/build/javaScriptLibraryLoader.js | 0 .../extension-browser.webpack.config.js | 0 .../server/extension.webpack.config.js | 0 .../server/lib/cgmanifest.json | 0 .../server/lib/jquery.d.ts | 0 .../server/package.json | 6 +- .../server/src/browser/htmlServerMain.ts | 0 .../server/src/customData.ts | 0 .../server/src/htmlServer.ts | 62 +- .../server/src/languageModelCache.ts | 0 .../server/src/modes/cssMode.ts | 0 .../server/src/modes/embeddedSupport.ts | 0 .../server/src/modes/formatting.ts | 0 .../server/src/modes/htmlFolding.ts | 0 .../server/src/modes/htmlMode.ts | 0 .../server/src/modes/javascriptLibs.ts | 0 .../server/src/modes/javascriptMode.ts | 1 - .../src/modes/javascriptSemanticTokens.ts | 0 .../server/src/modes/languageModes.ts | 0 .../server/src/modes/selectionRanges.ts | 0 .../server/src/modes/semanticTokens.ts | 0 .../server/src/node/htmlServerMain.ts | 0 .../server/src/node/nodeFs.ts | 0 .../server/src/requests.ts | 0 .../server/src/test/completions.test.ts | 14 +- .../server/src/test/documentContext.test.ts | 10 +- .../server/src/test/embedded.test.ts | 4 +- .../test/fixtures/expected/19813-4spaces.html | 0 .../src/test/fixtures/expected/19813-tab.html | 0 .../src/test/fixtures/expected/19813.html | 0 .../src/test/fixtures/expected/21634.html | 0 .../src/test/fixtures/inputs/19813.html | 0 .../src/test/fixtures/inputs/21634.html | 0 .../server/src/test/folding.test.ts | 2 +- .../server/src/test/formatting.test.ts | 2 +- .../src/test/pathCompletionFixtures/.foo.js | 0 .../pathCompletionFixtures/about/about.css | 0 .../pathCompletionFixtures/about/about.html | 0 .../about/media/icon.pic | 0 .../test/pathCompletionFixtures/index.html | 0 .../pathCompletionFixtures/src/feature.js | 0 .../test/pathCompletionFixtures/src/test.js | 0 .../server/src/test/rename.test.ts | 2 +- .../server/src/test/selectionRanges.test.ts | 6 +- .../server/src/test/semanticTokens.test.ts | 2 +- .../server/src/test/words.test.ts | 4 +- .../server/src/utils/arrays.ts | 0 .../server/src/utils/documentContext.ts | 0 .../server/src/utils/positions.ts | 0 .../server/src/utils/runner.ts | 0 .../server/src/utils/strings.ts | 0 .../server/test/index.js | 0 .../server/tsconfig.json | 0 .../html-language-features/server/yarn.lock | 24 +- .../html-language-features/yarn.lock | 8 +- .../html/.vscodeignore | 0 .../html/build/update-grammar.js | 0 .../html/cgmanifest.json | 0 .../html/language-configuration.json | 0 .../html/package.json | 0 .../html/package.nls.json | 0 .../syntaxes/html-derivative.tmLanguage.json | 0 .../html/syntaxes/html.tmLanguage.json | 0 .../extensions => extensions}/html/yarn.lock | 0 .../image-preview/.vscodeignore | 0 .../image-preview/README.md | 0 .../extension-browser.webpack.config.js | 0 .../image-preview/extension.webpack.config.js | 0 .../image-preview/icon.png | Bin .../image-preview/icon.svg | 0 .../image-preview/media/loading-dark.svg | 0 .../image-preview/media/loading-hc.svg | 0 .../image-preview/media/loading.svg | 0 .../image-preview/media/main.css | 0 .../image-preview/media/main.js | 0 .../image-preview/package.json | 0 .../image-preview/package.nls.json | 0 .../src/binarySizeStatusBarEntry.ts | 7 +- .../image-preview/src/dispose.ts | 0 .../image-preview/src/extension.ts | 0 .../image-preview/src/ownedStatusBarEntry.ts | 5 +- .../image-preview/src/preview.ts | 0 .../image-preview/src/sizeStatusBarEntry.ts | 7 +- .../image-preview/src/typings/ref.d.ts | 0 .../image-preview/src/zoomStatusBarEntry.ts | 7 +- .../image-preview/tsconfig.json | 0 .../image-preview/yarn.lock | 0 .../ini/.vscodeignore | 0 .../ini/cgmanifest.json | 0 .../ini/ini.language-configuration.json | 0 .../ini/package.json | 0 .../ini/package.nls.json | 0 .../properties.language-configuration.json | 0 .../ini/syntaxes/ini.tmLanguage.json | 0 .../extensions => extensions}/ini/yarn.lock | 0 .../jake/.vscodeignore | 0 .../extensions => extensions}/jake/README.md | 0 .../jake/extension.webpack.config.js | 0 .../jake/images/cowboy_hat.png | Bin .../jake/package.json | 6 +- .../jake/package.nls.json | 2 +- .../jake/src/main.ts | 0 .../jake/src/typings/refs.d.ts | 0 .../jake/tsconfig.json | 0 extensions/jake/yarn.lock | 13 + .../java/.vscodeignore | 0 .../java/cgmanifest.json | 0 .../java/language-configuration.json | 0 .../java/package.json | 0 .../java/package.nls.json | 0 .../java/snippets/java.code-snippets | 0 .../java/syntaxes/java.tmLanguage.json | 0 .../extensions => extensions}/java/yarn.lock | 0 .../javascript/.vscodeignore | 0 .../javascript/cgmanifest.json | 0 .../javascript-language-configuration.json | 0 .../javascript/package.json | 0 .../javascript/package.nls.json | 0 .../snippets/javascript.code-snippets | 0 .../syntaxes/JavaScript.tmLanguage.json | 0 .../syntaxes/JavaScriptReact.tmLanguage.json | 0 .../javascript/syntaxes/Readme.md | 0 ...egular Expressions (JavaScript).tmLanguage | 0 .../tags-language-configuration.json | 0 .../javascript/yarn.lock | 0 .../.vscode/launch.json | 0 .../json-language-features/.vscode/tasks.json | 0 .../json-language-features/.vscodeignore | 0 .../json-language-features/CONTRIBUTING.md | 0 .../json-language-features/README.md | 0 .../client/src/browser/jsonClientMain.ts | 0 .../client/src/jsonClient.ts | 8 +- .../client/src/node/jsonClientMain.ts | 0 .../client/src/requests.ts | 0 .../client/src/typings/ref.d.ts | 0 .../client/src/utils/hash.ts | 0 .../client/tsconfig.json | 0 .../extension-browser.webpack.config.js | 0 .../extension.webpack.config.js | 0 .../json-language-features/icons/json.png | Bin .../json-language-features/package.json | 2 +- .../json-language-features/package.nls.json | 0 .../json-language-features/server/.npmignore | 0 .../server/.vscode/launch.json | 0 .../server/.vscode/tasks.json | 0 .../json-language-features/server/README.md | 0 .../server/bin/vscode-json-languageserver | 0 .../extension-browser.webpack.config.js | 0 .../server/extension.webpack.config.js | 0 .../server/package.json | 4 +- .../server/src/browser/jsonServerMain.ts | 0 .../server/src/jsonServer.ts | 53 +- .../server/src/languageModelCache.ts | 0 .../server/src/node/jsonServerMain.ts | 0 .../server/src/requests.ts | 0 .../server/src/utils/runner.ts | 0 .../server/src/utils/strings.ts | 0 .../server/test/mocha.opts | 0 .../server/tsconfig.json | 0 .../json-language-features/server/yarn.lock | 16 +- .../json-language-features/yarn.lock | 8 +- .../json/.vscodeignore | 0 .../json/build/update-grammars.js | 0 .../json/cgmanifest.json | 0 .../json/language-configuration.json | 0 .../json/package.json | 5 +- .../json/package.nls.json | 0 .../json/syntaxes/JSON.tmLanguage.json | 0 .../json/syntaxes/JSONC.tmLanguage.json | 0 .../extensions => extensions}/json/yarn.lock | 0 extensions/julia/.vscodeignore | 2 + .../julia/cgmanifest.json | 4 +- .../julia/language-configuration.json | 0 .../julia/package.json | 0 .../julia/package.nls.json | 0 .../julia/syntaxes/julia.tmLanguage.json | 0 .../less/.vscodeignore | 0 .../less/cgmanifest.json | 0 .../less/language-configuration.json | 0 .../less/package.json | 0 .../less/package.nls.json | 0 .../less/syntaxes/less.tmLanguage.json | 0 .../extensions => extensions}/less/yarn.lock | 0 .../log/.vscodeignore | 0 .../log/cgmanifest.json | 0 .../log/package.json | 0 .../log/package.nls.json | 0 .../log/syntaxes/log.tmLanguage.json | 0 .../extensions => extensions}/log/yarn.lock | 0 .../lua/.vscodeignore | 0 .../lua/cgmanifest.json | 0 .../lua/language-configuration.json | 0 .../lua/package.json | 0 .../lua/package.nls.json | 0 .../lua/syntaxes/lua.tmLanguage.json | 0 .../extensions => extensions}/lua/yarn.lock | 0 .../make/.vscodeignore | 0 .../make/cgmanifest.json | 0 .../make/language-configuration.json | 0 .../make/package.json | 1 + .../make/package.nls.json | 0 .../make/syntaxes/make.tmLanguage.json | 0 .../extensions => extensions}/make/yarn.lock | 0 .../markdown-basics/.vscodeignore | 0 .../markdown-basics/cgmanifest.json | 2 +- .../language-configuration.json | 0 .../markdown-basics/package.json | 0 .../markdown-basics/package.nls.json | 0 .../snippets/markdown.code-snippets | 0 .../syntaxes/markdown.tmLanguage.json | 166 +- .../markdown-basics/yarn.lock | 0 .../markdown-language-features/.gitignore | 0 .../markdown-language-features/.vscodeignore | 0 .../markdown-language-features/README.md | 0 .../markdown-language-features/esbuild.js | 0 .../extension-browser.webpack.config.js | 0 .../extension.webpack.config.js | 0 .../markdown-language-features/icon.png | Bin .../media/highlight.css | 0 .../media/markdown.css | 8 + .../media/preview-dark.svg | 0 .../media/preview-light.svg | 0 .../notebook/index.ts | 27 + .../notebook/tsconfig.json | 0 .../markdown-language-features/package.json | 5 +- .../package.nls.json | 0 .../preview-src/activeLineMarker.ts | 0 .../preview-src/csp.ts | 0 .../preview-src/events.ts | 0 .../preview-src/index.ts | 2 - .../preview-src/loading.ts | 0 .../preview-src/messaging.ts | 0 .../preview-src/pre.ts | 0 .../preview-src/scroll-sync.ts | 0 .../preview-src/settings.ts | 0 .../preview-src/strings.ts | 0 .../preview-src/tsconfig.json | 5 + .../schemas/package.schema.json | 0 .../src/commandManager.ts | 0 .../src/commands/index.ts | 0 .../src/commands/moveCursorToPosition.ts | 0 .../src/commands/openDocumentLink.ts | 0 .../src/commands/refreshPreview.ts | 0 .../src/commands/renderDocument.ts | 0 .../src/commands/showPreview.ts | 0 .../commands/showPreviewSecuritySelector.ts | 0 .../src/commands/showSource.ts | 0 .../src/commands/toggleLock.ts | 0 .../src/extension.ts | 0 .../src/features/documentLinkProvider.ts | 0 .../src/features/documentSymbolProvider.ts | 0 .../src/features/foldingProvider.ts | 0 .../src/features/preview.ts | 57 +- .../src/features/previewConfig.ts | 0 .../src/features/previewContentProvider.ts | 2 +- .../src/features/previewManager.ts | 23 +- .../src/features/smartSelect.ts | 0 .../src/features/workspaceSymbolProvider.ts | 0 .../markdown-language-features/src/logger.ts | 0 .../src/markdownEngine.ts | 131 +- .../src/markdownExtensions.ts | 0 .../src/security.ts | 0 .../markdown-language-features/src/slugify.ts | 0 .../src/tableOfContentsProvider.ts | 0 .../src/telemetryReporter.ts | 0 .../src/test/documentLink.test.ts | 0 .../src/test/documentLinkProvider.test.ts | 0 .../src/test/documentSymbolProvider.test.ts | 0 .../src/test/engine.test.ts | 8 +- .../src/test/engine.ts | 0 .../src/test/foldingProvider.test.ts | 0 .../src/test/inMemoryDocument.ts | 0 .../src/test/index.ts | 0 .../src/test/smartSelect.test.ts | 0 .../src/test/tableOfContentsProvider.test.ts | 0 .../src/test/urlToUri.test.ts | 0 .../src/test/util.ts | 0 .../src/test/workspaceSymbolProvider.test.ts | 2 +- .../src/typings/ref.d.ts | 0 .../src/util/arrays.ts | 0 .../src/util/dispose.ts | 0 .../src/util/file.ts | 0 .../src/util/hash.ts | 0 .../src/util/lazy.ts | 0 .../src/util/links.ts | 1 - .../src/util/resources.ts | 10 +- .../src/util/topmostLineMonitor.ts | 25 +- .../src/util/url.ts | 0 .../test-workspace/a.md | 0 .../test-workspace/b.md | 0 .../test-workspace/sub/c.md | 0 .../test-workspace/sub/d.md | 0 .../markdown-language-features/tsconfig.json | 0 .../webpack.config.js | 0 .../markdown-language-features/yarn.lock | 13 +- .../merge-conflict/.vscodeignore | 0 .../merge-conflict/README.md | 0 .../extension-browser.webpack.config.js | 0 .../extension.webpack.config.js | 0 .../merge-conflict/media/icon.png | Bin .../merge-conflict/package.json | 2 +- .../merge-conflict/package.nls.json | 0 .../merge-conflict/src/codelensProvider.ts | 0 .../merge-conflict/src/commandHandler.ts | 0 .../merge-conflict/src/contentProvider.ts | 0 .../merge-conflict/src/delayer.ts | 0 .../src/documentMergeConflict.ts | 0 .../merge-conflict/src/documentTracker.ts | 0 .../merge-conflict/src/interfaces.ts | 0 .../merge-conflict/src/mergeConflictMain.ts | 0 .../merge-conflict/src/mergeConflictParser.ts | 0 .../merge-conflict/src/mergeDecorator.ts | 0 .../merge-conflict/src/services.ts | 0 .../merge-conflict/src/typings/refs.d.ts | 0 .../merge-conflict/tsconfig.json | 0 extensions/merge-conflict/yarn.lock | 13 + .../microsoft-authentication/.vscodeignore | 0 .../extension-browser.webpack.config.js | 0 .../extension.webpack.config.js | 0 .../microsoft-authentication/media/auth.css | 0 .../microsoft-authentication/media/auth.html | 0 .../microsoft-authentication/media/icon.png | Bin .../microsoft-authentication/package.json | 2 +- .../microsoft-authentication/package.nls.json | 0 .../microsoft-authentication/src/AADHelper.ts | 22 +- .../src/authServer.ts | 0 .../src/env/browser/authServer.ts | 0 .../src/env/browser/sha256.ts | 0 .../src/env/node/sha256.ts | 0 .../microsoft-authentication/src/extension.ts | 0 .../microsoft-authentication/src/keychain.ts | 0 .../microsoft-authentication/src/logger.ts | 0 .../src/microsoft-authentication.d.ts | 0 .../src/typings/refs.d.ts | 0 .../microsoft-authentication/src/utils.ts | 0 .../microsoft-authentication/tsconfig.json | 0 .../microsoft-authentication/yarn.lock | 8 +- .../notebook-markdown-extensions/.gitignore | 0 .../.vscodeignore | 0 .../notebook-markdown-extensions/README.md | 0 .../notebook-markdown-extensions/esbuild.js | 0 .../notebook-markdown-extensions/icon.png | Bin .../notebook/emoji.ts | 22 +- .../notebook/katex.ts | 36 + .../notebook/tsconfig.json | 0 .../notebook-markdown-extensions/package.json | 19 +- .../package.nls.json | 0 .../notebook-markdown-extensions/yarn.lock | 2 +- .../npm/.vscode/launch.json | 0 .../npm/.vscode/tasks.json | 0 .../npm/.vscodeignore | 0 .../extensions => extensions}/npm/README.md | 0 .../npm/extension-browser.webpack.config.js | 0 .../npm/extension.webpack.config.js | 0 .../npm/images/code.svg | 0 .../npm/images/npm_icon.png | Bin .../npm/package.json | 2 +- .../npm/package.nls.json | 2 +- .../npm/src/commands.ts | 0 .../npm/src/features/bowerJSONContribution.ts | 0 .../npm/src/features/jsonContributions.ts | 0 .../src/features/packageJSONContribution.ts | 0 .../npm/src/npmBrowserMain.ts | 0 .../npm/src/npmMain.ts | 0 .../npm/src/npmScriptLens.ts | 0 .../npm/src/npmView.ts | 0 .../npm/src/preferred-pm.ts | 0 .../npm/src/readScripts.ts | 0 .../npm/src/scriptHover.ts | 0 .../npm/src/tasks.ts | 0 .../npm/src/typings/refs.d.ts | 0 .../npm/tsconfig.json | 0 .../extensions => extensions}/npm/yarn.lock | 8 +- .../objective-c/.vscodeignore | 0 .../objective-c/build/update-grammars.js | 0 .../objective-c/cgmanifest.json | 0 .../objective-c/language-configuration.json | 0 .../objective-c/package.json | 0 .../objective-c/package.nls.json | 0 .../syntaxes/objective-c++.tmLanguage.json | 0 .../syntaxes/objective-c.tmLanguage.json | 0 .../objective-c/yarn.lock | 0 .../extensions => extensions}/package.json | 2 +- .../perl/.vscodeignore | 0 .../perl/cgmanifest.json | 0 .../perl/package.json | 0 .../perl/package.nls.json | 0 .../perl/perl.language-configuration.json | 0 .../perl/perl6.language-configuration.json | 0 .../perl/syntaxes/perl.tmLanguage.json | 0 .../perl/syntaxes/perl6.tmLanguage.json | 0 .../extensions => extensions}/perl/yarn.lock | 0 .../php-language-features/.vscodeignore | 0 .../php-language-features/README.md | 0 .../extension.webpack.config.js | 0 .../php-language-features/icons/logo.png | Bin .../php-language-features/package.json | 2 +- .../php-language-features/package.nls.json | 0 .../src/features/completionItemProvider.ts | 0 .../src/features/hoverProvider.ts | 0 .../src/features/phpGlobalFunctions.ts | 0 .../src/features/phpGlobals.ts | 0 .../src/features/signatureHelpProvider.ts | 0 .../src/features/utils/async.ts | 0 .../src/features/utils/markedTextUtil.ts | 0 .../src/features/validationProvider.ts | 22 +- .../php-language-features/src/phpMain.ts | 0 .../src/typings/node.additions.d.ts | 0 .../src/typings/refs.d.ts | 0 .../php-language-features/tsconfig.json | 0 .../php-language-features/yarn.lock | 8 +- .../php/.vscode/launch.json | 0 .../php/.vscode/tasks.json | 0 .../php/.vscodeignore | 0 .../php/build/update-grammar.js | 0 .../php/cgmanifest.json | 4 +- .../php/language-configuration.json | 2 +- .../php/package.json | 0 .../php/package.nls.json | 0 .../php/snippets/php.code-snippets | 0 extensions/php/syntaxes/html.tmLanguage.json | 88 + .../php/syntaxes/php.tmLanguage.json | 87 +- .../extensions => extensions}/php/yarn.lock | 0 .../extensions => extensions}/postinstall.js | 3 - .../powershell/.vscodeignore | 0 .../powershell/cgmanifest.json | 0 .../powershell/language-configuration.json | 0 .../powershell/package.json | 0 .../powershell/package.nls.json | 0 .../snippets/powershell.code-snippets | 0 .../syntaxes/powershell.tmLanguage.json | 0 .../powershell/yarn.lock | 0 .../pug/.vscodeignore | 0 .../pug/cgmanifest.json | 0 .../pug/language-configuration.json | 0 .../pug/package.json | 0 .../pug/package.nls.json | 0 .../pug/syntaxes/pug.tmLanguage.json | 0 .../extensions => extensions}/pug/yarn.lock | 0 .../python/.vscode/launch.json | 0 .../python/.vscode/tasks.json | 0 .../python/.vscodeignore | 0 .../python/cgmanifest.json | 0 .../python/language-configuration.json | 0 .../python/package.json | 0 .../python/package.nls.json | 0 .../syntaxes/MagicPython.tmLanguage.json | 0 .../syntaxes/MagicRegExp.tmLanguage.json | 0 .../colorize-fixtures/test-freeze-56377.py | 0 .../python/test/colorize-fixtures/test.py | 0 .../test-freeze-56377_py.json | 0 .../python/test/colorize-results/test_py.json | 0 .../python/yarn.lock | 0 .../extensions => extensions}/r/.vscodeignore | 0 .../r/cgmanifest.json | 0 .../r/language-configuration.json | 0 .../extensions => extensions}/r/package.json | 0 .../r/package.nls.json | 0 .../r/syntaxes/r.tmLanguage.json | 0 .../extensions => extensions}/r/yarn.lock | 0 .../razor/.vscodeignore | 0 .../razor/cgmanifest.json | 0 .../razor/language-configuration.json | 0 .../razor/package.json | 0 .../razor/package.nls.json | 0 .../razor/syntaxes/cshtml.tmLanguage.json | 0 .../extensions => extensions}/razor/yarn.lock | 0 .../ruby/.vscodeignore | 0 .../ruby/cgmanifest.json | 0 .../ruby/language-configuration.json | 4 +- .../ruby/package.json | 0 .../ruby/package.nls.json | 0 .../ruby/syntaxes/ruby.tmLanguage.json | 0 .../extensions => extensions}/ruby/yarn.lock | 0 .../rust/.vscodeignore | 0 .../rust/cgmanifest.json | 0 .../rust/language-configuration.json | 0 .../rust/package.json | 0 .../rust/package.nls.json | 0 .../rust/syntaxes/rust.tmLanguage.json | 0 .../extensions => extensions}/rust/yarn.lock | 0 .../scss/.vscodeignore | 0 .../scss/cgmanifest.json | 4 +- .../scss/language-configuration.json | 0 .../scss/package.json | 0 .../scss/package.nls.json | 0 .../scss/syntaxes/sassdoc.tmLanguage.json | 0 .../scss/syntaxes/scss.tmLanguage.json | 0 .../extensions => extensions}/scss/yarn.lock | 0 .../search-result/.vscodeignore | 0 .../search-result/README.md | 0 .../extension-browser.webpack.config.js | 0 .../search-result/extension.webpack.config.js | 0 .../search-result/package.json | 0 .../search-result/package.nls.json | 0 .../search-result/src/extension.ts | 0 .../search-result/src/media/refresh-dark.svg | 0 .../search-result/src/media/refresh-light.svg | 0 .../search-result}/src/typings/refs.d.ts | 0 .../syntaxes/generateTMLanguage.js | 0 .../syntaxes/searchResult.tmLanguage.json | 0 .../search-result/tsconfig.json | 0 .../search-result/yarn.lock | 0 .../shaderlab/.vscodeignore | 0 .../shaderlab/cgmanifest.json | 0 .../shaderlab/language-configuration.json | 0 .../shaderlab/package.json | 0 .../shaderlab/package.nls.json | 0 .../syntaxes/shaderlab.tmLanguage.json | 0 .../shaderlab/yarn.lock | 0 .../shared.webpack.config.js | 0 .../shellscript/.vscodeignore | 0 .../shellscript/cgmanifest.json | 0 .../shellscript/language-configuration.json | 0 .../shellscript/package.json | 1 - .../shellscript/package.nls.json | 0 .../syntaxes/shell-unix-bash.tmLanguage.json | 0 .../shellscript/yarn.lock | 0 .../simple-browser/.gitignore | 0 .../simple-browser/.vscodeignore | 0 .../simple-browser/README.md | 0 .../extension-browser.webpack.config.js | 0 .../extension.webpack.config.js | 0 .../simple-browser/media/icon.png | Bin .../simple-browser/media/main.css | 0 .../simple-browser/media/preview-dark.svg | 0 .../simple-browser/media/preview-light.svg | 0 .../simple-browser/package.json | 5 +- .../simple-browser/package.nls.json | 0 .../simple-browser/preview-src/events.ts | 0 .../simple-browser/preview-src/index.ts | 1 - .../simple-browser}/preview-src/tsconfig.json | 0 .../simple-browser/src/dispose.ts | 0 .../simple-browser/src/extension.ts | 0 .../src/simpleBrowserManager.ts | 0 .../simple-browser/src/simpleBrowserView.ts | 0 .../simple-browser}/src/typings/ref.d.ts | 3 - .../simple-browser/tsconfig.json | 0 .../simple-browser/webpack.config.js | 0 .../simple-browser/yarn.lock | 13 +- .../sql/.vscodeignore | 0 .../sql/build/update-grammar.js | 0 .../sql/cgmanifest.json | 0 .../sql/language-configuration.json | 0 .../sql/package.json | 0 .../sql/package.nls.json | 0 .../sql/syntaxes/sql.tmLanguage.json | 0 .../extensions => extensions}/sql/yarn.lock | 0 .../swift/.vscodeignore | 0 .../swift/LICENSE.md | 0 .../swift/cgmanifest.json | 0 .../swift/language-configuration.json | 0 .../swift/package.json | 0 .../swift/package.nls.json | 0 .../swift/snippets/swift.code-snippets | 0 .../swift/syntaxes/swift.tmLanguage.json | 10 +- .../extensions => extensions}/swift/yarn.lock | 0 .../.vscodeignore | 0 .../testing-editor-contributions/README.md | 0 .../extension-browser.webpack.config.js | 0 .../extension.webpack.config.js | 0 .../media/icon.png | Bin .../testing-editor-contributions/package.json | 0 .../package.nls.json | 0 .../src/extension.ts | 0 .../src/typings/refs.d.ts | 3 - .../tsconfig.json | 0 .../testing-editor-contributions/yarn.lock | 0 .../theme-abyss/.vscodeignore | 0 .../theme-abyss/cgmanifest.json | 0 .../theme-abyss/package.json | 0 .../theme-abyss/package.nls.json | 0 .../theme-abyss/themes/abyss-color-theme.json | 0 .../theme-abyss/yarn.lock | 0 .../fileicons/images/document-dark.svg | 0 .../fileicons/images/document-light.svg | 0 .../fileicons/images/folder-dark.svg | 0 .../fileicons/images/folder-light.svg | 0 .../fileicons/images/folder-open-dark.svg | 0 .../fileicons/images/folder-open-light.svg | 0 .../fileicons/images/root-folder-dark.svg | 0 .../fileicons/images/root-folder-light.svg | 0 .../images/root-folder-open-dark.svg | 0 .../images/root-folder-open-light.svg | 0 .../fileicons/vs_minimal-icon-theme.json | 0 .../theme-defaults/package.json | 0 .../theme-defaults/package.nls.json | 0 .../theme-defaults/themes/dark_plus.json | 0 .../theme-defaults/themes/dark_vs.json | 0 .../theme-defaults/themes/hc_black.json | 3 +- .../theme-defaults/themes/light_plus.json | 0 .../theme-defaults/themes/light_vs.json | 3 +- .../theme-defaults/yarn.lock | 0 .../theme-kimbie-dark/.vscodeignore | 0 .../theme-kimbie-dark/cgmanifest.json | 0 .../theme-kimbie-dark/package.json | 0 .../theme-kimbie-dark/package.nls.json | 0 .../themes/kimbie-dark-color-theme.json | 0 .../theme-kimbie-dark/yarn.lock | 0 .../theme-monokai-dimmed/.vscodeignore | 0 .../theme-monokai-dimmed/cgmanifest.json | 0 .../theme-monokai-dimmed/package.json | 0 .../theme-monokai-dimmed/package.nls.json | 0 .../themes/dimmed-monokai-color-theme.json | 0 .../theme-monokai-dimmed/yarn.lock | 0 .../theme-monokai/.vscodeignore | 0 .../theme-monokai/cgmanifest.json | 0 .../theme-monokai/package.json | 0 .../theme-monokai/package.nls.json | 0 .../themes/monokai-color-theme.json | 2 +- .../theme-monokai/yarn.lock | 0 .../theme-quietlight/.vscodeignore | 0 .../theme-quietlight/cgmanifest.json | 0 .../theme-quietlight/package.json | 0 .../theme-quietlight/package.nls.json | 0 .../themes/quietlight-color-theme.json | 0 .../theme-quietlight/yarn.lock | 0 .../theme-red/.vscodeignore | 0 .../theme-red/cgmanifest.json | 0 .../theme-red/package.json | 0 .../theme-red/package.nls.json | 0 .../theme-red/themes/Red-color-theme.json | 0 .../theme-red/yarn.lock | 0 .../theme-seti/.vscodeignore | 0 extensions/theme-seti/CONTRIBUTING.md | 33 + .../theme-seti/README.md | 0 .../theme-seti/ThirdPartyNotices.txt | 0 .../theme-seti/build/update-icon-theme.js | 0 .../theme-seti/cgmanifest.json | 2 +- .../theme-seti/icons/preview.html | 0 .../icons/seti-circular-128x128.png | Bin extensions/theme-seti/icons/seti.woff | Bin 0 -> 36572 bytes .../theme-seti/icons/vs-seti-icon-theme.json | 210 +- .../theme-seti/package.json | 0 .../theme-seti/package.nls.json | 0 .../theme-seti/yarn.lock | 0 .../theme-solarized-dark/.vscodeignore | 0 .../theme-solarized-dark/cgmanifest.json | 0 .../theme-solarized-dark/package.json | 0 .../theme-solarized-dark/package.nls.json | 0 .../themes/solarized-dark-color-theme.json | 0 .../theme-solarized-dark/yarn.lock | 0 .../theme-solarized-light/.vscodeignore | 0 .../theme-solarized-light/cgmanifest.json | 0 .../theme-solarized-light/package.json | 0 .../theme-solarized-light/package.nls.json | 0 .../themes/solarized-light-color-theme.json | 32 +- .../theme-solarized-light/yarn.lock | 0 .../theme-tomorrow-night-blue/.vscodeignore | 0 .../theme-tomorrow-night-blue/cgmanifest.json | 0 .../theme-tomorrow-night-blue/package.json | 0 .../package.nls.json | 0 .../tomorrow-night-blue-color-theme.json | 0 .../theme-tomorrow-night-blue/yarn.lock | 0 .../tsconfig.base.json | 0 .../types/lib.textEncoder.d.ts | 0 .../types/lib.url.d.ts | 0 .../typescript-basics/.vscodeignore | 0 .../build/update-grammars.js | 0 .../typescript-basics/cgmanifest.json | 0 .../language-configuration.json | 0 .../typescript-basics/package.json | 0 .../typescript-basics/package.nls.json | 0 .../snippets/typescript.code-snippets | 0 .../typescript-basics/syntaxes/Readme.md | 0 .../syntaxes/TypeScript.tmLanguage.json | 0 .../syntaxes/TypeScriptReact.tmLanguage.json | 0 .../jsdoc.js.injection.tmLanguage.json | 0 .../jsdoc.ts.injection.tmLanguage.json | 0 .../typescript-basics/yarn.lock | 0 .../.eslintrc.json | 0 .../.vscodeignore | 0 .../typescript-language-features/README.md | 0 .../cgmanifest.json | 0 .../extension-browser.webpack.config.js | 0 .../extension.webpack.config.js | 0 .../language-configuration.json | 0 .../media/icon.png | Bin .../typescript-language-features/package.json | 22 +- .../package.nls.json | 1 + .../schemas/jsconfig.schema.json | 0 .../schemas/package.schema.json | 0 .../schemas/tsconfig.schema.json | 0 .../typescript-language-features/src/api.ts | 0 .../src/commands/commandManager.ts | 16 +- .../src/commands/configurePlugin.ts | 0 .../src/commands/goToProjectConfiguration.ts | 0 .../src/commands/index.ts | 0 .../commands/learnMoreAboutRefactorings.ts | 0 .../src/commands/openTsServerLog.ts | 0 .../src/commands/reloadProject.ts | 0 .../src/commands/restartTsServer.ts | 0 .../src/commands/selectTypeScriptVersion.ts | 0 .../src/extension.browser.ts | 0 .../src/extension.ts | 0 .../src/languageFeatures/callHierarchy.ts | 0 .../codeLens/baseCodeLensProvider.ts | 0 .../codeLens/implementationsCodeLens.ts | 0 .../codeLens/referencesCodeLens.ts | 0 .../src/languageFeatures/completions.ts | 19 +- .../definitionProviderBase.ts | 0 .../src/languageFeatures/definitions.ts | 0 .../src/languageFeatures/diagnostics.ts | 0 .../directiveCommentCompletions.ts | 0 .../src/languageFeatures/documentHighlight.ts | 0 .../src/languageFeatures/documentSymbol.ts | 0 .../fileConfigurationManager.ts | 1 - .../src/languageFeatures/fileReferences.ts | 0 .../src/languageFeatures/fixAll.ts | 0 .../src/languageFeatures/folding.ts | 0 .../src/languageFeatures/formatting.ts | 0 .../src/languageFeatures/hover.ts | 0 .../src/languageFeatures/implementations.ts | 0 .../src/languageFeatures/jsDocCompletions.ts | 0 .../languageFeatures/languageConfiguration.ts | 0 .../src/languageFeatures/organizeImports.ts | 79 +- .../src/languageFeatures/quickFix.ts | 0 .../src/languageFeatures/refactor.ts | 10 +- .../src/languageFeatures/references.ts | 0 .../src/languageFeatures/rename.ts | 0 .../src/languageFeatures/semanticTokens.ts | 0 .../src/languageFeatures/signatureHelp.ts | 0 .../src/languageFeatures/smartSelect.ts | 0 .../src/languageFeatures/tagClosing.ts | 0 .../src/languageFeatures/tsconfig.ts | 0 .../src/languageFeatures/typeDefinitions.ts | 0 .../languageFeatures/updatePathsOnRename.ts | 0 .../src/languageFeatures/workspaceSymbols.ts | 0 .../src/languageProvider.ts | 0 .../src/lazyClientHost.ts | 0 .../src/protocol.const.ts | 0 .../src/protocol.d.ts | 0 .../src/task/taskProvider.ts | 0 .../src/task/tsconfigProvider.ts | 0 .../src/test-all.ts | 0 .../src/test/index.ts | 0 .../src/test/smoke/completions.test.ts | 0 .../src/test/smoke/fixAll.test.ts | 0 .../src/test/smoke/index.ts | 0 .../src/test/smoke/jsDocCompletions.test.ts | 0 .../src/test/smoke/quickFix.test.ts | 0 .../src/test/smoke/referencesCodeLens.test.ts | 0 .../src/test/suggestTestHelpers.ts | 0 .../src/test/testUtils.ts | 2 +- .../src/test/unit/cachedResponse.test.ts | 0 .../src/test/unit/functionCallSnippet.test.ts | 0 .../src/test/unit/index.ts | 0 .../src/test/unit/jsdocSnippet.test.ts | 0 .../src/test/unit/onEnter.test.ts | 0 .../src/test/unit/previewer.test.ts | 0 .../src/test/unit/requestQueue.test.ts | 0 .../src/test/unit/server.test.ts | 0 .../src/tsServer/bufferSyncSupport.ts | 0 .../src/tsServer/cachedResponse.ts | 0 .../src/tsServer/callbackMap.ts | 0 .../src/tsServer/cancellation.electron.ts | 0 .../src/tsServer/cancellation.ts | 0 .../tsServer/logDirectoryProvider.electron.ts | 0 .../src/tsServer/logDirectoryProvider.ts | 0 .../src/tsServer/requestQueue.ts | 0 .../src/tsServer/server.ts | 40 +- .../src/tsServer/serverError.ts | 0 .../src/tsServer/serverProcess.browser.ts | 0 .../src/tsServer/serverProcess.electron.ts | 0 .../src/tsServer/spawner.ts | 3 + .../src/tsServer/versionManager.ts | 2 +- .../src/tsServer/versionProvider.electron.ts | 0 .../src/tsServer/versionProvider.ts | 0 .../src/tsServer/versionStatus.ts | 8 +- .../src/typeScriptServiceClientHost.ts | 2 + .../src/typescriptService.ts | 0 .../src/typescriptServiceClient.ts | 52 +- .../src/typings/ref.d.ts | 0 .../src/utils/activeJsTsEditorTracker.ts | 0 .../src/utils/api.ts | 0 .../src/utils/arrays.ts | 0 .../src/utils/async.ts | 0 .../src/utils/cancellation.ts | 0 .../src/utils/codeAction.ts | 0 .../src/utils/configuration.ts | 7 +- .../src/utils/dependentRegistration.ts | 0 .../src/utils/dispose.ts | 0 .../src/utils/documentSelector.ts | 0 .../src/utils/errorCodes.ts | 0 .../src/utils/fileSchemes.ts | 0 .../src/utils/fileSystem.electron.ts | 0 .../src/utils/fixNames.ts | 0 .../src/utils/fs.ts | 0 .../src/utils/languageDescription.ts | 0 .../src/utils/languageModeIds.ts | 0 .../src/utils/largeProjectStatus.ts | 8 +- .../src/utils/lazy.ts | 0 .../src/utils/logLevelMonitor.ts | 106 + .../src/utils/logger.ts | 0 .../src/utils/managedFileContext.ts | 0 .../src/utils/memoize.ts | 0 .../src/utils/modifiers.ts | 0 .../src/utils/objects.ts | 0 .../src/utils/platform.ts | 0 .../src/utils/pluginPathsProvider.ts | 0 .../src/utils/plugins.ts | 0 .../src/utils/previewer.ts | 0 .../src/utils/regexp.ts | 0 .../src/utils/relativePathResolver.ts | 0 .../src/utils/resourceMap.ts | 0 .../src/utils/snippetForFunctionCall.ts | 0 .../src/utils/telemetry.ts | 0 .../src/utils/temp.electron.ts | 0 .../src/utils/tracer.ts | 0 .../src/utils/tsconfig.ts | 0 .../src/utils/typeConverters.ts | 0 .../src/utils/typingsStatus.ts | 0 .../test-workspace/bar.ts | 0 .../test-workspace/foo.ts | 0 .../test-workspace/foojs.js | 0 .../test-workspace/index.ts | 0 .../test-workspace/tsconfig.json | 0 .../tsconfig.json | 0 .../typescript-language-features/yarn.lock | 8 +- .../vb/.vscodeignore | 0 .../vb/cgmanifest.json | 0 .../vb/language-configuration.json | 0 .../extensions => extensions}/vb/package.json | 0 .../vb/package.nls.json | 0 .../vb/snippets/vb.code-snippets | 0 .../vb/syntaxes/asp-vb-net.tmlanguage.json | 0 .../extensions => extensions}/vb/yarn.lock | 0 .../vscode-api-tests/.gitignore | 0 .../vscode-api-tests/.vscode/launch.json | 0 .../vscode-api-tests/.vscode/tasks.json | 0 .../vscode-api-tests/.vscodeignore | 0 .../vscode-api-tests/media/icon.png | Bin .../vscode-api-tests/package.json | 10 +- .../vscode-api-tests/src/extension.ts | 0 .../vscode-api-tests/src/memfs.ts | 0 .../src/singlefolder-tests/commands.test.ts | 6 +- .../singlefolder-tests/configuration.test.ts | 18 +- .../src/singlefolder-tests/debug.test.ts | 40 +- .../src/singlefolder-tests/editor.test.ts | 50 +- .../src/singlefolder-tests/env.test.ts | 26 +- .../src/singlefolder-tests/extensions.test.ts | 0 .../src/singlefolder-tests/index.ts | 0 .../src/singlefolder-tests/languages.test.ts | 24 +- .../notebook.document.test.ts | 137 +- .../notebook.editor.test.ts | 17 +- .../src/singlefolder-tests/notebook.test.ts | 509 +- .../src/singlefolder-tests/quickInput.test.ts | 20 +- .../src/singlefolder-tests/rpc.test.ts | 8 +- .../src/singlefolder-tests/terminal.test.ts | 35 + .../src/singlefolder-tests/types.test.ts | 0 .../src/singlefolder-tests/webview.test.ts | 6 +- .../src/singlefolder-tests/window.test.ts | 98 +- .../workspace.event.test.ts | 44 +- .../singlefolder-tests/workspace.fs.test.ts | 18 +- .../workspace.tasks.test.ts | 0 .../src/singlefolder-tests/workspace.test.ts | 210 +- .../vscode-api-tests/src/typings/ref.d.ts | 0 .../vscode-api-tests/src/utils.ts | 12 + .../src/workspace-tests/index.ts | 0 .../src/workspace-tests/workspace.test.ts | 2 +- .../testWorkspace/.vscode/launch.json | 0 .../testWorkspace/.vscode/settings.json | 0 .../testWorkspace/10linefile.ts | 0 .../testWorkspace/30linefile.ts | 0 .../vscode-api-tests/testWorkspace/bower.json | 0 .../vscode-api-tests/testWorkspace/debug.js | 0 .../vscode-api-tests/testWorkspace/far.js | 0 .../testWorkspace/files-exclude/file.txt | 0 .../vscode-api-tests/testWorkspace/image%.png | Bin .../testWorkspace/image%02.png | Bin .../vscode-api-tests/testWorkspace/image.png | Bin .../vscode-api-tests/testWorkspace/lorem.txt | 0 .../testWorkspace/search-exclude/file.txt | 0 .../vscode-api-tests/testWorkspace/simple.txt | 0 .../testWorkspace/sub/image.png | Bin .../testWorkspace2/.vscode/settings.json | 0 .../testWorkspace2/simple.txt | 0 .../testworkspace.code-workspace | 0 .../vscode-api-tests/tsconfig.json | 0 .../vscode-api-tests/yarn.lock | 8 +- .../vscode-colorize-tests/.gitignore | 0 .../vscode-colorize-tests/.vscode/launch.json | 0 .../vscode-colorize-tests/.vscode/tasks.json | 0 .../vscode-colorize-tests/media/icon.png | Bin .../vscode-colorize-tests/package.json | 2 +- .../producticons/ElegantIcons.woff | Bin .../producticons/index.html | 0 .../producticons/mit_license.txt | 0 .../producticons/test-product-icon-theme.json | 0 .../src/colorizer.test.ts | 4 +- .../src/colorizerTestMain.ts | 0 .../vscode-colorize-tests/src/index.ts | 0 .../src/typings/ref.d.ts | 0 .../test/colorize-fixtures/12750.html | 0 .../test/colorize-fixtures/13448.html | 0 .../test/colorize-fixtures/14119.less | 0 .../test/colorize-fixtures/25920.html | 0 .../test/colorize-fixtures/Dockerfile | 0 .../test/colorize-fixtures/basic.java | 0 .../test/colorize-fixtures/issue-1550.yaml | 0 .../test/colorize-fixtures/issue-28354.php | 0 .../test/colorize-fixtures/issue-4008.yaml | 0 .../test/colorize-fixtures/issue-6303.yaml | 0 .../test/colorize-fixtures/issue-76997.php | 0 .../test/colorize-fixtures/makefile | 0 .../test/colorize-fixtures/test-13777.go | 0 .../test/colorize-fixtures/test-23630.cpp | 0 .../test/colorize-fixtures/test-23850.cpp | 0 .../test/colorize-fixtures/test-33886.md | 0 .../test/colorize-fixtures/test-4287.pug | 0 .../test/colorize-fixtures/test-6611.rs | 0 .../test/colorize-fixtures/test-7115.xml | 0 .../test/colorize-fixtures/test-78769.cpp | 0 .../test/colorize-fixtures/test-80644.cpp | 0 .../test/colorize-fixtures/test-brackets.tsx | 0 .../colorize-fixtures/test-cssvariables.less | 0 .../colorize-fixtures/test-cssvariables.scss | 0 .../colorize-fixtures/test-embedding.html | 0 .../colorize-fixtures/test-freeze-56476.ps1 | 0 .../colorize-fixtures/test-function-inv.ts | 0 .../test/colorize-fixtures/test-issue11.ts | 0 .../test/colorize-fixtures/test-issue5431.ts | 0 .../test/colorize-fixtures/test-issue5465.ts | 0 .../test/colorize-fixtures/test-issue5566.ts | 0 .../test-jsdoc-multiline-type.ts | 0 .../test/colorize-fixtures/test-keywords.ts | 0 .../test/colorize-fixtures/test-members.ts | 0 .../colorize-fixtures/test-object-literals.ts | 0 .../test/colorize-fixtures/test-regex.coffee | 0 .../test/colorize-fixtures/test-strings.ts | 0 .../test/colorize-fixtures/test-this.ts | 0 .../test/colorize-fixtures/test-variables.css | 0 .../test/colorize-fixtures/test.bat | 0 .../test/colorize-fixtures/test.c | 0 .../test/colorize-fixtures/test.cc | 0 .../test/colorize-fixtures/test.clj | 0 .../test/colorize-fixtures/test.coffee | 0 .../test/colorize-fixtures/test.cpp | 0 .../test/colorize-fixtures/test.cs | 12 +- .../test/colorize-fixtures/test.cshtml | 0 .../test/colorize-fixtures/test.css | 0 .../test/colorize-fixtures/test.cu | 0 .../test/colorize-fixtures/test.dart | 19 + .../test/colorize-fixtures/test.fs | 0 .../test/colorize-fixtures/test.go | 0 .../test/colorize-fixtures/test.groovy | 0 .../test/colorize-fixtures/test.handlebars | 0 .../test/colorize-fixtures/test.hbs | 0 .../test/colorize-fixtures/test.hlsl | 0 .../test/colorize-fixtures/test.html | 0 .../test/colorize-fixtures/test.ini | 0 .../test/colorize-fixtures/test.jl | 0 .../test/colorize-fixtures/test.js | 0 .../test/colorize-fixtures/test.json | 0 .../test/colorize-fixtures/test.jsx | 0 .../test/colorize-fixtures/test.less | 0 .../test/colorize-fixtures/test.log | 0 .../test/colorize-fixtures/test.lua | 0 .../test/colorize-fixtures/test.m | 0 .../test/colorize-fixtures/test.md | 0 .../test/colorize-fixtures/test.mm | 0 .../test/colorize-fixtures/test.php | 0 .../test/colorize-fixtures/test.pl | 0 .../test/colorize-fixtures/test.ps1 | 0 .../test/colorize-fixtures/test.pug | 0 .../test/colorize-fixtures/test.r | 0 .../test/colorize-fixtures/test.rb | 0 .../test/colorize-fixtures/test.rs | 0 .../test/colorize-fixtures/test.scss | 0 .../test/colorize-fixtures/test.sh | 0 .../test/colorize-fixtures/test.shader | 0 .../test/colorize-fixtures/test.sql | 0 .../test/colorize-fixtures/test.swift | 0 .../test/colorize-fixtures/test.ts | 0 .../test/colorize-fixtures/test.vb | 0 .../test/colorize-fixtures/test.xml | 0 .../test/colorize-fixtures/test.yaml | 0 .../test/colorize-fixtures/test2.pl | 0 .../test/colorize-fixtures/test6916.js | 0 .../test/colorize-fixtures/tsconfig_off.json | 0 .../test/colorize-results/12750_html.json | 0 .../test/colorize-results/13448_html.json | 0 .../test/colorize-results/14119_less.json | 0 .../test/colorize-results/25920_html.json | 0 .../test/colorize-results/Dockerfile.json | 0 .../test/colorize-results/basic_java.json | 0 .../colorize-results/issue-1550_yaml.json | 0 .../colorize-results/issue-28354_php.json | 0 .../colorize-results/issue-4008_yaml.json | 0 .../colorize-results/issue-6303_yaml.json | 0 .../colorize-results/issue-76997_php.json | 0 .../test/colorize-results/makefile.json | 0 .../test/colorize-results/test-13777_go.json | 0 .../test/colorize-results/test-23630_cpp.json | 0 .../test/colorize-results/test-23850_cpp.json | 0 .../test/colorize-results/test-33886_md.json | 0 .../test/colorize-results/test-4287_pug.json | 0 .../test/colorize-results/test-6611_rs.json | 0 .../test/colorize-results/test-7115_xml.json | 0 .../test/colorize-results/test-78769_cpp.json | 0 .../test/colorize-results/test-80644_cpp.json | 0 .../colorize-results/test-brackets_tsx.json | 0 .../test-cssvariables_less.json | 0 .../test-cssvariables_scss.json | 0 .../colorize-results/test-embedding_html.json | 0 .../test-freeze-56476_ps1.json | 0 .../test-function-inv_ts.json | 0 .../colorize-results/test-issue11_ts.json | 0 .../colorize-results/test-issue5431_ts.json | 0 .../colorize-results/test-issue5465_ts.json | 0 .../colorize-results/test-issue5566_ts.json | 0 .../test-jsdoc-multiline-type_ts.json | 0 .../colorize-results/test-keywords_ts.json | 0 .../colorize-results/test-members_ts.json | 0 .../test-object-literals_ts.json | 0 .../colorize-results/test-regex_coffee.json | 0 .../colorize-results/test-strings_ts.json | 0 .../test/colorize-results/test-this_ts.json | 0 .../colorize-results/test-variables_css.json | 0 .../test/colorize-results/test2_pl.json | 0 .../test/colorize-results/test6916_js.json | 0 .../test/colorize-results/test_bat.json | 8 +- .../test/colorize-results/test_c.json | 0 .../test/colorize-results/test_cc.json | 0 .../test/colorize-results/test_clj.json | 0 .../test/colorize-results/test_coffee.json | 0 .../test/colorize-results/test_cpp.json | 0 .../test/colorize-results/test_cs.json | 739 +- .../test/colorize-results/test_cshtml.json | 0 .../test/colorize-results/test_css.json | 0 .../test/colorize-results/test_cu.json | 0 .../test/colorize-results/test_dart.json | 673 + .../test/colorize-results/test_fs.json | 0 .../test/colorize-results/test_go.json | 0 .../test/colorize-results/test_groovy.json | 0 .../colorize-results/test_handlebars.json | 0 .../test/colorize-results/test_hbs.json | 0 .../test/colorize-results/test_hlsl.json | 0 .../test/colorize-results/test_html.json | 0 .../test/colorize-results/test_ini.json | 0 .../test/colorize-results/test_jl.json | 0 .../test/colorize-results/test_js.json | 0 .../test/colorize-results/test_json.json | 0 .../test/colorize-results/test_jsx.json | 0 .../test/colorize-results/test_less.json | 0 .../test/colorize-results/test_log.json | 0 .../test/colorize-results/test_lua.json | 0 .../test/colorize-results/test_m.json | 0 .../test/colorize-results/test_md.json | 0 .../test/colorize-results/test_mm.json | 0 .../test/colorize-results/test_php.json | 0 .../test/colorize-results/test_pl.json | 0 .../test/colorize-results/test_ps1.json | 0 .../test/colorize-results/test_pug.json | 0 .../test/colorize-results/test_r.json | 0 .../test/colorize-results/test_rb.json | 0 .../test/colorize-results/test_rs.json | 0 .../test/colorize-results/test_scss.json | 0 .../test/colorize-results/test_sh.json | 0 .../test/colorize-results/test_shader.json | 0 .../test/colorize-results/test_sql.json | 0 .../test/colorize-results/test_swift.json | 0 .../test/colorize-results/test_ts.json | 0 .../test/colorize-results/test_vb.json | 0 .../test/colorize-results/test_xml.json | 0 .../test/colorize-results/test_yaml.json | 0 .../colorize-results/tsconfig_off_json.json | 0 .../test/semantic-test/.vscode/settings.json | 0 .../test/semantic-test/semantic-test.json | 0 .../vscode-colorize-tests/tsconfig.json | 0 .../vscode-colorize-tests/yarn.lock | 8 +- .../vscode-custom-editor-tests/.vscodeignore | 0 .../customEditorMedia/textEditor.js | 0 .../vscode-custom-editor-tests/media/icon.png | Bin .../vscode-custom-editor-tests/package.json | 2 +- .../src/customTextEditor.ts | 0 .../vscode-custom-editor-tests/src/dispose.ts | 0 .../src/extension.ts | 0 .../src/test/customEditor.test.ts | 34 +- .../src/test/index.ts | 0 .../src/test/utils.ts | 0 .../src/typings/ref.d.ts | 0 .../test-workspace/index.abc | 0 .../vscode-custom-editor-tests/tsconfig.json | 0 .../vscode-custom-editor-tests/yarn.lock | 8 +- .../vscode-notebook-tests/.vscode/launch.json | 0 .../vscode-notebook-tests/.vscode/tasks.json | 0 .../vscode-notebook-tests/media/icon.png | Bin .../vscode-notebook-tests/package.json | 10 +- .../src/customRenderer.js | 9 +- .../vscode-notebook-tests/src/extension.ts | 26 +- .../vscode-notebook-tests/src/index.ts | 0 .../src/typings/ref.d.ts | 0 .../vscode-notebook-tests/src/utils.ts | 0 .../test/customRenderer.vsctestnb | 0 .../test/empty.vsctestnb | 0 .../test/first.vsctestnb | 0 .../test/second.vsctestnb | 0 .../vscode-notebook-tests/tsconfig.json | 0 extensions/vscode-notebook-tests/yarn.lock | 8 + .../vscode-test-resolver/.gitignore | 0 .../vscode-test-resolver/.vscode/launch.json | 0 .../vscode-test-resolver/.vscodeignore | 0 .../vscode-test-resolver/media/icon.png | Bin .../vscode-test-resolver/package.json | 10 +- .../scripts/terminateProcess.sh | 0 .../vscode-test-resolver/src/download.ts | 0 .../vscode-test-resolver/src/extension.ts | 17 +- .../vscode-test-resolver/src/typings/ref.d.ts | 0 .../src/util/processes.ts | 0 .../vscode-test-resolver/tsconfig.json | 0 extensions/vscode-test-resolver/yarn.lock | 8 + .../xml/.vscodeignore | 0 .../xml/cgmanifest.json | 0 .../xml/package.json | 0 .../xml/package.nls.json | 0 .../xml/syntaxes/xml.tmLanguage.json | 0 .../xml/syntaxes/xsl.tmLanguage.json | 0 .../xml/xml.language-configuration.json | 0 .../xml/xsl.language-configuration.json | 0 .../extensions => extensions}/xml/yarn.lock | 0 .../yaml/.vscodeignore | 0 .../yaml/cgmanifest.json | 0 .../yaml/language-configuration.json | 0 .../yaml/package.json | 0 .../yaml/package.nls.json | 0 .../yaml/syntaxes/yaml.tmLanguage.json | 0 .../extensions => extensions}/yaml/yarn.lock | 0 .../extensions => extensions}/yarn.lock | 8 +- lib/vscode/gulpfile.js => gulpfile.js | 0 install.sh | 577 - lib/vscode/.devcontainer/README.md | 100 - lib/vscode/.editorconfig | 15 - lib/vscode/.gitattributes | 10 - lib/vscode/.github/ISSUE_TEMPLATE/config.yml | 5 - lib/vscode/.gitignore | 18 - lib/vscode/LICENSE.txt | 21 - lib/vscode/README.md | 75 - lib/vscode/ThirdPartyNotices.txt | 2853 --- .../azure-pipelines/common/createAsset.js | 94 - .../azure-pipelines/common/sync-mooncake.js | 87 - .../azure-pipelines/common/sync-mooncake.ts | 131 - .../azure-pipelines/darwin/publish-server.sh | 14 - .../azure-pipelines/linux/alpine/publish.sh | 28 - .../build/azure-pipelines/sync-mooncake.yml | 24 - .../build/azure-pipelines/web/publish.sh | 15 - lib/vscode/build/lib/i18n.js | 1204 -- .../npm/update-localization-extension.js | 132 - lib/vscode/coder.js | 63 - .../github-authentication/src/extension.ts | 91 - lib/vscode/extensions/jake/yarn.lock | 13 - .../notebook/index.ts | 39 - .../src/util/resources.ts | 33 - .../extensions/merge-conflict/yarn.lock | 13 - .../php/syntaxes/html.tmLanguage.json | 189 - .../extensions/theme-seti/CONTRIBUTING.md | 32 - .../extensions/theme-seti/icons/seti.woff | Bin 36472 -> 0 bytes .../vscode-notebook-tests/yarn.lock | 8 - .../extensions/vscode-test-resolver/yarn.lock | 8 - lib/vscode/package.json | 227 - lib/vscode/src/typings/electron.d.ts | 16051 ---------------- lib/vscode/src/typings/keytar.d.ts | 58 - lib/vscode/src/typings/native-keymap.d.ts | 75 - lib/vscode/src/vs/base/node/proxy_agent.ts | 1 - .../vs/base/test/browser/comparers.test.ts | 283 - .../electron-sandbox/workbench/workbench.js | 116 - .../editor/contrib/hover/modesContentHover.ts | 637 - lib/vscode/src/vs/ipc.d.ts | 1 - .../dialogs/test/common/testDialogService.ts | 17 - .../src/vs/platform/opener/browser/link.ts | 92 - .../vs/platform/state/node/stateService.ts | 158 - .../vs/platform/state/test/node/state.test.ts | 57 - lib/vscode/src/vs/server/browser/client.ts | 198 - lib/vscode/src/vs/server/common/telemetry.ts | 65 - lib/vscode/src/vs/server/common/util.ts | 1 - lib/vscode/src/vs/server/entry.ts | 83 - lib/vscode/src/vs/server/fork.js | 3 - lib/vscode/src/vs/server/node/channel.ts | 813 - lib/vscode/src/vs/server/node/connection.ts | 231 - lib/vscode/src/vs/server/node/insights.ts | 124 - lib/vscode/src/vs/server/node/ipc.ts | 61 - lib/vscode/src/vs/server/node/logger.ts | 2 - lib/vscode/src/vs/server/node/marketplace.ts | 183 - lib/vscode/src/vs/server/node/nls.ts | 88 - lib/vscode/src/vs/server/node/protocol.ts | 153 - lib/vscode/src/vs/server/node/server.ts | 300 - lib/vscode/src/vs/server/node/util.ts | 13 - .../api/common/extHostNotebookKernels.ts | 259 - .../vs/workbench/api/common/shared/webview.ts | 30 - .../api/node/extHostTerminalService.ts | 145 - .../browser/parts/editor/media/back-tb.png | Bin 266 -> 0 bytes .../browser/parts/editor/media/forward-tb.png | Bin 258 -> 0 bytes .../common/editor/resourceEditorInput.ts | 134 - .../contrib/cli/node/cli.contribution.ts | 193 - .../codeEditor/browser/inspectKeybindings.ts | 56 - .../codeEditor/browser/toggleMinimap.ts | 43 - .../browser/toggleRenderControlCharacter.ts | 44 - .../browser/toggleRenderWhitespace.ts | 52 - .../debug/browser/media/continue-tb.png | Bin 339 -> 0 bytes .../media/continue-without-debugging-tb.png | Bin 363 -> 0 bytes .../contrib/debug/browser/media/pause-tb.png | Bin 217 -> 0 bytes .../debug/browser/media/restart-tb.png | Bin 701 -> 0 bytes .../debug/browser/media/stepinto-tb.png | Bin 418 -> 0 bytes .../debug/browser/media/stepout-tb.png | Bin 411 -> 0 bytes .../debug/browser/media/stepover-tb.png | Bin 548 -> 0 bytes .../contrib/debug/browser/media/stop-tb.png | Bin 197 -> 0 bytes ...onEnablementByWorkspaceTrustRequirement.ts | 36 - .../electron-sandbox/extensionsActions.ts | 45 - .../electron-sandbox/issue.contribution.ts | 50 - .../issue/electron-sandbox/issueActions.ts | 43 - .../contrib/notebook/browser/constants.ts | 46 - .../contrib/statusBar/cellStatusBar.ts | 142 - .../browser/view/output/outputRenderer.ts | 85 - .../browser/view/renderers/cellActionView.ts | 97 - .../common/notebookMarkdownRenderer.ts | 39 - .../notebook/common/notebookSelector.ts | 31 - .../notebook/test/notebookDiff.test.ts | 177 - .../notebook/test/notebookEditorModel.test.ts | 59 - .../searchEditor/browser/searchEditorModel.ts | 95 - .../partsSplash.contribution.ts | 143 - .../browser/terminalInstanceService.ts | 61 - .../browser/terminalProfileResolverService.ts | 336 - .../terminal/browser/terminalTabsWidget.ts | 378 - .../contrib/terminal/common/terminalMenu.ts | 54 - .../electron-browser/terminal.contribution.ts | 34 - .../terminalInstanceService.ts | 60 - .../terminalNativeContribution.ts | 54 - .../contrib/terminal/node/terminal.ts | 28 - .../terminal/node/terminalEnvironment.ts | 79 - .../contrib/terminal/node/terminalProfiles.ts | 318 - .../explorerProjections/locationStore.ts | 76 - .../testing/browser/testingOutputPeek.ts | 557 - .../testing/common/getComputedState.ts | 84 - .../contrib/webview/common/webviewUri.ts | 25 - .../common/media/dark/keymaps.png | Bin 49149 -> 0 bytes .../common/media/dark/openVSC.png | Bin 7282 -> 0 bytes .../common/media/forwardPorts.png | Bin 17327 -> 0 bytes .../common/media/hc/keymaps.png | Bin 50010 -> 0 bytes .../common/media/light/keymaps.png | Bin 49954 -> 0 bytes .../common/media/light/openVSC.png | Bin 17144 -> 0 bytes .../common/media/pullRequests.png | Bin 51090 -> 0 bytes .../common/media/remoteTerminal.png | Bin 49686 -> 0 bytes .../common/media/runProject.png | Bin 65764 -> 0 bytes .../page/browser/welcomePage.contribution.ts | 34 - .../browser/workspace.contribution.ts | 551 - .../workspace/browser/workspaceTrustColors.ts | 14 - .../workspace/browser/workspaceTrustEditor.ts | 483 - .../workspace/browser/workspaceTrustTree.ts | 624 - .../electron-sandbox/actions/windowActions.ts | 254 - .../browser/localizationsService.ts | 23 - .../browser/browserTextFileService.ts | 28 - .../common/legacyBackupRestorer.ts | 136 - .../test/browser/legacyBackupRestorer.test.ts | 113 - .../workspaces/common/workspaceTrust.ts | 378 - .../api/extHostNotebookKernel2.test.ts | 96 - .../parts/editor/resourceEditorInput.test.ts | 54 - lib/vscode/yarn.lock | 9823 ---------- package.json | 366 +- lib/vscode/product.json => product.json | 62 +- {lib/vscode/remote => remote}/.yarnrc | 0 {lib/vscode/remote => remote}/package.json | 20 +- .../vscode/remote => remote}/web/package.json | 10 +- {lib/vscode/remote => remote}/web/yarn.lock | 40 +- {lib/vscode/remote => remote}/yarn.lock | 90 +- .../completions/bash/code | 0 .../completions/zsh/_code | 0 .../resources => resources}/darwin/bat.icns | Bin .../darwin/bin/code.sh | 0 .../resources => resources}/darwin/bower.icns | Bin .../resources => resources}/darwin/c.icns | Bin .../resources => resources}/darwin/code.icns | Bin .../darwin/config.icns | Bin .../resources => resources}/darwin/cpp.icns | Bin .../darwin/csharp.icns | Bin .../resources => resources}/darwin/css.icns | Bin .../darwin/default.icns | Bin .../resources => resources}/darwin/go.icns | Bin .../resources => resources}/darwin/html.icns | Bin .../resources => resources}/darwin/jade.icns | Bin .../resources => resources}/darwin/java.icns | Bin .../darwin/javascript.icns | Bin .../resources => resources}/darwin/json.icns | Bin .../resources => resources}/darwin/less.icns | Bin .../darwin/markdown.icns | Bin .../resources => resources}/darwin/php.icns | Bin .../darwin/powershell.icns | Bin .../darwin/python.icns | Bin .../resources => resources}/darwin/react.icns | Bin .../resources => resources}/darwin/ruby.icns | Bin .../resources => resources}/darwin/sass.icns | Bin .../resources => resources}/darwin/shell.icns | Bin .../resources => resources}/darwin/sql.icns | Bin .../darwin/typescript.icns | Bin .../resources => resources}/darwin/vue.icns | Bin .../resources => resources}/darwin/xml.icns | Bin .../resources => resources}/darwin/yaml.icns | Bin .../resources => resources}/linux/bin/code.sh | 0 .../linux/code-url-handler.desktop | 2 +- .../linux/code-workspace.xml | 0 .../linux/code.appdata.xml | 0 .../linux/code.desktop | 4 +- .../resources => resources}/linux/code.png | Bin .../linux/debian/control.template | 0 .../linux/debian/postinst.template | 0 .../linux/debian/postrm.template | 0 .../linux/debian/prerm.template | 0 .../linux/rpm/code.spec.template | 0 .../linux/rpm/code.xpm | 0 .../linux/rpm/dependencies.json | 0 .../linux/snap/electron-launch | 0 .../linux/snap/snapcraft.yaml | 0 .../resources => resources}/web/callback.html | 0 .../resources => resources}/web/code-web.js | 0 .../win32/VisualElementsManifest.xml | 0 .../win32/bin/code.cmd | 0 .../resources => resources}/win32/bin/code.sh | 0 .../resources => resources}/win32/bower.ico | Bin .../resources => resources}/win32/c.ico | Bin .../resources => resources}/win32/code.ico | Bin .../win32/code_150x150.png | Bin .../win32/code_70x70.png | Bin .../resources => resources}/win32/config.ico | Bin .../resources => resources}/win32/cpp.ico | Bin .../resources => resources}/win32/csharp.ico | Bin .../resources => resources}/win32/css.ico | Bin .../resources => resources}/win32/default.ico | Bin .../resources => resources}/win32/go.ico | Bin .../resources => resources}/win32/html.ico | Bin .../win32/inno-big-100.bmp | Bin .../win32/inno-big-125.bmp | Bin .../win32/inno-big-150.bmp | Bin .../win32/inno-big-175.bmp | Bin .../win32/inno-big-200.bmp | Bin .../win32/inno-big-225.bmp | Bin .../win32/inno-big-250.bmp | Bin .../win32/inno-small-100.bmp | Bin .../win32/inno-small-125.bmp | Bin .../win32/inno-small-150.bmp | Bin .../win32/inno-small-175.bmp | Bin .../win32/inno-small-200.bmp | Bin .../win32/inno-small-225.bmp | Bin .../win32/inno-small-250.bmp | Bin .../resources => resources}/win32/jade.ico | Bin .../resources => resources}/win32/java.ico | Bin .../win32/javascript.ico | Bin .../resources => resources}/win32/json.ico | Bin .../resources => resources}/win32/less.ico | Bin .../win32/markdown.ico | Bin .../resources => resources}/win32/php.ico | Bin .../win32/powershell.ico | Bin .../resources => resources}/win32/python.ico | Bin .../resources => resources}/win32/react.ico | Bin .../resources => resources}/win32/ruby.ico | Bin .../resources => resources}/win32/sass.ico | Bin .../resources => resources}/win32/shell.ico | Bin .../resources => resources}/win32/sql.ico | Bin .../win32/typescript.ico | Bin .../resources => resources}/win32/vue.ico | Bin .../resources => resources}/win32/xml.ico | Bin .../resources => resources}/win32/yaml.ico | Bin {lib/vscode/scripts => scripts}/code-cli.bat | 0 {lib/vscode/scripts => scripts}/code-cli.sh | 0 {lib/vscode/scripts => scripts}/code.bat | 0 {lib/vscode/scripts => scripts}/code.sh | 2 +- .../generate-definitelytyped.sh | 0 .../scripts => scripts}/node-electron.bat | 0 .../scripts => scripts}/node-electron.sh | 0 {lib/vscode/scripts => scripts}/npm.bat | 0 {lib/vscode/scripts => scripts}/npm.sh | 0 .../test-documentation.bat | 0 .../scripts => scripts}/test-documentation.sh | 0 .../scripts => scripts}/test-integration.bat | 0 .../scripts => scripts}/test-integration.sh | 13 +- {lib/vscode/scripts => scripts}/test.bat | 2 +- {lib/vscode/scripts => scripts}/test.sh | 6 +- {lib/vscode/src => src}/bootstrap-amd.js | 0 {lib/vscode/src => src}/bootstrap-fork.js | 0 {lib/vscode/src => src}/bootstrap-node.js | 1 + {lib/vscode/src => src}/bootstrap-window.js | 17 +- {lib/vscode/src => src}/bootstrap.js | 0 src/browser/favicon.afdesign | 3 - src/browser/media/favicon-dark-support.svg | 7 - src/browser/media/favicon.ico | Bin 4868 -> 0 bytes src/browser/media/favicon.svg | 1 - src/browser/media/manifest.json | 20 - src/browser/media/pwa-icon-192.png | Bin 5486 -> 0 bytes src/browser/media/pwa-icon-512.png | Bin 14689 -> 0 bytes src/browser/media/pwa-icon.png | Bin 19318 -> 0 bytes src/browser/pages/error.css | 32 - src/browser/pages/error.html | 34 - src/browser/pages/global.css | 85 - src/browser/pages/login.css | 58 - src/browser/pages/login.html | 53 - src/browser/pages/login.ts | 7 - src/browser/pages/vscode.html | 55 - src/browser/pages/vscode.ts | 55 - src/browser/register.ts | 27 - src/browser/robots.txt | 2 - src/browser/serviceWorker.ts | 14 - {lib/vscode/src => src}/buildfile.js | 0 {lib/vscode/src => src}/cli.js | 0 src/common/emitter.ts | 61 - src/common/http.ts | 20 - src/common/util.ts | 130 - {lib/vscode/src => src}/main.js | 0 src/node/app.ts | 78 - src/node/cli.ts | 652 - src/node/coder_cloud.ts | 41 - src/node/constants.ts | 22 - src/node/entry.ts | 220 - src/node/heart.ts | 57 - src/node/http.ts | 160 - src/node/plugin.ts | 302 - src/node/proxy.ts | 17 - src/node/proxy_agent.ts | 81 - src/node/routes/apps.ts | 17 - src/node/routes/domainProxy.ts | 89 - src/node/routes/health.ts | 28 - src/node/routes/index.ts | 191 - src/node/routes/login.ts | 110 - src/node/routes/logout.ts | 17 - src/node/routes/pathProxy.ts | 59 - src/node/routes/static.ts | 70 - src/node/routes/update.ts | 18 - src/node/routes/vscode.ts | 222 - src/node/settings.ts | 67 - src/node/socket.ts | 100 - src/node/update.ts | 132 - src/node/util.ts | 294 - src/node/vscode.ts | 168 - src/node/wrapper.ts | 370 - src/node/wsRouter.ts | 53 - {lib/vscode/src => src}/tsconfig.base.json | 0 {lib/vscode/src => src}/tsconfig.json | 0 {lib/vscode/src => src}/tsconfig.monaco.json | 0 {lib/vscode/src => src}/tsconfig.tsec.json | 0 {lib/vscode/src => src}/tsec.exemptions.json | 1 + {lib/vscode/src => src}/typings/require.d.ts | 0 {lib/vscode/src => src}/typings/thenable.d.ts | 0 .../src => src}/vs/base/browser/browser.ts | 1 - .../src => src}/vs/base/browser/canIUse.ts | 0 .../vs/base/browser/contextmenu.ts | 0 .../vscode/src => src}/vs/base/browser/dnd.ts | 0 .../vscode/src => src}/vs/base/browser/dom.ts | 96 +- .../src => src}/vs/base/browser/event.ts | 34 + .../vs/base/browser/fastDomNode.ts | 0 .../vs/base/browser/formattedTextRenderer.ts | 0 .../vs/base/browser/globalMouseMoveMonitor.ts | 3 +- .../src => src}/vs/base/browser/hash.ts | 0 .../src => src}/vs/base/browser/history.ts | 0 .../src => src}/vs/base/browser/iframe.ts | 0 .../vs/base/browser/keyboardEvent.ts | 0 .../vs/base/browser/markdownRenderer.ts | 9 + .../src => src}/vs/base/browser/mouseEvent.ts | 0 .../src => src}/vs/base/browser/touch.ts | 0 .../browser/ui/actionbar/actionViewItems.ts | 0 .../base/browser/ui/actionbar/actionbar.css | 10 + .../vs/base/browser/ui/actionbar/actionbar.ts | 0 .../vs/base/browser/ui/aria/aria.css | 0 .../vs/base/browser/ui/aria/aria.ts | 0 .../ui/breadcrumbs/breadcrumbsWidget.css | 0 .../ui/breadcrumbs/breadcrumbsWidget.ts | 0 .../vs/base/browser/ui/button/button.css | 1 + .../vs/base/browser/ui/button/button.ts | 0 .../browser/ui/centered/centeredViewLayout.ts | 1 + .../vs/base/browser/ui/checkbox/checkbox.css | 0 .../vs/base/browser/ui/checkbox/checkbox.ts | 0 .../ui/codicons/codicon/codicon-modifiers.css | 0 .../browser/ui/codicons/codicon/codicon.css | 0 .../browser/ui/codicons/codicon/codicon.ttf | Bin 70964 -> 71056 bytes .../base/browser/ui/codicons/codiconStyles.ts | 0 .../browser/ui/contextview/contextview.css | 0 .../browser/ui/contextview/contextview.ts | 0 .../base/browser/ui/countBadge/countBadge.css | 0 .../base/browser/ui/countBadge/countBadge.ts | 0 .../vs/base/browser/ui/dialog/dialog.css | 0 .../vs/base/browser/ui/dialog/dialog.ts | 34 +- .../vs/base/browser/ui/dropdown/dropdown.css | 7 + .../vs/base/browser/ui/dropdown/dropdown.ts | 0 .../ui/dropdown/dropdownActionViewItem.ts | 0 .../base/browser/ui/findinput/findInput.css | 0 .../vs/base/browser/ui/findinput/findInput.ts | 0 .../ui/findinput/findInputCheckboxes.ts | 0 .../base/browser/ui/findinput/replaceInput.ts | 0 .../vs/base/browser/ui/grid/grid.ts | 9 +- .../vs/base/browser/ui/grid/gridview.css | 0 .../vs/base/browser/ui/grid/gridview.ts | 69 +- .../ui/highlightedlabel/highlightedLabel.ts | 0 .../vs/base/browser/ui/hover/hover.css | 5 + .../vs/base/browser/ui/hover/hoverWidget.ts | 0 .../browser/ui/iconLabel/iconHoverDelegate.ts | 2 + .../vs/base/browser/ui/iconLabel/iconLabel.ts | 140 +- .../browser/ui/iconLabel/iconLabelHover.ts | 130 + .../base/browser/ui/iconLabel/iconLabels.ts | 0 .../base/browser/ui/iconLabel/iconlabel.css | 0 .../browser/ui/iconLabel/simpleIconLabel.ts | 0 .../vs/base/browser/ui/inputbox/inputBox.css | 0 .../vs/base/browser/ui/inputbox/inputBox.ts | 0 .../ui/keybindingLabel/keybindingLabel.css | 0 .../ui/keybindingLabel/keybindingLabel.ts | 0 .../vs/base/browser/ui/list/list.css | 0 .../vs/base/browser/ui/list/list.ts | 0 .../vs/base/browser/ui/list/listPaging.ts | 0 .../vs/base/browser/ui/list/listView.ts | 2 +- .../vs/base/browser/ui/list/listWidget.ts | 12 +- .../vs/base/browser/ui/list/rangeMap.ts | 0 .../vs/base/browser/ui/list/rowCache.ts | 0 .../vs/base/browser/ui/list/splice.ts | 0 .../vs/base/browser/ui/menu/menu.ts | 0 .../vs/base/browser/ui/menu/menubar.css | 0 .../vs/base/browser/ui/menu/menubar.ts | 0 .../browser/ui/mouseCursor/mouseCursor.css | 0 .../browser/ui/mouseCursor/mouseCursor.ts | 0 .../browser/ui/progressbar/progressbar.css | 0 .../browser/ui/progressbar/progressbar.ts | 0 .../vs/base/browser/ui/sash/sash.css | 0 .../vs/base/browser/ui/sash/sash.ts | 192 +- .../browser/ui/scrollbar/abstractScrollbar.ts | 0 .../ui/scrollbar/horizontalScrollbar.ts | 0 .../browser/ui/scrollbar/media/scrollbars.css | 0 .../browser/ui/scrollbar/scrollableElement.ts | 0 .../ui/scrollbar/scrollableElementOptions.ts | 0 .../browser/ui/scrollbar/scrollbarArrow.ts | 0 .../browser/ui/scrollbar/scrollbarState.ts | 0 .../scrollbarVisibilityController.ts | 0 .../browser/ui/scrollbar/verticalScrollbar.ts | 0 .../base/browser/ui/selectBox/selectBox.css | 0 .../vs/base/browser/ui/selectBox/selectBox.ts | 0 .../browser/ui/selectBox/selectBoxCustom.css | 0 .../browser/ui/selectBox/selectBoxCustom.ts | 2 +- .../browser/ui/selectBox/selectBoxNative.ts | 0 .../vs/base/browser/ui/splitview/paneview.css | 0 .../vs/base/browser/ui/splitview/paneview.ts | 3 + .../base/browser/ui/splitview/splitview.css | 0 .../vs/base/browser/ui/splitview/splitview.ts | 7 +- .../vs/base/browser/ui/table/table.css | 0 .../vs/base/browser/ui/table/table.ts | 0 .../vs/base/browser/ui/table/tableWidget.ts | 0 .../vs/base/browser/ui/toolbar/toolbar.css | 0 .../vs/base/browser/ui/toolbar/toolbar.ts | 0 .../vs/base/browser/ui/tree/abstractTree.ts | 0 .../vs/base/browser/ui/tree/asyncDataTree.ts | 0 .../ui/tree/compressedObjectTreeModel.ts | 0 .../vs/base/browser/ui/tree/dataTree.ts | 0 .../vs/base/browser/ui/tree/indexTree.ts | 0 .../vs/base/browser/ui/tree/indexTreeModel.ts | 0 .../browser/ui/tree/media/paneviewlet.css | 0 .../vs/base/browser/ui/tree/media/tree.css | 0 .../vs/base/browser/ui/tree/objectTree.ts | 0 .../base/browser/ui/tree/objectTreeModel.ts | 0 .../vs/base/browser/ui/tree/tree.ts | 0 .../vs/base/browser/ui/tree/treeDefaults.ts | 0 .../vs/base/browser/ui/tree/treeIcons.ts | 0 .../src => src}/vs/base/browser/ui/widget.ts | 0 .../src => src}/vs/base/common/actions.ts | 8 +- {lib/vscode/src => src}/vs/base/common/amd.ts | 0 .../src => src}/vs/base/common/arrays.ts | 34 + .../src => src}/vs/base/common/assert.ts | 0 .../src => src}/vs/base/common/async.ts | 1 - .../src => src}/vs/base/common/buffer.ts | 0 .../src => src}/vs/base/common/cache.ts | 0 .../vs/base/common/cancellation.ts | 0 .../src => src}/vs/base/common/charCode.ts | 0 .../src => src}/vs/base/common/codicons.ts | 1 + .../src => src}/vs/base/common/collections.ts | 22 +- .../src => src}/vs/base/common/color.ts | 2 +- .../src => src}/vs/base/common/comparers.ts | 163 +- .../src => src}/vs/base/common/console.ts | 0 .../vscode/src => src}/vs/base/common/date.ts | 0 .../src => src}/vs/base/common/decorators.ts | 79 +- .../src => src}/vs/base/common/diff/diff.ts | 0 .../vs/base/common/diff/diffChange.ts | 0 .../vs/base/common/errorMessage.ts | 0 .../src => src}/vs/base/common/errors.ts | 0 .../src => src}/vs/base/common/event.ts | 27 +- .../src => src}/vs/base/common/extpath.ts | 17 + .../src => src}/vs/base/common/filters.ts | 0 .../src => src}/vs/base/common/functional.ts | 0 .../src => src}/vs/base/common/fuzzyScorer.ts | 0 .../vscode/src => src}/vs/base/common/glob.ts | 0 .../vscode/src => src}/vs/base/common/hash.ts | 0 .../src => src}/vs/base/common/history.ts | 0 .../src => src}/vs/base/common/htmlContent.ts | 17 +- .../src => src}/vs/base/common/iconLabels.ts | 0 .../src => src}/vs/base/common/idGenerator.ts | 0 .../vs/base/common/insane/cgmanifest.json | 0 .../vs/base/common/insane/insane.d.ts | 0 .../vs/base/common/insane/insane.js | 0 .../vs/base/common/insane/insane.license.txt | 0 .../src => src}/vs/base/common/iterator.ts | 5 +- .../vscode/src => src}/vs/base/common/json.ts | 0 .../src => src}/vs/base/common/jsonEdit.ts | 0 .../vs/base/common/jsonErrorMessages.ts | 0 .../vs/base/common/jsonFormatter.ts | 0 .../src => src}/vs/base/common/jsonSchema.ts | 0 .../src => src}/vs/base/common/keyCodes.ts | 0 .../vs/base/common/keybindingLabels.ts | 0 .../vs/base/common/keybindingParser.ts | 0 .../src => src}/vs/base/common/labels.ts | 0 .../vscode/src => src}/vs/base/common/lazy.ts | 0 .../src => src}/vs/base/common/lifecycle.ts | 0 .../src => src}/vs/base/common/linkedList.ts | 8 + .../src => src}/vs/base/common/linkedText.ts | 0 {lib/vscode/src => src}/vs/base/common/map.ts | 12 +- .../vs/base/common/marked/cgmanifest.json | 0 .../vs/base/common/marked/marked.d.ts | 0 .../vs/base/common/marked/marked.js | 0 .../vs/base/common/marked/marked.license.txt | 0 .../src => src}/vs/base/common/marshalling.ts | 0 .../vscode/src => src}/vs/base/common/mime.ts | 17 + .../src => src}/vs/base/common/navigator.ts | 0 .../src => src}/vs/base/common/network.ts | 8 +- .../vs/base/common/normalization.ts | 0 .../src => src}/vs/base/common/numbers.ts | 0 .../src => src}/vs/base/common/objects.ts | 10 + .../src => src}/vs/base/common/paging.ts | 0 .../src => src}/vs/base/common/parsers.ts | 0 .../vscode/src => src}/vs/base/common/path.ts | 0 .../vs/base/common/performance.d.ts | 0 .../src => src}/vs/base/common/performance.js | 0 .../src => src}/vs/base/common/platform.ts | 14 +- src/vs/base/common/ports.ts | 13 + .../src => src}/vs/base/common/process.ts | 4 +- .../src => src}/vs/base/common/processes.ts | 1 - .../src => src}/vs/base/common/product.ts | 13 +- .../src => src}/vs/base/common/range.ts | 0 .../vs/base/common/resourceTree.ts | 0 .../src => src}/vs/base/common/resources.ts | 9 +- .../src => src}/vs/base/common/scanCode.ts | 0 .../src => src}/vs/base/common/scrollable.ts | 0 .../src => src}/vs/base/common/search.ts | 0 .../vs/base/common/semver/cgmanifest.json | 0 .../vs/base/common/semver/semver.d.ts | 0 .../vs/base/common/semver/semver.js | 0 .../src => src}/vs/base/common/sequence.ts | 0 .../src => src}/vs/base/common/severity.ts | 0 .../src => src}/vs/base/common/skipList.ts | 0 .../src => src}/vs/base/common/stopwatch.ts | 0 .../src => src}/vs/base/common/stream.ts | 0 .../src => src}/vs/base/common/strings.ts | 78 + .../src => src}/vs/base/common/styler.ts | 0 .../src => src}/vs/base/common/types.ts | 0 .../vscode/src => src}/vs/base/common/uint.ts | 0 {lib/vscode/src => src}/vs/base/common/uri.ts | 4 +- .../src => src}/vs/base/common/uriIpc.ts | 31 +- .../vscode/src => src}/vs/base/common/uuid.ts | 0 .../vs/base/common/worker/simpleWorker.ts | 0 .../src => src}/vs/base/node/cpuUsage.sh | 0 .../vscode/src => src}/vs/base/node/crypto.ts | 0 .../src => src}/vs/base/node/decoder.ts | 0 .../src => src}/vs/base/node/extpath.ts | 7 +- {lib/vscode/src => src}/vs/base/node/id.ts | 0 .../vs/base/node/languagePacks.d.ts | 0 .../src => src}/vs/base/node/languagePacks.js | 5 +- .../src => src}/vs/base/node/macAddress.ts | 0 {lib/vscode/src => src}/vs/base/node/pfs.ts | 93 +- {lib/vscode/src => src}/vs/base/node/ports.ts | 9 - .../src => src}/vs/base/node/powershell.ts | 0 .../src => src}/vs/base/node/processes.ts | 3 +- {lib/vscode/src => src}/vs/base/node/ps.sh | 0 {lib/vscode/src => src}/vs/base/node/ps.ts | 0 {lib/vscode/src => src}/vs/base/node/shell.ts | 0 .../vs/base/node/terminalEncoding.ts | 0 .../vs/base/node/terminateProcess.sh | 0 .../src => src}/vs/base/node/watcher.ts | 0 {lib/vscode/src => src}/vs/base/node/zip.ts | 8 +- .../parts/contextmenu/common/contextmenu.ts | 0 .../contextmenu/electron-main/contextmenu.ts | 0 .../electron-sandbox/contextmenu.ts | 0 .../vs/base/parts/ipc/browser/ipc.mp.ts | 0 .../vs/base/parts/ipc/common/ipc.electron.ts | 0 .../vs/base/parts/ipc/common/ipc.mp.ts | 0 .../vs/base/parts/ipc/common/ipc.net.ts | 5 - .../vs/base/parts/ipc/common/ipc.ts | 8 +- .../base/parts/ipc/electron-browser/ipc.mp.ts | 0 .../parts/ipc/electron-main/ipc.electron.ts | 0 .../vs/base/parts/ipc/electron-main/ipc.mp.ts | 0 .../ipc/electron-sandbox/ipc.electron.ts | 0 .../vs/base/parts/ipc/node/ipc.cp.ts | 0 .../vs/base/parts/ipc/node/ipc.net.ts | 0 .../parts/ipc/test/browser/ipc.mp.test.ts | 0 .../vs/base/parts/ipc/test/common/ipc.test.ts | 0 .../ipc/test/electron-sandbox/ipc.mp.test.ts | 0 .../base/parts/ipc/test/node/ipc.cp.test.ts | 0 .../base/parts/ipc/test/node/ipc.net.test.ts | 0 .../vs/base/parts/ipc/test/node/testApp.ts | 0 .../base/parts/ipc/test/node/testService.ts | 0 .../quickinput/browser/media/quickInput.css | 13 +- .../parts/quickinput/browser/quickInput.ts | 36 +- .../parts/quickinput/browser/quickInputBox.ts | 0 .../quickinput/browser/quickInputList.ts | 0 .../quickinput/browser/quickInputUtils.ts | 0 .../parts/quickinput/common/quickInput.ts | 15 +- .../vs/base/parts/request/browser/request.ts | 0 .../vs/base/parts/request/common/request.ts | 0 .../parts/sandbox/common/electronTypes.ts | 8 +- .../base/parts/sandbox/common/sandboxTypes.ts | 0 .../parts/sandbox/electron-browser/preload.js | 6 - .../sandbox/electron-sandbox/electronTypes.ts | 32 +- .../parts/sandbox/electron-sandbox/globals.ts | 0 .../test/electron-sandbox/globals.test.ts | 0 .../vs/base/parts/storage/common/storage.ts | 0 .../vs/base/parts/storage/node/storage.ts | 9 +- .../parts/storage/test/node/storage.test.ts | 9 +- .../vs/base/test/browser/actionbar.test.ts | 0 .../vs/base/test/browser/browser.test.ts | 0 src/vs/base/test/browser/comparers.test.ts | 709 + .../vs/base/test/browser/dom.test.ts | 0 .../browser/formattedTextRenderer.test.ts | 0 .../vs/base/test/browser/hash.test.ts | 0 .../test/browser/highlightedLabel.test.ts | 0 .../vs/base/test/browser/iconLabels.test.ts | 0 .../test/browser/markdownRenderer.test.ts | 0 .../vs/base/test/browser/progressBar.test.ts | 0 .../ui/contextview/contextview.test.ts | 0 .../vs/base/test/browser/ui/grid/grid.test.ts | 0 .../test/browser/ui/grid/gridview.test.ts | 0 .../vs/base/test/browser/ui/grid/util.ts | 0 .../test/browser/ui/list/listView.test.ts | 0 .../test/browser/ui/list/rangeMap.test.ts | 0 .../base/test/browser/ui/menu/menubar.test.ts | 0 .../ui/scrollbar/scrollableElement.test.ts | 0 .../ui/scrollbar/scrollbarState.test.ts | 0 .../browser/ui/splitview/splitview.test.ts | 0 .../browser/ui/tree/asyncDataTree.test.ts | 0 .../ui/tree/compressedObjectTreeModel.test.ts | 0 .../test/browser/ui/tree/dataTree.test.ts | 0 .../browser/ui/tree/indexTreeModel.test.ts | 0 .../test/browser/ui/tree/objectTree.test.ts | 0 .../browser/ui/tree/objectTreeModel.test.ts | 0 .../vs/base/test/common/arrays.test.ts | 16 + .../vs/base/test/common/assert.test.ts | 0 .../vs/base/test/common/async.test.ts | 0 .../vs/base/test/common/buffer.test.ts | 0 .../vs/base/test/common/cache.test.ts | 0 .../vs/base/test/common/cancellation.test.ts | 0 .../vs/base/test/common/charCode.test.ts | 0 .../vs/base/test/common/codicons.test.ts | 0 .../vs/base/test/common/collections.test.ts | 22 - .../vs/base/test/common/color.test.ts | 0 .../vs/base/test/common/console.test.ts | 0 .../vs/base/test/common/decorators.test.ts | 24 +- .../vs/base/test/common/diff/diff.test.ts | 0 .../vs/base/test/common/errors.test.ts | 0 .../vs/base/test/common/event.test.ts | 68 +- .../vs/base/test/common/extpath.test.ts | 0 .../base/test/common/filters.perf.data.d.ts | 0 .../vs/base/test/common/filters.perf.data.js | 0 .../vs/base/test/common/filters.perf.test.ts | 0 .../vs/base/test/common/filters.test.ts | 0 .../vs/base/test/common/fuzzyScorer.test.ts | 0 .../vs/base/test/common/glob.test.ts | 0 .../vs/base/test/common/history.test.ts | 0 .../vs/base/test/common/iconLabels.test.ts | 0 .../vs/base/test/common/iterator.test.ts | 0 .../vs/base/test/common/json.test.ts | 0 .../vs/base/test/common/jsonEdit.test.ts | 0 .../vs/base/test/common/jsonFormatter.test.ts | 0 .../vs/base/test/common/keyCodes.test.ts | 0 .../vs/base/test/common/labels.test.ts | 0 .../vs/base/test/common/lazy.test.ts | 0 .../vs/base/test/common/lifecycle.test.ts | 0 .../vs/base/test/common/linkedList.test.ts | 0 .../vs/base/test/common/linkedText.test.ts | 0 .../vs/base/test/common/map.test.ts | 0 .../base/test/common/markdownString.test.ts | 0 .../vs/base/test/common/marshalling.test.ts | 0 .../vs/base/test/common/mime.test.ts | 11 +- .../src => src}/vs/base/test/common/mock.ts | 0 .../vs/base/test/common/network.test.ts | 0 .../vs/base/test/common/normalization.test.ts | 0 .../vs/base/test/common/objects.test.ts | 0 .../vs/base/test/common/paging.test.ts | 0 .../vs/base/test/common/path.test.ts | 0 .../vs/base/test/common/processes.test.ts | 0 .../vs/base/test/common/resourceTree.test.ts | 0 .../vs/base/test/common/resources.test.ts | 0 .../vs/base/test/common/scrollable.test.ts | 0 .../vs/base/test/common/skipList.test.ts | 0 .../vs/base/test/common/stream.test.ts | 2 +- .../vs/base/test/common/strings.test.ts | 0 .../vs/base/test/common/troubleshooting.ts | 0 .../vs/base/test/common/types.test.ts | 0 .../vs/base/test/common/uri.test.ts | 0 .../src => src}/vs/base/test/common/utils.ts | 0 .../vs/base/test/common/uuid.test.ts | 0 .../vs/base/test/node/crypto.test.ts | 5 +- .../vs/base/test/node/decoder.test.ts | 0 .../vs/base/test/node/extpath.test.ts | 5 +- .../src => src}/vs/base/test/node/id.test.ts | 0 .../vs/base/test/node/keytar.test.ts | 0 .../node/pfs/fixtures/examples/company.jxs | 0 .../node/pfs/fixtures/examples/conway.jxs | 0 .../node/pfs/fixtures/examples/employee.jxs | 0 .../test/node/pfs/fixtures/examples/small.jxs | 0 .../vs/base/test/node/pfs/fixtures/index.html | 0 .../vs/base/test/node/pfs/fixtures/site.css | 0 .../vs/base/test/node/pfs/pfs.test.ts | 24 +- .../vs/base/test/node/port.test.ts | 0 .../vs/base/test/node/powershell.test.ts | 0 .../base/test/node/processes/fixtures/fork.ts | 0 .../node/processes/fixtures/fork_large.ts | 0 .../test/node/processes/processes.test.ts | 0 .../vs/base/test/node/testUtils.ts | 0 .../vs/base/test/node/uri.test.data.txt | 0 .../vs/base/test/node/uri.test.perf.ts | 0 .../base/test/node/zip/fixtures/extract.zip | Bin .../vs/base/test/node/zip/zip.test.ts | 5 +- .../quickinput/browser/quickinput.test.ts | 75 + .../vs/base/worker/defaultWorkerFactory.ts | 0 .../src => src}/vs/base/worker/workerMain.ts | 0 .../vs/code/browser/workbench/callback.html | 0 .../code/browser/workbench/workbench-dev.html | 0 .../vs/code/browser/workbench/workbench.html | 0 .../vs/code/browser/workbench/workbench.ts | 88 +- {lib/vscode/src => src}/vs/code/buildfile.js | 0 .../contrib/deprecatedExtensionsCleaner.ts | 0 .../contrib/languagePackCachedDataCleaner.ts | 5 +- .../contrib/localizationsUpdater.ts | 0 .../sharedProcess/contrib/logsDataCleaner.ts | 0 .../contrib/nodeCachedDataCleaner.ts | 5 +- .../contrib/storageDataCleaner.ts | 5 +- .../sharedProcess/sharedProcess.html | 0 .../sharedProcess/sharedProcess.js | 5 +- .../sharedProcess/sharedProcessMain.ts | 16 +- .../electron-browser/workbench/workbench.html | 2 +- .../electron-browser/workbench/workbench.js | 42 +- .../src => src}/vs/code/electron-main/app.ts | 136 +- .../src => src}/vs/code/electron-main/auth.ts | 0 .../src => src}/vs/code/electron-main/main.ts | 64 +- .../electron-sandbox/issue/issueReporter.html | 0 .../electron-sandbox/issue/issueReporter.js | 5 +- .../issue/issueReporterMain.ts | 22 +- .../issue/issueReporterModel.ts | 2 + .../issue/issueReporterPage.ts | 0 .../issue/media/issueReporter.css | 0 .../issue/test/testReporterModel.test.ts | 6 + .../processExplorer/media/processExplorer.css | 4 + .../processExplorer/processExplorer.html | 0 .../processExplorer/processExplorer.js | 5 +- .../processExplorer/processExplorerMain.ts | 64 +- .../electron-sandbox/workbench/workbench.html | 2 +- .../electron-sandbox/workbench/workbench.js | 210 + {lib/vscode/src => src}/vs/code/node/cli.ts | 9 +- .../vs/code/node/cliProcessMain.ts | 25 +- {lib/vscode/src => src}/vs/css.build.js | 0 {lib/vscode/src => src}/vs/css.d.ts | 0 {lib/vscode/src => src}/vs/css.js | 0 .../editor/browser/config/charWidthReader.ts | 0 .../vs/editor/browser/config/configuration.ts | 0 .../browser/config/elementSizeObserver.ts | 0 .../editor/browser/controller/coreCommands.ts | 0 .../editor/browser/controller/mouseHandler.ts | 0 .../editor/browser/controller/mouseTarget.ts | 202 +- .../browser/controller/pointerHandler.ts | 0 .../browser/controller/textAreaHandler.css | 0 .../browser/controller/textAreaHandler.ts | 0 .../browser/controller/textAreaInput.ts | 0 .../browser/controller/textAreaState.ts | 0 .../vs/editor/browser/core/editorState.ts | 0 .../browser/core/keybindingCancellation.ts | 0 .../editor/browser/core/markdownRenderer.ts | 6 +- .../vs/editor/browser/editorBrowser.ts | 10 +- .../vs/editor/browser/editorDom.ts | 0 .../vs/editor/browser/editorExtensions.ts | 69 +- .../services/abstractCodeEditorService.ts | 2 +- .../browser/services/bulkEditService.ts | 0 .../browser/services/codeEditorService.ts | 6 +- .../browser/services/codeEditorServiceImpl.ts | 10 +- .../browser/services/markerDecorations.ts | 0 .../editor/browser/services/openerService.ts | 28 +- .../browser/view/domLineBreaksComputer.ts | 0 .../editor/browser/view/dynamicViewOverlay.ts | 0 .../vs/editor/browser/view/viewController.ts | 0 .../vs/editor/browser/view/viewImpl.ts | 0 .../vs/editor/browser/view/viewLayer.ts | 0 .../vs/editor/browser/view/viewOverlays.ts | 0 .../vs/editor/browser/view/viewPart.ts | 0 .../browser/view/viewUserInputEvents.ts | 0 .../contentWidgets/contentWidgets.ts | 0 .../currentLineHighlight.css | 0 .../currentLineHighlight.ts | 0 .../viewParts/decorations/decorations.css | 0 .../viewParts/decorations/decorations.ts | 0 .../editorScrollbar/editorScrollbar.ts | 0 .../viewParts/glyphMargin/glyphMargin.css | 0 .../viewParts/glyphMargin/glyphMargin.ts | 0 .../viewParts/indentGuides/indentGuides.css | 0 .../viewParts/indentGuides/indentGuides.ts | 0 .../viewParts/lineNumbers/lineNumbers.css | 0 .../viewParts/lineNumbers/lineNumbers.ts | 0 .../browser/viewParts/lines/rangeUtil.ts | 0 .../browser/viewParts/lines/viewLine.ts | 0 .../browser/viewParts/lines/viewLines.css | 0 .../browser/viewParts/lines/viewLines.ts | 0 .../linesDecorations/linesDecorations.css | 0 .../linesDecorations/linesDecorations.ts | 0 .../editor/browser/viewParts/margin/margin.ts | 0 .../marginDecorations/marginDecorations.css | 0 .../marginDecorations/marginDecorations.ts | 0 .../browser/viewParts/minimap/minimap.css | 0 .../browser/viewParts/minimap/minimap.ts | 2 +- .../viewParts/minimap/minimapCharRenderer.ts | 0 .../minimap/minimapCharRendererFactory.ts | 0 .../viewParts/minimap/minimapCharSheet.ts | 0 .../viewParts/minimap/minimapPreBaked.ts | 0 .../overlayWidgets/overlayWidgets.css | 0 .../overlayWidgets/overlayWidgets.ts | 0 .../overviewRuler/decorationsOverviewRuler.ts | 0 .../viewParts/overviewRuler/overviewRuler.ts | 0 .../browser/viewParts/rulers/rulers.css | 0 .../editor/browser/viewParts/rulers/rulers.ts | 0 .../scrollDecoration/scrollDecoration.css | 0 .../scrollDecoration/scrollDecoration.ts | 0 .../viewParts/selections/selections.css | 0 .../viewParts/selections/selections.ts | 0 .../viewParts/viewCursors/viewCursor.ts | 0 .../viewParts/viewCursors/viewCursors.css | 0 .../viewParts/viewCursors/viewCursors.ts | 0 .../browser/viewParts/viewZones/viewZones.ts | 0 .../editor/browser/widget/codeEditorWidget.ts | 42 +- .../editor/browser/widget/diffEditorWidget.ts | 9 + .../vs/editor/browser/widget/diffNavigator.ts | 0 .../vs/editor/browser/widget/diffReview.ts | 15 +- .../widget/embeddedCodeEditorWidget.ts | 0 .../editor/browser/widget/inlineDiffMargin.ts | 0 .../browser/widget/media/diffEditor.css | 0 .../browser/widget/media/diffReview.css | 0 .../vs/editor/browser/widget/media/editor.css | 0 .../editor/common/commands/replaceCommand.ts | 0 .../vs/editor/common/commands/shiftCommand.ts | 0 .../commands/surroundSelectionCommand.ts | 0 .../commands/trimTrailingWhitespaceCommand.ts | 0 .../common/config/commonEditorConfig.ts | 1 + .../vs/editor/common/config/editorOptions.ts | 117 +- .../vs/editor/common/config/editorZoom.ts | 0 .../vs/editor/common/config/fontInfo.ts | 0 .../vs/editor/common/controller/cursor.ts | 2 + .../controller/cursorAtomicMoveOperations.ts | 0 .../common/controller/cursorCollection.ts | 0 .../controller/cursorColumnSelection.ts | 0 .../editor/common/controller/cursorCommon.ts | 63 +- .../controller/cursorDeleteOperations.ts | 94 +- .../editor/common/controller/cursorEvents.ts | 0 .../common/controller/cursorMoveCommands.ts | 56 +- .../common/controller/cursorMoveOperations.ts | 102 +- .../common/controller/cursorTypeOperations.ts | 70 +- .../common/controller/cursorWordOperations.ts | 0 .../vs/editor/common/controller/oneCursor.ts | 0 .../controller/wordCharacterClassifier.ts | 0 .../editor/common/core/characterClassifier.ts | 0 .../vs/editor/common/core/editOperation.ts | 0 .../vs/editor/common/core/lineTokens.ts | 16 +- .../vs/editor/common/core/position.ts | 0 .../vs/editor/common/core/range.ts | 0 .../src => src}/vs/editor/common/core/rgba.ts | 0 .../vs/editor/common/core/selection.ts | 0 .../vs/editor/common/core/stringBuilder.ts | 0 .../vs/editor/common/core/token.ts | 0 .../vs/editor/common/diff/diffComputer.ts | 0 .../vs/editor/common/editorAction.ts | 0 .../vs/editor/common/editorCommon.ts | 3 +- .../vs/editor/common/editorContextKeys.ts | 2 +- .../src => src}/vs/editor/common/model.ts | 34 +- .../vs/editor/common/model/editStack.ts | 0 .../editor/common/model/indentationGuesser.ts | 0 .../vs/editor/common/model/intervalTree.ts | 0 .../vs/editor/common/model/mirrorTextModel.ts | 0 .../pieceTreeTextBuffer/pieceTreeBase.ts | 0 .../pieceTreeTextBuffer.ts | 0 .../pieceTreeTextBufferBuilder.ts | 0 .../model/pieceTreeTextBuffer/rbTreeBase.ts | 0 .../vs/editor/common/model/textChange.ts | 0 .../vs/editor/common/model/textModel.ts | 36 +- .../vs/editor/common/model/textModelEvents.ts | 0 .../vs/editor/common/model/textModelSearch.ts | 0 .../vs/editor/common/model/textModelTokens.ts | 0 .../vs/editor/common/model/tokensStore.ts | 0 .../vs/editor/common/model/wordHelper.ts | 0 .../src => src}/vs/editor/common/modes.ts | 121 +- .../vs/editor/common/modes/abstractMode.ts | 0 .../common/modes/languageConfiguration.ts | 0 .../modes/languageConfigurationRegistry.ts | 0 .../common/modes/languageFeatureRegistry.ts | 0 .../editor/common/modes/languageSelector.ts | 0 .../vs/editor/common/modes/linkComputer.ts | 2 +- .../vs/editor/common/modes/modesRegistry.ts | 0 .../vs/editor/common/modes/nullMode.ts | 0 .../vs/editor/common/modes/supports.ts | 0 .../common/modes/supports/characterPair.ts | 0 .../modes/supports/electricCharacter.ts | 0 .../common/modes/supports/indentRules.ts | 0 .../modes/supports/inplaceReplaceSupport.ts | 0 .../editor/common/modes/supports/onEnter.ts | 7 +- .../common/modes/supports/richEditBrackets.ts | 0 .../common/modes/supports/tokenization.ts | 0 .../common/modes/textToHtmlTokenizer.ts | 0 .../common/modes/tokenization/typescript.ts | 0 .../common/modes/tokenizationRegistry.ts | 0 .../common/services/editorSimpleWorker.ts | 0 .../common/services/editorWorkerService.ts | 0 .../services/editorWorkerServiceImpl.ts | 0 .../editor/common/services/getIconClasses.ts | 0 .../common/services/getSemanticTokens.ts | 0 .../common/services/languagesRegistry.ts | 0 .../services/markerDecorationsServiceImpl.ts | 1 + .../services/markersDecorationService.ts | 0 .../vs/editor/common/services/modeService.ts | 0 .../editor/common/services/modeServiceImpl.ts | 0 .../vs/editor/common/services/modelService.ts | 0 .../common/services/modelServiceImpl.ts | 0 .../services/modelUndoRedoParticipant.ts | 0 .../editor/common/services/resolverService.ts | 0 .../common/services/semanticTokensDto.ts | 0 .../services/semanticTokensProviderStyling.ts | 0 .../textResourceConfigurationService.ts | 0 .../textResourceConfigurationServiceImpl.ts | 0 .../vs/editor/common/services/webWorker.ts | 0 .../common/standalone/standaloneBase.ts | 0 .../common/standalone/standaloneEnums.ts | 172 +- .../vs/editor/common/standaloneStrings.ts | 0 .../editor/common/view/editorColorRegistry.ts | 3 + .../editor/common/view/overviewZoneManager.ts | 0 .../vs/editor/common/view/renderingContext.ts | 0 .../vs/editor/common/view/viewContext.ts | 0 .../vs/editor/common/view/viewEvents.ts | 0 .../common/viewLayout/lineDecorations.ts | 0 .../editor/common/viewLayout/linesLayout.ts | 0 .../vs/editor/common/viewLayout/viewLayout.ts | 0 .../common/viewLayout/viewLineRenderer.ts | 27 +- .../viewLayout/viewLinesViewportData.ts | 0 .../viewModel/minimapTokensColorTracker.ts | 0 .../viewModel/monospaceLineBreaksComputer.ts | 0 .../common/viewModel/prefixSumComputer.ts | 0 .../common/viewModel/splitLinesCollection.ts | 72 +- .../common/viewModel/viewEventHandler.ts | 0 .../vs/editor/common/viewModel/viewModel.ts | 0 .../common/viewModel/viewModelDecorations.ts | 0 .../viewModel/viewModelEventDispatcher.ts | 0 .../editor/common/viewModel/viewModelImpl.ts | 14 +- .../contrib/anchorSelect/anchorSelect.css | 0 .../contrib/anchorSelect/anchorSelect.ts | 1 + .../bracketMatching/bracketMatching.css | 0 .../bracketMatching/bracketMatching.ts | 2 + .../test/bracketMatching.test.ts | 0 .../caretOperations/caretOperations.ts | 0 .../caretOperations/moveCaretCommand.ts | 0 .../test/moveCarretCommand.test.ts | 0 .../contrib/caretOperations/transpose.ts | 4 +- .../vs/editor/contrib/clipboard/clipboard.ts | 17 + .../editor/contrib/codeAction/codeAction.ts | 0 .../contrib/codeAction/codeActionCommands.ts | 0 .../codeAction/codeActionContributions.ts | 0 .../contrib/codeAction/codeActionMenu.ts | 5 +- .../contrib/codeAction/codeActionModel.ts | 0 .../editor/contrib/codeAction/codeActionUi.ts | 0 .../contrib/codeAction/lightBulbWidget.css | 0 .../contrib/codeAction/lightBulbWidget.ts | 0 .../codeAction/test/codeAction.test.ts | 0 .../test/codeActionKeybindingResolver.test.ts | 0 .../codeAction/test/codeActionModel.test.ts | 0 .../vs/editor/contrib/codeAction/types.ts | 0 .../editor/contrib/codelens/codeLensCache.ts | 0 .../vs/editor/contrib/codelens/codelens.ts | 0 .../contrib/codelens/codelensController.ts | 0 .../contrib/codelens/codelensWidget.css | 0 .../editor/contrib/codelens/codelensWidget.ts | 0 .../vs/editor/contrib/colorPicker/color.ts | 0 .../contrib/colorPicker/colorContributions.ts | 0 .../contrib/colorPicker/colorDetector.ts | 2 +- .../contrib/colorPicker/colorPicker.css | 0 .../contrib/colorPicker/colorPickerModel.ts | 0 .../contrib/colorPicker/colorPickerWidget.ts | 0 .../colorPicker/images/opacity-background.png | Bin .../contrib/comment/blockCommentCommand.ts | 0 .../vs/editor/contrib/comment/comment.ts | 0 .../contrib/comment/lineCommentCommand.ts | 0 .../comment/test/blockCommentCommand.test.ts | 0 .../comment/test/lineCommentCommand.test.ts | 0 .../editor/contrib/contextmenu/contextmenu.ts | 8 +- .../editor/contrib/cursorUndo/cursorUndo.ts | 0 .../cursorUndo/test/cursorUndo.test.ts | 0 .../src => src}/vs/editor/contrib/dnd/dnd.css | 0 .../src => src}/vs/editor/contrib/dnd/dnd.ts | 1 + .../editor/contrib/dnd/dragAndDropCommand.ts | 0 .../documentSymbols/documentSymbols.ts | 0 .../contrib/documentSymbols/outlineModel.ts | 0 .../documentSymbols/test/outlineModel.test.ts | 0 .../vs/editor/contrib/find/findController.ts | 67 +- .../vs/editor/contrib/find/findDecorations.ts | 6 + .../vs/editor/contrib/find/findModel.ts | 0 .../editor/contrib/find/findOptionsWidget.ts | 0 .../vs/editor/contrib/find/findState.ts | 0 .../vs/editor/contrib/find/findWidget.css | 0 .../vs/editor/contrib/find/findWidget.ts | 0 .../editor/contrib/find/replaceAllCommand.ts | 0 .../vs/editor/contrib/find/replacePattern.ts | 0 .../vs/editor/contrib/find/test/find.test.ts | 0 .../contrib/find/test/findController.test.ts | 0 .../contrib/find/test/findModel.test.ts | 0 .../contrib/find/test/replacePattern.test.ts | 0 .../vs/editor/contrib/folding/folding.css | 0 .../vs/editor/contrib/folding/folding.ts | 2 +- .../contrib/folding/foldingDecorations.ts | 5 + .../vs/editor/contrib/folding/foldingModel.ts | 0 .../editor/contrib/folding/foldingRanges.ts | 0 .../contrib/folding/hiddenRangeModel.ts | 0 .../contrib/folding/indentRangeProvider.ts | 0 .../folding/intializingRangeProvider.ts | 1 + .../contrib/folding/syntaxRangeProvider.ts | 0 .../contrib/folding/test/foldingModel.test.ts | 3 + .../folding/test/foldingRanges.test.ts | 0 .../folding/test/hiddenRangeModel.test.ts | 0 .../contrib/folding/test/indentFold.test.ts | 0 .../folding/test/indentRangeProvider.test.ts | 0 .../contrib/folding/test/syntaxFold.test.ts | 0 .../vs/editor/contrib/fontZoom/fontZoom.ts | 0 .../vs/editor/contrib/format/format.ts | 0 .../vs/editor/contrib/format/formatActions.ts | 0 .../editor/contrib/format/formattingEdit.ts | 0 .../vs/editor/contrib/gotoError/gotoError.ts | 0 .../contrib/gotoError/gotoErrorWidget.ts | 0 .../gotoError/markerNavigationService.ts | 0 .../gotoError/media/gotoErrorWidget.css | 0 .../editor/contrib/gotoSymbol/goToCommands.ts | 2 +- .../editor/contrib/gotoSymbol/goToSymbol.ts | 0 .../gotoSymbol/link/clickLinkGesture.ts | 0 .../link/goToDefinitionAtPosition.css | 0 .../link/goToDefinitionAtPosition.ts | 1 + .../gotoSymbol/peek/referencesController.ts | 0 .../contrib/gotoSymbol/peek/referencesTree.ts | 0 .../gotoSymbol/peek/referencesWidget.css | 0 .../gotoSymbol/peek/referencesWidget.ts | 1 + .../contrib/gotoSymbol/referencesModel.ts | 0 .../contrib/gotoSymbol/symbolNavigation.ts | 0 .../gotoSymbol/test/referencesModel.test.ts | 0 .../contrib/hover/colorHoverParticipant.ts | 153 + .../vs/editor/contrib/hover/getHover.ts | 0 .../vs/editor/contrib/hover/hover.ts | 62 +- .../vs/editor/contrib/hover/hoverOperation.ts | 0 src/vs/editor/contrib/hover/hoverTypes.ts | 87 + .../vs/editor/contrib/hover/hoverWidgets.ts | 0 .../contrib/hover/markdownHoverParticipant.ts | 47 +- .../contrib/hover/markerHoverParticipant.ts | 53 +- .../editor/contrib/hover/modesContentHover.ts | 586 + .../editor/contrib/hover/modesGlyphHover.ts | 0 .../contrib/inPlaceReplace/inPlaceReplace.ts | 1 + .../inPlaceReplace/inPlaceReplaceCommand.ts | 0 .../editor/contrib/indentation/indentUtils.ts | 0 .../editor/contrib/indentation/indentation.ts | 0 .../indentation/test/indentation.test.ts | 0 .../inlayHints/inlayHintsController.ts | 82 +- .../contrib/inlineCompletions/ghostText.css | 20 + .../inlineCompletions/ghostTextController.ts | 339 + .../inlineCompletions/ghostTextWidget.ts | 427 + .../inlineCompletionsHoverParticipant.ts | 114 + .../inlineCompletionsModel.ts | 582 + .../suggestWidgetAdapterModel.ts | 172 + .../editor/contrib/inlineCompletions/utils.ts | 51 + .../linesOperations/copyLinesCommand.ts | 0 .../linesOperations/linesOperations.ts | 49 +- .../linesOperations/moveLinesCommand.ts | 0 .../linesOperations/sortLinesCommand.ts | 0 .../test/copyLinesCommand.test.ts | 0 .../test/linesOperations.test.ts | 0 .../test/moveLinesCommand.test.ts | 0 .../test/sortLinesCommand.test.ts | 0 .../contrib/linkedEditing/linkedEditing.ts | 1 + .../linkedEditing/test/linkedEditing.test..ts | 0 .../vs/editor/contrib/links/getLinks.ts | 0 .../vs/editor/contrib/links/links.css | 0 .../vs/editor/contrib/links/links.ts | 2 + .../contrib/message/messageController.css | 0 .../contrib/message/messageController.ts | 0 .../editor/contrib/multicursor/multicursor.ts | 2 + .../multicursor/test/multicursor.test.ts | 0 .../contrib/parameterHints/parameterHints.css | 0 .../contrib/parameterHints/parameterHints.ts | 0 .../parameterHints/parameterHintsModel.ts | 0 .../parameterHints/parameterHintsWidget.ts | 0 .../parameterHints/provideSignatureHelp.ts | 0 .../test/parameterHintsModel.test.ts | 0 .../contrib/peekView/media/peekViewWidget.css | 1 + .../vs/editor/contrib/peekView/peekView.ts | 2 +- .../quickAccess/commandsQuickAccess.ts | 6 +- .../editorNavigationQuickAccess.ts | 2 + .../quickAccess/gotoLineQuickAccess.ts | 0 .../quickAccess/gotoSymbolQuickAccess.ts | 0 .../vs/editor/contrib/rename/rename.ts | 0 .../contrib/rename/renameInputField.css | 0 .../editor/contrib/rename/renameInputField.ts | 0 .../contrib/smartSelect/bracketSelections.ts | 0 .../editor/contrib/smartSelect/smartSelect.ts | 0 .../smartSelect/test/smartSelect.test.ts | 0 .../contrib/smartSelect/wordSelections.ts | 0 .../vs/editor/contrib/snippet/snippet.md | 0 .../contrib/snippet/snippetController2.ts | 2 +- .../editor/contrib/snippet/snippetParser.ts | 4 +- .../editor/contrib/snippet/snippetSession.css | 0 .../editor/contrib/snippet/snippetSession.ts | 8 +- .../contrib/snippet/snippetVariables.ts | 0 .../test/snippetController2.old.test.ts | 0 .../snippet/test/snippetController2.test.ts | 0 .../snippet/test/snippetParser.test.ts | 1 + .../snippet/test/snippetSession.test.ts | 0 .../snippet/test/snippetVariables.test.ts | 0 .../editor/contrib/suggest/completionModel.ts | 0 .../editor/contrib/suggest/media/suggest.css | 4 + .../vs/editor/contrib/suggest/resizable.ts | 2 + .../vs/editor/contrib/suggest/suggest.ts | 5 + .../contrib/suggest/suggestAlternatives.ts | 0 .../suggest/suggestCommitCharacters.ts | 0 .../contrib/suggest/suggestController.ts | 10 +- .../editor/contrib/suggest/suggestMemory.ts | 0 .../vs/editor/contrib/suggest/suggestModel.ts | 8 +- .../suggest/suggestOvertypingCapturer.ts | 0 .../editor/contrib/suggest/suggestWidget.ts | 29 +- .../contrib/suggest/suggestWidgetDetails.ts | 1 + .../contrib/suggest/suggestWidgetRenderer.ts | 12 +- .../contrib/suggest/suggestWidgetStatus.ts | 0 .../suggest/test/completionModel.test.ts | 1 + .../contrib/suggest/test/suggest.test.ts | 0 .../suggest/test/suggestController.test.ts | 0 .../suggest/test/suggestMemory.test.ts | 0 .../contrib/suggest/test/suggestModel.test.ts | 0 .../contrib/suggest/test/wordDistance.test.ts | 0 .../editor/contrib/suggest/wordContextKey.ts | 0 .../vs/editor/contrib/suggest/wordDistance.ts | 0 .../editor/contrib/symbolIcons/symbolIcons.ts | 0 .../toggleTabFocusMode/toggleTabFocusMode.ts | 0 .../contrib/tokenization/tokenization.ts | 0 .../unusualLineTerminators.ts | 0 .../viewportSemanticTokens.ts | 0 .../wordHighlighter/wordHighlighter.ts | 3 + .../test/wordOperations.test.ts | 0 .../wordOperations/test/wordTestUtils.ts | 0 .../contrib/wordOperations/wordOperations.ts | 0 .../test/wordPartOperations.test.ts | 0 .../wordPartOperations/wordPartOperations.ts | 0 .../editor/contrib/zoneWidget/zoneWidget.css | 0 .../editor/contrib/zoneWidget/zoneWidget.ts | 2 +- .../src => src}/vs/editor/editor.all.ts | 3 +- .../src => src}/vs/editor/editor.api.ts | 0 .../src => src}/vs/editor/editor.main.ts | 0 .../src => src}/vs/editor/editor.worker.ts | 0 .../accessibilityHelp/accessibilityHelp.css | 0 .../accessibilityHelp/accessibilityHelp.ts | 0 .../vs/editor/standalone/browser/colorizer.ts | 0 .../iPadShowKeyboard/iPadShowKeyboard.css | 0 .../iPadShowKeyboard/iPadShowKeyboard.ts | 4 +- .../iPadShowKeyboard/keyboard-dark.svg | 0 .../iPadShowKeyboard/keyboard-light.svg | 0 .../browser/inspectTokens/inspectTokens.css | 0 .../browser/inspectTokens/inspectTokens.ts | 0 .../standaloneCommandsQuickAccess.ts | 6 +- .../standaloneGotoLineQuickAccess.ts | 0 .../standaloneGotoSymbolQuickAccess.ts | 0 .../quickAccess/standaloneHelpQuickAccess.ts | 0 .../quickInput/standaloneQuickInput.css | 5 + .../standaloneQuickInputServiceImpl.ts | 0 .../standaloneReferenceSearch.ts | 0 .../standalone/browser/simpleServices.ts | 0 .../standalone/browser/standalone-tokens.css | 0 .../browser/standaloneCodeEditor.ts | 15 + .../browser/standaloneCodeServiceImpl.ts | 12 +- .../standalone/browser/standaloneEditor.ts | 0 .../standalone/browser/standaloneLanguages.ts | 11 +- .../standalone/browser/standaloneServices.ts | 0 .../browser/standaloneThemeServiceImpl.ts | 2 +- .../toggleHighContrast/toggleHighContrast.ts | 0 .../common/monarch/monarchCommon.ts | 0 .../common/monarch/monarchCompile.ts | 13 +- .../standalone/common/monarch/monarchLexer.ts | 0 .../standalone/common/monarch/monarchTypes.ts | 0 .../common/standaloneThemeService.ts | 0 .../vs/editor/standalone/common/themes.ts | 5 +- .../test/browser/simpleServices.test.ts | 0 .../test/browser/standaloneLanguages.test.ts | 0 .../standalone/test/monarch/monarch.test.ts | 27 + .../browser/commands/shiftCommand.test.ts | 0 .../test/browser/commands/sideEditing.test.ts | 0 .../trimTrailingWhitespaceCommand.test.ts | 0 .../test/browser/controller/cursor.test.ts | 238 + .../controller/cursorMoveCommand.test.ts | 0 .../test/browser/controller/imeTester.html | 0 .../test/browser/controller/imeTester.ts | 0 .../browser/controller/inputRecorder.html | 0 .../browser/controller/textAreaState.test.ts | 0 .../test/browser/core/editorState.test.ts | 0 .../editor/test/browser/editorTestServices.ts | 4 +- .../services/decorationRenderOptions.test.ts | 22 +- .../browser/services/openerService.test.ts | 60 +- .../vs/editor/test/browser/testCodeEditor.ts | 0 .../vs/editor/test/browser/testCommand.ts | 0 .../browser/view/minimapCharRenderer.test.ts | 0 .../test/browser/view/viewLayer.test.ts | 0 .../vs/editor/test/common/commentMode.ts | 0 .../common/config/commonEditorConfig.test.ts | 0 .../cursorAtomicMoveOperations.test.ts | 0 .../controller/cursorMoveHelper.test.ts | 0 .../common/core/characterClassifier.test.ts | 0 .../test/common/core/lineTokens.test.ts | 0 .../vs/editor/test/common/core/range.test.ts | 0 .../test/common/core/stringBuilder.test.ts | 0 .../editor/test/common/core/viewLineToken.ts | 0 .../test/common/diff/diffComputer.test.ts | 0 .../vs/editor/test/common/editorTestUtils.ts | 0 .../vs/editor/test/common/mocks/mockMode.ts | 0 .../test/common/mocks/testConfiguration.ts | 0 .../common/model/benchmark/benchmarkUtils.ts | 0 .../test/common/model/benchmark/bootstrap.js | 0 .../test/common/model/benchmark/entry.ts | 0 .../model/benchmark/modelbuilder.benchmark.ts | 0 .../model/benchmark/operations.benchmark.ts | 0 .../benchmark/searchNReplace.benchmark.ts | 0 .../test/common/model/editStack.test.ts | 0 .../common/model/editableTextModel.test.ts | 0 .../model/editableTextModelAuto.test.ts | 0 .../model/editableTextModelTestUtils.ts | 0 .../test/common/model/intervalTree.test.ts | 0 .../linesTextBuffer/linesTextBuffer.test.ts | 0 .../linesTextBufferBuilder.test.ts | 0 .../textBufferAutoTestUtils.ts | 0 .../test/common/model/model.line.test.ts | 0 .../test/common/model/model.modes.test.ts | 0 .../vs/editor/test/common/model/model.test.ts | 0 .../common/model/modelDecorations.test.ts | 38 +- .../common/model/modelEditOperation.test.ts | 0 .../pieceTreeTextBuffer.test.ts | 0 .../test/common/model/textChange.test.ts | 0 .../test/common/model/textModel.test.ts | 0 .../test/common/model/textModelSearch.test.ts | 0 .../common/model/textModelWithTokens.test.ts | 0 .../test/common/model/tokensStore.test.ts | 0 .../modes/languageConfiguration.test.ts | 0 .../common/modes/languageSelector.test.ts | 0 .../test/common/modes/linkComputer.test.ts | 21 + .../modes/supports/characterPair.test.ts | 0 .../modes/supports/electricCharacter.test.ts | 0 .../modes/supports/javascriptOnEnterRules.ts | 0 .../common/modes/supports/onEnter.test.ts | 34 + .../modes/supports/richEditBrackets.test.ts | 0 .../modes/supports/tokenization.test.ts | 0 .../common/modes/textToHtmlTokenizer.test.ts | 0 .../vs/editor/test/common/modesTestUtils.ts | 0 .../services/editorSimpleWorker.test.ts | 0 .../common/services/languagesRegistry.test.ts | 0 .../test/common/services/modelService.test.ts | 0 .../common/services/semanticTokensDto.test.ts | 0 .../testTextResourcePropertiesService.ts | 0 .../textResourceConfigurationService.test.ts | 0 .../common/view/overviewZoneManager.test.ts | 0 .../viewLayout/editorLayoutProvider.test.ts | 0 .../common/viewLayout/lineDecorations.test.ts | 0 .../common/viewLayout/linesLayout.test.ts | 0 .../viewLayout/viewLineRenderer.test.ts | 142 +- .../monospaceLineBreaksComputer.test.ts | 0 .../viewModel/prefixSumComputer.test.ts | 0 .../viewModel/splitLinesCollection.test.ts | 0 .../test/common/viewModel/testViewModel.ts | 0 .../viewModel/viewModelDecorations.test.ts | 3 + .../common/viewModel/viewModelImpl.test.ts | 0 .../node/classification/typescript-test.ts | 0 .../node/classification/typescript.test.ts | 0 {lib/vscode/src => src}/vs/loader.js | 0 {lib/vscode/src => src}/vs/monaco.d.ts | 319 +- {lib/vscode/src => src}/vs/nls.build.js | 0 {lib/vscode/src => src}/vs/nls.d.ts | 0 {lib/vscode/src => src}/vs/nls.js | 0 {lib/vscode/src => src}/vs/nls.mock.ts | 0 .../accessibility/common/accessibility.ts | 0 .../common/accessibilityService.ts | 0 .../dropdownWithPrimaryActionViewItem.ts | 63 +- .../browser/menuEntryActionViewItem.css | 1 + .../browser/menuEntryActionViewItem.ts | 30 +- .../vs/platform/actions/common/actions.ts | 31 +- .../vs/platform/actions/common/menuService.ts | 0 .../actions/test/common/menuService.test.ts | 0 .../platform/backup/electron-main/backup.ts | 0 .../backup/electron-main/backupMainService.ts | 6 +- .../vs/platform/backup/node/backup.ts | 0 .../electron-main/backupMainService.test.ts | 34 +- .../browser/contextScopedHistoryWidget.ts | 0 .../checksum/common/checksumService.ts | 0 .../electron-sandbox/checksumService.ts | 0 .../platform/checksum/node/checksumService.ts | 0 .../test/node/checksumService.test.ts | 0 .../checksum/test/node/fixtures/lorem.txt | 0 .../clipboard/browser/clipboardService.ts | 0 .../clipboard/common/clipboardService.ts | 0 .../vs/platform/commands/common/commands.ts | 0 .../commands/test/common/commands.test.ts | 0 .../configuration/common/configuration.ts | 0 .../common/configurationModels.ts | 0 .../common/configurationRegistry.ts | 0 .../common/configurationService.ts | 0 .../test/common/configuration.test.ts | 0 .../test/common/configurationModels.test.ts | 0 .../test/common/configurationRegistry.test.ts | 0 .../test/common/configurationService.test.ts | 0 .../test/common/testConfigurationService.ts | 0 .../contextkey/browser/contextKeyService.ts | 0 .../platform/contextkey/common/contextkey.ts | 1 - .../platform/contextkey/common/contextkeys.ts | 3 +- .../test/browser/contextkey.test.ts | 0 .../contextkey/test/common/contextkey.test.ts | 0 .../browser/contextMenuHandler.css | 0 .../contextview/browser/contextMenuHandler.ts | 0 .../contextview/browser/contextMenuService.ts | 3 + .../contextview/browser/contextView.ts | 3 + .../contextview/browser/contextViewService.ts | 0 .../debug/common/extensionHostDebug.ts | 0 .../debug/common/extensionHostDebugIpc.ts | 0 .../electron-main/extensionHostDebugIpc.ts | 0 .../diagnostics/common/diagnostics.ts | 0 .../electron-sandbox/diagnosticsService.ts | 0 .../diagnostics/node/diagnosticsService.ts | 0 .../vs/platform/dialogs/common/dialogs.ts | 0 .../electron-main/dialogMainService.ts | 9 +- .../dialogs/test/common/testDialogService.ts | 32 + .../vs/platform/download/common/download.ts | 0 .../platform/download/common/downloadIpc.ts | 0 .../download/common/downloadService.ts | 0 .../vs/platform/driver/browser/baseDriver.ts | 0 .../vs/platform/driver/browser/driver.ts | 0 .../vs/platform/driver/common/driver.ts | 0 .../vs/platform/driver/common/driverIpc.ts | 0 .../platform/driver/electron-main/driver.ts | 0 .../driver/electron-sandbox/driver.ts | 0 .../vs/platform/driver/node/driver.ts | 0 .../vs/platform/editor/common/editor.ts | 92 +- .../encryption/common/encryptionService.ts | 0 .../electron-main/encryptionMainService.ts | 0 .../vs/platform/environment/common/argv.ts | 3 +- .../environment/common/environment.ts | 5 +- .../environment/common/environmentService.ts | 33 +- .../electron-main/environmentMainService.ts | 0 .../vs/platform/environment/node/argv.ts | 11 +- .../platform/environment/node/argvHelper.ts | 0 .../environment/node/environmentService.ts | 0 .../vs/platform/environment/node/shellEnv.ts | 0 .../vs/platform/environment/node/stdin.ts | 0 .../environment/node/userDataPath.d.ts | 0 .../platform/environment/node/userDataPath.js | 0 .../vs/platform/environment/node/wait.ts | 0 .../environment/test/node/argv.test.ts | 0 .../test/node/environmentService.test.ts | 0 .../test/node/nativeModules.test.ts | 0 .../test/node/userDataPath.test.ts | 0 .../common/configRemotes.ts | 0 .../common/extensionEnablementService.ts | 0 .../common/extensionGalleryService.ts | 131 +- .../common/extensionManagement.ts | 3 +- .../common/extensionManagementCLIService.ts | 0 .../common/extensionManagementIpc.ts | 8 +- .../common/extensionManagementUtil.ts | 0 .../common/extensionNls.ts | 0 .../common/extensionTipsService.ts | 0 .../common/extensionUrlTrust.ts | 0 .../common/media/defaultIcon.png | Bin .../electron-sandbox/extensionTipsService.ts | 0 .../node/extensionDownloader.ts | 6 +- .../node/extensionLifecycle.ts | 0 .../node/extensionManagementService.ts | 18 +- .../node/extensionManagementUtil.ts | 0 .../node/extensionUrlTrustService.ts | 0 .../node/extensionsManifestCache.ts | 0 .../node/extensionsScanner.ts | 38 +- .../node/extensionsWatcher.ts | 0 .../test/common/configRemotes.test.ts | 0 .../common/extensionGalleryService.test.ts | 0 .../test/common/extensionManagement.test.ts | 0 .../common/extensionRecommendations.ts | 0 .../extensionRecommendationsIpc.ts | 0 .../extensions/common/extensionValidator.ts | 53 +- .../platform/extensions/common/extensions.ts | 32 +- .../test/common/extensionValidator.test.ts | 22 +- .../common/externalTerminal.ts | 19 +- .../externalTerminalService.test.ts | 4 +- .../externalTerminalMainService.ts | 16 + .../node/externalTerminalService.ts | 176 +- .../files/browser/htmlFileSystemProvider.ts | 0 .../browser/indexedDBFileSystemProvider.ts | 4 +- .../vs/platform/files/common/fileService.ts | 37 +- .../vs/platform/files/common/files.ts | 48 +- .../common/inMemoryFilesystemProvider.ts | 0 .../vs/platform/files/common/io.ts | 0 .../files/common/ipcFileSystemProvider.ts | 0 .../diskFileSystemProvider.ts | 13 +- .../files/node/diskFileSystemProvider.ts | 29 +- .../node/watcher/nodejs/watcherService.ts | 0 .../node/watcher/nsfw/nsfwWatcherService.ts | 0 .../nsfw/test/nsfwWatcherService.test.ts | 0 .../files/node/watcher/nsfw/watcher.ts | 0 .../files/node/watcher/nsfw/watcherApp.ts | 0 .../files/node/watcher/nsfw/watcherService.ts | 0 .../watcher/unix/chokidarWatcherService.ts | 0 .../unix/test/chockidarWatcherService.test.ts | 0 .../files/node/watcher/unix/watcher.ts | 0 .../files/node/watcher/unix/watcherApp.ts | 0 .../files/node/watcher/unix/watcherService.ts | 0 .../vs/platform/files/node/watcher/watcher.ts | 0 .../files/node/watcher/win32/CodeHelper.exe | Bin .../files/node/watcher/win32/CodeHelper.md | 0 .../watcher/win32/csharpWatcherService.ts | 0 .../node/watcher/win32/watcherService.ts | 0 .../files/test/browser/fileService.test.ts | 0 .../test/browser/indexedDBFileService.test.ts | 0 .../platform/files/test/common/files.test.ts | 0 .../test/common/nullFileSystemProvider.ts | 0 .../electron-browser/diskFileService.test.ts | 68 +- .../fixtures/resolver/examples/company.js | 0 .../fixtures/resolver/examples/conway.js | 0 .../fixtures/resolver/examples/employee.js | 0 .../fixtures/resolver/examples/small.js | 0 .../fixtures/resolver/index.html | 0 .../fixtures/resolver/other/deep/company.js | 0 .../fixtures/resolver/other/deep/conway.js | 0 .../fixtures/resolver/other/deep/employee.js | 0 .../fixtures/resolver/other/deep/small.js | 0 .../fixtures/resolver/site.css | 0 .../fixtures/service/binary.txt | Bin .../fixtures/service/deep/company.js | 0 .../fixtures/service/deep/conway.js | 0 .../fixtures/service/deep/employee.js | 0 .../fixtures/service/deep/small.js | 0 .../fixtures/service/index.html | 0 .../fixtures/service/lorem.txt | 0 .../fixtures/service/small.txt | 0 .../fixtures/service/small_umlaut.txt | 0 .../fixtures/service/some_utf16le.css | Bin .../fixtures/service/some_utf8_bom.txt | 0 .../test/electron-browser/normalizer.test.ts | 0 .../instantiation/common/descriptors.ts | 0 .../instantiation/common/extensions.ts | 0 .../vs/platform/instantiation/common/graph.ts | 0 .../instantiation/common/instantiation.ts | 0 .../common/instantiationService.ts | 0 .../instantiation/common/serviceCollection.ts | 0 .../instantiation/test/common/graph.test.ts | 0 .../test/common/instantiationService.test.ts | 0 .../test/common/instantiationServiceMock.ts | 0 .../electron-browser/mainProcessService.ts | 0 .../electron-sandbox/mainProcessService.ts | 0 .../platform/ipc/electron-sandbox/services.ts | 0 .../vs/platform/issue/common/issue.ts | 11 +- .../issue/common/issueReporterUtil.ts | 0 .../issue/electron-main/issueMainService.ts | 34 +- .../platform/issue/electron-sandbox/issue.ts | 0 .../common/jsonContributionRegistry.ts | 0 .../common/abstractKeybindingService.ts | 4 +- .../common/baseResolvedKeybinding.ts | 0 .../platform/keybinding/common/keybinding.ts | 4 +- .../keybinding/common/keybindingResolver.ts | 8 +- .../keybinding/common/keybindingsRegistry.ts | 0 .../common/resolvedKeybindingItem.ts | 0 .../common/usLayoutResolvedKeybinding.ts | 0 .../common/abstractKeybindingService.test.ts | 0 .../test/common/keybindingLabels.test.ts | 0 .../test/common/keybindingResolver.test.ts | 0 .../test/common/mockKeybindingService.ts | 0 .../keyboardLayout/common/dispatchConfig.ts | 0 .../keyboardLayout/common/keyboardLayout.ts | 0 .../common/keyboardLayoutService.ts | 0 .../keyboardLayout/common/keyboardMapper.ts | 0 .../keyboardLayoutMainService.ts | 0 .../vs/platform/label/common/label.ts | 0 .../vs/platform/launch/common/launch.ts | 0 .../launch/electron-main/launchMainService.ts | 0 .../platform/layout/browser/layoutService.ts | 0 .../vs/platform/lifecycle/common/lifecycle.ts | 0 .../electron-main/lifecycleMainService.ts | 106 +- .../vs/platform/list/browser/listService.ts | 86 +- .../localizations/common/localizations.ts | 0 .../localizations/node/localizations.ts | 5 +- .../vs/platform/log/browser/log.ts | 0 .../vs/platform/log/common/bufferLog.ts | 0 .../vs/platform/log/common/fileLog.ts | 0 .../src => src}/vs/platform/log/common/log.ts | 0 .../vs/platform/log/common/logIpc.ts | 0 .../vs/platform/log/node/loggerService.ts | 0 .../vs/platform/log/node/spdlogLog.ts | 13 +- .../platform/markers/common/markerService.ts | 0 .../vs/platform/markers/common/markers.ts | 0 .../markers/test/common/markerService.test.ts | 0 .../vs/platform/menubar/common/menubar.ts | 0 .../platform/menubar/electron-main/menubar.ts | 96 +- .../electron-main/menubarMainService.ts | 0 .../menubar/electron-sandbox/menubar.ts | 0 .../vs/platform/native/common/native.ts | 10 +- .../electron-main/nativeHostMainService.ts | 144 +- .../native/electron-sandbox/native.ts | 2 +- .../electron-sandbox/nativeHostService.ts | 0 .../notification/common/notification.ts | 0 .../test/common/testNotificationService.ts | 0 src/vs/platform/opener/browser/link.ts | 104 + .../vs/platform/opener/common/opener.ts | 1 + .../vs/platform/product/common/product.ts | 16 +- .../platform/product/common/productService.ts | 0 .../vs/platform/progress/common/progress.ts | 10 +- .../protocol/electron-main/protocol.ts | 6 +- .../electron-main/protocolMainService.ts | 11 +- .../quickinput/browser/commandsQuickAccess.ts | 9 +- .../quickinput/browser/helpQuickAccess.ts | 0 .../quickinput/browser/pickerQuickAccess.ts | 8 +- .../quickinput/browser/quickAccess.ts | 30 + .../platform/quickinput/browser/quickInput.ts | 4 +- .../platform/quickinput/common/quickAccess.ts | 7 + .../platform/quickinput/common/quickInput.ts | 0 .../vs/platform/registry/common/platform.ts | 0 .../registry/test/common/platform.test.ts | 0 .../remote/browser/browserSocketFactory.ts | 6 +- .../browser/remoteAuthorityResolverService.ts | 7 + .../remote/common/remoteAgentConnection.ts | 0 .../remote/common/remoteAgentEnvironment.ts | 0 .../remote/common/remoteAuthorityResolver.ts | 18 +- .../vs/platform/remote/common/remoteHosts.ts | 6 +- .../vs/platform/remote/common/tunnel.ts | 5 + .../remoteAuthorityResolverService.ts | 74 +- .../platform/remote/node/nodeSocketFactory.ts | 0 .../vs/platform/remote/node/tunnelService.ts | 31 +- .../request/browser/requestService.ts | 0 .../vs/platform/request/common/request.ts | 0 .../vs/platform/request/common/requestIpc.ts | 0 .../electron-main/requestMainService.ts | 0 .../vs/platform/request/node/proxy.ts | 0 .../platform/request/node/requestService.ts | 0 .../common/serviceMachineId.ts | 0 .../severityIcon/common/severityIcon.ts | 0 .../electron-main/sharedProcess.ts | 4 - .../sharedProcess/node/sharedProcess.ts | 0 .../vs/platform/sign/browser/signService.ts | 0 .../vs/platform/sign/common/sign.ts | 0 .../vs/platform/sign/node/signService.ts | 0 .../vs/platform/state/electron-main}/state.ts | 8 +- .../state/electron-main/stateMainService.ts | 189 + .../state/test/electron-main/state.test.ts | 202 + .../storage/browser/storageService.ts | 0 .../vs/platform/storage/common/storage.ts | 2 +- .../vs/platform/storage/common/storageIpc.ts | 0 .../storage/electron-main/storageIpc.ts | 0 .../storage/electron-main/storageMain.ts | 5 +- .../electron-main/storageMainService.ts | 0 .../electron-sandbox/storageService.ts | 0 .../test/browser/storageService.test.ts | 0 .../test/common/storageService.test.ts | 0 .../electron-main/storageMainService.test.ts | 4 +- .../telemetry/browser/errorTelemetry.ts | 0 .../telemetry/common/commonProperties.ts | 2 +- .../telemetry/common/errorTelemetry.ts | 0 .../platform/telemetry/common/gdprTypings.ts | 0 .../vs/platform/telemetry/common/telemetry.ts | 0 .../platform/telemetry/common/telemetryIpc.ts | 0 .../telemetry/common/telemetryLogAppender.ts | 0 .../telemetry/common/telemetryService.ts | 0 .../telemetry/common/telemetryUtils.ts | 0 .../customEndpointTelemetryService.ts | 0 .../telemetry/node/appInsightsAppender.ts | 0 .../node/customEndpointTelemetryService.ts | 0 .../platform/telemetry/node/errorTelemetry.ts | 0 .../vs/platform/telemetry/node/telemetry.ts | 0 .../test/browser/telemetryService.test.ts | 0 .../test/common/telemetryLogAppender.test.ts | 0 .../appInsightsAppender.test.ts | 0 .../terminal/common/environmentVariable.ts | 0 .../vs/platform/terminal/common/terminal.ts | 190 +- .../terminal/common/terminalDataBuffering.ts | 0 .../terminal/common/terminalEnvironment.ts | 14 + .../common/terminalPlatformConfiguration.ts | 388 + .../terminal/common/terminalProcess.ts | 7 +- .../terminal/common/terminalRecorder.ts | 6 +- .../terminal/electron-sandbox/terminal.ts | 0 .../terminal/node/heartbeatService.ts | 0 .../vs/platform/terminal/node/ptyHostMain.ts | 6 +- .../platform/terminal/node/ptyHostService.ts | 55 +- .../vs/platform/terminal/node/ptyService.ts | 93 +- .../terminal/node/terminalEnvironment.ts | 0 .../platform/terminal/node/terminalProcess.ts | 73 +- .../terminal/node/terminalProfiles.ts | 362 + .../terminal/node/windowsShellHelper.ts | 16 +- .../test/common/terminalRecorder.test.ts | 0 .../platform/theme/browser/iconsStyleSheet.ts | 0 .../vs/platform/theme/common/colorRegistry.ts | 131 +- .../vs/platform/theme/common/iconRegistry.ts | 0 .../vs/platform/theme/common/styler.ts | 22 +- .../vs/platform/theme/common/theme.ts | 0 .../vs/platform/theme/common/themeService.ts | 4 + .../common/tokenClassificationRegistry.ts | 0 .../theme/electron-main/themeMainService.ts | 56 +- .../theme/test/common/testThemeService.ts | 0 .../vs/platform/undoRedo/common/undoRedo.ts | 0 .../undoRedo/common/undoRedoService.ts | 2 +- .../test/common/undoRedoService.test.ts | 0 .../common/update.config.contribution.ts | 0 .../vs/platform/update/common/update.ts | 0 .../vs/platform/update/common/updateIpc.ts | 0 .../electron-main/abstractUpdateService.ts | 2 +- .../electron-main/updateService.darwin.ts | 0 .../electron-main/updateService.linux.ts | 0 .../electron-main/updateService.snap.ts | 2 +- .../electron-main/updateService.win32.ts | 6 +- .../src => src}/vs/platform/url/common/url.ts | 0 .../vs/platform/url/common/urlIpc.ts | 0 .../vs/platform/url/common/urlService.ts | 0 .../url/electron-main/electronUrlListener.ts | 0 .../common/abstractSynchronizer.ts | 0 .../platform/userDataSync/common/content.ts | 0 .../userDataSync/common/extensionsMerge.ts | 0 .../common/extensionsStorageSync.ts | 0 .../userDataSync/common/extensionsSync.ts | 0 .../userDataSync/common/globalStateMerge.ts | 0 .../userDataSync/common/globalStateSync.ts | 0 .../userDataSync/common/ignoredExtensions.ts | 0 .../userDataSync/common/keybindingsMerge.ts | 0 .../userDataSync/common/keybindingsSync.ts | 0 .../userDataSync/common/settingsMerge.ts | 0 .../userDataSync/common/settingsSync.ts | 0 .../userDataSync/common/snippetsMerge.ts | 0 .../userDataSync/common/snippetsSync.ts | 0 .../common/userDataAutoSyncService.ts | 0 .../userDataSync/common/userDataSync.ts | 0 .../common/userDataSyncAccount.ts | 0 .../common/userDataSyncBackupStoreService.ts | 0 .../userDataSync/common/userDataSyncIpc.ts | 0 .../userDataSync/common/userDataSyncLog.ts | 0 .../common/userDataSyncMachines.ts | 0 .../userDataSyncResourceEnablementService.ts | 0 .../common/userDataSyncService.ts | 0 .../common/userDataSyncServiceIpc.ts | 0 .../common/userDataSyncStoreService.ts | 0 .../userDataAutoSyncService.ts | 0 .../test/common/extensionsMerge.test.ts | 0 .../test/common/globalStateMerge.test.ts | 0 .../test/common/globalStateSync.test.ts | 0 .../test/common/keybindingsMerge.test.ts | 0 .../test/common/keybindingsSync.test.ts | 0 .../test/common/settingsMerge.test.ts | 0 .../test/common/settingsSync.test.ts | 0 .../test/common/snippetsMerge.test.ts | 0 .../test/common/snippetsSync.test.ts | 0 .../test/common/synchronizer.test.ts | 0 .../common/userDataAutoSyncService.test.ts | 0 .../test/common/userDataSyncClient.ts | 0 .../test/common/userDataSyncService.test.ts | 0 .../common/userDataSyncStoreService.test.ts | 0 .../vs/platform/webview/common/mimeTypes.ts | 0 .../webview/common/webviewManagerService.ts | 0 .../webview/common/webviewPortMapping.ts | 0 .../electron-main/webviewMainService.ts | 0 .../electron-main/webviewProtocolProvider.ts | 0 .../vs/platform/windows/common/windows.ts | 27 +- .../platform/windows/electron-main/window.ts | 37 +- .../platform/windows/electron-main/windows.ts | 0 .../windows/electron-main/windowsFinder.ts | 2 +- .../electron-main/windowsMainService.ts | 9 +- .../electron-main/windowsStateHandler.ts | 28 +- .../windows/electron-sandbox/window.ts | 0 .../vs/platform/windows/node/windowTracker.ts | 0 .../test/electron-main/windowsFinder.test.ts | 2 +- .../electron-main/windowsStateHandler.test.ts | 0 .../vs/platform/workspace/common/workspace.ts | 0 .../workspace/common/workspaceTrust.ts | 45 +- .../workspace/test/common/testWorkspace.ts | 0 .../workspace/test/common/workspace.test.ts | 0 .../platform/workspaces/common/workspaces.ts | 18 +- .../workspacesHistoryMainService.ts | 8 +- .../electron-main/workspacesMainService.ts | 4 +- .../workspacesManagementMainService.ts | 34 +- .../workspaces/test/common/workspaces.test.ts | 0 .../workspacesHistoryStorage.test.ts | 0 .../workspacesManagementMainService.test.ts | 2 +- {lib/vscode/src => src}/vs/vscode.d.ts | 2583 ++- .../src => src}/vs/vscode.proposed.d.ts | 1395 +- .../vs/workbench/api/browser/apiCommands.ts | 0 .../api/browser/extensionHost.contribution.ts | 1 + .../api/browser/mainThreadAuthentication.ts | 6 + .../api/browser/mainThreadBulkEdits.ts | 0 .../api/browser/mainThreadCLICommands.ts | 0 .../api/browser/mainThreadClipboard.ts | 0 .../api/browser/mainThreadCodeInsets.ts | 0 .../api/browser/mainThreadCommands.ts | 0 .../api/browser/mainThreadComments.ts | 0 .../api/browser/mainThreadConfiguration.ts | 0 .../api/browser/mainThreadConsole.ts | 0 .../api/browser/mainThreadCustomEditors.ts | 161 +- .../api/browser/mainThreadDebugService.ts | 3 +- .../api/browser/mainThreadDecorations.ts | 0 .../api/browser/mainThreadDiagnostics.ts | 0 .../api/browser/mainThreadDialogs.ts | 0 .../mainThreadDocumentContentProviders.ts | 0 .../api/browser/mainThreadDocuments.ts | 73 +- .../browser/mainThreadDocumentsAndEditors.ts | 0 .../api/browser/mainThreadDownloadService.ts | 0 .../workbench/api/browser/mainThreadEditor.ts | 2 +- .../api/browser/mainThreadEditorTabs.ts | 10 +- .../api/browser/mainThreadEditors.ts | 5 +- .../workbench/api/browser/mainThreadErrors.ts | 0 .../api/browser/mainThreadExtensionService.ts | 41 +- .../api/browser/mainThreadFileSystem.ts | 10 +- .../mainThreadFileSystemEventService.ts | 0 .../workbench/api/browser/mainThreadKeytar.ts | 0 .../api/browser/mainThreadLabelService.ts | 0 .../api/browser/mainThreadLanguageFeatures.ts | 31 +- .../api/browser/mainThreadLanguages.ts | 0 .../api/browser/mainThreadLogService.ts | 0 .../api/browser/mainThreadMessageService.ts | 0 .../api/browser/mainThreadNotebook.ts | 33 +- .../browser/mainThreadNotebookDocuments.ts | 52 +- .../mainThreadNotebookDocumentsAndEditors.ts | 9 +- .../api/browser/mainThreadNotebookEditors.ts | 8 +- .../api/browser/mainThreadNotebookKernels.ts | 23 +- .../browser/mainThreadNotebookRenderers.ts | 29 + .../api/browser/mainThreadOutputService.ts | 0 .../api/browser/mainThreadProgress.ts | 0 .../api/browser/mainThreadQuickOpen.ts | 0 .../browser/mainThreadRemoteConnectionData.ts | 0 .../vs/workbench/api/browser/mainThreadSCM.ts | 0 .../api/browser/mainThreadSaveParticipant.ts | 0 .../workbench/api/browser/mainThreadSearch.ts | 0 .../api/browser/mainThreadSecretState.ts | 0 .../api/browser/mainThreadStatusBar.ts | 10 +- .../api/browser/mainThreadStorage.ts | 4 +- .../workbench/api/browser/mainThreadTask.ts | 3 - .../api/browser/mainThreadTelemetry.ts | 0 .../api/browser/mainThreadTerminalService.ts | 107 +- .../api/browser/mainThreadTesting.ts | 0 .../api/browser/mainThreadTheming.ts | 0 .../api/browser/mainThreadTimeline.ts | 0 .../api/browser/mainThreadTreeViews.ts | 16 +- .../api/browser/mainThreadTunnelService.ts | 3 +- .../api/browser/mainThreadUriOpeners.ts | 0 .../workbench/api/browser/mainThreadUrls.ts | 0 .../api/browser/mainThreadWebviewManager.ts | 0 .../api/browser/mainThreadWebviewPanels.ts | 0 .../api/browser/mainThreadWebviewViews.ts | 0 .../api/browser/mainThreadWebviews.ts | 5 +- .../workbench/api/browser/mainThreadWindow.ts | 3 +- .../api/browser/mainThreadWorkspace.ts | 0 .../api/browser/viewsExtensionPoint.ts | 0 .../vs/workbench/api/common/apiCommands.ts | 96 - .../vs/workbench/api/common/cache.ts | 0 .../api/common/configurationExtensionPoint.ts | 0 .../workbench/api/common/exHostSecretState.ts | 0 .../workbench/api/common/extHost.api.impl.ts | 186 +- .../api/common/extHost.common.services.ts | 2 + .../workbench/api/common/extHost.protocol.ts | 153 +- .../api/common/extHostApiCommands.ts | 64 +- .../common/extHostApiDeprecationService.ts | 0 .../api/common/extHostAuthentication.ts | 8 +- .../workbench/api/common/extHostBulkEdits.ts | 0 .../workbench/api/common/extHostClipboard.ts | 0 .../workbench/api/common/extHostCodeInsets.ts | 8 +- .../workbench/api/common/extHostCommands.ts | 8 +- .../workbench/api/common/extHostComments.ts | 0 .../api/common/extHostConfiguration.ts | 0 .../api/common/extHostCustomEditors.ts | 0 .../workbench/api/common/extHostCustomers.ts | 0 .../api/common/extHostDebugService.ts | 56 +- .../api/common/extHostDecorations.ts | 0 .../api/common/extHostDiagnostics.ts | 22 +- .../vs/workbench/api/common/extHostDialogs.ts | 0 .../common/extHostDocumentContentProviders.ts | 0 .../api/common/extHostDocumentData.ts | 0 .../common/extHostDocumentSaveParticipant.ts | 0 .../workbench/api/common/extHostDocuments.ts | 0 .../api/common/extHostDocumentsAndEditors.ts | 0 .../workbench/api/common/extHostEditorTabs.ts | 17 +- .../api/common/extHostExtensionActivator.ts | 0 .../api/common/extHostExtensionService.ts | 43 +- .../workbench/api/common/extHostFileSystem.ts | 17 +- .../api/common/extHostFileSystemConsumer.ts | 0 .../common/extHostFileSystemEventService.ts | 0 .../api/common/extHostFileSystemInfo.ts | 0 .../api/common/extHostInitDataService.ts | 0 .../api/common/extHostLabelService.ts | 0 .../api/common/extHostLanguageFeatures.ts | 144 +- .../workbench/api/common/extHostLanguages.ts | 0 .../vs/workbench/api/common/extHostMemento.ts | 5 + .../api/common/extHostMessageService.ts | 0 .../workbench/api/common/extHostNotebook.ts | 343 +- .../common/extHostNotebookConcatDocument.ts | 0 .../api/common/extHostNotebookDocument.ts | 92 +- .../api/common/extHostNotebookEditor.ts | 8 +- .../api/common/extHostNotebookKernels.ts | 521 + .../api/common/extHostNotebookRenderers.ts | 63 + .../vs/workbench/api/common/extHostOutput.ts | 0 .../workbench/api/common/extHostProgress.ts | 0 .../workbench/api/common/extHostQuickOpen.ts | 0 .../api/common/extHostRequireInterceptor.ts | 0 .../workbench/api/common/extHostRpcService.ts | 0 .../vs/workbench/api/common/extHostSCM.ts | 0 .../vs/workbench/api/common/extHostSearch.ts | 0 .../vs/workbench/api/common/extHostSecrets.ts | 0 .../workbench/api/common/extHostStatusBar.ts | 75 +- .../vs/workbench/api/common/extHostStorage.ts | 0 .../api/common/extHostStoragePaths.ts | 0 .../vs/workbench/api/common/extHostTask.ts | 6 - .../workbench/api/common/extHostTelemetry.ts | 0 .../api/common/extHostTerminalService.ts | 149 +- .../vs/workbench/api/common/extHostTesting.ts | 2 +- .../api/common/extHostTestingPrivateApi.ts | 0 .../workbench/api/common/extHostTextEditor.ts | 5 +- .../api/common/extHostTextEditors.ts | 5 +- .../vs/workbench/api/common/extHostTheming.ts | 0 .../workbench/api/common/extHostTimeline.ts | 0 .../workbench/api/common/extHostTreeViews.ts | 22 +- .../api/common/extHostTunnelService.ts | 0 .../api/common/extHostTypeConverters.ts | 151 +- .../vs/workbench/api/common/extHostTypes.ts | 313 +- .../workbench/api/common/extHostUriOpener.ts | 0 .../common/extHostUriTransformerService.ts | 0 .../vs/workbench/api/common/extHostUrls.ts | 0 .../vs/workbench/api/common/extHostWebview.ts | 47 +- .../api/common/extHostWebviewMessaging.ts | 4 +- .../api/common/extHostWebviewPanels.ts | 0 .../api/common/extHostWebviewView.ts | 0 .../vs/workbench/api/common/extHostWindow.ts | 2 - .../workbench/api/common/extHostWorkspace.ts | 3 +- .../common/jsonValidationExtensionPoint.ts | 0 .../api/common/menusExtensionPoint.ts | 31 +- .../vs/workbench/api/common/shared/tasks.ts | 1 + src/vs/workbench/api/common/shared/webview.ts | 65 + .../api/common/shared/workspaceContains.ts | 0 .../api/node/extHost.node.services.ts | 0 .../vs/workbench/api/node/extHostCLIServer.ts | 7 - .../workbench/api/node/extHostDebugService.ts | 20 +- .../api/node/extHostDownloadService.ts | 0 .../api/node/extHostExtensionService.ts | 0 .../workbench/api/node/extHostLogService.ts | 0 .../api/node/extHostOutputService.ts | 21 +- .../vs/workbench/api/node/extHostSearch.ts | 0 .../vs/workbench/api/node/extHostTask.ts | 10 +- .../api/node/extHostTerminalService.ts | 29 + .../api/node/extHostTunnelService.ts | 11 +- .../api/worker/extHost.worker.services.ts | 0 .../api/worker/extHostExtensionService.ts | 0 .../workbench/api/worker/extHostLogService.ts | 0 .../vs/workbench/browser/actions.ts | 8 + .../browser/actions/developerActions.ts | 30 +- .../workbench/browser/actions/helpActions.ts | 243 +- .../browser/actions/layoutActions.ts | 675 +- .../workbench/browser/actions/listCommands.ts | 0 .../browser/actions/media/actions.css | 0 .../browser/actions/navigationActions.ts | 0 .../browser/actions/quickAccessActions.ts | 0 .../browser/actions/textInputActions.ts | 0 .../browser/actions/windowActions.ts | 352 +- .../browser/actions/workspaceActions.ts | 196 +- .../browser/actions/workspaceCommands.ts | 95 +- .../vs/workbench/browser/codeeditor.ts | 2 + .../vs/workbench/browser/composite.ts | 11 +- .../vs/workbench/browser/contextkeys.ts | 13 +- .../src => src}/vs/workbench/browser/dnd.ts | 449 +- .../vs/workbench/browser/editor.ts | 136 +- .../vs/workbench/browser/labels.ts | 0 .../vs/workbench/browser/layout.ts | 52 +- .../vs/workbench/browser/media/code-icon.svg | 0 .../vs/workbench/browser/media/part.css | 0 .../vs/workbench/browser/media/style.css | 0 .../vs/workbench/browser/panecomposite.ts | 0 .../src => src}/vs/workbench/browser/panel.ts | 2 +- .../src => src}/vs/workbench/browser/part.ts | 0 .../parts/activitybar/activitybarActions.ts | 0 .../parts/activitybar/activitybarPart.ts | 27 +- .../activitybar/media/activityaction.css | 0 .../activitybar/media/activitybarpart.css | 0 .../browser/parts/banner/bannerPart.ts | 331 + .../browser/parts/banner/media/bannerpart.css | 52 + .../workbench/browser/parts/compositeBar.ts | 0 .../browser/parts/compositeBarActions.ts | 0 .../workbench/browser/parts/compositePart.ts | 0 .../parts/dialogs/dialog.web.contribution.ts | 0 .../browser/parts/dialogs/dialogHandler.ts | 5 +- .../browser/parts/editor/binaryDiffEditor.ts | 0 .../browser/parts/editor/binaryEditor.ts | 10 +- .../browser/parts/editor/breadcrumbs.ts | 0 .../parts/editor/breadcrumbsControl.ts | 6 +- .../browser/parts/editor/breadcrumbsModel.ts | 0 .../browser/parts/editor/breadcrumbsPicker.ts | 0 .../parts/editor/editor.contribution.ts | 241 +- .../workbench/browser/parts/editor/editor.ts | 16 +- .../browser/parts/editor/editorActions.ts | 28 +- .../browser/parts/editor/editorAutoSave.ts | 4 +- .../browser/parts/editor/editorCommands.ts | 32 +- .../browser/parts/editor/editorControl.ts | 56 +- .../browser/parts/editor/editorDropTarget.ts | 36 +- .../browser/parts/editor/editorGroupView.ts | 101 +- .../browser/parts/editor/editorPane.ts | 14 +- .../browser/parts/editor/editorPart.ts | 6 - .../browser/parts/editor/editorQuickAccess.ts | 2 +- .../browser/parts/editor/editorStatus.ts | 46 +- .../browser/parts/editor/editorsObserver.ts | 3 +- .../browser/parts/editor/media/back-tb.png | Bin 0 -> 254 bytes .../parts/editor/media/binaryeditor.css | 0 .../parts/editor/media/breadcrumbscontrol.css | 0 .../parts/editor/media/editordroptarget.css | 0 .../parts/editor/media/editorgroupview.css | 0 .../parts/editor/media/editorquickaccess.css | 0 .../parts/editor/media/editorstatus.css | 0 .../browser/parts/editor/media/forward-tb.png | Bin 0 -> 267 bytes .../parts/editor/media/letterpress-dark.svg | 0 .../parts/editor/media/letterpress-hc.svg | 0 .../parts/editor/media/letterpress.svg | 0 .../parts/editor/media/notabstitlecontrol.css | 0 .../parts/editor/media/tabstitlecontrol.css | 0 .../parts/editor/media/titlecontrol.css | 0 .../editor/media/workspacetrusteditor.css | 20 + .../parts/editor/noTabsTitleControl.ts | 8 +- .../browser/parts/editor/sideBySideEditor.ts | 54 +- .../browser/parts/editor/tabsTitleControl.ts | 18 +- .../browser/parts/editor/textDiffEditor.ts | 140 +- .../browser/parts/editor/textEditor.ts | 39 +- .../parts/editor/textResourceEditor.ts | 28 +- .../browser/parts/editor/titleControl.ts | 63 +- .../editor/workspaceTrustRequiredEditor.ts | 129 + .../browser/parts/media/compositepart.css | 0 .../media/notificationsActions.css | 0 .../media/notificationsCenter.css | 0 .../notifications/media/notificationsList.css | 0 .../media/notificationsToasts.css | 0 .../notifications/notificationsActions.ts | 2 +- .../notifications/notificationsAlerts.ts | 0 .../notifications/notificationsCenter.ts | 0 .../notifications/notificationsCommands.ts | 0 .../parts/notifications/notificationsList.ts | 0 .../notifications/notificationsStatus.ts | 9 +- .../notifications/notificationsTelemetry.ts | 0 .../notifications/notificationsToasts.ts | 0 .../notifications/notificationsViewer.ts | 16 +- .../browser/parts/panel/media/panelpart.css | 0 .../browser/parts/panel/panelActions.ts | 0 .../browser/parts/panel/panelPart.ts | 0 .../parts/sidebar/media/sidebarpart.css | 0 .../browser/parts/sidebar/sidebarPart.ts | 0 .../parts/statusbar/media/statusbarpart.css | 0 .../browser/parts/statusbar/statusbarPart.ts | 134 +- .../parts/titlebar/media/titlebarpart.css | 0 .../browser/parts/titlebar/menubarControl.ts | 164 +- .../browser/parts/titlebar/titlebarPart.ts | 1 + .../browser/parts/views/media/paneviewlet.css | 0 .../browser/parts/views/media/views.css | 9 +- .../workbench/browser/parts/views/treeView.ts | 44 +- .../workbench/browser/parts/views/viewPane.ts | 13 +- .../browser/parts/views/viewPaneContainer.ts | 9 +- .../browser/parts/views/viewsService.ts | 0 .../browser/parts/views/viewsViewlet.ts | 0 .../vs/workbench/browser/quickaccess.ts | 0 .../src => src}/vs/workbench/browser/style.ts | 12 +- .../vs/workbench/browser/viewlet.ts | 0 .../vs/workbench/browser/web.main.ts | 13 +- .../vs/workbench/browser/window.ts | 19 +- .../browser/workbench.contribution.ts | 0 .../vs/workbench/browser/workbench.ts | 17 +- .../vs/workbench/buildfile.desktop.js | 0 .../src => src}/vs/workbench/buildfile.web.js | 0 .../vs/workbench/common/actions.ts | 0 .../vs/workbench/common/activity.ts | 0 .../vs/workbench/common/component.ts | 0 .../vs/workbench/common/composite.ts | 0 .../vs/workbench/common/configuration.ts | 0 .../vs/workbench/common/contributions.ts | 0 .../vs/workbench/common/dialogs.ts | 0 .../src => src}/vs/workbench/common/editor.ts | 813 +- .../common/editor/binaryEditorModel.ts | 12 +- .../common/editor/diffEditorInput.ts | 43 +- .../common/editor/diffEditorModel.ts | 2 +- .../common/editor/editorGroupModel.ts | 19 +- src/vs/workbench/common/editor/editorInput.ts | 140 + src/vs/workbench/common/editor/editorModel.ts | 53 + .../workbench/common/editor/editorOptions.ts | 44 + .../common/editor/resourceEditorInput.ts | 130 +- .../common/editor/sideBySideEditorInput.ts | 227 + .../common/editor/textDiffEditorModel.ts | 0 .../common/editor/textEditorModel.ts | 2 +- .../common/editor/textResourceEditorInput.ts | 226 + .../common/editor/textResourceEditorModel.ts | 5 +- .../vs/workbench/common/memento.ts | 0 .../vs/workbench/common/notifications.ts | 6 +- .../vs/workbench/common/panecomposite.ts | 0 .../src => src}/vs/workbench/common/panel.ts | 0 .../vs/workbench/common/resources.ts | 4 +- .../src => src}/vs/workbench/common/theme.ts | 29 +- .../vs/workbench/common/viewlet.ts | 0 .../src => src}/vs/workbench/common/views.ts | 5 + .../contrib/bulkEdit/browser/bulkCellEdits.ts | 0 .../bulkEdit/browser/bulkEditService.ts | 12 +- .../contrib/bulkEdit/browser/bulkFileEdits.ts | 0 .../contrib/bulkEdit/browser/bulkTextEdits.ts | 16 +- .../contrib/bulkEdit/browser/conflicts.ts | 0 .../browser/preview/bulkEdit.contribution.ts | 0 .../bulkEdit/browser/preview/bulkEdit.css | 0 .../bulkEdit/browser/preview/bulkEditPane.ts | 4 +- .../browser/preview/bulkEditPreview.ts | 0 .../bulkEdit/browser/preview/bulkEditTree.ts | 0 .../test/browser/bulkEditPreview.test.ts | 0 .../browser/callHierarchy.contribution.ts | 0 .../browser/callHierarchyPeek.ts | 1 + .../browser/callHierarchyTree.ts | 0 .../browser/media/callHierarchy.css | 0 .../callHierarchy/common/callHierarchy.ts | 0 .../common/codeActions.contribution.ts | 0 .../common/codeActionsContribution.ts | 0 .../common/codeActionsExtensionPoint.ts | 0 .../common/documentationContribution.ts | 0 .../common/documentationExtensionPoint.ts | 0 .../browser/accessibility/accessibility.css | 0 .../browser/accessibility/accessibility.ts | 0 .../browser/codeEditor.contribution.ts | 1 + .../codeEditor/browser/diffEditorHelper.ts | 2 +- .../browser/find/simpleFindReplaceWidget.css | 0 .../browser/find/simpleFindReplaceWidget.ts | 0 .../browser/find/simpleFindWidget.css | 0 .../browser/find/simpleFindWidget.ts | 20 +- .../inspectEditorTokens.css | 0 .../inspectEditorTokens.ts | 13 +- .../codeEditor/browser/inspectKeybindings.ts | 54 + .../languageConfigurationExtensionPoint.ts | 0 .../browser/largeFileOptimizations.ts | 0 .../codeEditor/browser/menuPreventer.ts | 0 .../browser/outline/documentSymbolsOutline.ts | 1 + .../browser/outline/documentSymbolsTree.css | 0 .../browser/outline/documentSymbolsTree.ts | 0 .../quickaccess/gotoLineQuickAccess.ts | 7 +- .../quickaccess/gotoSymbolQuickAccess.ts | 7 +- .../codeEditor/browser/saveParticipants.ts | 0 .../codeEditor/browser/selectionClipboard.ts | 0 .../codeEditor/browser/simpleEditorOptions.ts | 0 .../suggestEnabledInput.css | 0 .../suggestEnabledInput.ts | 0 .../browser/toggleColumnSelection.ts | 79 +- .../codeEditor/browser/toggleMinimap.ts | 44 + .../browser/toggleMultiCursorModifier.ts | 45 +- .../browser/toggleRenderControlCharacter.ts | 44 + .../browser/toggleRenderWhitespace.ts | 52 + .../codeEditor/browser/toggleWordWrap.ts | 2 +- .../browser/untitledTextEditorHint.ts | 29 +- .../browser/workbenchReferenceSearch.ts | 0 .../codeEditor.contribution.ts | 0 .../displayChangeRemeasureFonts.ts | 0 .../electron-sandbox/inputClipboardActions.ts | 0 .../electron-sandbox/selectionClipboard.ts | 0 .../sleepResumeRepaintMinimap.ts | 0 .../electron-sandbox/startDebugTextMate.ts | 0 .../test/browser/saveParticipant.test.ts | 0 .../comments/browser/commentFormActions.ts | 0 .../comments/browser/commentGlyphWidget.ts | 1 + .../contrib/comments/browser/commentMenus.ts | 0 .../contrib/comments/browser/commentNode.ts | 0 .../comments/browser/commentService.ts | 0 .../comments/browser/commentThreadWidget.ts | 6 +- .../comments/browser/comments.contribution.ts | 0 .../browser/commentsEditorContribution.ts | 3 +- .../comments/browser/commentsTreeViewer.ts | 0 .../contrib/comments/browser/commentsView.ts | 0 .../contrib/comments/browser/media/panel.css | 0 .../contrib/comments/browser/media/review.css | 0 .../comments/browser/reactionsAction.ts | 0 .../comments/browser/simpleCommentEditor.ts | 0 .../comments/common/commentContextKeys.ts | 0 .../contrib/comments/common/commentModel.ts | 0 .../comments/common/commentThreadWidget.ts | 0 .../configurationExportHelper.contribution.ts | 0 .../configurationExportHelper.ts | 0 .../browser/customEditor.contribution.ts | 9 +- .../customEditor/browser/customEditorInput.ts | 190 +- .../browser/customEditorInputFactory.ts | 97 +- .../customEditor/browser/customEditors.ts | 8 +- .../common/contributedCustomEditors.ts | 0 .../customEditor/common/customEditor.ts | 6 +- .../common/customEditorModelManager.ts | 10 + .../common/customTextEditorModel.ts | 16 +- .../customEditor/common/extensionPoint.ts | 0 .../contrib/debug/browser/baseDebugView.ts | 0 .../browser/breakpointEditorContribution.ts | 3 + .../contrib/debug/browser/breakpointWidget.ts | 8 +- .../contrib/debug/browser/breakpointsView.ts | 17 + .../browser/callStackEditorContribution.ts | 5 + .../contrib/debug/browser/callStackView.ts | 3 +- .../debug/browser/debug.contribution.ts | 18 +- .../debug/browser/debugANSIHandling.ts | 0 .../debug/browser/debugActionViewItems.ts | 0 .../debug/browser/debugAdapterManager.ts | 47 +- .../contrib/debug/browser/debugColors.ts | 16 +- .../contrib/debug/browser/debugCommands.ts | 6 +- .../browser/debugConfigurationManager.ts | 0 .../debug/browser/debugEditorActions.ts | 2 +- .../debug/browser/debugEditorContribution.ts | 47 +- .../contrib/debug/browser/debugHover.ts | 1 + .../contrib/debug/browser/debugIcons.ts | 0 .../contrib/debug/browser/debugProgress.ts | 0 .../contrib/debug/browser/debugQuickAccess.ts | 2 +- .../contrib/debug/browser/debugService.ts | 9 +- .../contrib/debug/browser/debugSession.ts | 0 .../contrib/debug/browser/debugStatus.ts | 3 +- .../contrib/debug/browser/debugTaskRunner.ts | 0 .../contrib/debug/browser/debugTitle.ts | 0 .../contrib/debug/browser/debugToolBar.ts | 0 .../contrib/debug/browser/debugViewlet.ts | 0 .../contrib/debug/browser/exceptionWidget.ts | 0 .../browser/extensionHostDebugService.ts | 0 .../contrib/debug/browser/linkDetector.ts | 0 .../debug/browser/loadedScriptsView.ts | 0 .../debug/browser/media/breakpointWidget.css | 0 .../debug/browser/media/continue-tb.png | Bin 0 -> 668 bytes .../media/continue-without-debugging-tb.png | Bin 0 -> 1418 bytes .../browser/media/debug.contribution.css | 0 .../debug/browser/media/debugHover.css | 0 .../debug/browser/media/debugToolBar.css | 0 .../debug/browser/media/debugViewlet.css | 0 .../debug/browser/media/exceptionWidget.css | 0 .../contrib/debug/browser/media/pause-tb.png | Bin 0 -> 299 bytes .../contrib/debug/browser/media/repl.css | 0 .../debug/browser/media/restart-tb.png | Bin 0 -> 1276 bytes .../debug/browser/media/stepinto-tb.png | Bin 0 -> 700 bytes .../debug/browser/media/stepout-tb.png | Bin 0 -> 701 bytes .../debug/browser/media/stepover-tb.png | Bin 0 -> 914 bytes .../contrib/debug/browser/media/stop-tb.png | Bin 0 -> 310 bytes .../contrib/debug/browser/rawDebugSession.ts | 2 +- .../workbench/contrib/debug/browser/repl.ts | 21 +- .../contrib/debug/browser/replFilter.ts | 0 .../contrib/debug/browser/replViewer.ts | 2 +- .../debug/browser/statusbarColorProvider.ts | 0 .../contrib/debug/browser/variablesView.ts | 0 .../debug/browser/watchExpressionsView.ts | 0 .../contrib/debug/browser/welcomeView.ts | 6 +- .../debug/common/abstractDebugAdapter.ts | 0 .../workbench/contrib/debug/common/debug.ts | 1 + .../contrib/debug/common/debugCompoundRoot.ts | 0 .../debug/common/debugContentProvider.ts | 0 .../contrib/debug/common/debugModel.ts | 0 .../contrib/debug/common/debugProtocol.d.ts | 0 .../contrib/debug/common/debugSchemas.ts | 0 .../contrib/debug/common/debugSource.ts | 0 .../contrib/debug/common/debugStorage.ts | 0 .../contrib/debug/common/debugTelemetry.ts | 0 .../contrib/debug/common/debugUtils.ts | 0 .../contrib/debug/common/debugViewModel.ts | 0 .../contrib/debug/common/debugger.ts | 91 +- .../contrib/debug/common/replModel.ts | 0 .../extensionHostDebugService.ts | 0 .../contrib/debug/node/debugAdapter.ts | 0 .../contrib/debug/node/telemetryApp.ts | 0 .../workbench/contrib/debug/node/terminals.ts | 52 +- .../debug/test/browser/baseDebugView.test.ts | 0 .../debug/test/browser/breakpoints.test.ts | 0 .../debug/test/browser/callStack.test.ts | 0 .../test/browser/debugANSIHandling.test.ts | 0 .../debug/test/browser/debugHover.test.ts | 0 .../debug/test/browser/debugSource.test.ts | 0 .../debug/test/browser/debugUtils.test.ts | 0 .../debug/test/browser/debugViewModel.test.ts | 0 .../debug/test/browser/linkDetector.test.ts | 0 .../contrib/debug/test/browser/mockDebug.ts | 0 .../test/browser/rawDebugSession.test.ts | 0 .../contrib/debug/test/browser/repl.test.ts | 0 .../contrib/debug/test/browser/watch.test.ts | 0 .../contrib/debug/test/node/debugger.test.ts | 14 - .../test/node/streamDebugAdapter.test.ts | 0 .../browser/actions/expandAbbreviation.ts | 0 .../emmet/browser/emmet.contribution.ts | 0 .../contrib/emmet/browser/emmetActions.ts | 0 .../emmet/test/browser/emmetAction.test.ts | 18 - .../experiments/browser/experimentalPrompt.ts | 0 .../browser/experiments.contribution.ts | 0 .../experiments/common/experimentService.ts | 0 .../experimentService.test.ts | 0 .../experimentalPrompts.test.ts | 0 .../abstractRuntimeExtensionsEditor.ts | 39 +- .../browser/browserRuntimeExtensionsEditor.ts | 0 .../browser/configBasedRecommendations.ts | 0 .../dynamicWorkspaceRecommendations.ts | 0 .../browser/exeBasedRecommendations.ts | 0 .../browser/experimentalRecommendations.ts | 0 .../extensions/browser/extensionEditor.ts | 5 +- ...mentWorkspaceTrustTransitionParticipant.ts | 53 + ...ensionRecommendationNotificationService.ts | 0 .../browser/extensionRecommendations.ts | 0 .../extensionRecommendationsService.ts | 20 +- .../browser/extensions.contribution.ts | 67 +- .../browser/extensions.web.contribution.ts | 0 .../extensions/browser/extensionsActions.ts | 40 +- .../browser/extensionsActivationProgress.ts | 0 .../extensionsCompletionItemsProvider.ts | 66 + .../browser/extensionsDependencyChecker.ts | 0 .../extensions/browser/extensionsIcons.ts | 0 .../extensions/browser/extensionsList.ts | 0 .../browser/extensionsQuickAccess.ts | 4 +- .../extensions/browser/extensionsViewer.ts | 0 .../extensions/browser/extensionsViewlet.ts | 110 +- .../extensions/browser/extensionsViews.ts | 133 +- .../extensions/browser/extensionsWidgets.ts | 0 .../browser/extensionsWorkbenchService.ts | 0 .../browser/fileBasedRecommendations.ts | 0 .../browser/keymapRecommendations.ts | 0 .../browser/languageRecommendations.ts | 34 + .../extensions/browser/media/extension.css | 0 .../browser/media/extensionActions.css | 0 .../browser/media/extensionEditor.css | 0 .../browser/media/extensionsViewlet.css | 0 .../browser/media/extensionsWidgets.css | 0 .../browser/media/language-icon.svg | 0 .../extensions/browser/media/loading.svg | 0 .../browser/media/runtimeExtensionsEditor.css | 0 .../extensions/browser/media/theme-icon.png | Bin .../browser/workspaceRecommendations.ts | 0 .../extensions/common/extensionQuery.ts | 2 +- .../contrib/extensions/common/extensions.ts | 2 + .../common/extensionsFileTemplate.ts | 0 .../extensions/common/extensionsInput.ts | 11 +- .../extensions/common/extensionsUtils.ts | 0 .../common/runtimeExtensionsInput.ts | 11 +- .../extensionProfileService.ts | 7 +- .../extensions.contribution.ts | 18 + .../extensionsAutoProfiler.ts | 4 +- .../debugExtensionHostAction.ts | 2 +- .../extensions.contribution.ts | 27 +- .../electron-sandbox/extensionsActions.ts | 47 + .../extensionsSlowActions.ts | 0 .../reportExtensionIssueAction.ts | 0 .../runtimeExtensionsEditor.ts | 14 +- .../test/common/extensionQuery.test.ts | 0 .../extensionRecommendationsService.test.ts | 30 +- .../extensionsActions.test.ts | 0 .../electron-browser/extensionsViews.test.ts | 0 .../extensionsWorkbenchService.test.ts | 12 +- .../browser/externalTerminal.contribution.ts | 9 +- .../externalTerminal.contribution.ts | 105 +- .../externalTerminal/node/TerminalHelper.scpt | Bin .../externalTerminal/node/iTermHelper.scpt | Bin .../externalUriOpener/common/configuration.ts | 0 .../common/contributedOpeners.ts | 0 .../common/externalUriOpener.contribution.ts | 0 .../common/externalUriOpenerService.ts | 0 .../common/externalUriOpenerService.test.ts | 0 .../feedback/browser/feedback.contribution.ts | 0 .../contrib/feedback/browser/feedback.ts | 4 +- .../feedback/browser/feedbackStatusbarItem.ts | 6 +- .../feedback/browser/media/feedback.css | 0 .../contrib/feedback/browser/media/happy.svg | 0 .../contrib/feedback/browser/media/sad.svg | 0 .../files/browser/editors/binaryFileEditor.ts | 15 +- .../browser/editors/fileEditorHandler.ts | 92 + .../files/browser}/editors/fileEditorInput.ts | 156 +- .../files/browser/editors/textFileEditor.ts | 74 +- .../browser/editors/textFileEditorTracker.ts | 17 +- .../editors/textFileSaveErrorHandler.ts | 2 +- .../contrib/files/browser/explorerService.ts | 34 +- .../contrib/files/browser/explorerViewlet.ts | 4 +- .../files/browser/fileActions.contribution.ts | 31 +- .../contrib/files/browser/fileActions.ts | 341 +- .../contrib/files/browser/fileCommands.ts | 15 +- .../contrib/files/browser/fileImportExport.ts | 825 + .../files/browser/files.contribution.ts | 56 +- .../workbench/contrib/files/browser/files.ts | 63 +- .../files/browser/files.web.contribution.ts | 10 +- .../files/browser/media/explorerviewlet.css | 0 .../contrib/files/browser/views/emptyView.ts | 0 .../views/explorerDecorationsProvider.ts | 0 .../files/browser/views/explorerView.ts | 10 +- .../files/browser/views/explorerViewer.ts | 497 +- .../files/browser/views/media/openeditors.css | 0 .../files/browser/views/openEditorsView.ts | 25 +- .../files/common/dirtyFilesIndicator.ts | 0 .../contrib/files/common/explorerModel.ts | 7 +- .../workbench/contrib/files/common/files.ts | 17 +- .../contrib/files/common/workspaceWatcher.ts | 0 .../fileActions.contribution.ts | 0 .../files/electron-sandbox/fileCommands.ts | 0 .../electron-sandbox/files.contribution.ts | 6 +- .../files/electron-sandbox/textFileEditor.ts | 6 +- .../files/test/browser/editorAutoSave.test.ts | 0 .../files/test/browser/explorerModel.test.ts | 10 +- .../files/test/browser/explorerView.test.ts | 2 +- .../files/test/browser/fileActions.test.ts | 0 .../test/browser/fileEditorInput.test.ts | 112 +- .../test/browser/fileOnDiskProvider.test.ts | 0 .../browser/textFileEditorTracker.test.ts | 11 +- .../format/browser/format.contribution.ts | 0 .../format/browser/formatActionsMultiple.ts | 0 .../format/browser/formatActionsNone.ts | 0 .../contrib/format/browser/formatModified.ts | 0 .../issue/browser/issue.web.contribution.ts | 49 +- .../contrib/issue/browser/issueService.ts | 0 .../contrib/issue/common/commands.ts | 2 + .../electron-sandbox/issue.contribution.ts | 110 + .../issue/electron-sandbox/issueActions.ts | 51 + .../browser/keybindings.contribution.ts | 0 .../browser/localizations.contribution.ts | 0 .../browser/localizationsActions.ts | 2 +- .../browser/minimalTranslations.ts | 0 .../contrib/logs/common/logConstants.ts | 0 .../contrib/logs/common/logs.contribution.ts | 0 .../contrib/logs/common/logsActions.ts | 0 .../contrib/logs/common/logsDataCleaner.ts | 0 .../electron-sandbox/logs.contribution.ts | 0 .../logs/electron-sandbox/logsActions.ts | 0 .../common/markdownDocumentRenderer.ts | 11 +- .../contrib/markers/browser/constants.ts | 0 .../markers/browser/markers.contribution.ts | 3 +- .../contrib/markers/browser/markers.ts | 0 .../markers/browser/markersFileDecorations.ts | 0 .../markers/browser/markersFilterOptions.ts | 0 .../contrib/markers/browser/markersModel.ts | 0 .../markers/browser/markersTreeViewer.ts | 6 +- .../contrib/markers/browser/markersView.ts | 0 .../markers/browser/markersViewActions.ts | 0 .../contrib/markers/browser/media/markers.css | 0 .../contrib/markers/browser/messages.ts | 0 .../markers/test/browser/markersModel.test.ts | 0 .../contrib/cellOperations/cellOperations.ts | 12 + .../test/cellOperations.test.ts | 37 +- .../contrib/clipboard/notebookClipboard.ts | 0 .../clipboard/test/notebookClipboard.test.ts | 64 +- .../notebook/browser/contrib/coreActions.ts | 900 +- .../browser/contrib/find/findController.ts | 213 +- .../browser/contrib/find/findModel.ts | 340 + .../contrib/find/media/notebookFind.css | 0 .../browser/contrib/find/test/find.test.ts | 195 + .../notebook/browser/contrib/fold/folding.ts | 4 +- .../browser/contrib/fold/foldingModel.ts | 0 .../contrib/fold/test/notebookFolding.test.ts | 204 +- .../browser/contrib/format/formatting.ts | 0 .../gettingStarted/notebookGettingStarted.ts | 98 + .../browser/contrib/layout/layoutActions.ts | 6 +- .../contrib/layout/test/layoutActions.test.ts | 0 .../browser/contrib/marker/markerProvider.ts | 0 .../browser/contrib/navigation/arrow.ts | 4 +- .../contrib/outline/notebookOutline.css | 0 .../contrib/outline/notebookOutline.ts | 2 +- .../outline/test/notebookOutline.test.ts | 12 +- .../contrib/profile/notebookProfile.ts | 130 + .../browser/contrib/status/editorStatus.ts | 158 +- .../contributedStatusBarItemController.ts | 22 +- .../executionStatusBarItemController.ts | 123 +- .../statusBar/notebookVisibleCellObserver.ts | 0 .../contrib/statusBar/statusBarProviders.ts | 48 +- .../browser/contrib/troubleshoot/layout.ts | 0 .../contrib/undoRedo/notebookUndoRedo.ts | 10 +- .../undoRedo/test/notebookUndoRedo.test.ts | 16 +- .../viewportCustomMarkdown.ts | 22 +- .../notebook/browser/diff/diffComponents.ts | 41 +- .../browser/diff/diffElementOutputs.ts | 9 +- .../browser/diff/diffElementViewModel.ts | 0 .../browser/diff/diffNestedCellViewModel.ts | 0 .../notebook/browser/diff/eventDispatcher.ts | 0 .../notebook/browser/diff/notebookDiff.css | 0 .../browser/diff/notebookDiffActions.ts | 20 +- .../browser/diff/notebookDiffEditorBrowser.ts | 2 + .../browser/diff/notebookTextDiffEditor.ts | 75 +- .../browser/diff/notebookTextDiffList.ts | 0 .../notebook/browser/extensionPoint.ts | 124 +- .../notebook/browser/media/notebook.css | 206 +- .../media/notebookKernelActionViewItem.css | 24 + .../notebook/browser/notebook.contribution.ts | 347 +- .../notebook/browser/notebookBrowser.ts | 90 +- .../notebookCellStatusBarServiceImpl.ts | 3 +- .../browser/notebookDiffEditorInput.ts | 54 +- .../notebook/browser/notebookEditor.ts | 60 +- .../browser/notebookEditorDecorations.ts | 0 .../browser/notebookEditorExtensions.ts | 0 .../browser/notebookEditorKernelManager.ts | 24 +- .../notebook/browser/notebookEditorService.ts | 0 .../browser/notebookEditorServiceImpl.ts | 1 + .../notebook/browser/notebookEditorToolbar.ts | 230 + .../notebook/browser/notebookEditorWidget.ts | 815 +- .../notebookEditorWidgetContextKeys.ts | 64 +- .../contrib/notebook/browser/notebookIcons.ts | 2 + .../browser/notebookKernelActionViewItem.ts | 102 + .../browser/notebookKernelServiceImpl.ts | 4 +- .../notebookRendererMessagingServiceImpl.ts | 70 + .../notebook/browser/notebookServiceImpl.ts | 222 +- .../notebook/browser/view/notebookCellList.ts | 18 +- .../browser/view/output/outputRenderer.ts | 73 + .../browser/view/output/rendererRegistry.ts | 12 +- .../view/output/transforms/richTransform.ts | 325 +- .../view/output/transforms/textHelper.ts | 22 +- .../view/renderers/backLayerWebView.ts | 491 +- .../browser/view/renderers/cellActionView.ts | 54 + .../browser/view/renderers/cellContextKeys.ts | 45 +- .../browser/view/renderers/cellDnd.ts | 63 +- .../view/renderers/cellEditorOptions.ts | 134 +- .../browser/view/renderers/cellMenus.ts | 4 + .../browser/view/renderers/cellOutput.ts | 165 +- .../browser/view/renderers/cellRenderer.ts | 234 +- .../browser/view/renderers/cellWidgets.ts | 2 +- .../browser/view/renderers/codeCell.ts | 30 +- .../browser/view/renderers/markdownCell.ts | 50 +- .../browser/view/renderers/webviewPreloads.ts | 752 +- .../view/renderers/webviewThemeMapping.ts | 19 +- .../browser/viewModel/baseCellViewModel.ts | 42 +- .../notebook/browser/viewModel/cellEdit.ts | 0 .../browser/viewModel/cellOutputViewModel.ts | 26 +- .../viewModel/cellSelectionCollection.ts | 0 .../browser/viewModel/codeCellViewModel.ts | 110 +- .../browser/viewModel/eventDispatcher.ts | 0 .../viewModel/markdownCellViewModel.ts | 95 +- .../browser/viewModel/notebookViewModel.ts | 98 +- .../notebook/browser/viewModel/viewContext.ts | 15 + .../contrib/notebook/common/model/cellEdit.ts | 0 .../model/notebookCellOutputTextModel.ts | 13 +- .../common/model/notebookCellTextModel.ts | 72 +- .../common/model/notebookTextModel.ts | 74 +- .../common/notebookCellStatusBarService.ts | 0 .../contrib/notebook/common/notebookCommon.ts | 232 +- .../notebook/common/notebookEditorInput.ts | 74 +- .../notebook/common/notebookEditorModel.ts | 115 +- .../notebookEditorModelResolverService.ts | 0 .../notebookEditorModelResolverServiceImpl.ts | 25 +- .../notebook/common/notebookKernelService.ts | 1 + .../notebook/common/notebookOptions.ts | 488 + .../notebook/common/notebookOutputRenderer.ts | 32 +- .../notebook/common/notebookPerformance.ts | 0 .../notebook/common/notebookProvider.ts | 53 +- .../contrib/notebook/common/notebookRange.ts | 8 + .../notebookRendererMessagingService.ts | 44 + .../notebook/common/notebookService.ts | 21 +- .../common/services/notebookSimpleWorker.ts | 12 +- .../common/services/notebookWorkerService.ts | 0 .../services/notebookWorkerServiceImpl.ts | 6 +- .../notebook/test/notebookBrowser.test.ts | 12 +- .../notebook/test/notebookCellList.test.ts | 63 +- .../notebook/test/notebookCommon.test.ts | 12 +- .../notebook/test/notebookDiff.test.ts | 354 + .../notebook/test/notebookEditor.test.ts | 4 +- .../test/notebookEditorKernelManager.test.ts | 2 +- .../notebook/test/notebookEditorModel.test.ts | 213 + .../test/notebookKernelService.test.ts | 6 +- .../notebookRendererMessagingService.test.ts | 59 + .../notebook/test/notebookSelection.test.ts | 32 +- .../notebook/test/notebookServiceImpl.test.ts | 8 +- .../notebook/test/notebookTextModel.test.ts | 53 +- .../notebook/test/notebookViewModel.test.ts | 22 +- .../notebook/test/testNotebookEditor.ts | 33 +- .../outline/browser/outline.contribution.ts | 0 .../contrib/outline/browser/outlinePane.css | 0 .../contrib/outline/browser/outlinePane.ts | 12 +- .../outline/browser/outlineViewState.ts | 0 .../contrib/output/browser/logViewer.ts | 14 +- .../contrib/output/browser/media/output.css | 0 .../output/browser/output.contribution.ts | 0 .../contrib/output/browser/outputServices.ts | 0 .../contrib/output/browser/outputView.ts | 19 +- .../workbench/contrib/output/common/output.ts | 0 .../output/common/outputChannelModel.ts | 1 - .../common/outputChannelModelService.ts | 0 .../output/common/outputLinkComputer.ts | 0 .../output/common/outputLinkProvider.ts | 0 .../outputChannelModelService.ts | 0 .../test/browser/outputLinkProvider.test.ts | 0 .../browser/performance.contribution.ts | 0 .../performance/browser/perfviewEditor.ts | 16 +- .../performance.contribution.ts | 0 .../electron-sandbox/startupProfiler.ts | 0 .../electron-sandbox/startupTimings.ts | 12 +- .../preferences/browser/keybindingWidgets.ts | 0 .../preferences/browser/keybindingsEditor.ts | 11 +- .../browser/keybindingsEditorContribution.ts | 1 + .../browser/keyboardLayoutPicker.ts | 7 +- .../preferences/browser/media/keybindings.css | 0 .../browser/media/keybindingsEditor.css | 0 .../preferences/browser/media/preferences.css | 0 .../browser/media/settingsEditor2.css | 0 .../browser/media/settingsWidgets.css | 0 .../browser/preferences.contribution.ts | 20 +- .../preferences/browser/preferencesActions.ts | 0 .../preferences/browser/preferencesEditor.ts | 35 +- .../preferences/browser/preferencesIcons.ts | 0 .../browser/preferencesRenderers.ts | 3 +- .../preferences/browser/preferencesSearch.ts | 0 .../preferences/browser/preferencesWidgets.ts | 1 + .../preferences/browser/settingsEditor2.ts | 60 +- .../preferences/browser/settingsLayout.ts | 0 .../preferences/browser/settingsTree.ts | 9 +- .../preferences/browser/settingsTreeModels.ts | 18 +- .../preferences/browser/settingsWidgets.ts | 0 .../contrib/preferences/browser/tocTree.ts | 0 .../contrib/preferences/common/preferences.ts | 0 .../common/preferencesContribution.ts | 94 +- .../common/smartSnippetInserter.ts | 0 .../keybindingsEditorContribution.test.ts | 0 .../test/browser/settingsTreeModels.test.ts | 0 .../test/common/smartSnippetInserter.test.ts | 0 .../browser/commandsQuickAccess.ts | 6 +- .../browser/quickAccess.contribution.ts | 0 .../quickaccess/browser/viewQuickAccess.ts | 8 +- .../browser/relauncher.contribution.ts | 0 .../remote/browser/explorerViewItems.ts | 0 .../remote/browser/media/remoteViewlet.css | 0 .../remote/browser/media/tunnelView.css | 0 .../contrib/remote/browser/remote.ts | 0 .../contrib/remote/browser/remoteExplorer.ts | 41 +- .../contrib/remote/browser/remoteIcons.ts | 0 .../contrib/remote/browser/remoteIndicator.ts | 167 +- .../contrib/remote/browser/tunnelView.ts | 204 +- .../contrib/remote/browser/urlFinder.ts | 0 .../remote/common/remote.contribution.ts | 26 + .../contrib/remote/common/showCandidate.ts | 0 .../contrib/remote/common/tunnelFactory.ts | 13 +- .../electron-sandbox/remote.contribution.ts | 0 .../contrib/sash/browser/sash.contribution.ts | 4 +- .../vs/workbench/contrib/sash/browser/sash.ts | 0 .../workbench/contrib/scm/browser/activity.ts | 3 +- .../contrib/scm/browser/dirtydiffDecorator.ts | 1 + .../scm/browser/media/dirtydiffDecorator.css | 0 .../contrib/scm/browser/media/scm.css | 14 +- .../vs/workbench/contrib/scm/browser/menus.ts | 0 .../contrib/scm/browser/scm.contribution.ts | 0 .../scm/browser/scmRepositoriesViewPane.ts | 0 .../scm/browser/scmRepositoryRenderer.ts | 0 .../contrib/scm/browser/scmViewPane.ts | 9 +- .../scm/browser/scmViewPaneContainer.ts | 0 .../contrib/scm/browser/scmViewService.ts | 0 .../vs/workbench/contrib/scm/browser/util.ts | 0 .../vs/workbench/contrib/scm/common/scm.ts | 0 .../contrib/scm/common/scmService.ts | 0 .../search/browser/anythingQuickAccess.ts | 16 +- .../browser/media/anythingQuickAccess.css | 0 .../search/browser/media/searchEditor.css | 0 .../search/browser/media/searchview.css | 0 .../search/browser/patternInputWidget.ts | 0 .../search/browser/replaceContributions.ts | 0 .../contrib/search/browser/replaceService.ts | 4 +- .../search/browser/search.contribution.ts | 7 +- .../contrib/search/browser/searchActions.ts | 0 .../contrib/search/browser/searchIcons.ts | 0 .../search/browser/searchResultsView.ts | 7 +- .../contrib/search/browser/searchView.ts | 35 +- .../contrib/search/browser/searchWidget.ts | 0 .../search/browser/symbolsQuickAccess.ts | 2 +- .../contrib/search/common/cacheState.ts | 0 .../contrib/search/common/constants.ts | 0 .../contrib/search/common/queryBuilder.ts | 46 +- .../contrib/search/common/replace.ts | 0 .../workbench/contrib/search/common/search.ts | 0 .../search/common/searchHistoryService.ts | 0 .../contrib/search/common/searchModel.ts | 3 + .../search/test/browser/mockSearchTree.ts | 0 .../search/test/browser/queryBuilder.test.ts | 65 +- .../search/test/browser/searchActions.test.ts | 0 .../search/test/browser/searchViewlet.test.ts | 0 .../search/test/common/cacheState.test.ts | 0 .../search/test/common/extractRange.test.ts | 0 .../search/test/common/searchModel.test.ts | 0 .../search/test/common/searchResult.test.ts | 0 .../electron-browser/queryBuilder.test.ts | 0 .../contrib/searchEditor/browser/constants.ts | 0 .../browser/media/searchEditor.css | 0 .../browser/searchEditor.contribution.ts | 77 +- .../searchEditor/browser/searchEditor.ts | 162 +- .../browser/searchEditorActions.ts | 13 +- .../searchEditor/browser/searchEditorInput.ts | 209 +- .../searchEditor/browser/searchEditorModel.ts | 186 + .../browser/searchEditorSerialization.ts | 3 + .../snippets/browser/configureSnippets.ts | 0 .../contrib/snippets/browser/insertSnippet.ts | 0 .../browser/snippetCompletionProvider.ts | 0 .../snippets/browser/snippets.contribution.ts | 0 .../contrib/snippets/browser/snippetsFile.ts | 0 .../snippets/browser/snippetsService.ts | 0 .../contrib/snippets/browser/tabCompletion.ts | 0 .../snippets/test/browser/snippetFile.test.ts | 0 .../test/browser/snippetsRegistry.test.ts | 0 .../test/browser/snippetsRewrite.test.ts | 0 .../test/browser/snippetsService.test.ts | 0 .../surveys/browser/ces.contribution.ts | 15 +- .../browser/languageSurveys.contribution.ts | 32 +- .../surveys/browser/nps.contribution.ts | 0 .../tags/browser/workspaceTagsService.ts | 0 .../contrib/tags/common/javaWorkspaceTags.ts | 0 .../contrib/tags/common/workspaceTags.ts | 0 .../electron-sandbox/tags.contribution.ts | 0 .../tags/electron-sandbox/workspaceTags.ts | 0 .../electron-sandbox/workspaceTagsService.ts | 5 - .../electron-browser/workspaceTags.test.ts | 0 .../tasks/browser/abstractTaskService.ts | 57 +- .../tasks/browser/runAutomaticTasks.ts | 22 +- .../tasks/browser/task.contribution.ts | 18 +- .../contrib/tasks/browser/taskQuickPick.ts | 73 +- .../contrib/tasks/browser/taskService.ts | 0 .../tasks/browser/taskTerminalStatus.ts | 99 + .../contrib/tasks/browser/tasksQuickAccess.ts | 28 +- .../tasks/browser/terminalTaskSystem.ts | 58 +- .../contrib/tasks/common/jsonSchemaCommon.ts | 0 .../contrib/tasks/common/jsonSchema_v1.ts | 0 .../contrib/tasks/common/jsonSchema_v2.ts | 4 + .../contrib/tasks/common/problemCollectors.ts | 4 +- .../contrib/tasks/common/problemMatcher.ts | 0 .../contrib/tasks/common/taskConfiguration.ts | 13 +- .../tasks/common/taskDefinitionRegistry.ts | 0 .../contrib/tasks/common/taskService.ts | 2 + .../contrib/tasks/common/taskSystem.ts | 1 - .../contrib/tasks/common/taskTemplates.ts | 0 .../workbench/contrib/tasks/common/tasks.ts | 5 + .../tasks/electron-sandbox/taskService.ts | 0 .../tasks/test/common/configuration.test.ts | 7 +- .../tasks/test/common/problemMatcher.test.ts | 0 .../browser/telemetry.contribution.ts | 0 .../workbench/contrib/terminal/.eslintrc.json | 19 + .../browser/addons/commandTrackerAddon.ts | 20 +- .../browser/addons/navigationModeAddon.ts | 0 .../browser/environmentVariableInfo.ts | 4 +- .../browser/links/terminalBaseLinkProvider.ts | 0 .../terminalExternalLinkProviderAdapter.ts | 0 .../terminal/browser/links/terminalLink.ts | 8 +- .../browser/links/terminalLinkHelpers.ts | 15 +- .../browser/links/terminalLinkManager.ts | 22 +- .../links/terminalProtocolLinkProvider.ts | 2 +- .../terminalValidatedLocalLinkProvider.ts | 0 .../browser/links/terminalWordLinkProvider.ts | 106 +- .../terminal/browser/media/scrollbar.css | 0 .../terminal/browser/media/terminal.css | 101 +- .../terminal/browser/media/widgets.css | 0 .../contrib/terminal/browser/media/xterm.css | 0 .../contrib/terminal/browser/remotePty.ts | 40 +- .../terminal/browser/remoteTerminalService.ts | 90 +- .../terminal/browser/terminal.contribution.ts | 28 +- .../contrib/terminal/browser/terminal.ts | 158 +- .../browser/terminal.web.contribution.ts | 12 +- .../terminal/browser/terminalActions.ts | 520 +- .../terminal/browser/terminalCommands.ts | 0 .../terminal/browser/terminalConfigHelper.ts | 65 +- .../browser/terminalDecorationsProvider.ts | 0 .../terminal/browser/terminalFindWidget.ts | 16 +- .../contrib/terminal/browser/terminalGroup.ts | 196 +- .../contrib/terminal/browser/terminalIcon.ts | 57 + .../contrib/terminal/browser/terminalIcons.ts | 0 .../terminal/browser/terminalInstance.ts | 685 +- .../browser/terminalInstanceService.ts | 126 + .../contrib/terminal/browser/terminalMenus.ts | 350 + .../browser/terminalProcessExtHostProxy.ts | 72 +- .../browser/terminalProcessManager.ts | 172 +- .../browser/terminalProfileResolverService.ts | 482 + .../terminal/browser/terminalQuickAccess.ts | 46 +- .../terminal/browser/terminalService.ts | 881 +- .../terminal/browser/terminalStatusList.ts | 0 .../terminal/browser/terminalTabbedView.ts | 277 +- .../terminal/browser/terminalTabsList.ts | 639 + .../browser/terminalTypeAheadAddon.ts | 684 +- .../contrib/terminal/browser/terminalView.ts | 304 +- .../widgets/environmentVariableInfoWidget.ts | 2 +- .../browser/widgets/terminalHoverWidget.ts | 0 .../terminal/browser/widgets/widgetManager.ts | 0 .../terminal/browser/widgets/widgets.ts | 0 .../terminal/browser/xterm-private.d.ts | 0 .../environmentVariable.contribution.ts | 0 .../terminal/common/environmentVariable.ts | 0 .../common/environmentVariableCollection.ts | 0 .../common/environmentVariableService.ts | 0 .../common/environmentVariableShared.ts | 0 .../terminal/common/remoteTerminalChannel.ts | 96 +- .../contrib/terminal/common/terminal.ts | 403 +- .../terminal/common/terminalColorRegistry.ts | 7 +- .../terminal/common/terminalConfiguration.ts | 450 +- .../terminal/common/terminalEnvironment.ts | 32 +- .../terminalExtensionPoints.contribution.ts | 0 .../common/terminalExtensionPoints.ts | 23 +- .../terminal/common/terminalStrings.ts | 0 .../terminal/electron-sandbox/localPty.ts | 22 +- .../electron-sandbox/localTerminalService.ts | 64 +- .../electron-sandbox/terminal.contribution.ts | 8 +- .../terminalNativeContribution.ts | 2 +- .../terminalProfileResolverService.ts | 16 +- .../electron-sandbox/terminalRemote.ts | 8 +- .../browser/links/terminalLinkHelpers.test.ts | 6 +- .../terminalProtocolLinkProvider.test.ts | 0 ...terminalValidatedLocalLinkProvider.test.ts | 0 .../links/terminalWordLinkProvider.test.ts | 32 +- .../browser/terminalCommandTracker.test.ts | 0 .../test/browser/terminalConfigHelper.test.ts | 52 +- .../browser/terminalProcessManager.test.ts | 0 .../test/browser/terminalStatusList.test.ts | 0 .../test/browser/terminalTypeahead.test.ts | 32 +- .../environmentVariableCollection.test.ts | 0 .../common/environmentVariableService.test.ts | 0 .../common/environmentVariableShared.test.ts | 0 .../test/common/terminalColorRegistry.test.ts | 16 +- .../test/common/terminalDataBuffering.test.ts | 2 +- .../test/common/terminalEnvironment.test.ts | 0 .../test/node/terminalProfiles.test.ts | 90 +- .../browser/explorerProjections/display.ts | 2 +- .../hierarchalByLocation.ts | 80 +- .../explorerProjections/hierarchalByName.ts | 3 +- .../explorerProjections/hierarchalNodes.ts | 0 .../browser/explorerProjections/index.ts | 33 +- .../browser/explorerProjections/nodeHelper.ts | 0 .../contrib/testing/browser/icons.ts | 23 +- .../contrib/testing/browser/media/testing.css | 43 +- .../testing/browser/testExplorerActions.ts | 459 +- .../testing/browser/testing.contribution.ts | 61 +- .../testing/browser/testingDecorations.ts | 8 +- .../testing/browser/testingExplorerFilter.ts | 0 .../testing/browser/testingExplorerView.ts | 268 +- .../testing/browser/testingOutputPeek.ts | 1400 ++ .../browser/testingOutputTerminalService.ts | 14 +- .../browser/testingProgressUiService.ts | 0 .../browser/testingViewPaneContainer.ts | 0 .../contrib/testing/browser/theme.ts | 0 .../contrib/testing/common/configuration.ts | 0 .../contrib/testing/common/constants.ts | 0 .../testing/common/getComputedState.ts | 126 + .../contrib/testing/common/observableValue.ts | 0 .../testing/common/ownedTestCollection.ts | 0 .../contrib/testing/common/storedValue.ts | 0 .../contrib/testing/common/testCollection.ts | 6 +- .../contrib/testing/common/testResult.ts | 27 +- .../testing/common/testResultService.ts | 5 +- .../testing/common/testResultStorage.ts | 0 .../contrib/testing/common/testService.ts | 0 .../contrib/testing/common/testServiceImpl.ts | 1 - .../contrib/testing/common/testStubs.ts | 0 .../contrib/testing/common/testingAutoRun.ts | 52 +- .../testing/common/testingContentProvider.ts | 0 .../testing/common/testingContextKeys.ts | 13 + .../testing/common/testingPeekOpener.ts | 32 + .../contrib/testing/common/testingStates.ts | 0 .../contrib/testing/common/testingUri.ts | 0 .../common/workspaceTestCollectionService.ts | 148 +- .../hierarchalByLocation.test.ts | 0 .../hierarchalByName.test.ts | 0 .../testing/test/browser/testObjectTree.ts | 9 +- .../test/common/ownedTestCollection.ts | 0 .../test/common/testResultService.test.ts | 1 + .../test/common/testResultStorage.test.ts | 2 +- .../testing/test/common/testingUri.test.ts | 0 .../themes/browser/themes.contribution.ts | 0 .../browser/themes.test.contribution.ts | 0 .../timeline/browser/media/timelinePane.css | 0 .../timeline/browser/timeline.contribution.ts | 0 .../contrib/timeline/browser/timelinePane.ts | 7 +- .../contrib/timeline/common/timeline.ts | 0 .../timeline/common/timelineService.ts | 0 .../browser/media/releasenoteseditor.css | 0 .../update/browser/releaseNotesEditor.ts | 2 +- .../update/browser/update.contribution.ts | 0 .../contrib/update/browser/update.ts | 45 +- .../workbench/contrib/update/common/update.ts | 0 .../url/browser/externalUriResolver.ts | 0 .../contrib/url/browser/trustedDomains.ts | 16 +- .../trustedDomainsFileSystemProvider.ts | 0 .../url/browser/trustedDomainsValidator.ts | 6 + .../contrib/url/browser/url.contribution.ts | 0 .../workbench/contrib/url/common/urlGlob.ts | 0 .../url/test/browser/trustedDomains.test.ts | 0 .../browser/media/userDataSyncViews.css | 0 .../browser/userDataSync.contribution.ts | 0 .../userDataSync/browser/userDataSync.ts | 4 +- .../browser/userDataSyncMergesView.ts | 6 +- .../browser/userDataSyncTrigger.ts | 3 +- .../userDataSync/browser/userDataSyncViews.ts | 0 .../userDataSync.contribution.ts | 0 .../contrib/watermark/browser/watermark.css | 0 .../contrib/watermark/browser/watermark.ts | 4 +- .../webview/browser/baseWebviewElement.ts | 123 +- .../browser/dynamicWebviewEditorOverlay.ts | 66 +- .../contrib/webview/browser/pre/fake.html | 0 .../contrib/webview/browser/pre/host.js | 9 +- .../contrib/webview/browser/pre/index.html | 0 .../contrib/webview/browser/pre/main.js | 182 +- .../webview/browser/pre/service-worker.js | 131 +- .../webview/browser/resourceLoading.ts | 72 +- .../contrib/webview/browser/themeing.ts | 63 +- .../webview/browser/webview.contribution.ts | 41 + .../contrib/webview/browser/webview.ts | 60 +- .../browser/webview.web.contribution.ts | 0 .../contrib/webview/browser/webviewElement.ts | 31 +- .../webview/browser/webviewFindWidget.ts | 10 +- .../contrib/webview/browser/webviewService.ts | 19 +- .../browser/webviewWindowDragMonitor.ts | 0 .../electron-browser/pre/electron-index.js | 0 .../webview/electron-browser/pre/index.html | 0 .../electron-browser/webview.contribution.ts | 0 .../electron-browser/webviewCommands.ts | 0 .../electron-browser/webviewElement.ts | 15 +- .../webviewIgnoreMenuShortcutsManager.ts | 0 .../electron-browser/webviewService.ts | 6 +- .../electron-sandbox/iframeWebviewElement.ts | 26 +- .../windowIgnoreMenuShortcutsManager.ts | 0 .../webviewPanel/browser/webviewCommands.ts | 10 +- .../webviewPanel/browser/webviewEditor.ts | 6 +- .../browser/webviewEditorInput.ts | 11 +- .../browser/webviewEditorInputSerializer.ts | 0 .../browser/webviewIconManager.ts | 0 .../browser/webviewPanel.contribution.ts | 34 +- .../browser/webviewWorkbenchService.ts | 0 .../browser/webviewView.contribution.ts | 0 .../webviewView/browser/webviewViewPane.ts | 135 +- .../webviewView/browser/webviewViewService.ts | 0 .../common/viewsWelcome.contribution.ts | 0 .../common/viewsWelcomeContribution.ts | 0 .../common/viewsWelcomeExtensionPoint.ts | 0 .../browser/gettingStarted.contribution.ts | 73 +- .../gettingStarted/browser/gettingStarted.css | 67 +- .../gettingStarted/browser/gettingStarted.ts | 429 +- .../browser/gettingStartedExtensionPoint.ts | 64 +- .../browser/gettingStartedIcons.ts | 0 .../browser/gettingStartedInput.ts | 5 +- .../browser/gettingStartedService.ts | 428 +- .../common/gettingStartedContent.ts | 211 +- .../common/media/colorTheme.png | Bin .../gettingStarted/common/media/dark.png | Bin 0 -> 14165 bytes .../common/media/dark/commandPalette.png | Bin .../common/media/dark/debug.png | Bin .../common/media/dark/extensions.png | Bin .../common/media/dark/languageExtensions.png | Bin .../common/media/dark/openFolder.png | Bin .../common/media/dark/playground.png | Bin .../gettingStarted/common/media/dark/scm.png | Bin .../common/media/dark/settings.png | Bin .../common/media/dark/settingsSync.png | Bin .../common/media/dark/shortcuts.png | Bin .../common/media/dark/splitview.png | Bin .../common/media/dark/tasks.png | Bin .../common/media/dark/terminal.png | Bin .../common/media/dark/workspaceTrust.svg | 40 + .../common/media/example_markdown_media.ts | 29 + .../gettingStarted/common/media/github.png | Bin .../common/media/hc/commandPalette.png | Bin .../common/media/hc/extensions.png | Bin .../common/media/hc/languageExtensions.png | Bin .../common/media/hc/openFolder.png | Bin .../common/media/hc/settings.png | Bin .../common/media/hc/settingsSync.png | Bin .../common/media/hc/terminal.png | Bin .../gettingStarted/common/media/light.png | Bin 0 -> 14341 bytes .../common/media/light/commandPalette.png | Bin .../common/media/light/debug.png | Bin .../common/media/light/extensions.png | Bin .../common/media/light/languageExtensions.png | Bin .../common/media/light/openFolder.png | Bin .../common/media/light/playground.png | Bin .../gettingStarted/common/media/light/scm.png | Bin .../common/media/light/settings.png | Bin .../common/media/light/settingsSync.png | Bin .../common/media/light/shortcuts.png | Bin .../common/media/light/splitview.png | Bin .../common/media/light/tasks.png | Bin .../common/media/light/terminal.png | Bin .../common/media/light/workspaceTrust.svg | 40 + .../gettingStarted/common/media/monokai.png | Bin 0 -> 14287 bytes .../gettingStarted/common/media/more.png | Bin 0 -> 17121 bytes .../common/media/notebookProfile.ts | 29 + .../common/media/notebookThemes/colab.png | Bin 0 -> 2473 bytes .../common/media/notebookThemes/default.png | Bin 0 -> 2476 bytes .../common/media/notebookThemes/jupyter.png | Bin 0 -> 2489 bytes .../common/media/quiet-light.png | Bin 0 -> 14270 bytes .../common/media/tutorialVideo.png | Bin .../browser/media/commandpalette-dark.svg | 0 .../overlay/browser/media/commandpalette.svg | 0 .../overlay/browser/welcomeOverlay.css | 0 .../welcome/overlay/browser/welcomeOverlay.ts | 0 .../page/browser/vs_code_welcome_page.ts | 16 +- .../page/browser/welcomePage.contribution.ts | 55 + .../welcome/page/browser/welcomePage.css | 2 +- .../welcome/page/browser/welcomePage.ts | 107 +- .../welcome/page/browser/welcomePageColors.ts | 0 .../browser/telemetryOptOut.contribution.ts | 0 .../browser/telemetryOptOut.ts | 0 .../telemetryOptOut.contribution.ts | 0 .../electron-sandbox/telemetryOptOut.ts | 0 .../browser/editor/editorWalkThrough.ts | 7 +- .../editor/vs_code_editor_walkthrough.ts | 0 .../browser/walkThrough.contribution.ts | 0 .../walkThrough/browser/walkThroughActions.ts | 0 .../walkThrough/browser/walkThroughInput.ts | 8 +- .../walkThrough/browser/walkThroughPart.css | 0 .../walkThrough/browser/walkThroughPart.ts | 9 +- .../common/walkThroughContentProvider.ts | 0 .../walkThrough/common/walkThroughUtils.ts | 0 .../workspace/browser/media/trusted-badge.png | Bin .../browser/media/untrusted-status.png | Bin .../browser/workspace.contribution.ts | 766 + .../browser/workspaceTrustEditor.css | 137 +- .../workspace/browser/workspaceTrustEditor.ts | 978 + .../browser/workspaces.contribution.ts | 0 .../electron-browser/desktop.main.ts | 0 .../actions/developerActions.ts | 0 .../actions/installActions.ts | 74 + .../actions/media/actions.css | 0 .../electron-sandbox/actions/windowActions.ts | 297 + .../electron-sandbox/desktop.contribution.ts | 183 +- .../electron-sandbox/desktop.main.ts | 0 .../parts/dialogs/dialog.contribution.ts | 0 .../parts/dialogs/dialogHandler.ts | 0 .../parts/titlebar/menubarControl.ts | 8 +- .../parts/titlebar/titlebarPart.ts | 0 .../sandbox.simpleservices.ts | 53 +- .../electron-sandbox/shared.desktop.main.ts | 4 +- src/vs/workbench/electron-sandbox/splash.ts | 112 + .../vs/workbench/electron-sandbox/window.ts | 65 +- .../electron-sandbox/accessibilityService.ts | 0 .../activity/browser/activityService.ts | 0 .../services/activity/common/activity.ts | 8 +- .../activityBar/browser/activityBarService.ts | 0 .../browser/authenticationService.ts | 24 +- .../services/banner/browser/bannerService.ts | 31 + .../clipboard/browser/clipboardService.ts | 11 +- .../electron-sandbox/clipboardService.ts | 0 .../commands/common/commandService.ts | 0 .../test/common/commandService.test.ts | 0 .../configuration/browser/configuration.ts | 0 .../browser/configurationCache.ts | 0 .../browser/configurationService.ts | 0 .../configuration/common/configuration.ts | 11 +- .../common/configurationEditingService.ts | 0 .../common/configurationModels.ts | 0 .../configuration/common/jsonEditing.ts | 0 .../common/jsonEditingService.ts | 0 .../electron-sandbox/configurationCache.ts | 0 .../configurationEditingService.test.ts | 0 .../test/browser/configurationService.test.ts | 0 .../test/common/configurationModels.test.ts | 0 .../configuration/test/common/testServices.ts | 0 .../browser/configurationResolverService.ts | 0 .../common/configurationResolver.ts | 7 + .../common/configurationResolverSchema.ts | 0 .../common/configurationResolverUtils.ts | 0 .../common/variableResolver.ts | 8 +- .../configurationResolverService.ts | 0 .../configurationResolverService.test.ts | 0 .../electron-sandbox/contextmenuService.ts | 7 + .../credentials/browser/credentialsService.ts | 0 .../credentials/common/credentials.ts | 0 .../electron-sandbox/credentialsService.ts | 0 .../decorations/browser/decorations.ts | 0 .../decorations/browser/decorationsService.ts | 22 +- .../test/browser/decorationsService.test.ts | 0 .../browser/abstractFileDialogService.ts | 0 .../dialogs/browser/fileDialogService.ts | 0 .../dialogs/browser/simpleFileDialog.ts | 0 .../services/dialogs/common/dialogService.ts | 0 .../electron-sandbox/fileDialogService.ts | 0 .../editor/browser/codeEditorService.ts | 6 +- .../editor/browser/editorDropService.ts | 0 .../editor/browser/editorOverrideService.ts | 206 +- .../services/editor/browser/editorService.ts | 441 +- .../editor/common/editorGroupsService.ts | 24 +- .../editor/common/editorOverrideService.ts | 117 +- .../services/editor/common/editorService.ts | 66 +- .../test/browser/editorGroupsService.test.ts | 81 +- .../editor/test/browser/editorService.test.ts | 271 +- .../test/browser/editorsObserver.test.ts | 81 +- .../encryption/browser/encryptionService.ts | 0 .../encryption/common/encryptionService.ts | 0 .../electron-sandbox/encryptionService.ts | 0 .../environment/browser/environmentService.ts | 51 +- .../environment/common/environmentService.ts | 2 - .../electron-sandbox/environmentService.ts | 15 - .../shellEnvironmentService.ts | 0 .../experiment/common/experimentService.ts | 0 .../builtinExtensionsScannerService.ts | 0 .../browser/extensionBisect.ts | 1 - .../browser/extensionEnablementService.ts | 43 +- .../browser/extensionUrlTrustService.ts | 0 .../common/extensionManagement.ts | 6 + .../extensionManagementServerService.ts | 0 .../common/extensionManagementService.ts | 25 +- .../remoteExtensionManagementService.ts | 0 .../common/webExtensionManagementService.ts | 0 .../common/webExtensionsScannerService.ts | 20 +- .../extensionManagementServerService.ts | 0 .../extensionManagementService.ts | 6 +- .../electron-sandbox/extensionTipsService.ts | 0 .../extensionUrlTrustService.ts | 0 .../remoteExtensionManagementService.ts | 6 +- .../extensionEnablementService.test.ts | 5 +- .../extensionIgnoredRecommendationsService.ts | 0 .../common/extensionRecommendations.ts | 1 + .../common/workspaceExtensionsConfig.ts | 0 .../browser/extensionResourceLoaderService.ts | 0 .../common/extensionResourceLoader.ts | 0 .../extensionResourceLoaderService.ts | 0 .../extensions/browser/extensionService.ts | 6 +- .../extensions/browser/extensionUrlHandler.ts | 12 +- .../browser/webWorkerExtensionHost.ts | 2 - .../browser/webWorkerFileSystemProvider.ts | 0 .../common/abstractExtensionService.ts | 157 +- .../common/extensionDescriptionRegistry.ts | 0 .../extensions/common/extensionDevOptions.ts | 0 .../extensions/common/extensionHostMain.ts | 16 +- .../extensions/common/extensionHostManager.ts | 14 + .../common/extensionHostProtocol.ts | 0 .../extensionManifestPropertiesService.ts | 23 +- .../extensions/common/extensionPoints.ts | 0 .../services/extensions/common/extensions.ts | 0 .../extensions/common/extensionsRegistry.ts | 34 +- .../extensions/common/extensionsUtil.ts | 0 .../services/extensions/common/lazyPromise.ts | 0 .../common/polyfillNestedWorker.protocol.ts | 0 .../extensions/common/proxyIdentifier.ts | 0 .../extensions/common/remoteConsoleUtil.ts | 0 .../extensions/common/remoteExtensionHost.ts | 4 +- .../services/extensions/common/rpcProtocol.ts | 0 .../cachedExtensionScanner.ts | 23 +- .../electron-browser/extensionHostProfiler.ts | 0 .../electron-browser/extensionService.ts | 79 +- .../localProcessExtensionHost.ts | 4 +- .../extensions/node/extensionHostProcess.ts | 0 .../node/extensionHostProcessSetup.ts | 21 +- .../extensions/node/extensionPoints.ts | 41 +- .../services/extensions/node/proxyResolver.ts | 0 .../test/browser/extensionService.test.ts | 0 ...extensionManifestPropertiesService.test.ts | 27 +- .../test/common/rpcProtocol.test.ts | 0 .../extensions/worker/extensionHostWorker.ts | 0 .../worker/extensionHostWorkerMain.ts | 0 .../httpWebWorkerExtensionHostIframe.html | 0 .../httpsWebWorkerExtensionHostIframe.html | 0 .../extensions/worker/polyfillNestedWorker.ts | 0 .../files/browser/elevatedFileService.ts | 0 .../files/common/elevatedFileService.ts | 0 .../electron-sandbox/elevatedFileService.ts | 0 .../common/filesConfigurationService.ts | 0 .../services/history/browser/history.ts | 7 +- .../services/history/common/history.ts | 0 .../history/test/browser/history.test.ts | 27 +- .../host/browser/browserHostService.ts | 6 +- .../workbench/services/host/browser/host.ts | 2 +- .../electron-sandbox/nativeHostService.ts | 0 .../workbench/services/hover/browser/hover.ts | 0 .../services/hover/browser/hoverService.ts | 24 +- .../services/hover/browser/hoverWidget.ts | 3 +- .../services/hover/browser/media/hover.css | 0 .../integrity/browser/integrityService.ts | 0 .../services/integrity/common/integrity.ts | 0 .../electron-sandbox/integrityService.ts | 0 .../electron-sandbox/sharedProcessService.ts | 0 .../workbench/services/issue/common/issue.ts | 0 .../issue/electron-sandbox/issueService.ts | 29 +- .../keybinding/browser/keybindingService.ts | 0 .../browser/keyboardLayoutService.ts | 0 .../browser/keyboardLayouts/_.contribution.ts | 0 .../browser/keyboardLayouts/cz.win.ts | 0 .../browser/keyboardLayouts/de-swiss.win.ts | 0 .../browser/keyboardLayouts/de.darwin.ts | 0 .../browser/keyboardLayouts/de.linux.ts | 0 .../browser/keyboardLayouts/de.win.ts | 0 .../browser/keyboardLayouts/dk.win.ts | 0 .../browser/keyboardLayouts/dvorak.darwin.ts | 0 .../browser/keyboardLayouts/en-belgian.win.ts | 0 .../browser/keyboardLayouts/en-ext.darwin.ts | 0 .../browser/keyboardLayouts/en-in.win.ts | 0 .../browser/keyboardLayouts/en-intl.darwin.ts | 0 .../browser/keyboardLayouts/en-intl.win.ts | 0 .../browser/keyboardLayouts/en-uk.darwin.ts | 0 .../browser/keyboardLayouts/en-uk.win.ts | 0 .../browser/keyboardLayouts/en.darwin.ts | 0 .../browser/keyboardLayouts/en.linux.ts | 0 .../browser/keyboardLayouts/en.win.ts | 0 .../browser/keyboardLayouts/es-latin.win.ts | 0 .../browser/keyboardLayouts/es.darwin.ts | 0 .../browser/keyboardLayouts/es.linux.ts | 0 .../browser/keyboardLayouts/es.win.ts | 0 .../browser/keyboardLayouts/fr.darwin.ts | 0 .../browser/keyboardLayouts/fr.linux.ts | 0 .../browser/keyboardLayouts/fr.win.ts | 0 .../browser/keyboardLayouts/hu.win.ts | 0 .../browser/keyboardLayouts/it.darwin.ts | 0 .../browser/keyboardLayouts/it.win.ts | 0 .../keyboardLayouts/jp-roman.darwin.ts | 0 .../browser/keyboardLayouts/jp.darwin.ts | 0 .../browser/keyboardLayouts/ko.darwin.ts | 0 .../layout.contribution.darwin.ts | 0 .../layout.contribution.linux.ts | 0 .../layout.contribution.win.ts | 0 .../browser/keyboardLayouts/no.win.ts | 0 .../browser/keyboardLayouts/pl.darwin.ts | 0 .../browser/keyboardLayouts/pl.win.ts | 0 .../browser/keyboardLayouts/pt-br.win.ts | 0 .../browser/keyboardLayouts/pt.darwin.ts | 0 .../browser/keyboardLayouts/pt.win.ts | 0 .../browser/keyboardLayouts/ru.darwin.ts | 0 .../browser/keyboardLayouts/ru.linux.ts | 0 .../browser/keyboardLayouts/ru.win.ts | 0 .../browser/keyboardLayouts/sv.darwin.ts | 0 .../browser/keyboardLayouts/sv.win.ts | 0 .../browser/keyboardLayouts/thai.win.ts | 0 .../browser/keyboardLayouts/tr.win.ts | 0 .../browser/keyboardLayouts/zh-hans.darwin.ts | 0 .../keybinding/browser/navigatorKeyboard.ts | 0 .../keybinding/browser/unboundCommands.ts | 0 .../keybinding/common/keybindingEditing.ts | 0 .../keybinding/common/keybindingIO.ts | 0 .../services/keybinding/common/keymapInfo.ts | 0 .../common/macLinuxFallbackKeyboardMapper.ts | 0 .../common/macLinuxKeyboardMapper.ts | 1 + .../common/windowsKeyboardMapper.ts | 0 .../electron-sandbox/nativeKeyboardLayout.ts | 0 .../browser/browserKeyboardMapper.test.ts | 0 .../test/browser/keybindingEditing.test.ts | 0 .../test/browser/keybindingIO.test.ts | 0 .../keyboardMapperTestUtils.ts | 7 +- .../test/electron-browser/linux_de_ch.js | 0 .../test/electron-browser/linux_de_ch.txt | 0 .../test/electron-browser/linux_en_uk.js | 0 .../test/electron-browser/linux_en_uk.txt | 0 .../test/electron-browser/linux_en_us.js | 0 .../test/electron-browser/linux_en_us.txt | 0 .../test/electron-browser/linux_ru.js | 0 .../test/electron-browser/linux_ru.txt | 0 .../macLinuxFallbackKeyboardMapper.test.ts | 0 .../macLinuxKeyboardMapper.test.ts | 0 .../test/electron-browser/mac_de_ch.js | 0 .../test/electron-browser/mac_de_ch.txt | 0 .../test/electron-browser/mac_en_us.js | 0 .../test/electron-browser/mac_en_us.txt | 0 .../test/electron-browser/mac_zh_hant.js | 0 .../test/electron-browser/mac_zh_hant.txt | 0 .../test/electron-browser/win_de_ch.js | 0 .../test/electron-browser/win_de_ch.txt | 0 .../test/electron-browser/win_en_us.js | 0 .../test/electron-browser/win_en_us.txt | 0 .../test/electron-browser/win_por_ptb.js | 0 .../test/electron-browser/win_por_ptb.txt | 0 .../test/electron-browser/win_ru.js | 0 .../test/electron-browser/win_ru.txt | 0 .../windowsKeyboardMapper.test.ts | 0 .../services/label/common/labelService.ts | 0 .../services/label/test/browser/label.test.ts | 0 .../label/test/electron-browser/label.test.ts | 0 .../services/layout/browser/layoutService.ts | 6 + .../lifecycle/browser/lifecycleService.ts | 0 .../services/lifecycle/common/lifecycle.ts | 0 .../lifecycle/common/lifecycleService.ts | 0 .../electron-sandbox/lifecycleService.ts | 0 .../electron-sandbox/localizationsService.ts | 0 .../log/electron-sandbox/logService.ts | 0 .../electron-sandbox/menubarService.ts | 0 .../mode/common/workbenchModeService.ts | 0 .../common/notificationService.ts | 0 .../services/outline/browser/outline.ts | 0 .../outline/browser/outlineService.ts | 0 .../services/output/common/output.ts | 0 .../services/panel/common/panelService.ts | 0 .../services/path/browser/pathService.ts | 6 + .../services/path/common/pathService.ts | 0 .../path/electron-sandbox/pathService.ts | 22 +- .../browser/keybindingsEditorInput.ts | 54 + .../browser/keybindingsEditorModel.ts | 2 +- .../preferences/browser/preferencesService.ts | 57 +- .../preferences/common/preferences.ts | 39 +- .../common}/preferencesEditorInput.ts | 73 +- .../preferences/common/preferencesModels.ts | 2 +- .../common/preferencesValidation.ts | 0 .../browser/keybindingsEditorModel.test.ts | 0 .../test/browser/preferencesService.test.ts | 10 +- .../test/common/preferencesValidation.test.ts | 0 .../browser/media/progressService.css | 0 .../progress/browser/progressIndicator.ts | 0 .../progress/browser/progressService.ts | 51 +- .../test/browser/progressIndicator.test.ts | 0 .../quickinput/browser/quickInputService.ts | 0 .../remote/browser/remoteAgentServiceImpl.ts | 0 .../remote/browser/tunnelServiceImpl.ts | 0 .../common/abstractRemoteAgentService.ts | 0 .../common/remoteAgentEnvironmentChannel.ts | 0 .../common/remoteAgentFileSystemChannel.ts | 0 .../remote/common/remoteAgentService.ts | 0 .../remote/common/remoteExplorerService.ts | 199 +- .../electron-browser/tunnelServiceImpl.ts | 6 +- .../remoteAgentServiceImpl.ts | 0 .../remote/test/common/testServices.ts | 0 .../request/browser/requestService.ts | 0 .../electron-sandbox/requestService.ts | 0 .../services/search/browser/searchService.ts | 0 .../search/common/fileSearchManager.ts | 0 .../services/search/common/replace.ts | 2 +- .../services/search/common/search.ts | 12 +- .../services/search/common/searchExtTypes.ts | 20 +- .../services/search/common/searchHelpers.ts | 0 .../services/search/common/searchService.ts | 2 +- .../search/common/textSearchManager.ts | 0 .../search/electron-browser/searchService.ts | 4 + .../services/search/node/fileSearch.ts | 0 .../services/search/node/rawSearchService.ts | 0 .../services/search/node/ripgrepFileSearch.ts | 0 .../search/node/ripgrepSearchProvider.ts | 0 .../search/node/ripgrepSearchUtils.ts | 0 .../search/node/ripgrepTextSearchEngine.ts | 12 +- .../services/search/node/searchApp.ts | 0 .../services/search/node/searchIpc.ts | 0 .../services/search/node/textSearchAdapter.ts | 0 .../services/search/node/textSearchManager.ts | 0 .../search/test/common/replace.test.ts | 14 + .../search/test/common/search.test.ts | 0 .../search/test/common/searchHelpers.test.ts | 35 +- .../electron-browser/rawSearchService.test.ts | 0 .../test/node/fileSearch.integrationTest.ts | 0 .../search/test/node/fixtures/binary.wuff | Bin .../fixtures/examples/NullPoinderException.js | 0 .../test/node/fixtures/examples/company.js | 0 .../test/node/fixtures/examples/employee.js | 0 .../test/node/fixtures/examples/small.js | 0 .../subfolder/anotherfolder/anotherfile.txt | 0 .../fixtures/examples/subfolder/subfile.txt | 0 .../search/test/node/fixtures/index.html | 0 .../search/test/node/fixtures/more/file.txt | 0 .../search/test/node/fixtures/site.css | 0 .../search/test/node/fixtures/site.less | 0 .../test/node/fixtures/some_utf16be.css | Bin .../test/node/fixtures/some_utf16le.css | Bin .../\346\261\211\350\257\255.txt" | 0 .../fixtures2/36438/modules/do-not-find.txt | 0 .../fixtures2/36438/more/modules/find.txt | 0 .../test/node/ripgrepFileSearch.test.ts | 0 .../test/node/ripgrepTextSearchEngine.test.ts | 2 + .../services/search/test/node/search.test.ts | 0 .../test/node/textSearch.integrationTest.ts | 0 .../test/node/textSearchManager.test.ts | 0 .../services/statusbar/common/statusbar.ts | 13 +- .../telemetry/browser/telemetryService.ts | 0 .../browser/workbenchCommonProperties.ts | 0 .../electron-sandbox/telemetryService.ts | 0 .../workbenchCommonProperties.ts | 0 .../test/browser/commonProperties.test.ts | 0 .../electron-browser/commonProperties.test.ts | 4 +- .../browser/abstractTextMateService.ts | 0 .../textMate/browser/textMateService.ts | 0 .../textMate/common/TMGrammarFactory.ts | 0 .../services/textMate/common/TMGrammars.ts | 0 .../services/textMate/common/TMHelper.ts | 0 .../textMate/common/TMScopeRegistry.ts | 0 .../services/textMate/common/cgmanifest.json | 0 .../textMate/common/textMateService.ts | 0 .../electron-sandbox/textMateService.ts | 0 .../electron-sandbox/textMateWorker.ts | 0 .../browser/browserTextFileService.ts | 69 + .../textfile/browser/textFileService.ts | 10 +- .../services/textfile/common/encoding.ts | 0 .../textfile/common/textFileEditorModel.ts | 29 +- .../common/textFileEditorModelManager.ts | 71 +- .../common/textFileSaveParticipant.ts | 0 .../services/textfile/common/textfiles.ts | 1 + .../electron-sandbox/nativeTextFileService.ts | 5 +- .../browser/browserTextFileService.io.test.ts | 0 .../textfile/test/browser/fixtures/files.ts | 0 .../test/browser/textFileEditorModel.test.ts | 0 .../textFileEditorModelManager.test.ts | 2 +- .../test/browser/textFileService.test.ts | 0 .../test/common/textFileService.io.test.ts | 0 .../test/electron-browser/fixtures/binary.txt | Bin .../test/electron-browser/fixtures/index.html | 0 .../test/electron-browser/fixtures/lorem.txt | 0 .../electron-browser/fixtures/lorem_big5.txt | 0 .../fixtures/lorem_cp1252.txt | 0 .../electron-browser/fixtures/lorem_cp866.txt | 0 .../electron-browser/fixtures/lorem_gbk.txt | 0 .../fixtures/lorem_shiftjis.txt | 0 .../fixtures/lorem_utf16be.txt | Bin .../fixtures/lorem_utf16le.txt | Bin .../fixtures/lorem_utf8bom.txt | 0 .../test/electron-browser/fixtures/small.txt | 0 .../fixtures/small_umlaut.txt | 0 .../electron-browser/fixtures/some.utf16le | Bin .../electron-browser/fixtures/some_big5.txt | 0 .../electron-browser/fixtures/some_cp1252.txt | 0 .../fixtures/some_cyrillic.txt | 0 .../electron-browser/fixtures/some_gbk.txt | 0 .../fixtures/some_shiftjis.txt | 0 .../fixtures/some_small_cp1252.txt | 0 .../fixtures/some_utf16le.css | Bin .../fixtures/some_utf8_bom.txt | 0 .../fixtures/utf16_be_nobom.txt | Bin .../fixtures/utf16_le_nobom.txt | Bin .../nativeTextFileService.io.test.ts | 7 +- .../nativeTextFileService.test.ts | 0 .../test/node/encoding/encoding.test.ts | 0 .../test/node/encoding/fixtures/empty.txt | 0 .../node/encoding/fixtures/issue_102202.txt | 0 .../node/encoding/fixtures/some.cp1252.txt | 0 .../node/encoding/fixtures/some.css.qwoff | 0 .../test/node/encoding/fixtures/some.json.png | 0 .../test/node/encoding/fixtures/some.pdf | Bin .../test/node/encoding/fixtures/some.png.txt | Bin .../node/encoding/fixtures/some.qwoff.txt | Bin .../node/encoding/fixtures/some.shiftjis.txt | 0 .../test/node/encoding/fixtures/some.xml.png | 0 .../test/node/encoding/fixtures/some_ansi.css | 0 .../test/node/encoding/fixtures/some_file.css | 0 .../test/node/encoding/fixtures/some_gbk.txt | 0 .../node/encoding/fixtures/some_utf16be.css | Bin .../node/encoding/fixtures/some_utf16le.css | Bin .../test/node/encoding/fixtures/some_utf8.css | 0 .../node/encoding/fixtures/utf16_be_nobom.txt | Bin .../node/encoding/fixtures/utf16_le_nobom.txt | Bin .../common/textModelResolverService.ts | 6 +- .../browser/textModelResolverService.test.ts | 8 +- .../common/textResourcePropertiesService.ts | 0 .../browser/browserHostColorSchemeService.ts | 5 +- .../themes/browser/fileIconThemeData.ts | 0 .../themes/browser/productIconThemeData.ts | 0 .../themes/browser/workbenchThemeService.ts | 0 .../themes/common/colorExtensionPoint.ts | 0 .../services/themes/common/colorThemeData.ts | 0 .../themes/common/colorThemeSchema.ts | 0 .../themes/common/fileIconThemeSchema.ts | 0 .../themes/common/hostColorSchemeService.ts | 0 .../themes/common/iconExtensionPoint.ts | 6 +- .../services/themes/common/plistParser.ts | 0 .../themes/common/productIconThemeSchema.ts | 0 .../themes/common/textMateScopeMatcher.ts | 0 .../themes/common/themeCompatibility.ts | 0 .../themes/common/themeConfiguration.ts | 1 + .../themes/common/themeExtensionPoints.ts | 0 .../tokenClassificationExtensionPoint.ts | 0 .../themes/common/workbenchThemeService.ts | 0 .../nativeHostColorSchemeService.ts | 0 .../test/electron-browser/color-theme.json | 0 .../tokenStyleResolving.test.ts | 0 .../services/timer/browser/timerService.ts | 11 - .../timer/electron-sandbox/timerService.ts | 0 .../services/title/common/titleService.ts | 0 .../title/electron-sandbox/titleService.ts | 0 .../common/untitledTextEditorHandler.ts | 121 + .../common/untitledTextEditorInput.ts | 35 +- .../common/untitledTextEditorModel.ts | 79 +- .../common/untitledTextEditorService.ts | 0 .../test/browser/untitledTextEditor.test.ts | 29 +- .../services/update/browser/updateService.ts | 0 .../update/electron-sandbox/updateService.ts | 0 .../uriIdentity/common/uriIdentity.ts | 0 .../uriIdentity/common/uriIdentityService.ts | 0 .../test/common/uriIdentityService.test.ts | 0 .../services/url/browser/urlService.ts | 32 +- .../url/electron-sandbox/urlService.ts | 0 .../services/userData/browser/userDataInit.ts | 0 .../userData/common/fileUserDataProvider.ts | 0 .../test/browser/fileUserDataProvider.test.ts | 0 .../userDataAutoSyncEnablementService.ts | 0 .../userDataSyncResourceEnablementService.ts | 0 .../browser/userDataSyncWorkbenchService.ts | 0 .../userDataSync/common/userDataSync.ts | 0 .../userDataSync/common/userDataSyncUtil.ts | 0 .../userDataAutoSyncService.ts | 0 .../userDataSyncAccountService.ts | 0 .../userDataSyncMachinesService.ts | 0 .../electron-sandbox/userDataSyncService.ts | 0 .../userDataSyncStoreManagementService.ts | 0 .../services/viewlet/browser/viewlet.ts | 0 .../views/browser/viewDescriptorService.ts | 0 .../views/common/viewContainerModel.ts | 0 .../test/browser/viewContainerModel.test.ts | 0 .../browser/viewDescriptorService.test.ts | 0 .../browser/workingCopyBackupService.ts | 0 .../browser/workingCopyBackupTracker.ts | 0 .../common/abstractFileWorkingCopyManager.ts | 169 + .../workingCopy/common/fileWorkingCopy.ts | 113 + .../common/fileWorkingCopyManager.ts | 404 + .../workingCopy/common/resourceWorkingCopy.ts | 160 + .../common/storedFileWorkingCopy.ts | 426 +- .../common/storedFileWorkingCopyManager.ts | 418 +- .../common/untitledFileWorkingCopy.ts | 283 + .../common/untitledFileWorkingCopyManager.ts | 256 + .../workingCopy/common/workingCopy.ts | 0 .../workingCopy/common/workingCopyBackup.ts | 6 +- .../common/workingCopyBackupService.ts | 21 +- .../common/workingCopyBackupTracker.ts | 17 +- .../common/workingCopyEditorService.ts | 2 +- .../workingCopyFileOperationParticipant.ts | 0 .../common/workingCopyFileService.ts | 0 .../workingCopy/common/workingCopyService.ts | 29 +- .../workingCopyBackupService.ts | 0 .../workingCopyBackupTracker.ts | 83 +- .../browser/fileWorkingCopyManager.test.ts | 276 + .../test/browser/resourceWorkingCopyTest.ts | 84 + .../browser/storedFileWorkingCopy.test.ts | 220 +- .../storedFileWorkingCopyManager.test.ts | 282 +- .../browser/untitledFileWorkingCopy.test.ts | 308 + .../untitledFileWorkingCopyManager.test.ts | 238 + .../browser/workingCopyBackupTracker.test.ts | 16 +- .../browser/workingCopyEditorService.test.ts | 3 + .../browser/workingCopyFileService.test.ts | 0 .../test/common/workingCopyService.test.ts | 7 + .../test/electron-browser/fixtures/binary.txt | Bin .../workingCopyBackupService.test.ts | 24 +- .../workingCopyBackupTracker.test.ts | 49 +- .../abstractWorkspaceEditingService.ts | 12 +- .../browser/workspaceEditingService.ts | 0 .../browser/workspaceTrustEditorInput.ts | 2 +- .../services/workspaces/browser/workspaces.ts | 0 .../workspaces/browser/workspacesService.ts | 2 +- .../workspaces/common/workspaceEditing.ts | 0 .../workspaces/common/workspaceTrust.ts | 753 + .../workspaceEditingService.ts | 0 .../electron-sandbox/workspacesService.ts | 0 .../test/browser/workspaces.test.ts | 0 .../test/common/testWorkspaceTrustService.ts | 62 +- .../test/browser/api/extHost.api.impl.test.ts | 0 .../browser/api/extHostApiCommands.test.ts | 65 +- .../test/browser/api/extHostBulkEdits.test.ts | 0 .../test/browser/api/extHostCommands.test.ts | 0 .../browser/api/extHostConfiguration.test.ts | 0 .../browser/api/extHostDecorations.test.ts | 0 .../browser/api/extHostDiagnostics.test.ts | 0 .../api/extHostDocumentData.test.perf-data.ts | 0 .../browser/api/extHostDocumentData.test.ts | 0 .../extHostDocumentSaveParticipant.test.ts | 0 .../api/extHostDocumentsAndEditors.test.ts | 0 .../api/extHostFileSystemEventService.test.ts | 0 .../api/extHostLanguageFeatures.test.ts | 0 .../api/extHostMessagerService.test.ts | 0 .../test/browser/api/extHostNotebook.test.ts | 32 +- .../api/extHostNotebookConcatDocument.test.ts | 2 +- .../api/extHostNotebookKernel2.test.ts | 232 + .../test/browser/api/extHostTesting.test.ts | 0 .../browser/api/extHostTextEditor.test.ts | 0 .../test/browser/api/extHostTreeViews.test.ts | 0 .../browser/api/extHostTypeConverter.test.ts | 18 +- .../test/browser/api/extHostTypes.test.ts | 80 +- .../test/browser/api/extHostWebview.test.ts | 104 +- .../test/browser/api/extHostWorkspace.test.ts | 0 .../browser/api/mainThreadCommands.test.ts | 0 .../api/mainThreadConfiguration.test.ts | 0 .../browser/api/mainThreadDiagnostics.test.ts | 0 ...mainThreadDocumentContentProviders.test.ts | 0 .../browser/api/mainThreadDocuments.test.ts | 0 .../api/mainThreadDocumentsAndEditors.test.ts | 0 .../browser/api/mainThreadEditors.test.ts | 0 .../browser/api/mainThreadTreeViews.test.ts | 2 +- .../test/browser/api/testRPCProtocol.ts | 0 .../workbench/test/browser/codeeditor.test.ts | 0 .../vs/workbench/test/browser/part.test.ts | 0 .../parts/editor/breadcrumbModel.test.ts | 0 .../parts/editor/diffEditorInput.test.ts | 27 +- .../test/browser/parts/editor/editor.test.ts | 73 +- .../parts/editor/editorDiffModel.test.ts | 10 +- .../parts/editor/editorGroupModel.test.ts | 12 +- .../browser/parts/editor/editorInput.test.ts | 36 + .../browser/parts/editor/editorModel.test.ts | 6 +- .../browser/parts/editor/editorPane.test.ts | 189 +- .../parts/editor/resourceEditorInput.test.ts | 55 + .../editor/sideBySideEditorInput.test.ts | 61 + .../editor/textResourceEditorInput.test.ts | 108 + .../test/browser/quickAccess.test.ts | 25 +- .../vs/workbench/test/browser/viewlet.test.ts | 0 .../test/browser/workbenchTestServices.ts | 174 +- .../vs/workbench/test/common/memento.test.ts | 0 .../test/common/notifications.test.ts | 26 +- .../test/common/workbenchTestServices.ts | 2 +- .../api/extHostSearch.test.ts | 0 .../api/mainThreadWorkspace.test.ts | 4 +- .../colorRegistry.releaseTest.ts | 3 +- .../colorRegistryExport.test.ts | 20 + .../textsearch.perf.integrationTest.ts | 0 .../electron-browser/workbenchTestServices.ts | 11 +- .../node/api/extHostTunnelService.test.ts | 0 .../vs/workbench/workbench.common.main.ts | 5 +- .../vs/workbench/workbench.desktop.main.css | 0 .../workbench/workbench.desktop.main.nls.js | 0 .../vs/workbench/workbench.desktop.main.ts | 24 - .../workbench.desktop.sandbox.main.ts | 2 + .../vs/workbench/workbench.sandbox.main.ts | 6 + .../vs/workbench/workbench.web.api.css | 0 .../vs/workbench/workbench.web.api.nls.js | 0 .../vs/workbench/workbench.web.api.ts | 24 + .../vs/workbench/workbench.web.main.ts | 4 +- {lib/vscode/test => test}/.mocharc.json | 0 {lib/vscode/test => test}/README.md | 0 .../test => test}/automation/.gitignore | 0 .../test => test}/automation/.npmignore | 0 .../vscode/test => test}/automation/README.md | 0 .../test => test}/automation/package.json | 2 +- .../automation/src/activityBar.ts | 0 .../automation/src/application.ts | 16 + .../test => test}/automation/src/code.ts | 4 +- .../test => test}/automation/src/debug.ts | 0 .../test => test}/automation/src/driver.js | 0 .../test => test}/automation/src/editor.ts | 0 .../test => test}/automation/src/editors.ts | 0 .../test => test}/automation/src/explorer.ts | 0 .../automation/src/extensions.ts | 0 .../test => test}/automation/src/index.ts | 0 .../automation/src/keybindings.ts | 0 .../test => test}/automation/src/logger.ts | 0 .../test => test}/automation/src/notebook.ts | 0 .../test => test}/automation/src/peek.ts | 0 .../automation/src/playwrightDriver.ts | 0 .../test => test}/automation/src/problems.ts | 0 .../automation/src/quickaccess.ts | 0 .../automation/src/quickinput.ts | 0 .../test => test}/automation/src/scm.ts | 0 .../test => test}/automation/src/search.ts | 5 + .../test => test}/automation/src/settings.ts | 0 .../test => test}/automation/src/statusbar.ts | 0 .../test => test}/automation/src/terminal.ts | 0 .../test => test}/automation/src/viewlet.ts | 0 .../test => test}/automation/src/workbench.ts | 0 .../tools/copy-driver-definition.js | 0 .../automation/tools/copy-package-version.js | 0 .../test => test}/automation/tsconfig.json | 0 .../vscode/test => test}/automation/yarn.lock | 8 +- {lib/vscode/test => test}/cgmanifest.json | 0 test/config.ts | 74 - test/e2e/browser.test.ts | 23 - test/e2e/codeServer.test.ts | 49 - test/e2e/globalSetup.test.ts | 30 - test/e2e/login.test.ts | 76 - test/e2e/logout.test.ts | 53 - test/e2e/models/CodeServer.ts | 117 - test/e2e/openHelpAbout.test.ts | 46 - test/e2e/terminal.test.ts | 61 - .../integration/browser/.gitignore | 0 .../integration/browser/README.md | 0 .../integration/browser/package.json | 2 +- .../integration/browser/src/index.ts | 4 +- .../integration/browser/tsconfig.json | 0 .../integration/browser/yarn.lock | 8 +- .../integration/electron/testrunner.js | 0 test/leaks/index.html | 40 + test/leaks/package.json | 11 + test/leaks/server.js | 16 + test/leaks/yarn.lock | 371 + {lib/vscode/test => test}/monaco/.gitignore | 0 .../vscode/test => test}/monaco/.mocharc.json | 0 {lib/vscode/test => test}/monaco/README.md | 0 {lib/vscode/test => test}/monaco/core.js | 0 .../test => test}/monaco/dist/core.html | 0 .../test => test}/monaco/monaco.test.ts | 0 {lib/vscode/test => test}/monaco/package.json | 0 {lib/vscode/test => test}/monaco/runner.js | 0 .../vscode/test => test}/monaco/tsconfig.json | 0 .../test => test}/monaco/webpack.config.js | 0 {lib/vscode/test => test}/monaco/yarn.lock | 0 test/package.json | 20 - {lib/vscode/test => test}/smoke/.gitignore | 0 {lib/vscode/test => test}/smoke/Audit.md | 0 {lib/vscode/test => test}/smoke/README.md | 0 {lib/vscode/test => test}/smoke/package.json | 2 +- .../smoke/src/areas/editor/editor.test.ts | 0 .../src/areas/extensions/extensions.test.ts | 0 .../src/areas/languages/languages.test.ts | 0 .../src/areas/multiroot/multiroot.test.ts | 6 +- .../smoke/src/areas/notebook/notebook.test.ts | 0 .../src/areas/preferences/preferences.test.ts | 0 .../smoke/src/areas/search/search.test.ts | 9 + .../src/areas/statusbar/statusbar.test.ts | 0 .../src/areas/workbench/data-loss.test.ts | 0 .../areas/workbench/data-migration.test.ts | 0 .../smoke/src/areas/workbench/launch.test.ts | 0 .../src/areas/workbench/localization.test.ts | 5 +- {lib/vscode/test => test}/smoke/src/main.ts | 0 {lib/vscode/test => test}/smoke/src/utils.ts | 0 {lib/vscode/test => test}/smoke/test/index.js | 0 {lib/vscode/test => test}/smoke/tsconfig.json | 0 {lib/vscode/test => test}/smoke/yarn.lock | 14 +- test/tsconfig.json | 4 - {lib/vscode/test => test}/unit/README.md | 0 {lib/vscode/test => test}/unit/assert.js | 0 .../test => test}/unit/browser/index.js | 2 +- .../test => test}/unit/browser/renderer.html | 0 test/unit/cli.test.ts | 406 - test/unit/constants.test.ts | 68 - {lib/vscode/test => test}/unit/coverage.js | 0 .../test => test}/unit/electron/index.js | 0 .../test => test}/unit/electron/renderer.html | 0 .../test => test}/unit/electron/renderer.js | 0 test/unit/emitter.test.ts | 86 - .../unit/fullJsonStreamReporter.js | 0 test/unit/health.test.ts | 40 - test/unit/http.test.ts | 35 - {lib/vscode/test => test}/unit/node/all.js | 0 .../vscode/test => test}/unit/node/browser.js | 0 .../test => test}/unit/node/css.mock.js | 0 .../vscode/test => test}/unit/node/index.html | 0 test/unit/plugin.test.ts | 116 - test/unit/proxy.test.ts | 105 - test/unit/register.test.ts | 181 - test/unit/routes/login.test.ts | 37 - test/unit/serviceWorker.test.ts | 92 - test/unit/socket.test.ts | 127 - test/unit/test-plugin/.eslintrc.yaml | 5 - test/unit/test-plugin/.gitignore | 1 - test/unit/test-plugin/Makefile | 6 - test/unit/test-plugin/package.json | 16 - test/unit/test-plugin/public/icon.svg | 1 - test/unit/test-plugin/public/index.html | 10 - test/unit/test-plugin/src/index.ts | 52 - test/unit/test-plugin/tsconfig.json | 71 - test/unit/test-plugin/yarn.lock | 70 - test/unit/update.test.ts | 160 - test/unit/util.test.ts | 249 - test/utils/constants.ts | 14 - test/utils/cssStub.ts | 5 - test/utils/globalSetup.ts | 40 - test/utils/helpers.ts | 11 - test/utils/httpserver.ts | 114 - test/utils/integration.ts | 21 - test/utils/wtfnode.ts | 35 - test/yarn.lock | 4990 ----- tsconfig.json | 23 - lib/vscode/tsfmt.json => tsfmt.json | 0 typings/httpolyglot/index.d.ts | 10 - typings/ipc.d.ts | 138 - typings/pluginapi.d.ts | 293 - yarn.lock | 10395 ++++++---- 5503 files changed, 65867 insertions(+), 87503 deletions(-) create mode 100644 .devcontainer/README.md rename {lib/vscode/.devcontainer => .devcontainer}/cache/.gitignore (100%) rename {lib/vscode/.devcontainer => .devcontainer}/cache/before-cache.sh (100%) rename {lib/vscode/.devcontainer => .devcontainer}/cache/build-cache-image.sh (100%) rename {lib/vscode/.devcontainer => .devcontainer}/cache/cache-diff.sh (100%) rename {lib/vscode/.devcontainer => .devcontainer}/cache/cache.Dockerfile (100%) rename {lib/vscode/.devcontainer => .devcontainer}/cache/restore-diff.sh (100%) rename {lib/vscode/.devcontainer => .devcontainer}/devcontainer.json (70%) rename {lib/vscode/.devcontainer => .devcontainer}/prepare.sh (100%) delete mode 100644 .dockerignore rename lib/vscode/.eslintignore => .eslintignore (80%) rename lib/vscode/.eslintrc.json => .eslintrc.json (99%) delete mode 100644 .eslintrc.yaml delete mode 100644 .github/CODEOWNERS delete mode 100644 .github/ISSUE_TEMPLATE/bug-report.md rename {lib/vscode/.github => .github}/ISSUE_TEMPLATE/bug_report.md (99%) delete mode 100644 .github/ISSUE_TEMPLATE/doc.md delete mode 100644 .github/ISSUE_TEMPLATE/extension-request.md delete mode 100644 .github/ISSUE_TEMPLATE/feature-request.md rename {lib/vscode/.github => .github}/ISSUE_TEMPLATE/feature_request.md (100%) delete mode 100644 .github/PULL_REQUEST_TEMPLATE/pull_request_template.md delete mode 100644 .github/PULL_REQUEST_TEMPLATE/release_template.md rename {lib/vscode/.github => .github}/calendar.yml (100%) rename {lib/vscode/.github => .github}/classifier.json (93%) delete mode 100644 .github/codeql-config.yml rename {lib/vscode/.github => .github}/commands.json (97%) rename {lib/vscode/.github => .github}/commands.yml (100%) delete mode 100644 .github/dependabot.yml rename {lib/vscode/.github => .github}/endgame/insiders.yml (100%) rename {lib/vscode/.github => .github}/insiders.yml (100%) delete mode 100644 .github/lock.yml rename {lib/vscode/.github => .github}/pull_request_template.md (100%) delete mode 100644 .github/ranger.yml rename {lib/vscode/.github => .github}/similarity.yml (100%) rename {lib/vscode/.github => .github}/subscribers.json (72%) rename {lib/vscode/.github => .github}/workflows/author-verified.yml (100%) rename {lib/vscode/.github => .github}/workflows/build-chat.yml (100%) delete mode 100644 .github/workflows/ci.yaml rename {lib/vscode/.github => .github}/workflows/ci.yml (99%) delete mode 100644 .github/workflows/codeql-analysis.yml rename {lib/vscode/.github => .github}/workflows/codeql.yml (100%) rename {lib/vscode/.github => .github}/workflows/deep-classifier-monitor.yml (100%) rename {lib/vscode/.github => .github}/workflows/deep-classifier-runner.yml (100%) rename {lib/vscode/.github => .github}/workflows/deep-classifier-scraper.yml (100%) rename {lib/vscode/.github => .github}/workflows/devcontainer-cache.yml (100%) rename {lib/vscode/.github => .github}/workflows/english-please.yml (100%) rename {lib/vscode/.github => .github}/workflows/feature-request.yml (100%) rename {lib/vscode/.github => .github}/workflows/latest-release-monitor.yml (100%) rename {lib/vscode/.github => .github}/workflows/locker.yml (100%) rename {lib/vscode/.github => .github}/workflows/needs-more-info-closer.yml (100%) rename {lib/vscode/.github => .github}/workflows/no-yarn-lock-changes.yml (100%) rename {lib/vscode/.github => .github}/workflows/on-comment.yml (100%) rename {lib/vscode/.github => .github}/workflows/on-label.yml (100%) rename {lib/vscode/.github => .github}/workflows/on-open.yml (100%) delete mode 100644 .github/workflows/publish.yaml rename {lib/vscode/.github => .github}/workflows/release-pipeline-labeler.yml (100%) rename {lib/vscode/.github => .github}/workflows/rich-navigation.yml (100%) rename {lib/vscode/.github => .github}/workflows/test-plan-item-validator.yml (100%) rename lib/vscode/.mailmap => .mailmap (100%) rename lib/vscode/.mention-bot => .mention-bot (100%) delete mode 100644 .prettierrc.yaml delete mode 100644 .stylelintrc.yaml delete mode 100644 .tours/contributing.tour delete mode 100644 .tours/start-development.tour rename {lib/vscode/.vscode => .vscode}/cglicenses.schema.json (100%) rename {lib/vscode/.vscode => .vscode}/cgmanifest.schema.json (100%) rename {lib/vscode/.vscode => .vscode}/extensions.json (100%) rename {lib/vscode/.vscode => .vscode}/launch.json (100%) rename {lib/vscode/.vscode => .vscode}/notebooks/api.github-issues (52%) rename {lib/vscode/.vscode => .vscode}/notebooks/endgame.github-issues (99%) rename {lib/vscode/.vscode => .vscode}/notebooks/grooming-delta.github-issues (100%) rename {lib/vscode/.vscode => .vscode}/notebooks/grooming.github-issues (100%) rename {lib/vscode/.vscode => .vscode}/notebooks/inbox.github-issues (100%) rename {lib/vscode/.vscode => .vscode}/notebooks/my-endgame.github-issues (98%) rename {lib/vscode/.vscode => .vscode}/notebooks/my-work.github-issues (63%) rename {lib/vscode/.vscode => .vscode}/notebooks/papercuts.github-issues (100%) rename {lib/vscode/.vscode => .vscode}/notebooks/verification.github-issues (100%) rename {lib/vscode/.vscode => .vscode}/searches/TrustedTypes.code-search (100%) rename {lib/vscode/.vscode => .vscode}/searches/ts36031.code-search (100%) rename {lib/vscode/.vscode => .vscode}/settings.json (100%) rename {lib/vscode/.vscode => .vscode}/shared.code-snippets (100%) rename {lib/vscode/.vscode => .vscode}/tasks.json (80%) rename lib/vscode/.yarnrc => .yarnrc (78%) rename lib/vscode/CONTRIBUTING.md => CONTRIBUTING.md (100%) rename lib/vscode/SECURITY.md => SECURITY.md (100%) rename {lib/vscode/build => build}/.cachesalt (100%) rename {lib/vscode/build => build}/.gitattributes (100%) rename {lib/vscode/build => build}/.moduleignore (100%) rename {lib/vscode/build => build}/.webignore (100%) rename {lib/vscode/build => build}/azure-pipelines/common/computeNodeModulesCacheKey.js (100%) rename {lib/vscode/build => build}/azure-pipelines/common/computeNodeModulesCacheKey.ts (100%) create mode 100644 build/azure-pipelines/common/createAsset.js rename {lib/vscode/build => build}/azure-pipelines/common/createAsset.ts (50%) rename {lib/vscode/build => build}/azure-pipelines/common/createBuild.js (100%) rename {lib/vscode/build => build}/azure-pipelines/common/createBuild.ts (100%) rename {lib/vscode/build => build}/azure-pipelines/common/extract-telemetry.sh (100%) rename {lib/vscode/build => build}/azure-pipelines/common/installPlaywright.js (100%) rename {lib/vscode/build => build}/azure-pipelines/common/installPlaywright.ts (100%) rename {lib/vscode/build => build}/azure-pipelines/common/listNodeModules.js (100%) rename {lib/vscode/build => build}/azure-pipelines/common/listNodeModules.ts (100%) rename {lib/vscode/build => build}/azure-pipelines/common/publish-webview.js (100%) rename {lib/vscode/build => build}/azure-pipelines/common/publish-webview.sh (100%) rename {lib/vscode/build => build}/azure-pipelines/common/publish-webview.ts (100%) rename {lib/vscode/build => build}/azure-pipelines/common/releaseBuild.js (100%) rename {lib/vscode/build => build}/azure-pipelines/common/releaseBuild.ts (100%) rename {lib/vscode/build => build}/azure-pipelines/common/retry.js (100%) rename {lib/vscode/build => build}/azure-pipelines/common/retry.ts (100%) rename {lib/vscode/build => build}/azure-pipelines/common/telemetry-config.json (100%) rename {lib/vscode/build => build}/azure-pipelines/darwin/app-entitlements.plist (100%) rename {lib/vscode/build => build}/azure-pipelines/darwin/helper-gpu-entitlements.plist (100%) rename {lib/vscode/build => build}/azure-pipelines/darwin/helper-renderer-entitlements.plist (100%) rename {lib/vscode/build => build}/azure-pipelines/darwin/product-build-darwin-sign.yml (80%) rename {lib/vscode/build => build}/azure-pipelines/darwin/product-build-darwin.yml (92%) rename {lib/vscode/build => build}/azure-pipelines/distro-build.yml (100%) rename {lib/vscode/build => build}/azure-pipelines/exploration-build.yml (100%) rename {lib/vscode/build => build}/azure-pipelines/linux/.gitignore (100%) rename {lib/vscode/build => build}/azure-pipelines/linux/alpine/install-dependencies.sh (100%) rename lib/vscode/build/azure-pipelines/linux/publish.sh => build/azure-pipelines/linux/prepare-publish.sh (79%) rename {lib/vscode/build => build}/azure-pipelines/linux/product-build-alpine.yml (77%) rename {lib/vscode/build => build}/azure-pipelines/linux/product-build-linux.yml (94%) rename {lib/vscode/build => build}/azure-pipelines/linux/snap-build-linux.yml (84%) rename {lib/vscode/build => build}/azure-pipelines/linux/xvfb.init (100%) rename {lib/vscode/build => build}/azure-pipelines/mixin.js (100%) rename {lib/vscode/build => build}/azure-pipelines/mixin.ts (100%) rename {lib/vscode/build => build}/azure-pipelines/product-build.yml (89%) rename {lib/vscode/build => build}/azure-pipelines/product-compile.yml (93%) create mode 100644 build/azure-pipelines/product-publish.ps1 create mode 100644 build/azure-pipelines/product-publish.yml rename lib/vscode/build/azure-pipelines/release.yml => build/azure-pipelines/product-release.yml (100%) rename {lib/vscode/build => build}/azure-pipelines/publish-types/check-version.js (100%) rename {lib/vscode/build => build}/azure-pipelines/publish-types/check-version.ts (100%) rename {lib/vscode/build => build}/azure-pipelines/publish-types/publish-types.yml (100%) rename {lib/vscode/build => build}/azure-pipelines/publish-types/update-types.js (100%) rename {lib/vscode/build => build}/azure-pipelines/publish-types/update-types.ts (100%) rename {lib/vscode/build => build}/azure-pipelines/upload-cdn.js (100%) rename {lib/vscode/build => build}/azure-pipelines/upload-cdn.ts (100%) rename {lib/vscode/build => build}/azure-pipelines/upload-sourcemaps.js (100%) rename {lib/vscode/build => build}/azure-pipelines/upload-sourcemaps.ts (100%) rename {lib/vscode/build => build}/azure-pipelines/web/product-build-web.yml (90%) rename {lib/vscode/build => build}/azure-pipelines/win32/ESRPClient/NuGet.config (100%) rename {lib/vscode/build => build}/azure-pipelines/win32/ESRPClient/packages.config (100%) rename {lib/vscode/build => build}/azure-pipelines/win32/exec.ps1 (100%) rename {lib/vscode/build => build}/azure-pipelines/win32/import-esrp-auth-cert.ps1 (100%) rename lib/vscode/build/azure-pipelines/win32/publish.ps1 => build/azure-pipelines/win32/prepare-publish.ps1 (51%) rename {lib/vscode/build => build}/azure-pipelines/win32/product-build-win32.yml (96%) rename {lib/vscode/build => build}/azure-pipelines/win32/retry.ps1 (100%) rename {lib/vscode/build => build}/azure-pipelines/win32/sign.ps1 (100%) rename {lib/vscode/build => build}/builtin/.eslintrc (100%) rename {lib/vscode/build => build}/builtin/browser-main.js (100%) rename {lib/vscode/build => build}/builtin/index.html (100%) rename {lib/vscode/build => build}/builtin/main.js (100%) rename {lib/vscode/build => build}/builtin/package.json (100%) rename {lib/vscode/build => build}/darwin/create-universal-app.js (96%) rename {lib/vscode/build => build}/darwin/create-universal-app.ts (100%) rename {lib/vscode/build => build}/darwin/sign.js (100%) rename {lib/vscode/build => build}/darwin/sign.ts (100%) rename {lib/vscode/build => build}/eslint.js (100%) rename {lib/vscode/build => build}/filters.js (100%) rename {lib/vscode/build => build}/gulpfile.compile.js (100%) rename {lib/vscode/build => build}/gulpfile.editor.js (100%) rename {lib/vscode/build => build}/gulpfile.extensions.js (66%) rename {lib/vscode/build => build}/gulpfile.hygiene.js (100%) rename {lib/vscode/build => build}/gulpfile.js (100%) rename {lib/vscode/build => build}/gulpfile.reh.js (99%) rename {lib/vscode/build => build}/gulpfile.vscode.js (97%) rename {lib/vscode/build => build}/gulpfile.vscode.linux.js (100%) rename {lib/vscode/build => build}/gulpfile.vscode.web.js (100%) rename {lib/vscode/build => build}/gulpfile.vscode.win32.js (100%) rename {lib/vscode/build => build}/hygiene.js (100%) rename {lib/vscode/build => build}/jsconfig.json (100%) rename {lib/vscode/build => build}/lib/asar.js (100%) rename {lib/vscode/build => build}/lib/asar.ts (100%) rename {lib/vscode/build => build}/lib/builtInExtensions.js (97%) rename {lib/vscode/build => build}/lib/builtInExtensions.ts (99%) rename {lib/vscode/build => build}/lib/builtInExtensionsCG.js (96%) rename {lib/vscode/build => build}/lib/builtInExtensionsCG.ts (98%) rename {lib/vscode/build => build}/lib/bundle.js (100%) rename {lib/vscode/build => build}/lib/bundle.ts (100%) rename {lib/vscode/build => build}/lib/compilation.js (100%) rename {lib/vscode/build => build}/lib/compilation.ts (100%) rename {lib/vscode/build => build}/lib/dependencies.js (100%) rename {lib/vscode/build => build}/lib/dependencies.ts (100%) rename {lib/vscode/build => build}/lib/electron.js (100%) rename {lib/vscode/build => build}/lib/electron.ts (100%) rename {lib/vscode/build => build}/lib/eslint/code-import-patterns.js (100%) rename {lib/vscode/build => build}/lib/eslint/code-import-patterns.ts (100%) rename {lib/vscode/build => build}/lib/eslint/code-layering.js (100%) rename {lib/vscode/build => build}/lib/eslint/code-layering.ts (100%) rename {lib/vscode/build => build}/lib/eslint/code-no-nls-in-standalone-editor.js (100%) rename {lib/vscode/build => build}/lib/eslint/code-no-nls-in-standalone-editor.ts (100%) rename {lib/vscode/build => build}/lib/eslint/code-no-standalone-editor.js (100%) rename {lib/vscode/build => build}/lib/eslint/code-no-standalone-editor.ts (100%) rename {lib/vscode/build => build}/lib/eslint/code-no-unexternalized-strings.js (100%) rename {lib/vscode/build => build}/lib/eslint/code-no-unexternalized-strings.ts (100%) rename {lib/vscode/build => build}/lib/eslint/code-no-unused-expressions.js (100%) rename {lib/vscode/build => build}/lib/eslint/code-no-unused-expressions.ts (100%) rename {lib/vscode/build => build}/lib/eslint/code-translation-remind.js (100%) rename {lib/vscode/build => build}/lib/eslint/code-translation-remind.ts (100%) rename {lib/vscode/build => build}/lib/eslint/utils.js (100%) rename {lib/vscode/build => build}/lib/eslint/utils.ts (100%) rename {lib/vscode/build => build}/lib/eslint/vscode-dts-cancellation.js (100%) rename {lib/vscode/build => build}/lib/eslint/vscode-dts-cancellation.ts (100%) rename {lib/vscode/build => build}/lib/eslint/vscode-dts-create-func.js (100%) rename {lib/vscode/build => build}/lib/eslint/vscode-dts-create-func.ts (100%) rename {lib/vscode/build => build}/lib/eslint/vscode-dts-event-naming.js (100%) rename {lib/vscode/build => build}/lib/eslint/vscode-dts-event-naming.ts (100%) rename {lib/vscode/build => build}/lib/eslint/vscode-dts-interface-naming.js (100%) rename {lib/vscode/build => build}/lib/eslint/vscode-dts-interface-naming.ts (100%) rename {lib/vscode/build => build}/lib/eslint/vscode-dts-literal-or-types.js (100%) rename {lib/vscode/build => build}/lib/eslint/vscode-dts-literal-or-types.ts (100%) rename {lib/vscode/build => build}/lib/eslint/vscode-dts-provider-naming.js (100%) rename {lib/vscode/build => build}/lib/eslint/vscode-dts-provider-naming.ts (100%) rename {lib/vscode/build => build}/lib/eslint/vscode-dts-region-comments.js (100%) rename {lib/vscode/build => build}/lib/eslint/vscode-dts-region-comments.ts (100%) rename {lib/vscode/build => build}/lib/eslint/vscode-dts-use-thenable.js (100%) rename {lib/vscode/build => build}/lib/eslint/vscode-dts-use-thenable.ts (100%) rename {lib/vscode/build => build}/lib/extensions.js (73%) rename {lib/vscode/build => build}/lib/extensions.ts (76%) rename {lib/vscode/build => build}/lib/git.js (100%) rename {lib/vscode/build => build}/lib/git.ts (100%) create mode 100644 build/lib/i18n.js rename {lib/vscode/build => build}/lib/i18n.resources.json (100%) rename {lib/vscode/build => build}/lib/i18n.ts (93%) rename {lib/vscode/build => build}/lib/layersChecker.js (100%) rename {lib/vscode/build => build}/lib/layersChecker.ts (100%) rename {lib/vscode/build => build}/lib/monaco-api.js (100%) rename {lib/vscode/build => build}/lib/monaco-api.ts (100%) rename {lib/vscode/build => build}/lib/nls.js (100%) rename {lib/vscode/build => build}/lib/nls.ts (100%) rename {lib/vscode/build => build}/lib/node.js (100%) rename {lib/vscode/build => build}/lib/node.ts (78%) rename {lib/vscode/build => build}/lib/optimize.js (99%) rename {lib/vscode/build => build}/lib/optimize.ts (99%) rename {lib/vscode/build => build}/lib/preLaunch.js (100%) rename {lib/vscode/build => build}/lib/preLaunch.ts (100%) rename {lib/vscode/build => build}/lib/reporter.js (100%) rename {lib/vscode/build => build}/lib/reporter.ts (100%) rename {lib/vscode/build => build}/lib/snapshotLoader.js (100%) rename {lib/vscode/build => build}/lib/snapshotLoader.ts (100%) rename {lib/vscode/build => build}/lib/standalone.js (100%) rename {lib/vscode/build => build}/lib/standalone.ts (100%) rename {lib/vscode/build => build}/lib/stats.js (100%) rename {lib/vscode/build => build}/lib/stats.ts (100%) rename {lib/vscode/build => build}/lib/task.js (100%) rename {lib/vscode/build => build}/lib/task.ts (100%) rename {lib/vscode/build => build}/lib/test/i18n.test.js (100%) rename {lib/vscode/build => build}/lib/test/i18n.test.ts (100%) rename {lib/vscode/build => build}/lib/treeshaking.js (99%) rename {lib/vscode/build => build}/lib/treeshaking.ts (98%) rename {lib/vscode/build => build}/lib/typings/cgmanifest.json (100%) rename {lib/vscode/build => build}/lib/typings/event-stream.d.ts (100%) rename {lib/vscode/build => build}/lib/typings/github-releases.d.ts (100%) rename {lib/vscode/build => build}/lib/typings/gulp-bom.d.ts (100%) rename {lib/vscode/build => build}/lib/typings/gulp-flatmap.d.ts (100%) rename {lib/vscode/build => build}/lib/typings/gulp-remote-src.d.ts (100%) rename {lib/vscode/build => build}/lib/typings/gulp-tsb.d.ts (100%) rename {lib/vscode/build => build}/lib/typings/is.d.ts (100%) rename {lib/vscode/build => build}/lib/typings/lazy.js.d.ts (100%) rename {lib/vscode/build => build}/lib/typings/vinyl.d.ts (100%) rename {lib/vscode/build => build}/lib/util.js (100%) rename {lib/vscode/build => build}/lib/util.ts (99%) rename {lib/vscode/build => build}/lib/watch/.gitignore (100%) rename {lib/vscode/build => build}/lib/watch/index.js (100%) rename {lib/vscode/build => build}/lib/watch/index.ts (100%) rename {lib/vscode/build => build}/lib/watch/package.json (100%) rename {lib/vscode/build => build}/lib/watch/watch-win32.js (100%) rename {lib/vscode/build => build}/lib/watch/watch-win32.ts (100%) rename {lib/vscode/build => build}/lib/watch/watcher.exe (100%) rename {lib/vscode/build => build}/lib/watch/yarn.lock (100%) rename {lib/vscode/build => build}/monaco/LICENSE (100%) rename {lib/vscode/build => build}/monaco/README-npm.md (100%) rename {lib/vscode/build => build}/monaco/README.md (100%) rename {lib/vscode/build => build}/monaco/ThirdPartyNotices.txt (100%) rename {lib/vscode/build => build}/monaco/esm.core.js (100%) rename {lib/vscode/build => build}/monaco/monaco.d.ts.recipe (100%) rename {lib/vscode/build => build}/monaco/monaco.usage.recipe (100%) rename {lib/vscode/build => build}/monaco/monaco.webpack.config.js (100%) rename {lib/vscode/build => build}/monaco/package.json (100%) rename {lib/vscode/build => build}/monaco/version.txt (100%) rename {lib/vscode/build => build}/npm/dirs.js (100%) rename {lib/vscode/build => build}/npm/postinstall.js (100%) rename {lib/vscode/build => build}/npm/preinstall.js (100%) rename {lib/vscode/build => build}/npm/update-all-grammars.js (100%) rename {lib/vscode/build => build}/npm/update-distro.js (100%) create mode 100644 build/npm/update-localization-extension.js rename {lib/vscode/build => build}/package.json (95%) rename {lib/vscode/build => build}/polyfills/vscode-extension-telemetry.js (100%) rename {lib/vscode/build => build}/polyfills/vscode-nls.js (100%) rename {lib/vscode/build => build}/tsconfig.build.json (100%) rename {lib/vscode/build => build}/tsconfig.json (100%) rename {lib/vscode/build => build}/win32/.gitignore (100%) rename {lib/vscode/build => build}/win32/Cargo.lock (100%) rename {lib/vscode/build => build}/win32/code.iss (100%) rename {lib/vscode/build => build}/win32/i18n/Default.hu.isl (100%) rename {lib/vscode/build => build}/win32/i18n/Default.ko.isl (100%) rename {lib/vscode/build => build}/win32/i18n/Default.zh-cn.isl (100%) rename {lib/vscode/build => build}/win32/i18n/Default.zh-tw.isl (100%) rename {lib/vscode/build => build}/win32/i18n/messages.de.isl (100%) rename {lib/vscode/build => build}/win32/i18n/messages.en.isl (100%) rename {lib/vscode/build => build}/win32/i18n/messages.es.isl (100%) rename {lib/vscode/build => build}/win32/i18n/messages.fr.isl (100%) rename {lib/vscode/build => build}/win32/i18n/messages.hu.isl (100%) rename {lib/vscode/build => build}/win32/i18n/messages.it.isl (100%) rename {lib/vscode/build => build}/win32/i18n/messages.ja.isl (100%) rename {lib/vscode/build => build}/win32/i18n/messages.ko.isl (100%) rename {lib/vscode/build => build}/win32/i18n/messages.pt-br.isl (100%) rename {lib/vscode/build => build}/win32/i18n/messages.ru.isl (100%) rename {lib/vscode/build => build}/win32/i18n/messages.tr.isl (100%) rename {lib/vscode/build => build}/win32/i18n/messages.zh-cn.isl (100%) rename {lib/vscode/build => build}/win32/i18n/messages.zh-tw.isl (100%) rename {lib/vscode/build => build}/win32/inno_updater.exe (100%) rename {lib/vscode/build => build}/win32/vcruntime140.dll (100%) rename {lib/vscode/build => build}/yarn.lock (98%) rename lib/vscode/cglicenses.json => cglicenses.json (78%) rename lib/vscode/cgmanifest.json => cgmanifest.json (99%) delete mode 100644 ci/README.md delete mode 100755 ci/build/build-code-server.sh delete mode 100755 ci/build/build-packages.sh delete mode 100755 ci/build/build-release.sh delete mode 100755 ci/build/build-standalone-release.sh delete mode 100755 ci/build/build-vscode.sh delete mode 100755 ci/build/clean.sh delete mode 100755 ci/build/code-server-nfpm.sh delete mode 100644 ci/build/code-server-user.service delete mode 100755 ci/build/code-server.sh delete mode 100644 ci/build/code-server@.service delete mode 100644 ci/build/nfpm.yaml delete mode 100755 ci/build/npm-postinstall.sh delete mode 100755 ci/build/release-github-assets.sh delete mode 100755 ci/build/release-github-draft.sh delete mode 100755 ci/build/release-prep.sh delete mode 100755 ci/build/test-standalone-release.sh delete mode 100755 ci/dev/audit.sh delete mode 100755 ci/dev/ci.sh delete mode 100755 ci/dev/fmt.sh delete mode 100755 ci/dev/gen_icons.sh delete mode 100755 ci/dev/lint.sh delete mode 100755 ci/dev/postinstall.sh delete mode 100755 ci/dev/test-e2e.sh delete mode 100755 ci/dev/test-unit.sh delete mode 100755 ci/dev/update-vscode.sh delete mode 100644 ci/dev/watch.ts delete mode 100644 ci/helm-chart/.helmignore delete mode 100644 ci/helm-chart/Chart.yaml delete mode 100644 ci/helm-chart/README.md delete mode 100644 ci/helm-chart/templates/NOTES.txt delete mode 100644 ci/helm-chart/templates/_helpers.tpl delete mode 100644 ci/helm-chart/templates/deployment.yaml delete mode 100644 ci/helm-chart/templates/ingress.yaml delete mode 100644 ci/helm-chart/templates/pvc.yaml delete mode 100644 ci/helm-chart/templates/secrets.yaml delete mode 100644 ci/helm-chart/templates/service.yaml delete mode 100644 ci/helm-chart/templates/serviceaccount.yaml delete mode 100644 ci/helm-chart/templates/tests/test-connection.yaml delete mode 100644 ci/helm-chart/values.yaml delete mode 100755 ci/lib.sh delete mode 100644 ci/release-image/Dockerfile delete mode 100755 ci/release-image/build.sh delete mode 100755 ci/release-image/entrypoint.sh delete mode 100755 ci/steps/brew-bump.sh delete mode 100755 ci/steps/build-docker-image.sh delete mode 100755 ci/steps/publish-npm.sh delete mode 100755 ci/steps/push-docker-manifest.sh delete mode 100644 docs/CODE_OF_CONDUCT.md delete mode 100644 docs/CONTRIBUTING.md delete mode 100644 docs/FAQ.md delete mode 100644 docs/MAINTAINING.md delete mode 100644 docs/SECURITY.md delete mode 100644 docs/assets/screenshot.png delete mode 100644 docs/guide.md delete mode 100644 docs/install.md delete mode 100644 docs/ipad.md delete mode 100644 docs/npm.md delete mode 100644 docs/termux.md delete mode 100644 docs/triage.md rename {lib/vscode/extensions => extensions}/bat/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/bat/cgmanifest.json (74%) rename {lib/vscode/extensions => extensions}/bat/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/bat/package.json (100%) rename {lib/vscode/extensions => extensions}/bat/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/bat/snippets/batchfile.code-snippets (100%) rename {lib/vscode/extensions => extensions}/bat/syntaxes/batchfile.tmLanguage.json (89%) rename {lib/vscode/extensions => extensions}/bat/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/clojure/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/clojure/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/clojure/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/clojure/package.json (100%) rename {lib/vscode/extensions => extensions}/clojure/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/clojure/syntaxes/clojure.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/clojure/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/coffeescript/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/coffeescript/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/coffeescript/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/coffeescript/package.json (100%) rename {lib/vscode/extensions => extensions}/coffeescript/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/coffeescript/snippets/coffeescript.code-snippets (100%) rename {lib/vscode/extensions => extensions}/coffeescript/syntaxes/coffeescript.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/coffeescript/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/configuration-editing/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/configuration-editing/build/inline-allOf.ts (100%) rename {lib/vscode/extensions => extensions}/configuration-editing/build/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/configuration-editing/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/configuration-editing/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/configuration-editing/images/icon.png (100%) rename {lib/vscode/extensions => extensions}/configuration-editing/package.json (99%) rename {lib/vscode/extensions => extensions}/configuration-editing/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/configuration-editing/schemas/attachContainer.schema.json (85%) rename {lib/vscode/extensions => extensions}/configuration-editing/schemas/devContainer.schema.generated.json (74%) rename {lib/vscode/extensions => extensions}/configuration-editing/schemas/devContainer.schema.src.json (82%) rename {lib/vscode/extensions => extensions}/configuration-editing/src/configurationEditingMain.ts (100%) rename {lib/vscode/extensions => extensions}/configuration-editing/src/extensionsProposals.ts (100%) rename {lib/vscode/extensions => extensions}/configuration-editing/src/settingsDocumentHelper.ts (92%) rename {lib/vscode/extensions => extensions}/configuration-editing/src/typings/ref.d.ts (100%) rename {lib/vscode/extensions => extensions}/configuration-editing/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/configuration-editing/yarn.lock (69%) rename {lib/vscode/extensions => extensions}/cpp/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/cpp/build/update-grammars.js (100%) rename {lib/vscode/extensions => extensions}/cpp/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/cpp/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/cpp/package.json (100%) rename {lib/vscode/extensions => extensions}/cpp/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/cpp/snippets/c.code-snippets (100%) rename {lib/vscode/extensions => extensions}/cpp/snippets/cpp.code-snippets (100%) rename {lib/vscode/extensions => extensions}/cpp/syntaxes/c.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/cpp/syntaxes/cpp.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/cpp/syntaxes/cuda-cpp.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/cpp/syntaxes/platform.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/cpp/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/csharp/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/csharp/cgmanifest.json (86%) rename {lib/vscode/extensions => extensions}/csharp/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/csharp/package.json (100%) rename {lib/vscode/extensions => extensions}/csharp/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/csharp/snippets/csharp.code-snippets (100%) rename {lib/vscode/extensions => extensions}/csharp/syntaxes/csharp.tmLanguage.json (80%) rename {lib/vscode/extensions => extensions}/csharp/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/css-language-features/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/css-language-features/.vscode/settings.json (100%) rename {lib/vscode/extensions => extensions}/css-language-features/.vscode/tasks.json (100%) rename {lib/vscode/extensions => extensions}/css-language-features/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/css-language-features/CONTRIBUTING.md (100%) rename {lib/vscode/extensions => extensions}/css-language-features/README.md (100%) rename {lib/vscode/extensions => extensions}/css-language-features/client/src/browser/cssClientMain.ts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/client/src/cssClient.ts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/client/src/customData.ts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/client/src/node/cssClientMain.ts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/client/src/node/nodeFs.ts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/client/src/requests.ts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/client/src/typings/ref.d.ts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/client/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/css-language-features/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/css-language-features/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/css-language-features/icons/css.png (100%) rename {lib/vscode/extensions => extensions}/css-language-features/package.json (99%) rename {lib/vscode/extensions => extensions}/css-language-features/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/css-language-features/schemas/package.schema.json (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/.vscode/tasks.json (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/package.json (92%) rename {lib/vscode/extensions => extensions}/css-language-features/server/src/browser/cssServerMain.ts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/src/cssServer.ts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/src/customData.ts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/src/languageModelCache.ts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/src/node/cssServerMain.ts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/src/node/nodeFs.ts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/src/requests.ts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/src/test/completion.test.ts (96%) rename {lib/vscode/extensions => extensions}/css-language-features/server/src/test/links.test.ts (89%) rename {lib/vscode/extensions => extensions}/css-language-features/server/src/utils/documentContext.ts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/src/utils/runner.ts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/src/utils/strings.ts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/test/index.js (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/test/linksTestFixtures/.gitignore (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/test/linksTestFixtures/node_modules/foo/package.json (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/test/pathCompletionFixtures/.foo.js (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/test/pathCompletionFixtures/about/about.css (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/test/pathCompletionFixtures/about/about.html (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/test/pathCompletionFixtures/index.html (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/test/pathCompletionFixtures/scss/_foo.scss (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/test/pathCompletionFixtures/scss/main.scss (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/test/pathCompletionFixtures/src/data/foo.asar (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/test/pathCompletionFixtures/src/feature.js (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/test/pathCompletionFixtures/src/test.js (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/css-language-features/server/yarn.lock (84%) rename {lib/vscode/extensions => extensions}/css-language-features/test/mocha.opts (100%) rename {lib/vscode/extensions => extensions}/css-language-features/yarn.lock (93%) rename {lib/vscode/extensions => extensions}/css/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/css/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/css/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/css/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/css/package.json (100%) rename {lib/vscode/extensions => extensions}/css/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/css/syntaxes/css.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/css/yarn.lock (100%) rename {lib/vscode/extensions/julia => extensions/dart}/.vscodeignore (100%) create mode 100644 extensions/dart/cgmanifest.json create mode 100644 extensions/dart/language-configuration.json create mode 100644 extensions/dart/package.json create mode 100644 extensions/dart/package.nls.json create mode 100644 extensions/dart/syntaxes/dart.tmLanguage.json rename {lib/vscode/extensions => extensions}/debug-auto-launch/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/debug-auto-launch/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/debug-auto-launch/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/debug-auto-launch/media/icon.png (100%) rename {lib/vscode/extensions => extensions}/debug-auto-launch/package.json (97%) rename {lib/vscode/extensions => extensions}/debug-auto-launch/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/debug-auto-launch/src/extension.ts (97%) rename {lib/vscode/extensions => extensions}/debug-auto-launch/src/typings/ref.d.ts (100%) rename {lib/vscode/extensions => extensions}/debug-auto-launch/tsconfig.json (100%) rename {lib/vscode/extensions/gulp => extensions/debug-auto-launch}/yarn.lock (56%) rename {lib/vscode/extensions => extensions}/debug-server-ready/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/debug-server-ready/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/debug-server-ready/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/debug-server-ready/media/icon.png (100%) rename {lib/vscode/extensions => extensions}/debug-server-ready/package.json (93%) rename {lib/vscode/extensions => extensions}/debug-server-ready/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/debug-server-ready/src/extension.ts (93%) rename {lib/vscode/extensions => extensions}/debug-server-ready/src/typings/ref.d.ts (100%) rename {lib/vscode/extensions => extensions}/debug-server-ready/tsconfig.json (100%) rename {lib/vscode/extensions/debug-auto-launch => extensions/debug-server-ready}/yarn.lock (56%) rename {lib/vscode/extensions => extensions}/docker/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/docker/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/docker/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/docker/package.json (100%) rename {lib/vscode/extensions => extensions}/docker/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/docker/syntaxes/docker.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/docker/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/emmet/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/emmet/.vscode/settings.json (100%) rename {lib/vscode/extensions => extensions}/emmet/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/emmet/CONTRIBUTING.md (100%) rename {lib/vscode/extensions => extensions}/emmet/README.md (100%) rename {lib/vscode/extensions => extensions}/emmet/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/emmet/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/emmet/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/emmet/images/icon.png (100%) rename {lib/vscode/extensions => extensions}/emmet/package.json (99%) rename {lib/vscode/extensions => extensions}/emmet/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/emmet/src/abbreviationActions.ts (97%) rename {lib/vscode/extensions => extensions}/emmet/src/balance.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/browser/emmetBrowserMain.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/bufferStream.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/defaultCompletionProvider.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/editPoint.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/emmetCommon.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/evaluateMathExpression.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/imageSizeHelper.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/incrementDecrement.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/locateFile.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/matchTag.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/mergeLines.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/node/emmetNodeMain.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/parseDocument.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/reflectCssValue.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/removeTag.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/selectItem.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/selectItemHTML.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/selectItemStylesheet.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/splitJoinTag.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/test/abbreviationAction.test.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/test/completion.test.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/test/cssAbbreviationAction.test.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/test/editPointSelectItemBalance.test.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/test/evaluateMathExpression.test.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/test/incrementDecrement.test.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/test/index.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/test/partialParsingStylesheet.test.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/test/reflectCssValue.test.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/test/tagActions.test.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/test/testUtils.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/test/toggleComment.test.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/test/updateImageSize.test.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/test/wrapWithAbbreviation.test.ts (84%) rename {lib/vscode/extensions => extensions}/emmet/src/toggleComment.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/typings/EmmetFlatNode.d.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/typings/EmmetNode.d.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/typings/emmetio__css-parser.d.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/typings/emmetio__html-matcher.d.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/typings/image-size.d.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/typings/refs.d.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/updateImageSize.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/updateTag.ts (100%) rename {lib/vscode/extensions => extensions}/emmet/src/util.ts (95%) rename {lib/vscode/extensions => extensions}/emmet/test-workspace/.vscode/settings.json (100%) rename {lib/vscode/extensions => extensions}/emmet/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/emmet/yarn.lock (91%) rename {lib/vscode/extensions => extensions}/extension-editing/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/extension-editing/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/extension-editing/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/extension-editing/images/icon.png (100%) rename {lib/vscode/extensions => extensions}/extension-editing/package.json (98%) rename {lib/vscode/extensions => extensions}/extension-editing/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/extension-editing/src/extensionEditingBrowserMain.ts (100%) rename {lib/vscode/extensions => extensions}/extension-editing/src/extensionEditingMain.ts (100%) rename {lib/vscode/extensions => extensions}/extension-editing/src/extensionLinter.ts (100%) rename {lib/vscode/extensions => extensions}/extension-editing/src/packageDocumentHelper.ts (100%) rename {lib/vscode/extensions => extensions}/extension-editing/src/typings/ref.d.ts (100%) rename {lib/vscode/extensions => extensions}/extension-editing/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/extension-editing/yarn.lock (92%) rename {lib/vscode/extensions => extensions}/fsharp/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/fsharp/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/fsharp/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/fsharp/package.json (100%) rename {lib/vscode/extensions => extensions}/fsharp/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/fsharp/snippets/fsharp.code-snippets (100%) rename {lib/vscode/extensions => extensions}/fsharp/syntaxes/fsharp.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/fsharp/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/git/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/git/README.md (100%) rename {lib/vscode/extensions => extensions}/git/build/update-emoji.js (100%) rename {lib/vscode/extensions => extensions}/git/build/update-grammars.js (100%) rename {lib/vscode/extensions => extensions}/git/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/git/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/git/languages/diff.language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/git/languages/git-commit.language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/git/languages/git-rebase.language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/git/languages/ignore.language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/git/package.json (99%) rename {lib/vscode/extensions => extensions}/git/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/git/resources/emojis.json (100%) rename {lib/vscode/extensions => extensions}/git/resources/icons/dark/status-added.svg (100%) rename {lib/vscode/extensions => extensions}/git/resources/icons/dark/status-conflict.svg (100%) rename {lib/vscode/extensions => extensions}/git/resources/icons/dark/status-copied.svg (100%) rename {lib/vscode/extensions => extensions}/git/resources/icons/dark/status-deleted.svg (100%) rename {lib/vscode/extensions => extensions}/git/resources/icons/dark/status-ignored.svg (100%) rename {lib/vscode/extensions => extensions}/git/resources/icons/dark/status-modified.svg (100%) rename {lib/vscode/extensions => extensions}/git/resources/icons/dark/status-renamed.svg (100%) rename {lib/vscode/extensions => extensions}/git/resources/icons/dark/status-untracked.svg (100%) rename {lib/vscode/extensions => extensions}/git/resources/icons/git.png (100%) rename {lib/vscode/extensions => extensions}/git/resources/icons/light/status-added.svg (100%) rename {lib/vscode/extensions => extensions}/git/resources/icons/light/status-conflict.svg (100%) rename {lib/vscode/extensions => extensions}/git/resources/icons/light/status-copied.svg (100%) rename {lib/vscode/extensions => extensions}/git/resources/icons/light/status-deleted.svg (100%) rename {lib/vscode/extensions => extensions}/git/resources/icons/light/status-ignored.svg (100%) rename {lib/vscode/extensions => extensions}/git/resources/icons/light/status-modified.svg (100%) rename {lib/vscode/extensions => extensions}/git/resources/icons/light/status-renamed.svg (100%) rename {lib/vscode/extensions => extensions}/git/resources/icons/light/status-untracked.svg (100%) rename {lib/vscode/extensions => extensions}/git/src/api/api1.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/api/extension.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/api/git.d.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/askpass-empty.sh (100%) rename {lib/vscode/extensions => extensions}/git/src/askpass-main.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/askpass.sh (100%) rename {lib/vscode/extensions => extensions}/git/src/askpass.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/autofetch.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/commands.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/decorationProvider.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/decorators.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/emoji.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/encoding.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/fileSystemProvider.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/git.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/ipc/ipcClient.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/ipc/ipcServer.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/log.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/main.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/model.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/protocolHandler.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/pushError.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/remoteProvider.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/remoteSource.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/repository.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/staging.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/statusbar.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/terminal.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/test/git.test.ts (90%) rename {lib/vscode/extensions => extensions}/git/src/test/index.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/test/smoke.test.ts (86%) rename {lib/vscode/extensions => extensions}/git/src/timelineProvider.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/typings/refs.d.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/uri.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/util.ts (100%) rename {lib/vscode/extensions => extensions}/git/src/watch.ts (100%) rename {lib/vscode/extensions => extensions}/git/syntaxes/diff.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/git/syntaxes/git-commit.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/git/syntaxes/git-rebase.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/git/syntaxes/ignore.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/git/test/colorize-fixtures/COMMIT_EDITMSG (100%) rename {lib/vscode/extensions => extensions}/git/test/colorize-fixtures/example.diff (100%) rename {lib/vscode/extensions => extensions}/git/test/colorize-fixtures/git-rebase-todo (100%) rename {lib/vscode/extensions => extensions}/git/test/colorize-results/COMMIT_EDITMSG.json (100%) rename {lib/vscode/extensions => extensions}/git/test/colorize-results/example_diff.json (100%) rename {lib/vscode/extensions => extensions}/git/test/colorize-results/git-rebase-todo.json (100%) rename {lib/vscode/extensions => extensions}/git/test/mocha.opts (100%) rename {lib/vscode/extensions => extensions}/git/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/git/yarn.lock (96%) rename {lib/vscode/extensions => extensions}/github-authentication/.gitignore (100%) rename {lib/vscode/extensions => extensions}/github-authentication/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/github-authentication/README.md (100%) rename {lib/vscode/extensions => extensions}/github-authentication/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/github-authentication/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/github-authentication/images/icon.png (100%) rename {lib/vscode/extensions => extensions}/github-authentication/package.json (67%) rename {lib/vscode/extensions => extensions}/github-authentication/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/github-authentication/src/common/keychain.ts (89%) rename {lib/vscode/extensions => extensions}/github-authentication/src/common/logger.ts (100%) rename {lib/vscode/extensions => extensions}/github-authentication/src/common/utils.ts (100%) rename {lib/vscode/extensions => extensions}/github-authentication/src/experimentationService.ts (100%) create mode 100644 extensions/github-authentication/src/extension.ts rename {lib/vscode/extensions => extensions}/github-authentication/src/github.ts (59%) rename {lib/vscode/extensions => extensions}/github-authentication/src/githubServer.ts (74%) rename {lib/vscode/extensions/simple-browser => extensions/github-authentication}/src/typings/ref.d.ts (100%) rename {lib/vscode/extensions => extensions}/github-authentication/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/github-authentication/yarn.lock (96%) rename {lib/vscode/extensions => extensions}/github/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/github/README.md (100%) rename {lib/vscode/extensions => extensions}/github/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/github/images/icon.png (100%) rename {lib/vscode/extensions => extensions}/github/package.json (98%) rename {lib/vscode/extensions => extensions}/github/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/github/src/auth.ts (100%) rename {lib/vscode/extensions => extensions}/github/src/commands.ts (100%) rename {lib/vscode/extensions => extensions}/github/src/credentialProvider.ts (100%) rename {lib/vscode/extensions => extensions}/github/src/extension.ts (100%) rename {lib/vscode/extensions => extensions}/github/src/publish.ts (100%) rename {lib/vscode/extensions => extensions}/github/src/pushErrorHandler.ts (100%) rename {lib/vscode/extensions => extensions}/github/src/remoteSourceProvider.ts (100%) rename {lib/vscode/extensions => extensions}/github/src/typings/git.d.ts (100%) rename {lib/vscode/extensions => extensions}/github/src/typings/ref.d.ts (100%) rename {lib/vscode/extensions => extensions}/github/src/util.ts (100%) rename {lib/vscode/extensions => extensions}/github/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/github/yarn.lock (96%) rename {lib/vscode/extensions => extensions}/go/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/go/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/go/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/go/package.json (100%) rename {lib/vscode/extensions => extensions}/go/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/go/syntaxes/go.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/go/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/groovy/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/groovy/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/groovy/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/groovy/package.json (100%) rename {lib/vscode/extensions => extensions}/groovy/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/groovy/snippets/groovy.code-snippets (100%) rename {lib/vscode/extensions => extensions}/groovy/syntaxes/groovy.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/groovy/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/grunt/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/grunt/README.md (100%) rename {lib/vscode/extensions => extensions}/grunt/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/grunt/images/grunt.png (100%) rename {lib/vscode/extensions => extensions}/grunt/package.json (95%) rename {lib/vscode/extensions => extensions}/grunt/package.nls.json (71%) rename {lib/vscode/extensions => extensions}/grunt/src/main.ts (100%) rename {lib/vscode/extensions => extensions}/grunt/src/typings/refs.d.ts (100%) rename {lib/vscode/extensions => extensions}/grunt/tsconfig.json (100%) rename {lib/vscode/extensions/debug-server-ready => extensions/grunt}/yarn.lock (56%) rename {lib/vscode/extensions => extensions}/gulp/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/gulp/README.md (100%) rename {lib/vscode/extensions => extensions}/gulp/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/gulp/images/gulp.png (100%) rename {lib/vscode/extensions => extensions}/gulp/package.json (94%) rename {lib/vscode/extensions => extensions}/gulp/package.nls.json (65%) rename {lib/vscode/extensions => extensions}/gulp/src/main.ts (100%) rename {lib/vscode/extensions => extensions}/gulp/src/typings/refs.d.ts (100%) rename {lib/vscode/extensions => extensions}/gulp/tsconfig.json (100%) rename {lib/vscode/extensions/grunt => extensions/gulp}/yarn.lock (56%) rename {lib/vscode/extensions => extensions}/handlebars/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/handlebars/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/handlebars/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/handlebars/package.json (100%) rename {lib/vscode/extensions => extensions}/handlebars/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/handlebars/syntaxes/Handlebars.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/handlebars/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/hlsl/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/hlsl/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/hlsl/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/hlsl/package.json (100%) rename {lib/vscode/extensions => extensions}/hlsl/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/hlsl/syntaxes/hlsl.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/hlsl/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/html-language-features/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/html-language-features/.vscode/settings.json (100%) rename {lib/vscode/extensions => extensions}/html-language-features/.vscode/tasks.json (100%) rename {lib/vscode/extensions => extensions}/html-language-features/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/html-language-features/CONTRIBUTING.md (100%) rename {lib/vscode/extensions => extensions}/html-language-features/README.md (100%) rename {lib/vscode/extensions => extensions}/html-language-features/build/bundleTypeScriptLibraries.js (100%) rename {lib/vscode/extensions => extensions}/html-language-features/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/html-language-features/client/src/browser/htmlClientMain.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/client/src/customData.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/client/src/htmlClient.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/client/src/htmlEmptyTagsShared.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/client/src/node/htmlClientMain.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/client/src/node/nodeFs.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/client/src/requests.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/client/src/tagClosing.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/client/src/typings/ref.d.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/client/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/html-language-features/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/html-language-features/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/html-language-features/icons/html.png (100%) rename {lib/vscode/extensions => extensions}/html-language-features/package.json (99%) rename {lib/vscode/extensions => extensions}/html-language-features/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/html-language-features/schemas/package.schema.json (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/.vscode/tasks.json (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/build/javaScriptLibraryLoader.js (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/lib/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/lib/jquery.d.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/package.json (89%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/browser/htmlServerMain.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/customData.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/htmlServer.ts (90%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/languageModelCache.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/modes/cssMode.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/modes/embeddedSupport.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/modes/formatting.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/modes/htmlFolding.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/modes/htmlMode.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/modes/javascriptLibs.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/modes/javascriptMode.ts (99%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/modes/javascriptSemanticTokens.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/modes/languageModes.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/modes/selectionRanges.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/modes/semanticTokens.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/node/htmlServerMain.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/node/nodeFs.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/requests.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/completions.test.ts (95%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/documentContext.test.ts (62%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/embedded.test.ts (98%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/fixtures/expected/19813-4spaces.html (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/fixtures/expected/19813-tab.html (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/fixtures/expected/19813.html (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/fixtures/expected/21634.html (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/fixtures/inputs/19813.html (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/fixtures/inputs/21634.html (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/folding.test.ts (99%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/formatting.test.ts (99%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/pathCompletionFixtures/.foo.js (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/pathCompletionFixtures/about/about.css (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/pathCompletionFixtures/about/about.html (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/pathCompletionFixtures/about/media/icon.pic (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/pathCompletionFixtures/index.html (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/pathCompletionFixtures/src/feature.js (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/pathCompletionFixtures/src/test.js (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/rename.test.ts (97%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/selectionRanges.test.ts (95%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/semanticTokens.test.ts (99%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/test/words.test.ts (95%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/utils/arrays.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/utils/documentContext.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/utils/positions.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/utils/runner.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/src/utils/strings.ts (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/test/index.js (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/html-language-features/server/yarn.lock (79%) rename {lib/vscode/extensions => extensions}/html-language-features/yarn.lock (96%) rename {lib/vscode/extensions => extensions}/html/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/html/build/update-grammar.js (100%) rename {lib/vscode/extensions => extensions}/html/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/html/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/html/package.json (100%) rename {lib/vscode/extensions => extensions}/html/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/html/syntaxes/html-derivative.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/html/syntaxes/html.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/html/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/image-preview/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/image-preview/README.md (100%) rename {lib/vscode/extensions => extensions}/image-preview/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/image-preview/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/image-preview/icon.png (100%) rename {lib/vscode/extensions => extensions}/image-preview/icon.svg (100%) rename {lib/vscode/extensions => extensions}/image-preview/media/loading-dark.svg (100%) rename {lib/vscode/extensions => extensions}/image-preview/media/loading-hc.svg (100%) rename {lib/vscode/extensions => extensions}/image-preview/media/loading.svg (100%) rename {lib/vscode/extensions => extensions}/image-preview/media/main.css (100%) rename {lib/vscode/extensions => extensions}/image-preview/media/main.js (100%) rename {lib/vscode/extensions => extensions}/image-preview/package.json (100%) rename {lib/vscode/extensions => extensions}/image-preview/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/image-preview/src/binarySizeStatusBarEntry.ts (89%) rename {lib/vscode/extensions => extensions}/image-preview/src/dispose.ts (100%) rename {lib/vscode/extensions => extensions}/image-preview/src/extension.ts (100%) rename {lib/vscode/extensions => extensions}/image-preview/src/ownedStatusBarEntry.ts (85%) rename {lib/vscode/extensions => extensions}/image-preview/src/preview.ts (100%) rename {lib/vscode/extensions => extensions}/image-preview/src/sizeStatusBarEntry.ts (77%) rename {lib/vscode/extensions => extensions}/image-preview/src/typings/ref.d.ts (100%) rename {lib/vscode/extensions => extensions}/image-preview/src/zoomStatusBarEntry.ts (89%) rename {lib/vscode/extensions => extensions}/image-preview/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/image-preview/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/ini/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/ini/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/ini/ini.language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/ini/package.json (100%) rename {lib/vscode/extensions => extensions}/ini/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/ini/properties.language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/ini/syntaxes/ini.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/ini/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/jake/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/jake/README.md (100%) rename {lib/vscode/extensions => extensions}/jake/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/jake/images/cowboy_hat.png (100%) rename {lib/vscode/extensions => extensions}/jake/package.json (94%) rename {lib/vscode/extensions => extensions}/jake/package.nls.json (65%) rename {lib/vscode/extensions => extensions}/jake/src/main.ts (100%) rename {lib/vscode/extensions => extensions}/jake/src/typings/refs.d.ts (100%) rename {lib/vscode/extensions => extensions}/jake/tsconfig.json (100%) create mode 100644 extensions/jake/yarn.lock rename {lib/vscode/extensions => extensions}/java/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/java/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/java/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/java/package.json (100%) rename {lib/vscode/extensions => extensions}/java/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/java/snippets/java.code-snippets (100%) rename {lib/vscode/extensions => extensions}/java/syntaxes/java.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/java/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/javascript/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/javascript/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/javascript/javascript-language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/javascript/package.json (100%) rename {lib/vscode/extensions => extensions}/javascript/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/javascript/snippets/javascript.code-snippets (100%) rename {lib/vscode/extensions => extensions}/javascript/syntaxes/JavaScript.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/javascript/syntaxes/JavaScriptReact.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/javascript/syntaxes/Readme.md (100%) rename {lib/vscode/extensions => extensions}/javascript/syntaxes/Regular Expressions (JavaScript).tmLanguage (100%) rename {lib/vscode/extensions => extensions}/javascript/tags-language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/javascript/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/json-language-features/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/json-language-features/.vscode/tasks.json (100%) rename {lib/vscode/extensions => extensions}/json-language-features/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/json-language-features/CONTRIBUTING.md (100%) rename {lib/vscode/extensions => extensions}/json-language-features/README.md (100%) rename {lib/vscode/extensions => extensions}/json-language-features/client/src/browser/jsonClientMain.ts (100%) rename {lib/vscode/extensions => extensions}/json-language-features/client/src/jsonClient.ts (99%) rename {lib/vscode/extensions => extensions}/json-language-features/client/src/node/jsonClientMain.ts (100%) rename {lib/vscode/extensions => extensions}/json-language-features/client/src/requests.ts (100%) rename {lib/vscode/extensions => extensions}/json-language-features/client/src/typings/ref.d.ts (100%) rename {lib/vscode/extensions => extensions}/json-language-features/client/src/utils/hash.ts (100%) rename {lib/vscode/extensions => extensions}/json-language-features/client/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/json-language-features/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/json-language-features/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/json-language-features/icons/json.png (100%) rename {lib/vscode/extensions => extensions}/json-language-features/package.json (99%) rename {lib/vscode/extensions => extensions}/json-language-features/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/json-language-features/server/.npmignore (100%) rename {lib/vscode/extensions => extensions}/json-language-features/server/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/json-language-features/server/.vscode/tasks.json (100%) rename {lib/vscode/extensions => extensions}/json-language-features/server/README.md (100%) rename {lib/vscode/extensions => extensions}/json-language-features/server/bin/vscode-json-languageserver (100%) rename {lib/vscode/extensions => extensions}/json-language-features/server/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/json-language-features/server/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/json-language-features/server/package.json (94%) rename {lib/vscode/extensions => extensions}/json-language-features/server/src/browser/jsonServerMain.ts (100%) rename {lib/vscode/extensions => extensions}/json-language-features/server/src/jsonServer.ts (90%) rename {lib/vscode/extensions => extensions}/json-language-features/server/src/languageModelCache.ts (100%) rename {lib/vscode/extensions => extensions}/json-language-features/server/src/node/jsonServerMain.ts (100%) rename {lib/vscode/extensions => extensions}/json-language-features/server/src/requests.ts (100%) rename {lib/vscode/extensions => extensions}/json-language-features/server/src/utils/runner.ts (100%) rename {lib/vscode/extensions => extensions}/json-language-features/server/src/utils/strings.ts (100%) rename {lib/vscode/extensions => extensions}/json-language-features/server/test/mocha.opts (100%) rename {lib/vscode/extensions => extensions}/json-language-features/server/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/json-language-features/server/yarn.lock (93%) rename {lib/vscode/extensions => extensions}/json-language-features/yarn.lock (97%) rename {lib/vscode/extensions => extensions}/json/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/json/build/update-grammars.js (100%) rename {lib/vscode/extensions => extensions}/json/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/json/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/json/package.json (94%) rename {lib/vscode/extensions => extensions}/json/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/json/syntaxes/JSON.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/json/syntaxes/JSONC.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/json/yarn.lock (100%) create mode 100644 extensions/julia/.vscodeignore rename {lib/vscode/extensions => extensions}/julia/cgmanifest.json (83%) rename {lib/vscode/extensions => extensions}/julia/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/julia/package.json (100%) rename {lib/vscode/extensions => extensions}/julia/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/julia/syntaxes/julia.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/less/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/less/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/less/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/less/package.json (100%) rename {lib/vscode/extensions => extensions}/less/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/less/syntaxes/less.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/less/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/log/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/log/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/log/package.json (100%) rename {lib/vscode/extensions => extensions}/log/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/log/syntaxes/log.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/log/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/lua/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/lua/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/lua/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/lua/package.json (100%) rename {lib/vscode/extensions => extensions}/lua/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/lua/syntaxes/lua.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/lua/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/make/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/make/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/make/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/make/package.json (98%) rename {lib/vscode/extensions => extensions}/make/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/make/syntaxes/make.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/make/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/markdown-basics/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/markdown-basics/cgmanifest.json (95%) rename {lib/vscode/extensions => extensions}/markdown-basics/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/markdown-basics/package.json (100%) rename {lib/vscode/extensions => extensions}/markdown-basics/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/markdown-basics/snippets/markdown.code-snippets (100%) rename {lib/vscode/extensions => extensions}/markdown-basics/syntaxes/markdown.tmLanguage.json (95%) rename {lib/vscode/extensions => extensions}/markdown-basics/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/.gitignore (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/README.md (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/esbuild.js (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/icon.png (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/media/highlight.css (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/media/markdown.css (98%) rename {lib/vscode/extensions => extensions}/markdown-language-features/media/preview-dark.svg (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/media/preview-light.svg (100%) create mode 100644 extensions/markdown-language-features/notebook/index.ts rename {lib/vscode/extensions => extensions}/markdown-language-features/notebook/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/package.json (99%) rename {lib/vscode/extensions => extensions}/markdown-language-features/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/preview-src/activeLineMarker.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/preview-src/csp.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/preview-src/events.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/preview-src/index.ts (99%) rename {lib/vscode/extensions => extensions}/markdown-language-features/preview-src/loading.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/preview-src/messaging.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/preview-src/pre.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/preview-src/scroll-sync.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/preview-src/settings.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/preview-src/strings.ts (100%) rename {lib/vscode/extensions/simple-browser => extensions/markdown-language-features}/preview-src/tsconfig.json (69%) rename {lib/vscode/extensions => extensions}/markdown-language-features/schemas/package.schema.json (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/commandManager.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/commands/index.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/commands/moveCursorToPosition.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/commands/openDocumentLink.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/commands/refreshPreview.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/commands/renderDocument.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/commands/showPreview.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/commands/showPreviewSecuritySelector.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/commands/showSource.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/commands/toggleLock.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/extension.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/features/documentLinkProvider.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/features/documentSymbolProvider.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/features/foldingProvider.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/features/preview.ts (93%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/features/previewConfig.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/features/previewContentProvider.ts (99%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/features/previewManager.ts (88%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/features/smartSelect.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/features/workspaceSymbolProvider.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/logger.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/markdownEngine.ts (74%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/markdownExtensions.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/security.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/slugify.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/tableOfContentsProvider.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/telemetryReporter.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/test/documentLink.test.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/test/documentLinkProvider.test.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/test/documentSymbolProvider.test.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/test/engine.test.ts (91%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/test/engine.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/test/foldingProvider.test.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/test/inMemoryDocument.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/test/index.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/test/smartSelect.test.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/test/tableOfContentsProvider.test.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/test/urlToUri.test.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/test/util.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/test/workspaceSymbolProvider.test.ts (98%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/typings/ref.d.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/util/arrays.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/util/dispose.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/util/file.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/util/hash.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/util/lazy.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/util/links.ts (96%) rename lib/vscode/extensions/notebook-markdown-extensions/notebook/emoji.ts => extensions/markdown-language-features/src/util/resources.ts (66%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/util/topmostLineMonitor.ts (71%) rename {lib/vscode/extensions => extensions}/markdown-language-features/src/util/url.ts (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/test-workspace/a.md (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/test-workspace/b.md (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/test-workspace/sub/c.md (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/test-workspace/sub/d.md (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/markdown-language-features/yarn.lock (93%) rename {lib/vscode/extensions => extensions}/merge-conflict/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/README.md (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/media/icon.png (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/package.json (99%) rename {lib/vscode/extensions => extensions}/merge-conflict/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/src/codelensProvider.ts (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/src/commandHandler.ts (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/src/contentProvider.ts (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/src/delayer.ts (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/src/documentMergeConflict.ts (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/src/documentTracker.ts (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/src/interfaces.ts (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/src/mergeConflictMain.ts (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/src/mergeConflictParser.ts (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/src/mergeDecorator.ts (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/src/services.ts (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/src/typings/refs.d.ts (100%) rename {lib/vscode/extensions => extensions}/merge-conflict/tsconfig.json (100%) create mode 100644 extensions/merge-conflict/yarn.lock rename {lib/vscode/extensions => extensions}/microsoft-authentication/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/media/auth.css (100%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/media/auth.html (100%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/media/icon.png (100%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/package.json (98%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/src/AADHelper.ts (96%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/src/authServer.ts (100%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/src/env/browser/authServer.ts (100%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/src/env/browser/sha256.ts (100%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/src/env/node/sha256.ts (100%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/src/extension.ts (100%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/src/keychain.ts (100%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/src/logger.ts (100%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/src/microsoft-authentication.d.ts (100%) rename {lib/vscode/extensions/search-result => extensions/microsoft-authentication}/src/typings/refs.d.ts (100%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/src/utils.ts (100%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/microsoft-authentication/yarn.lock (97%) rename {lib/vscode/extensions => extensions}/notebook-markdown-extensions/.gitignore (100%) rename {lib/vscode/extensions => extensions}/notebook-markdown-extensions/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/notebook-markdown-extensions/README.md (100%) rename {lib/vscode/extensions => extensions}/notebook-markdown-extensions/esbuild.js (100%) rename {lib/vscode/extensions => extensions}/notebook-markdown-extensions/icon.png (100%) rename lib/vscode/extensions/notebook-markdown-extensions/notebook/katex.ts => extensions/notebook-markdown-extensions/notebook/emoji.ts (51%) create mode 100644 extensions/notebook-markdown-extensions/notebook/katex.ts rename {lib/vscode/extensions => extensions}/notebook-markdown-extensions/notebook/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/notebook-markdown-extensions/package.json (75%) rename {lib/vscode/extensions => extensions}/notebook-markdown-extensions/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/notebook-markdown-extensions/yarn.lock (96%) rename {lib/vscode/extensions => extensions}/npm/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/npm/.vscode/tasks.json (100%) rename {lib/vscode/extensions => extensions}/npm/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/npm/README.md (100%) rename {lib/vscode/extensions => extensions}/npm/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/npm/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/npm/images/code.svg (100%) rename {lib/vscode/extensions => extensions}/npm/images/npm_icon.png (100%) rename {lib/vscode/extensions => extensions}/npm/package.json (99%) rename {lib/vscode/extensions => extensions}/npm/package.nls.json (95%) rename {lib/vscode/extensions => extensions}/npm/src/commands.ts (100%) rename {lib/vscode/extensions => extensions}/npm/src/features/bowerJSONContribution.ts (100%) rename {lib/vscode/extensions => extensions}/npm/src/features/jsonContributions.ts (100%) rename {lib/vscode/extensions => extensions}/npm/src/features/packageJSONContribution.ts (100%) rename {lib/vscode/extensions => extensions}/npm/src/npmBrowserMain.ts (100%) rename {lib/vscode/extensions => extensions}/npm/src/npmMain.ts (100%) rename {lib/vscode/extensions => extensions}/npm/src/npmScriptLens.ts (100%) rename {lib/vscode/extensions => extensions}/npm/src/npmView.ts (100%) rename {lib/vscode/extensions => extensions}/npm/src/preferred-pm.ts (100%) rename {lib/vscode/extensions => extensions}/npm/src/readScripts.ts (100%) rename {lib/vscode/extensions => extensions}/npm/src/scriptHover.ts (100%) rename {lib/vscode/extensions => extensions}/npm/src/tasks.ts (100%) rename {lib/vscode/extensions => extensions}/npm/src/typings/refs.d.ts (100%) rename {lib/vscode/extensions => extensions}/npm/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/npm/yarn.lock (97%) rename {lib/vscode/extensions => extensions}/objective-c/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/objective-c/build/update-grammars.js (100%) rename {lib/vscode/extensions => extensions}/objective-c/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/objective-c/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/objective-c/package.json (100%) rename {lib/vscode/extensions => extensions}/objective-c/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/objective-c/syntaxes/objective-c++.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/objective-c/syntaxes/objective-c.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/objective-c/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/package.json (92%) rename {lib/vscode/extensions => extensions}/perl/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/perl/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/perl/package.json (100%) rename {lib/vscode/extensions => extensions}/perl/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/perl/perl.language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/perl/perl6.language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/perl/syntaxes/perl.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/perl/syntaxes/perl6.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/perl/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/php-language-features/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/php-language-features/README.md (100%) rename {lib/vscode/extensions => extensions}/php-language-features/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/php-language-features/icons/logo.png (100%) rename {lib/vscode/extensions => extensions}/php-language-features/package.json (98%) rename {lib/vscode/extensions => extensions}/php-language-features/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/php-language-features/src/features/completionItemProvider.ts (100%) rename {lib/vscode/extensions => extensions}/php-language-features/src/features/hoverProvider.ts (100%) rename {lib/vscode/extensions => extensions}/php-language-features/src/features/phpGlobalFunctions.ts (100%) rename {lib/vscode/extensions => extensions}/php-language-features/src/features/phpGlobals.ts (100%) rename {lib/vscode/extensions => extensions}/php-language-features/src/features/signatureHelpProvider.ts (100%) rename {lib/vscode/extensions => extensions}/php-language-features/src/features/utils/async.ts (100%) rename {lib/vscode/extensions => extensions}/php-language-features/src/features/utils/markedTextUtil.ts (100%) rename {lib/vscode/extensions => extensions}/php-language-features/src/features/validationProvider.ts (94%) rename {lib/vscode/extensions => extensions}/php-language-features/src/phpMain.ts (100%) rename {lib/vscode/extensions => extensions}/php-language-features/src/typings/node.additions.d.ts (100%) rename {lib/vscode/extensions => extensions}/php-language-features/src/typings/refs.d.ts (100%) rename {lib/vscode/extensions => extensions}/php-language-features/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/php-language-features/yarn.lock (80%) rename {lib/vscode/extensions => extensions}/php/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/php/.vscode/tasks.json (100%) rename {lib/vscode/extensions => extensions}/php/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/php/build/update-grammar.js (100%) rename {lib/vscode/extensions => extensions}/php/cgmanifest.json (72%) rename {lib/vscode/extensions => extensions}/php/language-configuration.json (93%) rename {lib/vscode/extensions => extensions}/php/package.json (100%) rename {lib/vscode/extensions => extensions}/php/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/php/snippets/php.code-snippets (100%) create mode 100644 extensions/php/syntaxes/html.tmLanguage.json rename {lib/vscode/extensions => extensions}/php/syntaxes/php.tmLanguage.json (98%) rename {lib/vscode/extensions => extensions}/php/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/postinstall.js (91%) rename {lib/vscode/extensions => extensions}/powershell/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/powershell/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/powershell/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/powershell/package.json (100%) rename {lib/vscode/extensions => extensions}/powershell/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/powershell/snippets/powershell.code-snippets (100%) rename {lib/vscode/extensions => extensions}/powershell/syntaxes/powershell.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/powershell/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/pug/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/pug/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/pug/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/pug/package.json (100%) rename {lib/vscode/extensions => extensions}/pug/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/pug/syntaxes/pug.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/pug/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/python/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/python/.vscode/tasks.json (100%) rename {lib/vscode/extensions => extensions}/python/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/python/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/python/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/python/package.json (100%) rename {lib/vscode/extensions => extensions}/python/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/python/syntaxes/MagicPython.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/python/syntaxes/MagicRegExp.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/python/test/colorize-fixtures/test-freeze-56377.py (100%) rename {lib/vscode/extensions => extensions}/python/test/colorize-fixtures/test.py (100%) rename {lib/vscode/extensions => extensions}/python/test/colorize-results/test-freeze-56377_py.json (100%) rename {lib/vscode/extensions => extensions}/python/test/colorize-results/test_py.json (100%) rename {lib/vscode/extensions => extensions}/python/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/r/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/r/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/r/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/r/package.json (100%) rename {lib/vscode/extensions => extensions}/r/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/r/syntaxes/r.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/r/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/razor/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/razor/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/razor/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/razor/package.json (100%) rename {lib/vscode/extensions => extensions}/razor/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/razor/syntaxes/cshtml.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/razor/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/ruby/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/ruby/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/ruby/language-configuration.json (81%) rename {lib/vscode/extensions => extensions}/ruby/package.json (100%) rename {lib/vscode/extensions => extensions}/ruby/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/ruby/syntaxes/ruby.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/ruby/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/rust/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/rust/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/rust/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/rust/package.json (100%) rename {lib/vscode/extensions => extensions}/rust/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/rust/syntaxes/rust.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/rust/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/scss/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/scss/cgmanifest.json (84%) rename {lib/vscode/extensions => extensions}/scss/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/scss/package.json (100%) rename {lib/vscode/extensions => extensions}/scss/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/scss/syntaxes/sassdoc.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/scss/syntaxes/scss.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/scss/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/search-result/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/search-result/README.md (100%) rename {lib/vscode/extensions => extensions}/search-result/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/search-result/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/search-result/package.json (100%) rename {lib/vscode/extensions => extensions}/search-result/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/search-result/src/extension.ts (100%) rename {lib/vscode/extensions => extensions}/search-result/src/media/refresh-dark.svg (100%) rename {lib/vscode/extensions => extensions}/search-result/src/media/refresh-light.svg (100%) rename {lib/vscode/extensions/testing-editor-contributions => extensions/search-result}/src/typings/refs.d.ts (100%) rename {lib/vscode/extensions => extensions}/search-result/syntaxes/generateTMLanguage.js (100%) rename {lib/vscode/extensions => extensions}/search-result/syntaxes/searchResult.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/search-result/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/search-result/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/shaderlab/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/shaderlab/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/shaderlab/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/shaderlab/package.json (100%) rename {lib/vscode/extensions => extensions}/shaderlab/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/shaderlab/syntaxes/shaderlab.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/shaderlab/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/shared.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/shellscript/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/shellscript/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/shellscript/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/shellscript/package.json (99%) rename {lib/vscode/extensions => extensions}/shellscript/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/shellscript/syntaxes/shell-unix-bash.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/shellscript/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/simple-browser/.gitignore (100%) rename {lib/vscode/extensions => extensions}/simple-browser/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/simple-browser/README.md (100%) rename {lib/vscode/extensions => extensions}/simple-browser/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/simple-browser/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/simple-browser/media/icon.png (100%) rename {lib/vscode/extensions => extensions}/simple-browser/media/main.css (100%) rename {lib/vscode/extensions => extensions}/simple-browser/media/preview-dark.svg (100%) rename {lib/vscode/extensions => extensions}/simple-browser/media/preview-light.svg (100%) rename {lib/vscode/extensions => extensions}/simple-browser/package.json (95%) rename {lib/vscode/extensions => extensions}/simple-browser/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/simple-browser/preview-src/events.ts (100%) rename {lib/vscode/extensions => extensions}/simple-browser/preview-src/index.ts (98%) rename {lib/vscode/extensions/markdown-language-features => extensions/simple-browser}/preview-src/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/simple-browser/src/dispose.ts (100%) rename {lib/vscode/extensions => extensions}/simple-browser/src/extension.ts (100%) rename {lib/vscode/extensions => extensions}/simple-browser/src/simpleBrowserManager.ts (100%) rename {lib/vscode/extensions => extensions}/simple-browser/src/simpleBrowserView.ts (100%) rename {lib/vscode/extensions/github-authentication => extensions/simple-browser}/src/typings/ref.d.ts (83%) rename {lib/vscode/extensions => extensions}/simple-browser/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/simple-browser/webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/simple-browser/yarn.lock (88%) rename {lib/vscode/extensions => extensions}/sql/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/sql/build/update-grammar.js (100%) rename {lib/vscode/extensions => extensions}/sql/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/sql/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/sql/package.json (100%) rename {lib/vscode/extensions => extensions}/sql/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/sql/syntaxes/sql.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/sql/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/swift/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/swift/LICENSE.md (100%) rename {lib/vscode/extensions => extensions}/swift/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/swift/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/swift/package.json (100%) rename {lib/vscode/extensions => extensions}/swift/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/swift/snippets/swift.code-snippets (100%) rename {lib/vscode/extensions => extensions}/swift/syntaxes/swift.tmLanguage.json (99%) rename {lib/vscode/extensions => extensions}/swift/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/testing-editor-contributions/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/testing-editor-contributions/README.md (100%) rename {lib/vscode/extensions => extensions}/testing-editor-contributions/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/testing-editor-contributions/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/testing-editor-contributions/media/icon.png (100%) rename {lib/vscode/extensions => extensions}/testing-editor-contributions/package.json (100%) rename {lib/vscode/extensions => extensions}/testing-editor-contributions/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/testing-editor-contributions/src/extension.ts (100%) rename {lib/vscode/extensions/microsoft-authentication => extensions/testing-editor-contributions}/src/typings/refs.d.ts (83%) rename {lib/vscode/extensions => extensions}/testing-editor-contributions/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/testing-editor-contributions/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/theme-abyss/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/theme-abyss/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/theme-abyss/package.json (100%) rename {lib/vscode/extensions => extensions}/theme-abyss/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/theme-abyss/themes/abyss-color-theme.json (100%) rename {lib/vscode/extensions => extensions}/theme-abyss/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/theme-defaults/fileicons/images/document-dark.svg (100%) rename {lib/vscode/extensions => extensions}/theme-defaults/fileicons/images/document-light.svg (100%) rename {lib/vscode/extensions => extensions}/theme-defaults/fileicons/images/folder-dark.svg (100%) rename {lib/vscode/extensions => extensions}/theme-defaults/fileicons/images/folder-light.svg (100%) rename {lib/vscode/extensions => extensions}/theme-defaults/fileicons/images/folder-open-dark.svg (100%) rename {lib/vscode/extensions => extensions}/theme-defaults/fileicons/images/folder-open-light.svg (100%) rename {lib/vscode/extensions => extensions}/theme-defaults/fileicons/images/root-folder-dark.svg (100%) rename {lib/vscode/extensions => extensions}/theme-defaults/fileicons/images/root-folder-light.svg (100%) rename {lib/vscode/extensions => extensions}/theme-defaults/fileicons/images/root-folder-open-dark.svg (100%) rename {lib/vscode/extensions => extensions}/theme-defaults/fileicons/images/root-folder-open-light.svg (100%) rename {lib/vscode/extensions => extensions}/theme-defaults/fileicons/vs_minimal-icon-theme.json (100%) rename {lib/vscode/extensions => extensions}/theme-defaults/package.json (100%) rename {lib/vscode/extensions => extensions}/theme-defaults/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/theme-defaults/themes/dark_plus.json (100%) rename {lib/vscode/extensions => extensions}/theme-defaults/themes/dark_vs.json (100%) rename {lib/vscode/extensions => extensions}/theme-defaults/themes/hc_black.json (98%) rename {lib/vscode/extensions => extensions}/theme-defaults/themes/light_plus.json (100%) rename {lib/vscode/extensions => extensions}/theme-defaults/themes/light_vs.json (98%) rename {lib/vscode/extensions => extensions}/theme-defaults/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/theme-kimbie-dark/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/theme-kimbie-dark/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/theme-kimbie-dark/package.json (100%) rename {lib/vscode/extensions => extensions}/theme-kimbie-dark/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/theme-kimbie-dark/themes/kimbie-dark-color-theme.json (100%) rename {lib/vscode/extensions => extensions}/theme-kimbie-dark/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/theme-monokai-dimmed/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/theme-monokai-dimmed/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/theme-monokai-dimmed/package.json (100%) rename {lib/vscode/extensions => extensions}/theme-monokai-dimmed/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json (100%) rename {lib/vscode/extensions => extensions}/theme-monokai-dimmed/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/theme-monokai/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/theme-monokai/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/theme-monokai/package.json (100%) rename {lib/vscode/extensions => extensions}/theme-monokai/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/theme-monokai/themes/monokai-color-theme.json (99%) rename {lib/vscode/extensions => extensions}/theme-monokai/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/theme-quietlight/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/theme-quietlight/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/theme-quietlight/package.json (100%) rename {lib/vscode/extensions => extensions}/theme-quietlight/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/theme-quietlight/themes/quietlight-color-theme.json (100%) rename {lib/vscode/extensions => extensions}/theme-quietlight/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/theme-red/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/theme-red/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/theme-red/package.json (100%) rename {lib/vscode/extensions => extensions}/theme-red/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/theme-red/themes/Red-color-theme.json (100%) rename {lib/vscode/extensions => extensions}/theme-red/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/theme-seti/.vscodeignore (100%) create mode 100644 extensions/theme-seti/CONTRIBUTING.md rename {lib/vscode/extensions => extensions}/theme-seti/README.md (100%) rename {lib/vscode/extensions => extensions}/theme-seti/ThirdPartyNotices.txt (100%) rename {lib/vscode/extensions => extensions}/theme-seti/build/update-icon-theme.js (100%) rename {lib/vscode/extensions => extensions}/theme-seti/cgmanifest.json (77%) rename {lib/vscode/extensions => extensions}/theme-seti/icons/preview.html (100%) rename {lib/vscode/extensions => extensions}/theme-seti/icons/seti-circular-128x128.png (100%) create mode 100644 extensions/theme-seti/icons/seti.woff rename {lib/vscode/extensions => extensions}/theme-seti/icons/vs-seti-icon-theme.json (97%) rename {lib/vscode/extensions => extensions}/theme-seti/package.json (100%) rename {lib/vscode/extensions => extensions}/theme-seti/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/theme-seti/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/theme-solarized-dark/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/theme-solarized-dark/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/theme-solarized-dark/package.json (100%) rename {lib/vscode/extensions => extensions}/theme-solarized-dark/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/theme-solarized-dark/themes/solarized-dark-color-theme.json (100%) rename {lib/vscode/extensions => extensions}/theme-solarized-dark/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/theme-solarized-light/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/theme-solarized-light/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/theme-solarized-light/package.json (100%) rename {lib/vscode/extensions => extensions}/theme-solarized-light/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/theme-solarized-light/themes/solarized-light-color-theme.json (98%) rename {lib/vscode/extensions => extensions}/theme-solarized-light/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/theme-tomorrow-night-blue/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/theme-tomorrow-night-blue/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/theme-tomorrow-night-blue/package.json (100%) rename {lib/vscode/extensions => extensions}/theme-tomorrow-night-blue/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/theme-tomorrow-night-blue/themes/tomorrow-night-blue-color-theme.json (100%) rename {lib/vscode/extensions => extensions}/theme-tomorrow-night-blue/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/tsconfig.base.json (100%) rename {lib/vscode/extensions => extensions}/types/lib.textEncoder.d.ts (100%) rename {lib/vscode/extensions => extensions}/types/lib.url.d.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-basics/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/typescript-basics/build/update-grammars.js (100%) rename {lib/vscode/extensions => extensions}/typescript-basics/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/typescript-basics/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/typescript-basics/package.json (100%) rename {lib/vscode/extensions => extensions}/typescript-basics/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/typescript-basics/snippets/typescript.code-snippets (100%) rename {lib/vscode/extensions => extensions}/typescript-basics/syntaxes/Readme.md (100%) rename {lib/vscode/extensions => extensions}/typescript-basics/syntaxes/TypeScript.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/typescript-basics/syntaxes/TypeScriptReact.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/typescript-basics/syntaxes/jsdoc.js.injection.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/typescript-basics/syntaxes/jsdoc.ts.injection.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/typescript-basics/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/.eslintrc.json (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/README.md (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/extension-browser.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/extension.webpack.config.js (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/media/icon.png (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/package.json (98%) rename {lib/vscode/extensions => extensions}/typescript-language-features/package.nls.json (99%) rename {lib/vscode/extensions => extensions}/typescript-language-features/schemas/jsconfig.schema.json (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/schemas/package.schema.json (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/schemas/tsconfig.schema.json (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/api.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/commands/commandManager.ts (66%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/commands/configurePlugin.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/commands/goToProjectConfiguration.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/commands/index.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/commands/learnMoreAboutRefactorings.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/commands/openTsServerLog.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/commands/reloadProject.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/commands/restartTsServer.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/commands/selectTypeScriptVersion.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/extension.browser.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/extension.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/callHierarchy.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/codeLens/baseCodeLensProvider.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/codeLens/implementationsCodeLens.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/codeLens/referencesCodeLens.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/completions.ts (97%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/definitionProviderBase.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/definitions.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/diagnostics.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/directiveCommentCompletions.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/documentHighlight.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/documentSymbol.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts (99%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/fileReferences.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/fixAll.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/folding.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/formatting.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/hover.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/implementations.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/jsDocCompletions.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/languageConfiguration.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/organizeImports.ts (63%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/quickFix.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/refactor.ts (98%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/references.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/rename.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/semanticTokens.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/signatureHelp.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/smartSelect.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/tagClosing.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/tsconfig.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/typeDefinitions.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/updatePathsOnRename.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageFeatures/workspaceSymbols.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/languageProvider.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/lazyClientHost.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/protocol.const.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/protocol.d.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/task/taskProvider.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/task/tsconfigProvider.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test-all.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test/index.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test/smoke/completions.test.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test/smoke/fixAll.test.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test/smoke/index.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test/smoke/jsDocCompletions.test.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test/smoke/quickFix.test.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test/smoke/referencesCodeLens.test.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test/suggestTestHelpers.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test/testUtils.ts (99%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test/unit/cachedResponse.test.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test/unit/functionCallSnippet.test.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test/unit/index.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test/unit/jsdocSnippet.test.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test/unit/onEnter.test.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test/unit/previewer.test.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test/unit/requestQueue.test.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/test/unit/server.test.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/tsServer/bufferSyncSupport.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/tsServer/cachedResponse.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/tsServer/callbackMap.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/tsServer/cancellation.electron.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/tsServer/cancellation.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/tsServer/logDirectoryProvider.electron.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/tsServer/logDirectoryProvider.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/tsServer/requestQueue.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/tsServer/server.ts (86%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/tsServer/serverError.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/tsServer/serverProcess.browser.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/tsServer/serverProcess.electron.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/tsServer/spawner.ts (98%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/tsServer/versionManager.ts (99%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/tsServer/versionProvider.electron.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/tsServer/versionProvider.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/tsServer/versionStatus.ts (96%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/typeScriptServiceClientHost.ts (99%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/typescriptService.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/typescriptServiceClient.ts (96%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/typings/ref.d.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/activeJsTsEditorTracker.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/api.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/arrays.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/async.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/cancellation.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/codeAction.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/configuration.ts (96%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/dependentRegistration.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/dispose.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/documentSelector.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/errorCodes.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/fileSchemes.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/fileSystem.electron.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/fixNames.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/fs.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/languageDescription.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/languageModeIds.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/largeProjectStatus.ts (93%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/lazy.ts (100%) create mode 100644 extensions/typescript-language-features/src/utils/logLevelMonitor.ts rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/logger.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/managedFileContext.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/memoize.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/modifiers.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/objects.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/platform.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/pluginPathsProvider.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/plugins.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/previewer.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/regexp.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/relativePathResolver.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/resourceMap.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/snippetForFunctionCall.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/telemetry.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/temp.electron.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/tracer.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/tsconfig.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/typeConverters.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/src/utils/typingsStatus.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/test-workspace/bar.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/test-workspace/foo.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/test-workspace/foojs.js (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/test-workspace/index.ts (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/test-workspace/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/typescript-language-features/yarn.lock (95%) rename {lib/vscode/extensions => extensions}/vb/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/vb/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/vb/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/vb/package.json (100%) rename {lib/vscode/extensions => extensions}/vb/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/vb/snippets/vb.code-snippets (100%) rename {lib/vscode/extensions => extensions}/vb/syntaxes/asp-vb-net.tmlanguage.json (100%) rename {lib/vscode/extensions => extensions}/vb/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/.gitignore (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/.vscode/tasks.json (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/media/icon.png (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/package.json (95%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/extension.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/memfs.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/commands.test.ts (96%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/configuration.test.ts (72%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/debug.test.ts (80%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/editor.test.ts (81%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/env.test.ts (77%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/extensions.test.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/index.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/languages.test.ts (90%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts (73%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts (83%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/notebook.test.ts (76%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/quickInput.test.ts (85%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/rpc.test.ts (91%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/terminal.test.ts (96%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/types.test.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/webview.test.ts (98%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/window.test.ts (86%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/workspace.event.test.ts (82%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.ts (90%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/singlefolder-tests/workspace.test.ts (84%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/typings/ref.d.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/utils.ts (91%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/workspace-tests/index.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/src/workspace-tests/workspace.test.ts (95%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testWorkspace/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testWorkspace/.vscode/settings.json (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testWorkspace/10linefile.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testWorkspace/30linefile.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testWorkspace/bower.json (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testWorkspace/debug.js (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testWorkspace/far.js (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testWorkspace/files-exclude/file.txt (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testWorkspace/image%.png (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testWorkspace/image%02.png (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testWorkspace/image.png (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testWorkspace/lorem.txt (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testWorkspace/search-exclude/file.txt (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testWorkspace/simple.txt (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testWorkspace/sub/image.png (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testWorkspace2/.vscode/settings.json (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testWorkspace2/simple.txt (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/testworkspace.code-workspace (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/vscode-api-tests/yarn.lock (56%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/.gitignore (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/.vscode/tasks.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/media/icon.png (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/package.json (97%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/producticons/ElegantIcons.woff (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/producticons/index.html (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/producticons/mit_license.txt (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/producticons/test-product-icon-theme.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/src/colorizer.test.ts (93%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/src/colorizerTestMain.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/src/index.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/src/typings/ref.d.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/12750.html (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/13448.html (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/14119.less (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/25920.html (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/Dockerfile (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/basic.java (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/issue-1550.yaml (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/issue-28354.php (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/issue-4008.yaml (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/issue-6303.yaml (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/issue-76997.php (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/makefile (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-13777.go (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-23630.cpp (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-23850.cpp (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-33886.md (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-4287.pug (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-6611.rs (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-7115.xml (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-78769.cpp (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-80644.cpp (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-brackets.tsx (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-cssvariables.less (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-cssvariables.scss (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-embedding.html (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-freeze-56476.ps1 (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-function-inv.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-issue11.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-issue5431.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-issue5465.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-issue5566.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-jsdoc-multiline-type.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-keywords.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-members.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-object-literals.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-regex.coffee (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-strings.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-this.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test-variables.css (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.bat (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.c (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.cc (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.clj (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.coffee (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.cpp (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.cs (68%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.cshtml (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.css (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.cu (100%) create mode 100644 extensions/vscode-colorize-tests/test/colorize-fixtures/test.dart rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.fs (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.go (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.groovy (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.handlebars (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.hbs (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.hlsl (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.html (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.ini (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.jl (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.js (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.jsx (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.less (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.log (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.lua (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.m (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.md (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.mm (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.php (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.pl (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.ps1 (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.pug (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.r (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.rb (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.rs (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.scss (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.sh (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.shader (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.sql (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.swift (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.vb (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.xml (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test.yaml (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test2.pl (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/test6916.js (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-fixtures/tsconfig_off.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/12750_html.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/13448_html.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/14119_less.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/25920_html.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/Dockerfile.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/basic_java.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/issue-1550_yaml.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/issue-28354_php.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/issue-4008_yaml.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/issue-6303_yaml.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/issue-76997_php.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/makefile.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-13777_go.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-23630_cpp.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-23850_cpp.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-33886_md.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-4287_pug.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-6611_rs.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-7115_xml.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-78769_cpp.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-80644_cpp.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-brackets_tsx.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-cssvariables_less.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-cssvariables_scss.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-embedding_html.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-freeze-56476_ps1.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-function-inv_ts.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-issue11_ts.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-issue5431_ts.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-issue5465_ts.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-issue5566_ts.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-jsdoc-multiline-type_ts.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-keywords_ts.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-members_ts.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-object-literals_ts.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-regex_coffee.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-strings_ts.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-this_ts.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test-variables_css.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test2_pl.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test6916_js.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_bat.json (98%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_c.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_cc.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_clj.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_coffee.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_cpp.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_cs.json (65%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_cshtml.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_css.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_cu.json (100%) create mode 100644 extensions/vscode-colorize-tests/test/colorize-results/test_dart.json rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_fs.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_go.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_groovy.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_handlebars.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_hbs.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_hlsl.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_html.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_ini.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_jl.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_js.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_json.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_jsx.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_less.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_log.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_lua.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_m.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_md.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_mm.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_php.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_pl.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_ps1.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_pug.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_r.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_rb.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_rs.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_scss.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_sh.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_shader.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_sql.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_swift.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_ts.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_vb.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_xml.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/test_yaml.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/colorize-results/tsconfig_off_json.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/semantic-test/.vscode/settings.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/test/semantic-test/semantic-test.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/vscode-colorize-tests/yarn.lock (57%) rename {lib/vscode/extensions => extensions}/vscode-custom-editor-tests/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/vscode-custom-editor-tests/customEditorMedia/textEditor.js (100%) rename {lib/vscode/extensions => extensions}/vscode-custom-editor-tests/media/icon.png (100%) rename {lib/vscode/extensions => extensions}/vscode-custom-editor-tests/package.json (97%) rename {lib/vscode/extensions => extensions}/vscode-custom-editor-tests/src/customTextEditor.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-custom-editor-tests/src/dispose.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-custom-editor-tests/src/extension.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-custom-editor-tests/src/test/customEditor.test.ts (92%) rename {lib/vscode/extensions => extensions}/vscode-custom-editor-tests/src/test/index.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-custom-editor-tests/src/test/utils.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-custom-editor-tests/src/typings/ref.d.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-custom-editor-tests/test-workspace/index.abc (100%) rename {lib/vscode/extensions => extensions}/vscode-custom-editor-tests/tsconfig.json (100%) rename {lib/vscode/extensions => extensions}/vscode-custom-editor-tests/yarn.lock (77%) rename {lib/vscode/extensions => extensions}/vscode-notebook-tests/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/vscode-notebook-tests/.vscode/tasks.json (100%) rename {lib/vscode/extensions => extensions}/vscode-notebook-tests/media/icon.png (100%) rename {lib/vscode/extensions => extensions}/vscode-notebook-tests/package.json (90%) rename {lib/vscode/extensions => extensions}/vscode-notebook-tests/src/customRenderer.js (76%) rename {lib/vscode/extensions => extensions}/vscode-notebook-tests/src/extension.ts (77%) rename {lib/vscode/extensions => extensions}/vscode-notebook-tests/src/index.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-notebook-tests/src/typings/ref.d.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-notebook-tests/src/utils.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-notebook-tests/test/customRenderer.vsctestnb (100%) rename {lib/vscode/extensions => extensions}/vscode-notebook-tests/test/empty.vsctestnb (100%) rename {lib/vscode/extensions => extensions}/vscode-notebook-tests/test/first.vsctestnb (100%) rename {lib/vscode/extensions => extensions}/vscode-notebook-tests/test/second.vsctestnb (100%) rename {lib/vscode/extensions => extensions}/vscode-notebook-tests/tsconfig.json (100%) create mode 100644 extensions/vscode-notebook-tests/yarn.lock rename {lib/vscode/extensions => extensions}/vscode-test-resolver/.gitignore (100%) rename {lib/vscode/extensions => extensions}/vscode-test-resolver/.vscode/launch.json (100%) rename {lib/vscode/extensions => extensions}/vscode-test-resolver/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/vscode-test-resolver/media/icon.png (100%) rename {lib/vscode/extensions => extensions}/vscode-test-resolver/package.json (95%) rename {lib/vscode/extensions => extensions}/vscode-test-resolver/scripts/terminateProcess.sh (100%) rename {lib/vscode/extensions => extensions}/vscode-test-resolver/src/download.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-test-resolver/src/extension.ts (97%) rename {lib/vscode/extensions => extensions}/vscode-test-resolver/src/typings/ref.d.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-test-resolver/src/util/processes.ts (100%) rename {lib/vscode/extensions => extensions}/vscode-test-resolver/tsconfig.json (100%) create mode 100644 extensions/vscode-test-resolver/yarn.lock rename {lib/vscode/extensions => extensions}/xml/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/xml/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/xml/package.json (100%) rename {lib/vscode/extensions => extensions}/xml/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/xml/syntaxes/xml.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/xml/syntaxes/xsl.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/xml/xml.language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/xml/xsl.language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/xml/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/yaml/.vscodeignore (100%) rename {lib/vscode/extensions => extensions}/yaml/cgmanifest.json (100%) rename {lib/vscode/extensions => extensions}/yaml/language-configuration.json (100%) rename {lib/vscode/extensions => extensions}/yaml/package.json (100%) rename {lib/vscode/extensions => extensions}/yaml/package.nls.json (100%) rename {lib/vscode/extensions => extensions}/yaml/syntaxes/yaml.tmLanguage.json (100%) rename {lib/vscode/extensions => extensions}/yaml/yarn.lock (100%) rename {lib/vscode/extensions => extensions}/yarn.lock (88%) rename lib/vscode/gulpfile.js => gulpfile.js (100%) delete mode 100755 install.sh delete mode 100644 lib/vscode/.devcontainer/README.md delete mode 100644 lib/vscode/.editorconfig delete mode 100644 lib/vscode/.gitattributes delete mode 100644 lib/vscode/.github/ISSUE_TEMPLATE/config.yml delete mode 100644 lib/vscode/.gitignore delete mode 100644 lib/vscode/LICENSE.txt delete mode 100644 lib/vscode/README.md delete mode 100644 lib/vscode/ThirdPartyNotices.txt delete mode 100644 lib/vscode/build/azure-pipelines/common/createAsset.js delete mode 100644 lib/vscode/build/azure-pipelines/common/sync-mooncake.js delete mode 100644 lib/vscode/build/azure-pipelines/common/sync-mooncake.ts delete mode 100755 lib/vscode/build/azure-pipelines/darwin/publish-server.sh delete mode 100755 lib/vscode/build/azure-pipelines/linux/alpine/publish.sh delete mode 100644 lib/vscode/build/azure-pipelines/sync-mooncake.yml delete mode 100755 lib/vscode/build/azure-pipelines/web/publish.sh delete mode 100644 lib/vscode/build/lib/i18n.js delete mode 100644 lib/vscode/build/npm/update-localization-extension.js delete mode 100644 lib/vscode/coder.js delete mode 100644 lib/vscode/extensions/github-authentication/src/extension.ts delete mode 100644 lib/vscode/extensions/jake/yarn.lock delete mode 100644 lib/vscode/extensions/markdown-language-features/notebook/index.ts delete mode 100644 lib/vscode/extensions/markdown-language-features/src/util/resources.ts delete mode 100644 lib/vscode/extensions/merge-conflict/yarn.lock delete mode 100644 lib/vscode/extensions/php/syntaxes/html.tmLanguage.json delete mode 100644 lib/vscode/extensions/theme-seti/CONTRIBUTING.md delete mode 100644 lib/vscode/extensions/theme-seti/icons/seti.woff delete mode 100644 lib/vscode/extensions/vscode-notebook-tests/yarn.lock delete mode 100644 lib/vscode/extensions/vscode-test-resolver/yarn.lock delete mode 100644 lib/vscode/package.json delete mode 100644 lib/vscode/src/typings/electron.d.ts delete mode 100644 lib/vscode/src/typings/keytar.d.ts delete mode 100644 lib/vscode/src/typings/native-keymap.d.ts delete mode 120000 lib/vscode/src/vs/base/node/proxy_agent.ts delete mode 100644 lib/vscode/src/vs/base/test/browser/comparers.test.ts delete mode 100644 lib/vscode/src/vs/code/electron-sandbox/workbench/workbench.js delete mode 100644 lib/vscode/src/vs/editor/contrib/hover/modesContentHover.ts delete mode 120000 lib/vscode/src/vs/ipc.d.ts delete mode 100644 lib/vscode/src/vs/platform/dialogs/test/common/testDialogService.ts delete mode 100644 lib/vscode/src/vs/platform/opener/browser/link.ts delete mode 100644 lib/vscode/src/vs/platform/state/node/stateService.ts delete mode 100644 lib/vscode/src/vs/platform/state/test/node/state.test.ts delete mode 100644 lib/vscode/src/vs/server/browser/client.ts delete mode 100644 lib/vscode/src/vs/server/common/telemetry.ts delete mode 120000 lib/vscode/src/vs/server/common/util.ts delete mode 100644 lib/vscode/src/vs/server/entry.ts delete mode 100644 lib/vscode/src/vs/server/fork.js delete mode 100644 lib/vscode/src/vs/server/node/channel.ts delete mode 100644 lib/vscode/src/vs/server/node/connection.ts delete mode 100644 lib/vscode/src/vs/server/node/insights.ts delete mode 100644 lib/vscode/src/vs/server/node/ipc.ts delete mode 100644 lib/vscode/src/vs/server/node/logger.ts delete mode 100644 lib/vscode/src/vs/server/node/marketplace.ts delete mode 100644 lib/vscode/src/vs/server/node/nls.ts delete mode 100644 lib/vscode/src/vs/server/node/protocol.ts delete mode 100644 lib/vscode/src/vs/server/node/server.ts delete mode 100644 lib/vscode/src/vs/server/node/util.ts delete mode 100644 lib/vscode/src/vs/workbench/api/common/extHostNotebookKernels.ts delete mode 100644 lib/vscode/src/vs/workbench/api/common/shared/webview.ts delete mode 100644 lib/vscode/src/vs/workbench/api/node/extHostTerminalService.ts delete mode 100644 lib/vscode/src/vs/workbench/browser/parts/editor/media/back-tb.png delete mode 100644 lib/vscode/src/vs/workbench/browser/parts/editor/media/forward-tb.png delete mode 100644 lib/vscode/src/vs/workbench/common/editor/resourceEditorInput.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/cli/node/cli.contribution.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/debug/browser/media/continue-tb.png delete mode 100644 lib/vscode/src/vs/workbench/contrib/debug/browser/media/continue-without-debugging-tb.png delete mode 100644 lib/vscode/src/vs/workbench/contrib/debug/browser/media/pause-tb.png delete mode 100644 lib/vscode/src/vs/workbench/contrib/debug/browser/media/restart-tb.png delete mode 100644 lib/vscode/src/vs/workbench/contrib/debug/browser/media/stepinto-tb.png delete mode 100644 lib/vscode/src/vs/workbench/contrib/debug/browser/media/stepout-tb.png delete mode 100644 lib/vscode/src/vs/workbench/contrib/debug/browser/media/stepover-tb.png delete mode 100644 lib/vscode/src/vs/workbench/contrib/debug/browser/media/stop-tb.png delete mode 100644 lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionEnablementByWorkspaceTrustRequirement.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/extensions/electron-sandbox/extensionsActions.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/issue/electron-sandbox/issueActions.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/notebook/browser/constants.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/cellStatusBar.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/notebook/browser/view/renderers/cellActionView.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/notebook/common/notebookMarkdownRenderer.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/notebook/common/notebookSelector.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/notebook/test/notebookDiff.test.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/notebook/test/notebookEditorModel.test.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/searchEditor/browser/searchEditorModel.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/terminal/browser/terminalTabsWidget.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/terminal/common/terminalMenu.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeContribution.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/terminal/node/terminal.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/terminal/node/terminalEnvironment.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/terminal/node/terminalProfiles.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/testing/browser/explorerProjections/locationStore.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/testing/common/getComputedState.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/webview/common/webviewUri.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/keymaps.png delete mode 100644 lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/openVSC.png delete mode 100644 lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/forwardPorts.png delete mode 100644 lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/keymaps.png delete mode 100644 lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/keymaps.png delete mode 100644 lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/openVSC.png delete mode 100644 lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/pullRequests.png delete mode 100644 lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/remoteTerminal.png delete mode 100644 lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/runProject.png delete mode 100644 lib/vscode/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/workspace/browser/workspaceTrustColors.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts delete mode 100644 lib/vscode/src/vs/workbench/contrib/workspace/browser/workspaceTrustTree.ts delete mode 100644 lib/vscode/src/vs/workbench/electron-sandbox/actions/windowActions.ts delete mode 100644 lib/vscode/src/vs/workbench/services/localizations/browser/localizationsService.ts delete mode 100644 lib/vscode/src/vs/workbench/services/textfile/browser/browserTextFileService.ts delete mode 100644 lib/vscode/src/vs/workbench/services/workingCopy/common/legacyBackupRestorer.ts delete mode 100644 lib/vscode/src/vs/workbench/services/workingCopy/test/browser/legacyBackupRestorer.test.ts delete mode 100644 lib/vscode/src/vs/workbench/services/workspaces/common/workspaceTrust.ts delete mode 100644 lib/vscode/src/vs/workbench/test/browser/api/extHostNotebookKernel2.test.ts delete mode 100644 lib/vscode/src/vs/workbench/test/browser/parts/editor/resourceEditorInput.test.ts delete mode 100644 lib/vscode/yarn.lock rename lib/vscode/product.json => product.json (67%) rename {lib/vscode/remote => remote}/.yarnrc (100%) rename {lib/vscode/remote => remote}/package.json (67%) rename {lib/vscode/remote => remote}/web/package.json (59%) rename {lib/vscode/remote => remote}/web/yarn.lock (54%) rename {lib/vscode/remote => remote}/yarn.lock (89%) rename {lib/vscode/resources => resources}/completions/bash/code (100%) rename {lib/vscode/resources => resources}/completions/zsh/_code (100%) rename {lib/vscode/resources => resources}/darwin/bat.icns (100%) rename {lib/vscode/resources => resources}/darwin/bin/code.sh (100%) rename {lib/vscode/resources => resources}/darwin/bower.icns (100%) rename {lib/vscode/resources => resources}/darwin/c.icns (100%) rename {lib/vscode/resources => resources}/darwin/code.icns (100%) rename {lib/vscode/resources => resources}/darwin/config.icns (100%) rename {lib/vscode/resources => resources}/darwin/cpp.icns (100%) rename {lib/vscode/resources => resources}/darwin/csharp.icns (100%) rename {lib/vscode/resources => resources}/darwin/css.icns (100%) rename {lib/vscode/resources => resources}/darwin/default.icns (100%) rename {lib/vscode/resources => resources}/darwin/go.icns (100%) rename {lib/vscode/resources => resources}/darwin/html.icns (100%) rename {lib/vscode/resources => resources}/darwin/jade.icns (100%) rename {lib/vscode/resources => resources}/darwin/java.icns (100%) rename {lib/vscode/resources => resources}/darwin/javascript.icns (100%) rename {lib/vscode/resources => resources}/darwin/json.icns (100%) rename {lib/vscode/resources => resources}/darwin/less.icns (100%) rename {lib/vscode/resources => resources}/darwin/markdown.icns (100%) rename {lib/vscode/resources => resources}/darwin/php.icns (100%) rename {lib/vscode/resources => resources}/darwin/powershell.icns (100%) rename {lib/vscode/resources => resources}/darwin/python.icns (100%) rename {lib/vscode/resources => resources}/darwin/react.icns (100%) rename {lib/vscode/resources => resources}/darwin/ruby.icns (100%) rename {lib/vscode/resources => resources}/darwin/sass.icns (100%) rename {lib/vscode/resources => resources}/darwin/shell.icns (100%) rename {lib/vscode/resources => resources}/darwin/sql.icns (100%) rename {lib/vscode/resources => resources}/darwin/typescript.icns (100%) rename {lib/vscode/resources => resources}/darwin/vue.icns (100%) rename {lib/vscode/resources => resources}/darwin/xml.icns (100%) rename {lib/vscode/resources => resources}/darwin/yaml.icns (100%) rename {lib/vscode/resources => resources}/linux/bin/code.sh (100%) rename {lib/vscode/resources => resources}/linux/code-url-handler.desktop (87%) rename {lib/vscode/resources => resources}/linux/code-workspace.xml (100%) rename {lib/vscode/resources => resources}/linux/code.appdata.xml (100%) rename {lib/vscode/resources => resources}/linux/code.desktop (82%) rename {lib/vscode/resources => resources}/linux/code.png (100%) rename {lib/vscode/resources => resources}/linux/debian/control.template (100%) rename {lib/vscode/resources => resources}/linux/debian/postinst.template (100%) rename {lib/vscode/resources => resources}/linux/debian/postrm.template (100%) rename {lib/vscode/resources => resources}/linux/debian/prerm.template (100%) rename {lib/vscode/resources => resources}/linux/rpm/code.spec.template (100%) rename {lib/vscode/resources => resources}/linux/rpm/code.xpm (100%) rename {lib/vscode/resources => resources}/linux/rpm/dependencies.json (100%) rename {lib/vscode/resources => resources}/linux/snap/electron-launch (100%) rename {lib/vscode/resources => resources}/linux/snap/snapcraft.yaml (100%) rename {lib/vscode/resources => resources}/web/callback.html (100%) rename {lib/vscode/resources => resources}/web/code-web.js (100%) rename {lib/vscode/resources => resources}/win32/VisualElementsManifest.xml (100%) rename {lib/vscode/resources => resources}/win32/bin/code.cmd (100%) rename {lib/vscode/resources => resources}/win32/bin/code.sh (100%) rename {lib/vscode/resources => resources}/win32/bower.ico (100%) rename {lib/vscode/resources => resources}/win32/c.ico (100%) rename {lib/vscode/resources => resources}/win32/code.ico (100%) rename {lib/vscode/resources => resources}/win32/code_150x150.png (100%) rename {lib/vscode/resources => resources}/win32/code_70x70.png (100%) rename {lib/vscode/resources => resources}/win32/config.ico (100%) rename {lib/vscode/resources => resources}/win32/cpp.ico (100%) rename {lib/vscode/resources => resources}/win32/csharp.ico (100%) rename {lib/vscode/resources => resources}/win32/css.ico (100%) rename {lib/vscode/resources => resources}/win32/default.ico (100%) rename {lib/vscode/resources => resources}/win32/go.ico (100%) rename {lib/vscode/resources => resources}/win32/html.ico (100%) rename {lib/vscode/resources => resources}/win32/inno-big-100.bmp (100%) rename {lib/vscode/resources => resources}/win32/inno-big-125.bmp (100%) rename {lib/vscode/resources => resources}/win32/inno-big-150.bmp (100%) rename {lib/vscode/resources => resources}/win32/inno-big-175.bmp (100%) rename {lib/vscode/resources => resources}/win32/inno-big-200.bmp (100%) rename {lib/vscode/resources => resources}/win32/inno-big-225.bmp (100%) rename {lib/vscode/resources => resources}/win32/inno-big-250.bmp (100%) rename {lib/vscode/resources => resources}/win32/inno-small-100.bmp (100%) rename {lib/vscode/resources => resources}/win32/inno-small-125.bmp (100%) rename {lib/vscode/resources => resources}/win32/inno-small-150.bmp (100%) rename {lib/vscode/resources => resources}/win32/inno-small-175.bmp (100%) rename {lib/vscode/resources => resources}/win32/inno-small-200.bmp (100%) rename {lib/vscode/resources => resources}/win32/inno-small-225.bmp (100%) rename {lib/vscode/resources => resources}/win32/inno-small-250.bmp (100%) rename {lib/vscode/resources => resources}/win32/jade.ico (100%) rename {lib/vscode/resources => resources}/win32/java.ico (100%) rename {lib/vscode/resources => resources}/win32/javascript.ico (100%) rename {lib/vscode/resources => resources}/win32/json.ico (100%) rename {lib/vscode/resources => resources}/win32/less.ico (100%) rename {lib/vscode/resources => resources}/win32/markdown.ico (100%) rename {lib/vscode/resources => resources}/win32/php.ico (100%) rename {lib/vscode/resources => resources}/win32/powershell.ico (100%) rename {lib/vscode/resources => resources}/win32/python.ico (100%) rename {lib/vscode/resources => resources}/win32/react.ico (100%) rename {lib/vscode/resources => resources}/win32/ruby.ico (100%) rename {lib/vscode/resources => resources}/win32/sass.ico (100%) rename {lib/vscode/resources => resources}/win32/shell.ico (100%) rename {lib/vscode/resources => resources}/win32/sql.ico (100%) rename {lib/vscode/resources => resources}/win32/typescript.ico (100%) rename {lib/vscode/resources => resources}/win32/vue.ico (100%) rename {lib/vscode/resources => resources}/win32/xml.ico (100%) rename {lib/vscode/resources => resources}/win32/yaml.ico (100%) rename {lib/vscode/scripts => scripts}/code-cli.bat (100%) rename {lib/vscode/scripts => scripts}/code-cli.sh (100%) rename {lib/vscode/scripts => scripts}/code.bat (100%) rename {lib/vscode/scripts => scripts}/code.sh (98%) rename {lib/vscode/scripts => scripts}/generate-definitelytyped.sh (100%) rename {lib/vscode/scripts => scripts}/node-electron.bat (100%) rename {lib/vscode/scripts => scripts}/node-electron.sh (100%) rename {lib/vscode/scripts => scripts}/npm.bat (100%) rename {lib/vscode/scripts => scripts}/npm.sh (100%) rename {lib/vscode/scripts => scripts}/test-documentation.bat (100%) rename {lib/vscode/scripts => scripts}/test-documentation.sh (100%) rename {lib/vscode/scripts => scripts}/test-integration.bat (100%) rename {lib/vscode/scripts => scripts}/test-integration.sh (91%) rename {lib/vscode/scripts => scripts}/test.bat (95%) rename {lib/vscode/scripts => scripts}/test.sh (67%) rename {lib/vscode/src => src}/bootstrap-amd.js (100%) rename {lib/vscode/src => src}/bootstrap-fork.js (100%) rename {lib/vscode/src => src}/bootstrap-node.js (98%) rename {lib/vscode/src => src}/bootstrap-window.js (96%) rename {lib/vscode/src => src}/bootstrap.js (100%) delete mode 100644 src/browser/favicon.afdesign delete mode 100644 src/browser/media/favicon-dark-support.svg delete mode 100644 src/browser/media/favicon.ico delete mode 100644 src/browser/media/favicon.svg delete mode 100644 src/browser/media/manifest.json delete mode 100644 src/browser/media/pwa-icon-192.png delete mode 100644 src/browser/media/pwa-icon-512.png delete mode 100644 src/browser/media/pwa-icon.png delete mode 100644 src/browser/pages/error.css delete mode 100644 src/browser/pages/error.html delete mode 100644 src/browser/pages/global.css delete mode 100644 src/browser/pages/login.css delete mode 100644 src/browser/pages/login.html delete mode 100644 src/browser/pages/login.ts delete mode 100644 src/browser/pages/vscode.html delete mode 100644 src/browser/pages/vscode.ts delete mode 100644 src/browser/register.ts delete mode 100644 src/browser/robots.txt delete mode 100644 src/browser/serviceWorker.ts rename {lib/vscode/src => src}/buildfile.js (100%) rename {lib/vscode/src => src}/cli.js (100%) delete mode 100644 src/common/emitter.ts delete mode 100644 src/common/http.ts delete mode 100644 src/common/util.ts rename {lib/vscode/src => src}/main.js (100%) delete mode 100644 src/node/app.ts delete mode 100644 src/node/cli.ts delete mode 100644 src/node/coder_cloud.ts delete mode 100644 src/node/constants.ts delete mode 100644 src/node/entry.ts delete mode 100644 src/node/heart.ts delete mode 100644 src/node/http.ts delete mode 100644 src/node/plugin.ts delete mode 100644 src/node/proxy.ts delete mode 100644 src/node/proxy_agent.ts delete mode 100644 src/node/routes/apps.ts delete mode 100644 src/node/routes/domainProxy.ts delete mode 100644 src/node/routes/health.ts delete mode 100644 src/node/routes/index.ts delete mode 100644 src/node/routes/login.ts delete mode 100644 src/node/routes/logout.ts delete mode 100644 src/node/routes/pathProxy.ts delete mode 100644 src/node/routes/static.ts delete mode 100644 src/node/routes/update.ts delete mode 100644 src/node/routes/vscode.ts delete mode 100644 src/node/settings.ts delete mode 100644 src/node/socket.ts delete mode 100644 src/node/update.ts delete mode 100644 src/node/util.ts delete mode 100644 src/node/vscode.ts delete mode 100644 src/node/wrapper.ts delete mode 100644 src/node/wsRouter.ts rename {lib/vscode/src => src}/tsconfig.base.json (100%) rename {lib/vscode/src => src}/tsconfig.json (100%) rename {lib/vscode/src => src}/tsconfig.monaco.json (100%) rename {lib/vscode/src => src}/tsconfig.tsec.json (100%) rename {lib/vscode/src => src}/tsec.exemptions.json (96%) rename {lib/vscode/src => src}/typings/require.d.ts (100%) rename {lib/vscode/src => src}/typings/thenable.d.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/browser.ts (97%) rename {lib/vscode/src => src}/vs/base/browser/canIUse.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/contextmenu.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/dnd.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/dom.ts (94%) rename {lib/vscode/src => src}/vs/base/browser/event.ts (59%) rename {lib/vscode/src => src}/vs/base/browser/fastDomNode.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/formattedTextRenderer.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/globalMouseMoveMonitor.ts (96%) rename {lib/vscode/src => src}/vs/base/browser/hash.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/history.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/iframe.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/keyboardEvent.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/markdownRenderer.ts (97%) rename {lib/vscode/src => src}/vs/base/browser/mouseEvent.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/touch.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/actionbar/actionViewItems.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/actionbar/actionbar.css (92%) rename {lib/vscode/src => src}/vs/base/browser/ui/actionbar/actionbar.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/aria/aria.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/aria/aria.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/button/button.css (98%) rename {lib/vscode/src => src}/vs/base/browser/ui/button/button.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/centered/centeredViewLayout.ts (99%) rename {lib/vscode/src => src}/vs/base/browser/ui/checkbox/checkbox.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/checkbox/checkbox.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/codicons/codicon/codicon-modifiers.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/codicons/codicon/codicon.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/codicons/codicon/codicon.ttf (91%) rename {lib/vscode/src => src}/vs/base/browser/ui/codicons/codiconStyles.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/contextview/contextview.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/contextview/contextview.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/countBadge/countBadge.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/countBadge/countBadge.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/dialog/dialog.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/dialog/dialog.ts (93%) rename {lib/vscode/src => src}/vs/base/browser/ui/dropdown/dropdown.css (82%) rename {lib/vscode/src => src}/vs/base/browser/ui/dropdown/dropdown.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/findinput/findInput.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/findinput/findInput.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/findinput/findInputCheckboxes.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/findinput/replaceInput.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/grid/grid.ts (98%) rename {lib/vscode/src => src}/vs/base/browser/ui/grid/gridview.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/grid/gridview.ts (94%) rename {lib/vscode/src => src}/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/hover/hover.css (96%) rename {lib/vscode/src => src}/vs/base/browser/ui/hover/hoverWidget.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/iconLabel/iconHoverDelegate.ts (94%) rename {lib/vscode/src => src}/vs/base/browser/ui/iconLabel/iconLabel.ts (63%) create mode 100644 src/vs/base/browser/ui/iconLabel/iconLabelHover.ts rename {lib/vscode/src => src}/vs/base/browser/ui/iconLabel/iconLabels.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/iconLabel/iconlabel.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/iconLabel/simpleIconLabel.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/inputbox/inputBox.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/inputbox/inputBox.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/keybindingLabel/keybindingLabel.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/keybindingLabel/keybindingLabel.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/list/list.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/list/list.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/list/listPaging.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/list/listView.ts (99%) rename {lib/vscode/src => src}/vs/base/browser/ui/list/listWidget.ts (99%) rename {lib/vscode/src => src}/vs/base/browser/ui/list/rangeMap.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/list/rowCache.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/list/splice.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/menu/menu.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/menu/menubar.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/menu/menubar.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/mouseCursor/mouseCursor.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/mouseCursor/mouseCursor.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/progressbar/progressbar.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/progressbar/progressbar.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/sash/sash.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/sash/sash.ts (72%) rename {lib/vscode/src => src}/vs/base/browser/ui/scrollbar/abstractScrollbar.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/scrollbar/media/scrollbars.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/scrollbar/scrollableElement.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/scrollbar/scrollableElementOptions.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/scrollbar/scrollbarArrow.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/scrollbar/scrollbarState.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/scrollbar/verticalScrollbar.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/selectBox/selectBox.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/selectBox/selectBox.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/selectBox/selectBoxCustom.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/selectBox/selectBoxCustom.ts (99%) rename {lib/vscode/src => src}/vs/base/browser/ui/selectBox/selectBoxNative.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/splitview/paneview.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/splitview/paneview.ts (99%) rename {lib/vscode/src => src}/vs/base/browser/ui/splitview/splitview.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/splitview/splitview.ts (99%) rename {lib/vscode/src => src}/vs/base/browser/ui/table/table.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/table/table.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/table/tableWidget.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/toolbar/toolbar.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/toolbar/toolbar.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/tree/abstractTree.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/tree/asyncDataTree.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/tree/compressedObjectTreeModel.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/tree/dataTree.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/tree/indexTree.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/tree/indexTreeModel.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/tree/media/paneviewlet.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/tree/media/tree.css (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/tree/objectTree.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/tree/objectTreeModel.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/tree/tree.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/tree/treeDefaults.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/tree/treeIcons.ts (100%) rename {lib/vscode/src => src}/vs/base/browser/ui/widget.ts (100%) rename {lib/vscode/src => src}/vs/base/common/actions.ts (96%) rename {lib/vscode/src => src}/vs/base/common/amd.ts (100%) rename {lib/vscode/src => src}/vs/base/common/arrays.ts (95%) rename {lib/vscode/src => src}/vs/base/common/assert.ts (100%) rename {lib/vscode/src => src}/vs/base/common/async.ts (99%) rename {lib/vscode/src => src}/vs/base/common/buffer.ts (100%) rename {lib/vscode/src => src}/vs/base/common/cache.ts (100%) rename {lib/vscode/src => src}/vs/base/common/cancellation.ts (100%) rename {lib/vscode/src => src}/vs/base/common/charCode.ts (100%) rename {lib/vscode/src => src}/vs/base/common/codicons.ts (99%) rename {lib/vscode/src => src}/vs/base/common/collections.ts (85%) rename {lib/vscode/src => src}/vs/base/common/color.ts (99%) rename {lib/vscode/src => src}/vs/base/common/comparers.ts (58%) rename {lib/vscode/src => src}/vs/base/common/console.ts (100%) rename {lib/vscode/src => src}/vs/base/common/date.ts (100%) rename {lib/vscode/src => src}/vs/base/common/decorators.ts (68%) rename {lib/vscode/src => src}/vs/base/common/diff/diff.ts (100%) rename {lib/vscode/src => src}/vs/base/common/diff/diffChange.ts (100%) rename {lib/vscode/src => src}/vs/base/common/errorMessage.ts (100%) rename {lib/vscode/src => src}/vs/base/common/errors.ts (100%) rename {lib/vscode/src => src}/vs/base/common/event.ts (96%) rename {lib/vscode/src => src}/vs/base/common/extpath.ts (93%) rename {lib/vscode/src => src}/vs/base/common/filters.ts (100%) rename {lib/vscode/src => src}/vs/base/common/functional.ts (100%) rename {lib/vscode/src => src}/vs/base/common/fuzzyScorer.ts (100%) rename {lib/vscode/src => src}/vs/base/common/glob.ts (100%) rename {lib/vscode/src => src}/vs/base/common/hash.ts (100%) rename {lib/vscode/src => src}/vs/base/common/history.ts (100%) rename {lib/vscode/src => src}/vs/base/common/htmlContent.ts (88%) rename {lib/vscode/src => src}/vs/base/common/iconLabels.ts (100%) rename {lib/vscode/src => src}/vs/base/common/idGenerator.ts (100%) rename {lib/vscode/src => src}/vs/base/common/insane/cgmanifest.json (100%) rename {lib/vscode/src => src}/vs/base/common/insane/insane.d.ts (100%) rename {lib/vscode/src => src}/vs/base/common/insane/insane.js (100%) rename {lib/vscode/src => src}/vs/base/common/insane/insane.license.txt (100%) rename {lib/vscode/src => src}/vs/base/common/iterator.ts (96%) rename {lib/vscode/src => src}/vs/base/common/json.ts (100%) rename {lib/vscode/src => src}/vs/base/common/jsonEdit.ts (100%) rename {lib/vscode/src => src}/vs/base/common/jsonErrorMessages.ts (100%) rename {lib/vscode/src => src}/vs/base/common/jsonFormatter.ts (100%) rename {lib/vscode/src => src}/vs/base/common/jsonSchema.ts (100%) rename {lib/vscode/src => src}/vs/base/common/keyCodes.ts (100%) rename {lib/vscode/src => src}/vs/base/common/keybindingLabels.ts (100%) rename {lib/vscode/src => src}/vs/base/common/keybindingParser.ts (100%) rename {lib/vscode/src => src}/vs/base/common/labels.ts (100%) rename {lib/vscode/src => src}/vs/base/common/lazy.ts (100%) rename {lib/vscode/src => src}/vs/base/common/lifecycle.ts (100%) rename {lib/vscode/src => src}/vs/base/common/linkedList.ts (94%) rename {lib/vscode/src => src}/vs/base/common/linkedText.ts (100%) rename {lib/vscode/src => src}/vs/base/common/map.ts (98%) rename {lib/vscode/src => src}/vs/base/common/marked/cgmanifest.json (100%) rename {lib/vscode/src => src}/vs/base/common/marked/marked.d.ts (100%) rename {lib/vscode/src => src}/vs/base/common/marked/marked.js (100%) rename {lib/vscode/src => src}/vs/base/common/marked/marked.license.txt (100%) rename {lib/vscode/src => src}/vs/base/common/marshalling.ts (100%) rename {lib/vscode/src => src}/vs/base/common/mime.ts (94%) rename {lib/vscode/src => src}/vs/base/common/navigator.ts (100%) rename {lib/vscode/src => src}/vs/base/common/network.ts (96%) rename {lib/vscode/src => src}/vs/base/common/normalization.ts (100%) rename {lib/vscode/src => src}/vs/base/common/numbers.ts (100%) rename {lib/vscode/src => src}/vs/base/common/objects.ts (95%) rename {lib/vscode/src => src}/vs/base/common/paging.ts (100%) rename {lib/vscode/src => src}/vs/base/common/parsers.ts (100%) rename {lib/vscode/src => src}/vs/base/common/path.ts (100%) rename {lib/vscode/src => src}/vs/base/common/performance.d.ts (100%) rename {lib/vscode/src => src}/vs/base/common/performance.js (100%) rename {lib/vscode/src => src}/vs/base/common/platform.ts (93%) create mode 100644 src/vs/base/common/ports.ts rename {lib/vscode/src => src}/vs/base/common/process.ts (94%) rename {lib/vscode/src => src}/vs/base/common/processes.ts (99%) rename {lib/vscode/src => src}/vs/base/common/product.ts (95%) rename {lib/vscode/src => src}/vs/base/common/range.ts (100%) rename {lib/vscode/src => src}/vs/base/common/resourceTree.ts (100%) rename {lib/vscode/src => src}/vs/base/common/resources.ts (98%) rename {lib/vscode/src => src}/vs/base/common/scanCode.ts (100%) rename {lib/vscode/src => src}/vs/base/common/scrollable.ts (100%) rename {lib/vscode/src => src}/vs/base/common/search.ts (100%) rename {lib/vscode/src => src}/vs/base/common/semver/cgmanifest.json (100%) rename {lib/vscode/src => src}/vs/base/common/semver/semver.d.ts (100%) rename {lib/vscode/src => src}/vs/base/common/semver/semver.js (100%) rename {lib/vscode/src => src}/vs/base/common/sequence.ts (100%) rename {lib/vscode/src => src}/vs/base/common/severity.ts (100%) rename {lib/vscode/src => src}/vs/base/common/skipList.ts (100%) rename {lib/vscode/src => src}/vs/base/common/stopwatch.ts (100%) rename {lib/vscode/src => src}/vs/base/common/stream.ts (100%) rename {lib/vscode/src => src}/vs/base/common/strings.ts (96%) rename {lib/vscode/src => src}/vs/base/common/styler.ts (100%) rename {lib/vscode/src => src}/vs/base/common/types.ts (100%) rename {lib/vscode/src => src}/vs/base/common/uint.ts (100%) rename {lib/vscode/src => src}/vs/base/common/uri.ts (99%) rename {lib/vscode/src => src}/vs/base/common/uriIpc.ts (81%) rename {lib/vscode/src => src}/vs/base/common/uuid.ts (100%) rename {lib/vscode/src => src}/vs/base/common/worker/simpleWorker.ts (100%) rename {lib/vscode/src => src}/vs/base/node/cpuUsage.sh (100%) rename {lib/vscode/src => src}/vs/base/node/crypto.ts (100%) rename {lib/vscode/src => src}/vs/base/node/decoder.ts (100%) rename {lib/vscode/src => src}/vs/base/node/extpath.ts (95%) rename {lib/vscode/src => src}/vs/base/node/id.ts (100%) rename {lib/vscode/src => src}/vs/base/node/languagePacks.d.ts (100%) rename {lib/vscode/src => src}/vs/base/node/languagePacks.js (97%) rename {lib/vscode/src => src}/vs/base/node/macAddress.ts (100%) rename {lib/vscode/src => src}/vs/base/node/pfs.ts (88%) rename {lib/vscode/src => src}/vs/base/node/ports.ts (94%) rename {lib/vscode/src => src}/vs/base/node/powershell.ts (100%) rename {lib/vscode/src => src}/vs/base/node/processes.ts (99%) rename {lib/vscode/src => src}/vs/base/node/ps.sh (100%) rename {lib/vscode/src => src}/vs/base/node/ps.ts (100%) rename {lib/vscode/src => src}/vs/base/node/shell.ts (100%) rename {lib/vscode/src => src}/vs/base/node/terminalEncoding.ts (100%) rename {lib/vscode/src => src}/vs/base/node/terminateProcess.sh (100%) rename {lib/vscode/src => src}/vs/base/node/watcher.ts (100%) rename {lib/vscode/src => src}/vs/base/node/zip.ts (96%) rename {lib/vscode/src => src}/vs/base/parts/contextmenu/common/contextmenu.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/contextmenu/electron-main/contextmenu.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/contextmenu/electron-sandbox/contextmenu.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/ipc/browser/ipc.mp.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/ipc/common/ipc.electron.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/ipc/common/ipc.mp.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/ipc/common/ipc.net.ts (99%) rename {lib/vscode/src => src}/vs/base/parts/ipc/common/ipc.ts (99%) rename {lib/vscode/src => src}/vs/base/parts/ipc/electron-browser/ipc.mp.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/ipc/electron-main/ipc.electron.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/ipc/electron-main/ipc.mp.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/ipc/electron-sandbox/ipc.electron.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/ipc/node/ipc.cp.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/ipc/node/ipc.net.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/ipc/test/browser/ipc.mp.test.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/ipc/test/common/ipc.test.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/ipc/test/electron-sandbox/ipc.mp.test.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/ipc/test/node/ipc.cp.test.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/ipc/test/node/ipc.net.test.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/ipc/test/node/testApp.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/ipc/test/node/testService.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/quickinput/browser/media/quickInput.css (90%) rename {lib/vscode/src => src}/vs/base/parts/quickinput/browser/quickInput.ts (98%) rename {lib/vscode/src => src}/vs/base/parts/quickinput/browser/quickInputBox.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/quickinput/browser/quickInputList.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/quickinput/browser/quickInputUtils.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/quickinput/common/quickInput.ts (95%) rename {lib/vscode/src => src}/vs/base/parts/request/browser/request.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/request/common/request.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/sandbox/common/electronTypes.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/sandbox/common/sandboxTypes.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/sandbox/electron-browser/preload.js (96%) rename {lib/vscode/src => src}/vs/base/parts/sandbox/electron-sandbox/electronTypes.ts (87%) rename {lib/vscode/src => src}/vs/base/parts/sandbox/electron-sandbox/globals.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/sandbox/test/electron-sandbox/globals.test.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/storage/common/storage.ts (100%) rename {lib/vscode/src => src}/vs/base/parts/storage/node/storage.ts (98%) rename {lib/vscode/src => src}/vs/base/parts/storage/test/node/storage.test.ts (99%) rename {lib/vscode/src => src}/vs/base/test/browser/actionbar.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/browser.test.ts (100%) create mode 100644 src/vs/base/test/browser/comparers.test.ts rename {lib/vscode/src => src}/vs/base/test/browser/dom.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/formattedTextRenderer.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/hash.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/highlightedLabel.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/iconLabels.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/markdownRenderer.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/progressBar.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/ui/contextview/contextview.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/ui/grid/grid.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/ui/grid/gridview.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/ui/grid/util.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/ui/list/listView.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/ui/list/rangeMap.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/ui/menu/menubar.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/ui/scrollbar/scrollableElement.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/ui/scrollbar/scrollbarState.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/ui/splitview/splitview.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/ui/tree/asyncDataTree.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/ui/tree/compressedObjectTreeModel.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/ui/tree/dataTree.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/ui/tree/indexTreeModel.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/ui/tree/objectTree.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/browser/ui/tree/objectTreeModel.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/arrays.test.ts (92%) rename {lib/vscode/src => src}/vs/base/test/common/assert.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/async.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/buffer.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/cache.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/cancellation.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/charCode.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/codicons.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/collections.test.ts (73%) rename {lib/vscode/src => src}/vs/base/test/common/color.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/console.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/decorators.test.ts (88%) rename {lib/vscode/src => src}/vs/base/test/common/diff/diff.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/errors.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/event.test.ts (92%) rename {lib/vscode/src => src}/vs/base/test/common/extpath.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/filters.perf.data.d.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/filters.perf.data.js (100%) rename {lib/vscode/src => src}/vs/base/test/common/filters.perf.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/filters.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/fuzzyScorer.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/glob.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/history.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/iconLabels.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/iterator.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/json.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/jsonEdit.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/jsonFormatter.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/keyCodes.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/labels.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/lazy.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/lifecycle.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/linkedList.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/linkedText.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/map.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/markdownString.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/marshalling.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/mime.test.ts (91%) rename {lib/vscode/src => src}/vs/base/test/common/mock.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/network.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/normalization.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/objects.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/paging.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/path.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/processes.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/resourceTree.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/resources.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/scrollable.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/skipList.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/stream.test.ts (99%) rename {lib/vscode/src => src}/vs/base/test/common/strings.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/troubleshooting.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/types.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/uri.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/utils.ts (100%) rename {lib/vscode/src => src}/vs/base/test/common/uuid.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/node/crypto.test.ts (87%) rename {lib/vscode/src => src}/vs/base/test/node/decoder.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/node/extpath.test.ts (92%) rename {lib/vscode/src => src}/vs/base/test/node/id.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/node/keytar.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/node/pfs/fixtures/examples/company.jxs (100%) rename {lib/vscode/src => src}/vs/base/test/node/pfs/fixtures/examples/conway.jxs (100%) rename {lib/vscode/src => src}/vs/base/test/node/pfs/fixtures/examples/employee.jxs (100%) rename {lib/vscode/src => src}/vs/base/test/node/pfs/fixtures/examples/small.jxs (100%) rename {lib/vscode/src => src}/vs/base/test/node/pfs/fixtures/index.html (100%) rename {lib/vscode/src => src}/vs/base/test/node/pfs/fixtures/site.css (100%) rename {lib/vscode/src => src}/vs/base/test/node/pfs/pfs.test.ts (94%) rename {lib/vscode/src => src}/vs/base/test/node/port.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/node/powershell.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/node/processes/fixtures/fork.ts (100%) rename {lib/vscode/src => src}/vs/base/test/node/processes/fixtures/fork_large.ts (100%) rename {lib/vscode/src => src}/vs/base/test/node/processes/processes.test.ts (100%) rename {lib/vscode/src => src}/vs/base/test/node/testUtils.ts (100%) rename {lib/vscode/src => src}/vs/base/test/node/uri.test.data.txt (100%) rename {lib/vscode/src => src}/vs/base/test/node/uri.test.perf.ts (100%) rename {lib/vscode/src => src}/vs/base/test/node/zip/fixtures/extract.zip (100%) rename {lib/vscode/src => src}/vs/base/test/node/zip/zip.test.ts (89%) create mode 100644 src/vs/base/test/parts/quickinput/browser/quickinput.test.ts rename {lib/vscode/src => src}/vs/base/worker/defaultWorkerFactory.ts (100%) rename {lib/vscode/src => src}/vs/base/worker/workerMain.ts (100%) rename {lib/vscode/src => src}/vs/code/browser/workbench/callback.html (100%) rename {lib/vscode/src => src}/vs/code/browser/workbench/workbench-dev.html (100%) rename {lib/vscode/src => src}/vs/code/browser/workbench/workbench.html (100%) rename {lib/vscode/src => src}/vs/code/browser/workbench/workbench.ts (89%) rename {lib/vscode/src => src}/vs/code/buildfile.js (100%) rename {lib/vscode/src => src}/vs/code/electron-browser/sharedProcess/contrib/deprecatedExtensionsCleaner.ts (100%) rename {lib/vscode/src => src}/vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner.ts (93%) rename {lib/vscode/src => src}/vs/code/electron-browser/sharedProcess/contrib/localizationsUpdater.ts (100%) rename {lib/vscode/src => src}/vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner.ts (100%) rename {lib/vscode/src => src}/vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner.ts (94%) rename {lib/vscode/src => src}/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts (94%) rename {lib/vscode/src => src}/vs/code/electron-browser/sharedProcess/sharedProcess.html (100%) rename {lib/vscode/src => src}/vs/code/electron-browser/sharedProcess/sharedProcess.js (90%) rename {lib/vscode/src => src}/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts (98%) rename {lib/vscode/src => src}/vs/code/electron-browser/workbench/workbench.html (79%) rename {lib/vscode/src => src}/vs/code/electron-browser/workbench/workbench.js (86%) rename {lib/vscode/src => src}/vs/code/electron-main/app.ts (93%) rename {lib/vscode/src => src}/vs/code/electron-main/auth.ts (100%) rename {lib/vscode/src => src}/vs/code/electron-main/main.ts (91%) rename {lib/vscode/src => src}/vs/code/electron-sandbox/issue/issueReporter.html (100%) rename {lib/vscode/src => src}/vs/code/electron-sandbox/issue/issueReporter.js (89%) rename {lib/vscode/src => src}/vs/code/electron-sandbox/issue/issueReporterMain.ts (98%) rename {lib/vscode/src => src}/vs/code/electron-sandbox/issue/issueReporterModel.ts (98%) rename {lib/vscode/src => src}/vs/code/electron-sandbox/issue/issueReporterPage.ts (100%) rename {lib/vscode/src => src}/vs/code/electron-sandbox/issue/media/issueReporter.css (100%) rename {lib/vscode/src => src}/vs/code/electron-sandbox/issue/test/testReporterModel.test.ts (98%) rename {lib/vscode/src => src}/vs/code/electron-sandbox/processExplorer/media/processExplorer.css (98%) rename {lib/vscode/src => src}/vs/code/electron-sandbox/processExplorer/processExplorer.html (100%) rename {lib/vscode/src => src}/vs/code/electron-sandbox/processExplorer/processExplorer.js (89%) rename {lib/vscode/src => src}/vs/code/electron-sandbox/processExplorer/processExplorerMain.ts (86%) rename {lib/vscode/src => src}/vs/code/electron-sandbox/workbench/workbench.html (79%) create mode 100644 src/vs/code/electron-sandbox/workbench/workbench.js rename {lib/vscode/src => src}/vs/code/node/cli.ts (97%) rename {lib/vscode/src => src}/vs/code/node/cliProcessMain.ts (92%) rename {lib/vscode/src => src}/vs/css.build.js (100%) rename {lib/vscode/src => src}/vs/css.d.ts (100%) rename {lib/vscode/src => src}/vs/css.js (100%) rename {lib/vscode/src => src}/vs/editor/browser/config/charWidthReader.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/config/configuration.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/config/elementSizeObserver.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/controller/coreCommands.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/controller/mouseHandler.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/controller/mouseTarget.ts (88%) rename {lib/vscode/src => src}/vs/editor/browser/controller/pointerHandler.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/controller/textAreaHandler.css (100%) rename {lib/vscode/src => src}/vs/editor/browser/controller/textAreaHandler.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/controller/textAreaInput.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/controller/textAreaState.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/core/editorState.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/core/keybindingCancellation.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/core/markdownRenderer.ts (96%) rename {lib/vscode/src => src}/vs/editor/browser/editorBrowser.ts (99%) rename {lib/vscode/src => src}/vs/editor/browser/editorDom.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/editorExtensions.ts (93%) rename {lib/vscode/src => src}/vs/editor/browser/services/abstractCodeEditorService.ts (97%) rename {lib/vscode/src => src}/vs/editor/browser/services/bulkEditService.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/services/codeEditorService.ts (86%) rename {lib/vscode/src => src}/vs/editor/browser/services/codeEditorServiceImpl.ts (97%) rename {lib/vscode/src => src}/vs/editor/browser/services/markerDecorations.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/services/openerService.ts (92%) rename {lib/vscode/src => src}/vs/editor/browser/view/domLineBreaksComputer.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/view/dynamicViewOverlay.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/view/viewController.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/view/viewImpl.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/view/viewLayer.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/view/viewOverlays.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/view/viewPart.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/view/viewUserInputEvents.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.css (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/decorations/decorations.css (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/decorations/decorations.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/glyphMargin/glyphMargin.css (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/indentGuides/indentGuides.css (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/indentGuides/indentGuides.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/lineNumbers/lineNumbers.css (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/lines/rangeUtil.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/lines/viewLine.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/lines/viewLines.css (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/lines/viewLines.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/linesDecorations/linesDecorations.css (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/margin/margin.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/marginDecorations/marginDecorations.css (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/marginDecorations/marginDecorations.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/minimap/minimap.css (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/minimap/minimap.ts (99%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/minimap/minimapCharRenderer.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/minimap/minimapCharRendererFactory.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/minimap/minimapCharSheet.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/minimap/minimapPreBaked.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.css (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/rulers/rulers.css (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/rulers/rulers.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.css (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/selections/selections.css (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/selections/selections.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/viewCursors/viewCursor.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/viewCursors/viewCursors.css (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/viewCursors/viewCursors.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/viewParts/viewZones/viewZones.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/widget/codeEditorWidget.ts (97%) rename {lib/vscode/src => src}/vs/editor/browser/widget/diffEditorWidget.ts (99%) rename {lib/vscode/src => src}/vs/editor/browser/widget/diffNavigator.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/widget/diffReview.ts (98%) rename {lib/vscode/src => src}/vs/editor/browser/widget/embeddedCodeEditorWidget.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/widget/inlineDiffMargin.ts (100%) rename {lib/vscode/src => src}/vs/editor/browser/widget/media/diffEditor.css (100%) rename {lib/vscode/src => src}/vs/editor/browser/widget/media/diffReview.css (100%) rename {lib/vscode/src => src}/vs/editor/browser/widget/media/editor.css (100%) rename {lib/vscode/src => src}/vs/editor/common/commands/replaceCommand.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/commands/shiftCommand.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/commands/surroundSelectionCommand.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/commands/trimTrailingWhitespaceCommand.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/config/commonEditorConfig.ts (99%) rename {lib/vscode/src => src}/vs/editor/common/config/editorOptions.ts (97%) rename {lib/vscode/src => src}/vs/editor/common/config/editorZoom.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/config/fontInfo.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/controller/cursor.ts (99%) rename {lib/vscode/src => src}/vs/editor/common/controller/cursorAtomicMoveOperations.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/controller/cursorCollection.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/controller/cursorColumnSelection.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/controller/cursorCommon.ts (91%) rename {lib/vscode/src => src}/vs/editor/common/controller/cursorDeleteOperations.ts (78%) rename {lib/vscode/src => src}/vs/editor/common/controller/cursorEvents.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/controller/cursorMoveCommands.ts (93%) rename {lib/vscode/src => src}/vs/editor/common/controller/cursorMoveOperations.ts (75%) rename {lib/vscode/src => src}/vs/editor/common/controller/cursorTypeOperations.ts (93%) rename {lib/vscode/src => src}/vs/editor/common/controller/cursorWordOperations.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/controller/oneCursor.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/controller/wordCharacterClassifier.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/core/characterClassifier.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/core/editOperation.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/core/lineTokens.ts (91%) rename {lib/vscode/src => src}/vs/editor/common/core/position.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/core/range.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/core/rgba.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/core/selection.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/core/stringBuilder.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/core/token.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/diff/diffComputer.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/editorAction.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/editorCommon.ts (99%) rename {lib/vscode/src => src}/vs/editor/common/editorContextKeys.ts (97%) rename {lib/vscode/src => src}/vs/editor/common/model.ts (98%) rename {lib/vscode/src => src}/vs/editor/common/model/editStack.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/model/indentationGuesser.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/model/intervalTree.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/model/mirrorTextModel.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/model/textChange.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/model/textModel.ts (98%) rename {lib/vscode/src => src}/vs/editor/common/model/textModelEvents.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/model/textModelSearch.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/model/textModelTokens.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/model/tokensStore.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/model/wordHelper.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/modes.ts (92%) rename {lib/vscode/src => src}/vs/editor/common/modes/abstractMode.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/modes/languageConfiguration.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/modes/languageConfigurationRegistry.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/modes/languageFeatureRegistry.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/modes/languageSelector.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/modes/linkComputer.ts (99%) rename {lib/vscode/src => src}/vs/editor/common/modes/modesRegistry.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/modes/nullMode.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/modes/supports.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/modes/supports/characterPair.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/modes/supports/electricCharacter.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/modes/supports/indentRules.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/modes/supports/inplaceReplaceSupport.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/modes/supports/onEnter.ts (96%) rename {lib/vscode/src => src}/vs/editor/common/modes/supports/richEditBrackets.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/modes/supports/tokenization.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/modes/textToHtmlTokenizer.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/modes/tokenization/typescript.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/modes/tokenizationRegistry.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/editorSimpleWorker.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/editorWorkerService.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/editorWorkerServiceImpl.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/getIconClasses.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/getSemanticTokens.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/languagesRegistry.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/markerDecorationsServiceImpl.ts (99%) rename {lib/vscode/src => src}/vs/editor/common/services/markersDecorationService.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/modeService.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/modeServiceImpl.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/modelService.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/modelServiceImpl.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/modelUndoRedoParticipant.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/resolverService.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/semanticTokensDto.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/semanticTokensProviderStyling.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/textResourceConfigurationService.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/textResourceConfigurationServiceImpl.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/services/webWorker.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/standalone/standaloneBase.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/standalone/standaloneEnums.ts (85%) rename {lib/vscode/src => src}/vs/editor/common/standaloneStrings.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/view/editorColorRegistry.ts (95%) rename {lib/vscode/src => src}/vs/editor/common/view/overviewZoneManager.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/view/renderingContext.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/view/viewContext.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/view/viewEvents.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/viewLayout/lineDecorations.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/viewLayout/linesLayout.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/viewLayout/viewLayout.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/viewLayout/viewLineRenderer.ts (97%) rename {lib/vscode/src => src}/vs/editor/common/viewLayout/viewLinesViewportData.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/viewModel/minimapTokensColorTracker.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/viewModel/prefixSumComputer.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/viewModel/splitLinesCollection.ts (94%) rename {lib/vscode/src => src}/vs/editor/common/viewModel/viewEventHandler.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/viewModel/viewModel.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/viewModel/viewModelDecorations.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/viewModel/viewModelEventDispatcher.ts (100%) rename {lib/vscode/src => src}/vs/editor/common/viewModel/viewModelImpl.ts (98%) rename {lib/vscode/src => src}/vs/editor/contrib/anchorSelect/anchorSelect.css (100%) rename {lib/vscode/src => src}/vs/editor/contrib/anchorSelect/anchorSelect.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/bracketMatching/bracketMatching.css (100%) rename {lib/vscode/src => src}/vs/editor/contrib/bracketMatching/bracketMatching.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/bracketMatching/test/bracketMatching.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/caretOperations/caretOperations.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/caretOperations/moveCaretCommand.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/caretOperations/test/moveCarretCommand.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/caretOperations/transpose.ts (97%) rename {lib/vscode/src => src}/vs/editor/contrib/clipboard/clipboard.ts (94%) rename {lib/vscode/src => src}/vs/editor/contrib/codeAction/codeAction.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/codeAction/codeActionCommands.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/codeAction/codeActionContributions.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/codeAction/codeActionMenu.ts (97%) rename {lib/vscode/src => src}/vs/editor/contrib/codeAction/codeActionModel.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/codeAction/codeActionUi.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/codeAction/lightBulbWidget.css (100%) rename {lib/vscode/src => src}/vs/editor/contrib/codeAction/lightBulbWidget.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/codeAction/test/codeAction.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/codeAction/test/codeActionKeybindingResolver.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/codeAction/test/codeActionModel.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/codeAction/types.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/codelens/codeLensCache.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/codelens/codelens.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/codelens/codelensController.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/codelens/codelensWidget.css (100%) rename {lib/vscode/src => src}/vs/editor/contrib/codelens/codelensWidget.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/colorPicker/color.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/colorPicker/colorContributions.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/colorPicker/colorDetector.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/colorPicker/colorPicker.css (100%) rename {lib/vscode/src => src}/vs/editor/contrib/colorPicker/colorPickerModel.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/colorPicker/colorPickerWidget.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/colorPicker/images/opacity-background.png (100%) rename {lib/vscode/src => src}/vs/editor/contrib/comment/blockCommentCommand.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/comment/comment.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/comment/lineCommentCommand.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/comment/test/blockCommentCommand.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/comment/test/lineCommentCommand.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/contextmenu/contextmenu.ts (96%) rename {lib/vscode/src => src}/vs/editor/contrib/cursorUndo/cursorUndo.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/cursorUndo/test/cursorUndo.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/dnd/dnd.css (100%) rename {lib/vscode/src => src}/vs/editor/contrib/dnd/dnd.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/dnd/dragAndDropCommand.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/documentSymbols/documentSymbols.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/documentSymbols/outlineModel.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/documentSymbols/test/outlineModel.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/find/findController.ts (94%) rename {lib/vscode/src => src}/vs/editor/contrib/find/findDecorations.ts (98%) rename {lib/vscode/src => src}/vs/editor/contrib/find/findModel.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/find/findOptionsWidget.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/find/findState.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/find/findWidget.css (100%) rename {lib/vscode/src => src}/vs/editor/contrib/find/findWidget.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/find/replaceAllCommand.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/find/replacePattern.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/find/test/find.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/find/test/findController.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/find/test/findModel.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/find/test/replacePattern.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/folding/folding.css (100%) rename {lib/vscode/src => src}/vs/editor/contrib/folding/folding.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/folding/foldingDecorations.ts (92%) rename {lib/vscode/src => src}/vs/editor/contrib/folding/foldingModel.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/folding/foldingRanges.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/folding/hiddenRangeModel.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/folding/indentRangeProvider.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/folding/intializingRangeProvider.ts (97%) rename {lib/vscode/src => src}/vs/editor/contrib/folding/syntaxRangeProvider.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/folding/test/foldingModel.test.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/folding/test/foldingRanges.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/folding/test/hiddenRangeModel.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/folding/test/indentFold.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/folding/test/indentRangeProvider.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/folding/test/syntaxFold.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/fontZoom/fontZoom.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/format/format.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/format/formatActions.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/format/formattingEdit.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/gotoError/gotoError.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/gotoError/gotoErrorWidget.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/gotoError/markerNavigationService.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/gotoError/media/gotoErrorWidget.css (100%) rename {lib/vscode/src => src}/vs/editor/contrib/gotoSymbol/goToCommands.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/gotoSymbol/goToSymbol.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/gotoSymbol/link/clickLinkGesture.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.css (100%) rename {lib/vscode/src => src}/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/gotoSymbol/peek/referencesController.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/gotoSymbol/peek/referencesTree.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/gotoSymbol/peek/referencesWidget.css (100%) rename {lib/vscode/src => src}/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/gotoSymbol/referencesModel.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/gotoSymbol/symbolNavigation.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/gotoSymbol/test/referencesModel.test.ts (100%) create mode 100644 src/vs/editor/contrib/hover/colorHoverParticipant.ts rename {lib/vscode/src => src}/vs/editor/contrib/hover/getHover.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/hover/hover.ts (83%) rename {lib/vscode/src => src}/vs/editor/contrib/hover/hoverOperation.ts (100%) create mode 100644 src/vs/editor/contrib/hover/hoverTypes.ts rename {lib/vscode/src => src}/vs/editor/contrib/hover/hoverWidgets.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/hover/markdownHoverParticipant.ts (67%) rename {lib/vscode/src => src}/vs/editor/contrib/hover/markerHoverParticipant.ts (83%) create mode 100644 src/vs/editor/contrib/hover/modesContentHover.ts rename {lib/vscode/src => src}/vs/editor/contrib/hover/modesGlyphHover.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/inPlaceReplace/inPlaceReplace.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/inPlaceReplace/inPlaceReplaceCommand.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/indentation/indentUtils.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/indentation/indentation.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/indentation/test/indentation.test.ts (100%) rename lib/vscode/src/vs/editor/contrib/inlineHints/inlineHintsController.ts => src/vs/editor/contrib/inlayHints/inlayHintsController.ts (68%) create mode 100644 src/vs/editor/contrib/inlineCompletions/ghostText.css create mode 100644 src/vs/editor/contrib/inlineCompletions/ghostTextController.ts create mode 100644 src/vs/editor/contrib/inlineCompletions/ghostTextWidget.ts create mode 100644 src/vs/editor/contrib/inlineCompletions/inlineCompletionsHoverParticipant.ts create mode 100644 src/vs/editor/contrib/inlineCompletions/inlineCompletionsModel.ts create mode 100644 src/vs/editor/contrib/inlineCompletions/suggestWidgetAdapterModel.ts create mode 100644 src/vs/editor/contrib/inlineCompletions/utils.ts rename {lib/vscode/src => src}/vs/editor/contrib/linesOperations/copyLinesCommand.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/linesOperations/linesOperations.ts (96%) rename {lib/vscode/src => src}/vs/editor/contrib/linesOperations/moveLinesCommand.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/linesOperations/sortLinesCommand.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/linesOperations/test/copyLinesCommand.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/linesOperations/test/linesOperations.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/linesOperations/test/moveLinesCommand.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/linesOperations/test/sortLinesCommand.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/linkedEditing/linkedEditing.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/linkedEditing/test/linkedEditing.test..ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/links/getLinks.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/links/links.css (100%) rename {lib/vscode/src => src}/vs/editor/contrib/links/links.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/message/messageController.css (100%) rename {lib/vscode/src => src}/vs/editor/contrib/message/messageController.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/multicursor/multicursor.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/multicursor/test/multicursor.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/parameterHints/parameterHints.css (100%) rename {lib/vscode/src => src}/vs/editor/contrib/parameterHints/parameterHints.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/parameterHints/parameterHintsModel.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/parameterHints/parameterHintsWidget.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/parameterHints/provideSignatureHelp.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/parameterHints/test/parameterHintsModel.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/peekView/media/peekViewWidget.css (98%) rename {lib/vscode/src => src}/vs/editor/contrib/peekView/peekView.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/quickAccess/commandsQuickAccess.ts (91%) rename {lib/vscode/src => src}/vs/editor/contrib/quickAccess/editorNavigationQuickAccess.ts (98%) rename {lib/vscode/src => src}/vs/editor/contrib/quickAccess/gotoLineQuickAccess.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/quickAccess/gotoSymbolQuickAccess.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/rename/rename.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/rename/renameInputField.css (100%) rename {lib/vscode/src => src}/vs/editor/contrib/rename/renameInputField.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/smartSelect/bracketSelections.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/smartSelect/smartSelect.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/smartSelect/test/smartSelect.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/smartSelect/wordSelections.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/snippet/snippet.md (100%) rename {lib/vscode/src => src}/vs/editor/contrib/snippet/snippetController2.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/snippet/snippetParser.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/snippet/snippetSession.css (100%) rename {lib/vscode/src => src}/vs/editor/contrib/snippet/snippetSession.ts (97%) rename {lib/vscode/src => src}/vs/editor/contrib/snippet/snippetVariables.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/snippet/test/snippetController2.old.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/snippet/test/snippetController2.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/snippet/test/snippetParser.test.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/snippet/test/snippetSession.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/snippet/test/snippetVariables.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/completionModel.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/media/suggest.css (99%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/resizable.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/suggest.ts (98%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/suggestAlternatives.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/suggestCommitCharacters.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/suggestController.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/suggestMemory.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/suggestModel.ts (98%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/suggestOvertypingCapturer.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/suggestWidget.ts (95%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/suggestWidgetDetails.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/suggestWidgetRenderer.ts (95%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/suggestWidgetStatus.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/test/completionModel.test.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/test/suggest.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/test/suggestController.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/test/suggestMemory.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/test/suggestModel.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/test/wordDistance.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/wordContextKey.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/suggest/wordDistance.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/symbolIcons/symbolIcons.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/tokenization/tokenization.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/unusualLineTerminators/unusualLineTerminators.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/viewportSemanticTokens/viewportSemanticTokens.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/wordHighlighter/wordHighlighter.ts (99%) rename {lib/vscode/src => src}/vs/editor/contrib/wordOperations/test/wordOperations.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/wordOperations/test/wordTestUtils.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/wordOperations/wordOperations.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/wordPartOperations/test/wordPartOperations.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/wordPartOperations/wordPartOperations.ts (100%) rename {lib/vscode/src => src}/vs/editor/contrib/zoneWidget/zoneWidget.css (100%) rename {lib/vscode/src => src}/vs/editor/contrib/zoneWidget/zoneWidget.ts (98%) rename {lib/vscode/src => src}/vs/editor/editor.all.ts (95%) rename {lib/vscode/src => src}/vs/editor/editor.api.ts (100%) rename {lib/vscode/src => src}/vs/editor/editor.main.ts (100%) rename {lib/vscode/src => src}/vs/editor/editor.worker.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.css (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/colorizer.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.css (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts (97%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-dark.svg (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-light.svg (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/inspectTokens/inspectTokens.css (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess.ts (93%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/quickAccess/standaloneGotoLineQuickAccess.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/quickAccess/standaloneGotoSymbolQuickAccess.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/quickAccess/standaloneHelpQuickAccess.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/quickInput/standaloneQuickInput.css (88%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/quickInput/standaloneQuickInputServiceImpl.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/simpleServices.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/standalone-tokens.css (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/standaloneCodeEditor.ts (97%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/standaloneCodeServiceImpl.ts (88%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/standaloneEditor.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/standaloneLanguages.ts (98%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/standaloneServices.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts (99%) rename {lib/vscode/src => src}/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/common/monarch/monarchCommon.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/common/monarch/monarchCompile.ts (98%) rename {lib/vscode/src => src}/vs/editor/standalone/common/monarch/monarchLexer.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/common/monarch/monarchTypes.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/common/standaloneThemeService.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/common/themes.ts (97%) rename {lib/vscode/src => src}/vs/editor/standalone/test/browser/simpleServices.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/test/browser/standaloneLanguages.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/standalone/test/monarch/monarch.test.ts (93%) rename {lib/vscode/src => src}/vs/editor/test/browser/commands/shiftCommand.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/browser/commands/sideEditing.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/browser/commands/trimTrailingWhitespaceCommand.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/browser/controller/cursor.test.ts (96%) rename {lib/vscode/src => src}/vs/editor/test/browser/controller/cursorMoveCommand.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/browser/controller/imeTester.html (100%) rename {lib/vscode/src => src}/vs/editor/test/browser/controller/imeTester.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/browser/controller/inputRecorder.html (100%) rename {lib/vscode/src => src}/vs/editor/test/browser/controller/textAreaState.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/browser/core/editorState.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/browser/editorTestServices.ts (92%) rename {lib/vscode/src => src}/vs/editor/test/browser/services/decorationRenderOptions.test.ts (87%) rename {lib/vscode/src => src}/vs/editor/test/browser/services/openerService.test.ts (74%) rename {lib/vscode/src => src}/vs/editor/test/browser/testCodeEditor.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/browser/testCommand.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/browser/view/minimapCharRenderer.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/browser/view/viewLayer.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/commentMode.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/config/commonEditorConfig.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/controller/cursorAtomicMoveOperations.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/controller/cursorMoveHelper.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/core/characterClassifier.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/core/lineTokens.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/core/range.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/core/stringBuilder.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/core/viewLineToken.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/diff/diffComputer.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/editorTestUtils.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/mocks/mockMode.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/mocks/testConfiguration.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/benchmark/benchmarkUtils.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/benchmark/bootstrap.js (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/benchmark/entry.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/benchmark/modelbuilder.benchmark.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/benchmark/operations.benchmark.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/benchmark/searchNReplace.benchmark.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/editStack.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/editableTextModel.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/editableTextModelAuto.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/editableTextModelTestUtils.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/intervalTree.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/linesTextBuffer/linesTextBuffer.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/linesTextBuffer/linesTextBufferBuilder.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/linesTextBuffer/textBufferAutoTestUtils.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/model.line.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/model.modes.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/model.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/modelDecorations.test.ts (97%) rename {lib/vscode/src => src}/vs/editor/test/common/model/modelEditOperation.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/textChange.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/textModel.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/textModelSearch.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/textModelWithTokens.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/model/tokensStore.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/modes/languageConfiguration.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/modes/languageSelector.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/modes/linkComputer.test.ts (90%) rename {lib/vscode/src => src}/vs/editor/test/common/modes/supports/characterPair.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/modes/supports/electricCharacter.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/modes/supports/javascriptOnEnterRules.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/modes/supports/onEnter.test.ts (84%) rename {lib/vscode/src => src}/vs/editor/test/common/modes/supports/richEditBrackets.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/modes/supports/tokenization.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/modes/textToHtmlTokenizer.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/modesTestUtils.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/services/editorSimpleWorker.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/services/languagesRegistry.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/services/modelService.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/services/semanticTokensDto.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/services/testTextResourcePropertiesService.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/services/textResourceConfigurationService.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/view/overviewZoneManager.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/viewLayout/lineDecorations.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/viewLayout/linesLayout.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts (95%) rename {lib/vscode/src => src}/vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/viewModel/prefixSumComputer.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/viewModel/splitLinesCollection.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/viewModel/testViewModel.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/common/viewModel/viewModelDecorations.test.ts (99%) rename {lib/vscode/src => src}/vs/editor/test/common/viewModel/viewModelImpl.test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/node/classification/typescript-test.ts (100%) rename {lib/vscode/src => src}/vs/editor/test/node/classification/typescript.test.ts (100%) rename {lib/vscode/src => src}/vs/loader.js (100%) rename {lib/vscode/src => src}/vs/monaco.d.ts (96%) rename {lib/vscode/src => src}/vs/nls.build.js (100%) rename {lib/vscode/src => src}/vs/nls.d.ts (100%) rename {lib/vscode/src => src}/vs/nls.js (100%) rename {lib/vscode/src => src}/vs/nls.mock.ts (100%) rename {lib/vscode/src => src}/vs/platform/accessibility/common/accessibility.ts (100%) rename {lib/vscode/src => src}/vs/platform/accessibility/common/accessibilityService.ts (100%) rename {lib/vscode/src/vs/base/browser/ui/dropdown => src/vs/platform/actions/browser}/dropdownWithPrimaryActionViewItem.ts (64%) rename {lib/vscode/src => src}/vs/platform/actions/browser/menuEntryActionViewItem.css (97%) rename {lib/vscode/src => src}/vs/platform/actions/browser/menuEntryActionViewItem.ts (89%) rename {lib/vscode/src => src}/vs/platform/actions/common/actions.ts (93%) rename {lib/vscode/src => src}/vs/platform/actions/common/menuService.ts (100%) rename {lib/vscode/src => src}/vs/platform/actions/test/common/menuService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/backup/electron-main/backup.ts (100%) rename {lib/vscode/src => src}/vs/platform/backup/electron-main/backupMainService.ts (98%) rename {lib/vscode/src => src}/vs/platform/backup/node/backup.ts (100%) rename {lib/vscode/src => src}/vs/platform/backup/test/electron-main/backupMainService.test.ts (96%) rename {lib/vscode/src => src}/vs/platform/browser/contextScopedHistoryWidget.ts (100%) rename {lib/vscode/src => src}/vs/platform/checksum/common/checksumService.ts (100%) rename {lib/vscode/src => src}/vs/platform/checksum/electron-sandbox/checksumService.ts (100%) rename {lib/vscode/src => src}/vs/platform/checksum/node/checksumService.ts (100%) rename {lib/vscode/src => src}/vs/platform/checksum/test/node/checksumService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/checksum/test/node/fixtures/lorem.txt (100%) rename {lib/vscode/src => src}/vs/platform/clipboard/browser/clipboardService.ts (100%) rename {lib/vscode/src => src}/vs/platform/clipboard/common/clipboardService.ts (100%) rename {lib/vscode/src => src}/vs/platform/commands/common/commands.ts (100%) rename {lib/vscode/src => src}/vs/platform/commands/test/common/commands.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/configuration/common/configuration.ts (100%) rename {lib/vscode/src => src}/vs/platform/configuration/common/configurationModels.ts (100%) rename {lib/vscode/src => src}/vs/platform/configuration/common/configurationRegistry.ts (100%) rename {lib/vscode/src => src}/vs/platform/configuration/common/configurationService.ts (100%) rename {lib/vscode/src => src}/vs/platform/configuration/test/common/configuration.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/configuration/test/common/configurationModels.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/configuration/test/common/configurationRegistry.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/configuration/test/common/configurationService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/configuration/test/common/testConfigurationService.ts (100%) rename {lib/vscode/src => src}/vs/platform/contextkey/browser/contextKeyService.ts (100%) rename {lib/vscode/src => src}/vs/platform/contextkey/common/contextkey.ts (99%) rename {lib/vscode/src => src}/vs/platform/contextkey/common/contextkeys.ts (87%) rename {lib/vscode/src => src}/vs/platform/contextkey/test/browser/contextkey.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/contextkey/test/common/contextkey.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/contextview/browser/contextMenuHandler.css (100%) rename {lib/vscode/src => src}/vs/platform/contextview/browser/contextMenuHandler.ts (100%) rename {lib/vscode/src => src}/vs/platform/contextview/browser/contextMenuService.ts (94%) rename {lib/vscode/src => src}/vs/platform/contextview/browser/contextView.ts (95%) rename {lib/vscode/src => src}/vs/platform/contextview/browser/contextViewService.ts (100%) rename {lib/vscode/src => src}/vs/platform/debug/common/extensionHostDebug.ts (100%) rename {lib/vscode/src => src}/vs/platform/debug/common/extensionHostDebugIpc.ts (100%) rename {lib/vscode/src => src}/vs/platform/debug/electron-main/extensionHostDebugIpc.ts (100%) rename {lib/vscode/src => src}/vs/platform/diagnostics/common/diagnostics.ts (100%) rename {lib/vscode/src => src}/vs/platform/diagnostics/electron-sandbox/diagnosticsService.ts (100%) rename {lib/vscode/src => src}/vs/platform/diagnostics/node/diagnosticsService.ts (100%) rename {lib/vscode/src => src}/vs/platform/dialogs/common/dialogs.ts (100%) rename {lib/vscode/src => src}/vs/platform/dialogs/electron-main/dialogMainService.ts (96%) create mode 100644 src/vs/platform/dialogs/test/common/testDialogService.ts rename {lib/vscode/src => src}/vs/platform/download/common/download.ts (100%) rename {lib/vscode/src => src}/vs/platform/download/common/downloadIpc.ts (100%) rename {lib/vscode/src => src}/vs/platform/download/common/downloadService.ts (100%) rename {lib/vscode/src => src}/vs/platform/driver/browser/baseDriver.ts (100%) rename {lib/vscode/src => src}/vs/platform/driver/browser/driver.ts (100%) rename {lib/vscode/src => src}/vs/platform/driver/common/driver.ts (100%) rename {lib/vscode/src => src}/vs/platform/driver/common/driverIpc.ts (100%) rename {lib/vscode/src => src}/vs/platform/driver/electron-main/driver.ts (100%) rename {lib/vscode/src => src}/vs/platform/driver/electron-sandbox/driver.ts (100%) rename {lib/vscode/src => src}/vs/platform/driver/node/driver.ts (100%) rename {lib/vscode/src => src}/vs/platform/editor/common/editor.ts (87%) rename {lib/vscode/src => src}/vs/platform/encryption/common/encryptionService.ts (100%) rename {lib/vscode/src => src}/vs/platform/encryption/electron-main/encryptionMainService.ts (100%) rename {lib/vscode/src => src}/vs/platform/environment/common/argv.ts (97%) rename {lib/vscode/src => src}/vs/platform/environment/common/environment.ts (98%) rename {lib/vscode/src => src}/vs/platform/environment/common/environmentService.ts (91%) rename {lib/vscode/src => src}/vs/platform/environment/electron-main/environmentMainService.ts (100%) rename {lib/vscode/src => src}/vs/platform/environment/node/argv.ts (96%) rename {lib/vscode/src => src}/vs/platform/environment/node/argvHelper.ts (100%) rename {lib/vscode/src => src}/vs/platform/environment/node/environmentService.ts (100%) rename {lib/vscode/src => src}/vs/platform/environment/node/shellEnv.ts (100%) rename {lib/vscode/src => src}/vs/platform/environment/node/stdin.ts (100%) rename {lib/vscode/src => src}/vs/platform/environment/node/userDataPath.d.ts (100%) rename {lib/vscode/src => src}/vs/platform/environment/node/userDataPath.js (100%) rename {lib/vscode/src => src}/vs/platform/environment/node/wait.ts (100%) rename {lib/vscode/src => src}/vs/platform/environment/test/node/argv.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/environment/test/node/environmentService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/environment/test/node/nativeModules.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/environment/test/node/userDataPath.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/common/configRemotes.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/common/extensionEnablementService.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/common/extensionGalleryService.ts (91%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/common/extensionManagement.ts (98%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/common/extensionManagementCLIService.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/common/extensionManagementIpc.ts (96%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/common/extensionManagementUtil.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/common/extensionNls.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/common/extensionTipsService.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/common/extensionUrlTrust.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/common/media/defaultIcon.png (100%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/electron-sandbox/extensionTipsService.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/node/extensionDownloader.ts (96%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/node/extensionLifecycle.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/node/extensionManagementService.ts (98%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/node/extensionManagementUtil.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/node/extensionUrlTrustService.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/node/extensionsManifestCache.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/node/extensionsScanner.ts (92%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/node/extensionsWatcher.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/test/common/configRemotes.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/test/common/extensionGalleryService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionManagement/test/common/extensionManagement.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionRecommendations/common/extensionRecommendations.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensionRecommendations/electron-sandbox/extensionRecommendationsIpc.ts (100%) rename {lib/vscode/src => src}/vs/platform/extensions/common/extensionValidator.ts (79%) rename {lib/vscode/src => src}/vs/platform/extensions/common/extensions.ts (89%) rename {lib/vscode/src => src}/vs/platform/extensions/test/common/extensionValidator.test.ts (95%) rename {lib/vscode/src/vs/workbench/contrib => src/vs/platform}/externalTerminal/common/externalTerminal.ts (67%) rename {lib/vscode/src/vs/workbench/contrib/externalTerminal/node => src/vs/platform/externalTerminal/electron-main}/externalTerminalService.test.ts (95%) create mode 100644 src/vs/platform/externalTerminal/electron-sandbox/externalTerminalMainService.ts rename {lib/vscode/src/vs/workbench/contrib => src/vs/platform}/externalTerminal/node/externalTerminalService.ts (75%) rename {lib/vscode/src => src}/vs/platform/files/browser/htmlFileSystemProvider.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/browser/indexedDBFileSystemProvider.ts (98%) rename {lib/vscode/src => src}/vs/platform/files/common/fileService.ts (97%) rename {lib/vscode/src => src}/vs/platform/files/common/files.ts (97%) rename {lib/vscode/src => src}/vs/platform/files/common/inMemoryFilesystemProvider.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/common/io.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/common/ipcFileSystemProvider.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/electron-browser/diskFileSystemProvider.ts (93%) rename {lib/vscode/src => src}/vs/platform/files/node/diskFileSystemProvider.ts (96%) rename {lib/vscode/src => src}/vs/platform/files/node/watcher/nodejs/watcherService.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/node/watcher/nsfw/test/nsfwWatcherService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/node/watcher/nsfw/watcher.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/node/watcher/nsfw/watcherApp.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/node/watcher/nsfw/watcherService.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/node/watcher/unix/test/chockidarWatcherService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/node/watcher/unix/watcher.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/node/watcher/unix/watcherApp.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/node/watcher/unix/watcherService.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/node/watcher/watcher.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/node/watcher/win32/CodeHelper.exe (100%) rename {lib/vscode/src => src}/vs/platform/files/node/watcher/win32/CodeHelper.md (100%) rename {lib/vscode/src => src}/vs/platform/files/node/watcher/win32/csharpWatcherService.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/node/watcher/win32/watcherService.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/test/browser/fileService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/test/browser/indexedDBFileService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/test/common/files.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/test/common/nullFileSystemProvider.ts (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/diskFileService.test.ts (97%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/resolver/examples/company.js (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/resolver/examples/conway.js (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/resolver/examples/employee.js (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/resolver/examples/small.js (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/resolver/index.html (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/company.js (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/conway.js (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/employee.js (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/small.js (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/resolver/site.css (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/service/binary.txt (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/service/deep/company.js (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/service/deep/conway.js (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/service/deep/employee.js (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/service/deep/small.js (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/service/index.html (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/service/lorem.txt (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/service/small.txt (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/service/small_umlaut.txt (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/service/some_utf16le.css (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/fixtures/service/some_utf8_bom.txt (100%) rename {lib/vscode/src => src}/vs/platform/files/test/electron-browser/normalizer.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/instantiation/common/descriptors.ts (100%) rename {lib/vscode/src => src}/vs/platform/instantiation/common/extensions.ts (100%) rename {lib/vscode/src => src}/vs/platform/instantiation/common/graph.ts (100%) rename {lib/vscode/src => src}/vs/platform/instantiation/common/instantiation.ts (100%) rename {lib/vscode/src => src}/vs/platform/instantiation/common/instantiationService.ts (100%) rename {lib/vscode/src => src}/vs/platform/instantiation/common/serviceCollection.ts (100%) rename {lib/vscode/src => src}/vs/platform/instantiation/test/common/graph.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/instantiation/test/common/instantiationService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/instantiation/test/common/instantiationServiceMock.ts (100%) rename {lib/vscode/src => src}/vs/platform/ipc/electron-browser/mainProcessService.ts (100%) rename {lib/vscode/src => src}/vs/platform/ipc/electron-sandbox/mainProcessService.ts (100%) rename {lib/vscode/src => src}/vs/platform/ipc/electron-sandbox/services.ts (100%) rename {lib/vscode/src => src}/vs/platform/issue/common/issue.ts (90%) rename {lib/vscode/src => src}/vs/platform/issue/common/issueReporterUtil.ts (100%) rename {lib/vscode/src => src}/vs/platform/issue/electron-main/issueMainService.ts (94%) rename {lib/vscode/src => src}/vs/platform/issue/electron-sandbox/issue.ts (100%) rename {lib/vscode/src => src}/vs/platform/jsonschemas/common/jsonContributionRegistry.ts (100%) rename {lib/vscode/src => src}/vs/platform/keybinding/common/abstractKeybindingService.ts (98%) rename {lib/vscode/src => src}/vs/platform/keybinding/common/baseResolvedKeybinding.ts (100%) rename {lib/vscode/src => src}/vs/platform/keybinding/common/keybinding.ts (94%) rename {lib/vscode/src => src}/vs/platform/keybinding/common/keybindingResolver.ts (95%) rename {lib/vscode/src => src}/vs/platform/keybinding/common/keybindingsRegistry.ts (100%) rename {lib/vscode/src => src}/vs/platform/keybinding/common/resolvedKeybindingItem.ts (100%) rename {lib/vscode/src => src}/vs/platform/keybinding/common/usLayoutResolvedKeybinding.ts (100%) rename {lib/vscode/src => src}/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/keybinding/test/common/keybindingLabels.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/keybinding/test/common/keybindingResolver.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/keybinding/test/common/mockKeybindingService.ts (100%) rename {lib/vscode/src => src}/vs/platform/keyboardLayout/common/dispatchConfig.ts (100%) rename {lib/vscode/src => src}/vs/platform/keyboardLayout/common/keyboardLayout.ts (100%) rename {lib/vscode/src => src}/vs/platform/keyboardLayout/common/keyboardLayoutService.ts (100%) rename {lib/vscode/src => src}/vs/platform/keyboardLayout/common/keyboardMapper.ts (100%) rename {lib/vscode/src => src}/vs/platform/keyboardLayout/electron-main/keyboardLayoutMainService.ts (100%) rename {lib/vscode/src => src}/vs/platform/label/common/label.ts (100%) rename {lib/vscode/src => src}/vs/platform/launch/common/launch.ts (100%) rename {lib/vscode/src => src}/vs/platform/launch/electron-main/launchMainService.ts (100%) rename {lib/vscode/src => src}/vs/platform/layout/browser/layoutService.ts (100%) rename {lib/vscode/src => src}/vs/platform/lifecycle/common/lifecycle.ts (100%) rename {lib/vscode/src => src}/vs/platform/lifecycle/electron-main/lifecycleMainService.ts (87%) rename {lib/vscode/src => src}/vs/platform/list/browser/listService.ts (94%) rename {lib/vscode/src => src}/vs/platform/localizations/common/localizations.ts (100%) rename {lib/vscode/src => src}/vs/platform/localizations/node/localizations.ts (98%) rename {lib/vscode/src => src}/vs/platform/log/browser/log.ts (100%) rename {lib/vscode/src => src}/vs/platform/log/common/bufferLog.ts (100%) rename {lib/vscode/src => src}/vs/platform/log/common/fileLog.ts (100%) rename {lib/vscode/src => src}/vs/platform/log/common/log.ts (100%) rename {lib/vscode/src => src}/vs/platform/log/common/logIpc.ts (100%) rename {lib/vscode/src => src}/vs/platform/log/node/loggerService.ts (100%) rename {lib/vscode/src => src}/vs/platform/log/node/spdlogLog.ts (88%) rename {lib/vscode/src => src}/vs/platform/markers/common/markerService.ts (100%) rename {lib/vscode/src => src}/vs/platform/markers/common/markers.ts (100%) rename {lib/vscode/src => src}/vs/platform/markers/test/common/markerService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/menubar/common/menubar.ts (100%) rename {lib/vscode/src => src}/vs/platform/menubar/electron-main/menubar.ts (91%) rename {lib/vscode/src => src}/vs/platform/menubar/electron-main/menubarMainService.ts (100%) rename {lib/vscode/src => src}/vs/platform/menubar/electron-sandbox/menubar.ts (100%) rename {lib/vscode/src => src}/vs/platform/native/common/native.ts (95%) rename {lib/vscode/src => src}/vs/platform/native/electron-main/nativeHostMainService.ts (84%) rename {lib/vscode/src => src}/vs/platform/native/electron-sandbox/native.ts (91%) rename {lib/vscode/src => src}/vs/platform/native/electron-sandbox/nativeHostService.ts (100%) rename {lib/vscode/src => src}/vs/platform/notification/common/notification.ts (100%) rename {lib/vscode/src => src}/vs/platform/notification/test/common/testNotificationService.ts (100%) create mode 100644 src/vs/platform/opener/browser/link.ts rename {lib/vscode/src => src}/vs/platform/opener/common/opener.ts (98%) rename {lib/vscode/src => src}/vs/platform/product/common/product.ts (84%) rename {lib/vscode/src => src}/vs/platform/product/common/productService.ts (100%) rename {lib/vscode/src => src}/vs/platform/progress/common/progress.ts (93%) rename {lib/vscode/src => src}/vs/platform/protocol/electron-main/protocol.ts (87%) rename {lib/vscode/src => src}/vs/platform/protocol/electron-main/protocolMainService.ts (93%) rename {lib/vscode/src => src}/vs/platform/quickinput/browser/commandsQuickAccess.ts (95%) rename {lib/vscode/src => src}/vs/platform/quickinput/browser/helpQuickAccess.ts (100%) rename {lib/vscode/src => src}/vs/platform/quickinput/browser/pickerQuickAccess.ts (96%) rename {lib/vscode/src => src}/vs/platform/quickinput/browser/quickAccess.ts (87%) rename {lib/vscode/src => src}/vs/platform/quickinput/browser/quickInput.ts (94%) rename {lib/vscode/src => src}/vs/platform/quickinput/common/quickAccess.ts (96%) rename {lib/vscode/src => src}/vs/platform/quickinput/common/quickInput.ts (100%) rename {lib/vscode/src => src}/vs/platform/registry/common/platform.ts (100%) rename {lib/vscode/src => src}/vs/platform/registry/test/common/platform.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/remote/browser/browserSocketFactory.ts (96%) rename {lib/vscode/src => src}/vs/platform/remote/browser/remoteAuthorityResolverService.ts (95%) rename {lib/vscode/src => src}/vs/platform/remote/common/remoteAgentConnection.ts (100%) rename {lib/vscode/src => src}/vs/platform/remote/common/remoteAgentEnvironment.ts (100%) rename {lib/vscode/src => src}/vs/platform/remote/common/remoteAuthorityResolver.ts (89%) rename {lib/vscode/src => src}/vs/platform/remote/common/remoteHosts.ts (90%) rename {lib/vscode/src => src}/vs/platform/remote/common/tunnel.ts (99%) rename {lib/vscode/src => src}/vs/platform/remote/electron-sandbox/remoteAuthorityResolverService.ts (63%) rename {lib/vscode/src => src}/vs/platform/remote/node/nodeSocketFactory.ts (100%) rename {lib/vscode/src => src}/vs/platform/remote/node/tunnelService.ts (82%) rename {lib/vscode/src => src}/vs/platform/request/browser/requestService.ts (100%) rename {lib/vscode/src => src}/vs/platform/request/common/request.ts (100%) rename {lib/vscode/src => src}/vs/platform/request/common/requestIpc.ts (100%) rename {lib/vscode/src => src}/vs/platform/request/electron-main/requestMainService.ts (100%) rename {lib/vscode/src => src}/vs/platform/request/node/proxy.ts (100%) rename {lib/vscode/src => src}/vs/platform/request/node/requestService.ts (100%) rename {lib/vscode/src => src}/vs/platform/serviceMachineId/common/serviceMachineId.ts (100%) rename {lib/vscode/src => src}/vs/platform/severityIcon/common/severityIcon.ts (100%) rename {lib/vscode/src => src}/vs/platform/sharedProcess/electron-main/sharedProcess.ts (97%) rename {lib/vscode/src => src}/vs/platform/sharedProcess/node/sharedProcess.ts (100%) rename {lib/vscode/src => src}/vs/platform/sign/browser/signService.ts (100%) rename {lib/vscode/src => src}/vs/platform/sign/common/sign.ts (100%) rename {lib/vscode/src => src}/vs/platform/sign/node/signService.ts (100%) rename {lib/vscode/src/vs/platform/state/node => src/vs/platform/state/electron-main}/state.ts (72%) create mode 100644 src/vs/platform/state/electron-main/stateMainService.ts create mode 100644 src/vs/platform/state/test/electron-main/state.test.ts rename {lib/vscode/src => src}/vs/platform/storage/browser/storageService.ts (100%) rename {lib/vscode/src => src}/vs/platform/storage/common/storage.ts (99%) rename {lib/vscode/src => src}/vs/platform/storage/common/storageIpc.ts (100%) rename {lib/vscode/src => src}/vs/platform/storage/electron-main/storageIpc.ts (100%) rename {lib/vscode/src => src}/vs/platform/storage/electron-main/storageMain.ts (98%) rename {lib/vscode/src => src}/vs/platform/storage/electron-main/storageMainService.ts (100%) rename {lib/vscode/src => src}/vs/platform/storage/electron-sandbox/storageService.ts (100%) rename {lib/vscode/src => src}/vs/platform/storage/test/browser/storageService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/storage/test/common/storageService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/storage/test/electron-main/storageMainService.test.ts (97%) rename {lib/vscode/src => src}/vs/platform/telemetry/browser/errorTelemetry.ts (100%) rename {lib/vscode/src => src}/vs/platform/telemetry/common/commonProperties.ts (98%) rename {lib/vscode/src => src}/vs/platform/telemetry/common/errorTelemetry.ts (100%) rename {lib/vscode/src => src}/vs/platform/telemetry/common/gdprTypings.ts (100%) rename {lib/vscode/src => src}/vs/platform/telemetry/common/telemetry.ts (100%) rename {lib/vscode/src => src}/vs/platform/telemetry/common/telemetryIpc.ts (100%) rename {lib/vscode/src => src}/vs/platform/telemetry/common/telemetryLogAppender.ts (100%) rename {lib/vscode/src => src}/vs/platform/telemetry/common/telemetryService.ts (100%) rename {lib/vscode/src => src}/vs/platform/telemetry/common/telemetryUtils.ts (100%) rename {lib/vscode/src => src}/vs/platform/telemetry/electron-sandbox/customEndpointTelemetryService.ts (100%) rename {lib/vscode/src => src}/vs/platform/telemetry/node/appInsightsAppender.ts (100%) rename {lib/vscode/src => src}/vs/platform/telemetry/node/customEndpointTelemetryService.ts (100%) rename {lib/vscode/src => src}/vs/platform/telemetry/node/errorTelemetry.ts (100%) rename {lib/vscode/src => src}/vs/platform/telemetry/node/telemetry.ts (100%) rename {lib/vscode/src => src}/vs/platform/telemetry/test/browser/telemetryService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/terminal/common/environmentVariable.ts (100%) rename {lib/vscode/src => src}/vs/platform/terminal/common/terminal.ts (65%) rename {lib/vscode/src => src}/vs/platform/terminal/common/terminalDataBuffering.ts (100%) create mode 100644 src/vs/platform/terminal/common/terminalEnvironment.ts create mode 100644 src/vs/platform/terminal/common/terminalPlatformConfiguration.ts rename {lib/vscode/src => src}/vs/platform/terminal/common/terminalProcess.ts (93%) rename {lib/vscode/src => src}/vs/platform/terminal/common/terminalRecorder.ts (94%) rename {lib/vscode/src => src}/vs/platform/terminal/electron-sandbox/terminal.ts (100%) rename {lib/vscode/src => src}/vs/platform/terminal/node/heartbeatService.ts (100%) rename {lib/vscode/src => src}/vs/platform/terminal/node/ptyHostMain.ts (80%) rename {lib/vscode/src => src}/vs/platform/terminal/node/ptyHostService.ts (80%) rename {lib/vscode/src => src}/vs/platform/terminal/node/ptyService.ts (83%) rename {lib/vscode/src => src}/vs/platform/terminal/node/terminalEnvironment.ts (100%) rename {lib/vscode/src => src}/vs/platform/terminal/node/terminalProcess.ts (89%) create mode 100644 src/vs/platform/terminal/node/terminalProfiles.ts rename {lib/vscode/src => src}/vs/platform/terminal/node/windowsShellHelper.ts (90%) rename {lib/vscode/src => src}/vs/platform/terminal/test/common/terminalRecorder.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/theme/browser/iconsStyleSheet.ts (100%) rename {lib/vscode/src => src}/vs/platform/theme/common/colorRegistry.ts (93%) rename {lib/vscode/src => src}/vs/platform/theme/common/iconRegistry.ts (100%) rename {lib/vscode/src => src}/vs/platform/theme/common/styler.ts (90%) rename {lib/vscode/src => src}/vs/platform/theme/common/theme.ts (100%) rename {lib/vscode/src => src}/vs/platform/theme/common/themeService.ts (98%) rename {lib/vscode/src => src}/vs/platform/theme/common/tokenClassificationRegistry.ts (100%) rename {lib/vscode/src => src}/vs/platform/theme/electron-main/themeMainService.ts (53%) rename {lib/vscode/src => src}/vs/platform/theme/test/common/testThemeService.ts (100%) rename {lib/vscode/src => src}/vs/platform/undoRedo/common/undoRedo.ts (100%) rename {lib/vscode/src => src}/vs/platform/undoRedo/common/undoRedoService.ts (99%) rename {lib/vscode/src => src}/vs/platform/undoRedo/test/common/undoRedoService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/update/common/update.config.contribution.ts (100%) rename {lib/vscode/src => src}/vs/platform/update/common/update.ts (100%) rename {lib/vscode/src => src}/vs/platform/update/common/updateIpc.ts (100%) rename {lib/vscode/src => src}/vs/platform/update/electron-main/abstractUpdateService.ts (98%) rename {lib/vscode/src => src}/vs/platform/update/electron-main/updateService.darwin.ts (100%) rename {lib/vscode/src => src}/vs/platform/update/electron-main/updateService.linux.ts (100%) rename {lib/vscode/src => src}/vs/platform/update/electron-main/updateService.snap.ts (98%) rename {lib/vscode/src => src}/vs/platform/update/electron-main/updateService.win32.ts (97%) rename {lib/vscode/src => src}/vs/platform/url/common/url.ts (100%) rename {lib/vscode/src => src}/vs/platform/url/common/urlIpc.ts (100%) rename {lib/vscode/src => src}/vs/platform/url/common/urlService.ts (100%) rename {lib/vscode/src => src}/vs/platform/url/electron-main/electronUrlListener.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/abstractSynchronizer.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/content.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/extensionsMerge.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/extensionsStorageSync.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/extensionsSync.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/globalStateMerge.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/globalStateSync.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/ignoredExtensions.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/keybindingsMerge.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/keybindingsSync.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/settingsMerge.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/settingsSync.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/snippetsMerge.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/snippetsSync.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/userDataAutoSyncService.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/userDataSync.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/userDataSyncAccount.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/userDataSyncBackupStoreService.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/userDataSyncIpc.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/userDataSyncLog.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/userDataSyncMachines.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/userDataSyncResourceEnablementService.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/userDataSyncService.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/userDataSyncServiceIpc.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/common/userDataSyncStoreService.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/electron-sandbox/userDataAutoSyncService.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/test/common/extensionsMerge.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/test/common/globalStateMerge.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/test/common/globalStateSync.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/test/common/keybindingsMerge.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/test/common/keybindingsSync.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/test/common/settingsMerge.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/test/common/settingsSync.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/test/common/snippetsMerge.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/test/common/snippetsSync.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/test/common/synchronizer.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/test/common/userDataAutoSyncService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/test/common/userDataSyncClient.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/test/common/userDataSyncService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/webview/common/mimeTypes.ts (100%) rename {lib/vscode/src => src}/vs/platform/webview/common/webviewManagerService.ts (100%) rename {lib/vscode/src => src}/vs/platform/webview/common/webviewPortMapping.ts (100%) rename {lib/vscode/src => src}/vs/platform/webview/electron-main/webviewMainService.ts (100%) rename {lib/vscode/src => src}/vs/platform/webview/electron-main/webviewProtocolProvider.ts (100%) rename {lib/vscode/src => src}/vs/platform/windows/common/windows.ts (91%) rename {lib/vscode/src => src}/vs/platform/windows/electron-main/window.ts (97%) rename {lib/vscode/src => src}/vs/platform/windows/electron-main/windows.ts (100%) rename {lib/vscode/src => src}/vs/platform/windows/electron-main/windowsFinder.ts (98%) rename {lib/vscode/src => src}/vs/platform/windows/electron-main/windowsMainService.ts (99%) rename {lib/vscode/src => src}/vs/platform/windows/electron-main/windowsStateHandler.ts (93%) rename {lib/vscode/src => src}/vs/platform/windows/electron-sandbox/window.ts (100%) rename {lib/vscode/src => src}/vs/platform/windows/node/windowTracker.ts (100%) rename {lib/vscode/src => src}/vs/platform/windows/test/electron-main/windowsFinder.test.ts (99%) rename {lib/vscode/src => src}/vs/platform/windows/test/electron-main/windowsStateHandler.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/workspace/common/workspace.ts (100%) rename {lib/vscode/src => src}/vs/platform/workspace/common/workspaceTrust.ts (65%) rename {lib/vscode/src => src}/vs/platform/workspace/test/common/testWorkspace.ts (100%) rename {lib/vscode/src => src}/vs/platform/workspace/test/common/workspace.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/workspaces/common/workspaces.ts (97%) rename {lib/vscode/src => src}/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts (97%) rename {lib/vscode/src => src}/vs/platform/workspaces/electron-main/workspacesMainService.ts (98%) rename {lib/vscode/src => src}/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts (94%) rename {lib/vscode/src => src}/vs/platform/workspaces/test/common/workspaces.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/workspaces/test/electron-main/workspacesHistoryStorage.test.ts (100%) rename {lib/vscode/src => src}/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts (99%) rename {lib/vscode/src => src}/vs/vscode.d.ts (78%) rename {lib/vscode/src => src}/vs/vscode.proposed.d.ts (72%) rename {lib/vscode/src => src}/vs/workbench/api/browser/apiCommands.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/extensionHost.contribution.ts (99%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadAuthentication.ts (98%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadBulkEdits.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadCLICommands.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadClipboard.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadCodeInsets.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadCommands.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadComments.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadConfiguration.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadConsole.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadCustomEditors.ts (86%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadDebugService.ts (99%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadDecorations.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadDiagnostics.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadDialogs.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadDocumentContentProviders.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadDocuments.ts (79%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadDownloadService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadEditor.ts (99%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadEditorTabs.ts (81%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadEditors.ts (97%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadErrors.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadExtensionService.ts (77%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadFileSystem.ts (96%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadFileSystemEventService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadKeytar.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadLabelService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadLanguageFeatures.ts (95%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadLanguages.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadLogService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadMessageService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadNotebook.ts (84%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadNotebookDocuments.ts (78%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts (96%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadNotebookEditors.ts (97%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadNotebookKernels.ts (93%) create mode 100644 src/vs/workbench/api/browser/mainThreadNotebookRenderers.ts rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadOutputService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadProgress.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadQuickOpen.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadRemoteConnectionData.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadSCM.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadSaveParticipant.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadSearch.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadSecretState.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadStatusBar.ts (78%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadStorage.ts (93%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadTask.ts (99%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadTelemetry.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadTerminalService.ts (82%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadTesting.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadTheming.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadTimeline.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadTreeViews.ts (93%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadTunnelService.ts (98%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadUriOpeners.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadUrls.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadWebviewManager.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadWebviewPanels.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadWebviewViews.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadWebviews.ts (95%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadWindow.ts (95%) rename {lib/vscode/src => src}/vs/workbench/api/browser/mainThreadWorkspace.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/browser/viewsExtensionPoint.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/apiCommands.ts (56%) rename {lib/vscode/src => src}/vs/workbench/api/common/cache.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/configurationExtensionPoint.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/exHostSecretState.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHost.api.impl.ts (92%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHost.common.services.ts (95%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHost.protocol.ts (94%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostApiCommands.ts (90%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostApiDeprecationService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostAuthentication.ts (92%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostBulkEdits.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostClipboard.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostCodeInsets.ts (93%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostCommands.ts (98%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostComments.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostConfiguration.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostCustomEditors.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostCustomers.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostDebugService.ts (96%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostDecorations.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostDiagnostics.ts (95%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostDialogs.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostDocumentContentProviders.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostDocumentData.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostDocumentSaveParticipant.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostDocuments.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostDocumentsAndEditors.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostEditorTabs.ts (67%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostExtensionActivator.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostExtensionService.ts (96%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostFileSystem.ts (94%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostFileSystemConsumer.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostFileSystemEventService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostFileSystemInfo.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostInitDataService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostLabelService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostLanguageFeatures.ts (93%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostLanguages.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostMemento.ts (92%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostMessageService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostNotebook.ts (67%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostNotebookConcatDocument.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostNotebookDocument.ts (79%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostNotebookEditor.ts (94%) create mode 100644 src/vs/workbench/api/common/extHostNotebookKernels.ts create mode 100644 src/vs/workbench/api/common/extHostNotebookRenderers.ts rename {lib/vscode/src => src}/vs/workbench/api/common/extHostOutput.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostProgress.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostQuickOpen.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostRequireInterceptor.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostRpcService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostSCM.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostSearch.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostSecrets.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostStatusBar.ts (71%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostStorage.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostStoragePaths.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostTask.ts (99%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostTelemetry.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostTerminalService.ts (84%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostTesting.ts (99%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostTestingPrivateApi.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostTextEditor.ts (98%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostTextEditors.ts (96%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostTheming.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostTimeline.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostTreeViews.ts (96%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostTunnelService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostTypeConverters.ts (94%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostTypes.ts (93%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostUriOpener.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostUriTransformerService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostUrls.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostWebview.ts (81%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostWebviewMessaging.ts (98%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostWebviewPanels.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostWebviewView.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostWindow.ts (95%) rename {lib/vscode/src => src}/vs/workbench/api/common/extHostWorkspace.ts (99%) rename {lib/vscode/src => src}/vs/workbench/api/common/jsonValidationExtensionPoint.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/common/menusExtensionPoint.ts (95%) rename {lib/vscode/src => src}/vs/workbench/api/common/shared/tasks.ts (99%) create mode 100644 src/vs/workbench/api/common/shared/webview.ts rename {lib/vscode/src => src}/vs/workbench/api/common/shared/workspaceContains.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/node/extHost.node.services.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/node/extHostCLIServer.ts (95%) rename {lib/vscode/src => src}/vs/workbench/api/node/extHostDebugService.ts (95%) rename {lib/vscode/src => src}/vs/workbench/api/node/extHostDownloadService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/node/extHostExtensionService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/node/extHostLogService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/node/extHostOutputService.ts (85%) rename {lib/vscode/src => src}/vs/workbench/api/node/extHostSearch.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/node/extHostTask.ts (96%) create mode 100644 src/vs/workbench/api/node/extHostTerminalService.ts rename {lib/vscode/src => src}/vs/workbench/api/node/extHostTunnelService.ts (97%) rename {lib/vscode/src => src}/vs/workbench/api/worker/extHost.worker.services.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/worker/extHostExtensionService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/api/worker/extHostLogService.ts (100%) rename lib/vscode/src/vs/workbench/browser/menuActions.ts => src/vs/workbench/browser/actions.ts (99%) rename {lib/vscode/src => src}/vs/workbench/browser/actions/developerActions.ts (92%) rename {lib/vscode/src => src}/vs/workbench/browser/actions/helpActions.ts (69%) rename {lib/vscode/src => src}/vs/workbench/browser/actions/layoutActions.ts (50%) rename {lib/vscode/src => src}/vs/workbench/browser/actions/listCommands.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/actions/media/actions.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/actions/navigationActions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/actions/quickAccessActions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/actions/textInputActions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/actions/windowActions.ts (56%) rename {lib/vscode/src => src}/vs/workbench/browser/actions/workspaceActions.ts (55%) rename {lib/vscode/src => src}/vs/workbench/browser/actions/workspaceCommands.ts (68%) rename {lib/vscode/src => src}/vs/workbench/browser/codeeditor.ts (99%) rename {lib/vscode/src => src}/vs/workbench/browser/composite.ts (99%) rename {lib/vscode/src => src}/vs/workbench/browser/contextkeys.ts (95%) rename {lib/vscode/src => src}/vs/workbench/browser/dnd.ts (56%) rename {lib/vscode/src => src}/vs/workbench/browser/editor.ts (72%) rename {lib/vscode/src => src}/vs/workbench/browser/labels.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/layout.ts (96%) rename {lib/vscode/src => src}/vs/workbench/browser/media/code-icon.svg (100%) rename {lib/vscode/src => src}/vs/workbench/browser/media/part.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/media/style.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/panecomposite.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/panel.ts (98%) rename {lib/vscode/src => src}/vs/workbench/browser/part.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/activitybar/activitybarActions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/activitybar/activitybarPart.ts (97%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/activitybar/media/activityaction.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/activitybar/media/activitybarpart.css (100%) create mode 100644 src/vs/workbench/browser/parts/banner/bannerPart.ts create mode 100644 src/vs/workbench/browser/parts/banner/media/bannerpart.css rename {lib/vscode/src => src}/vs/workbench/browser/parts/compositeBar.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/compositeBarActions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/compositePart.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/dialogs/dialog.web.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/dialogs/dialogHandler.ts (97%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/binaryDiffEditor.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/binaryEditor.ts (90%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/breadcrumbs.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/breadcrumbsControl.ts (99%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/breadcrumbsModel.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/editor.contribution.ts (85%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/editor.ts (88%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/editorActions.ts (98%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/editorAutoSave.ts (97%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/editorCommands.ts (97%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/editorControl.ts (77%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/editorDropTarget.ts (96%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/editorGroupView.ts (95%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/editorPane.ts (95%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/editorPart.ts (99%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/editorQuickAccess.ts (99%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/editorStatus.ts (96%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/editorsObserver.ts (99%) create mode 100644 src/vs/workbench/browser/parts/editor/media/back-tb.png rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/media/binaryeditor.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/media/breadcrumbscontrol.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/media/editordroptarget.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/media/editorgroupview.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/media/editorquickaccess.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/media/editorstatus.css (100%) create mode 100644 src/vs/workbench/browser/parts/editor/media/forward-tb.png rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/media/letterpress-dark.svg (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/media/letterpress-hc.svg (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/media/letterpress.svg (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/media/titlecontrol.css (100%) create mode 100644 src/vs/workbench/browser/parts/editor/media/workspacetrusteditor.css rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/noTabsTitleControl.ts (97%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/sideBySideEditor.ts (81%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/tabsTitleControl.ts (99%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/textDiffEditor.ts (75%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/textEditor.ts (88%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/textResourceEditor.ts (88%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/editor/titleControl.ts (91%) create mode 100644 src/vs/workbench/browser/parts/editor/workspaceTrustRequiredEditor.ts rename {lib/vscode/src => src}/vs/workbench/browser/parts/media/compositepart.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/notifications/media/notificationsActions.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/notifications/media/notificationsCenter.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/notifications/media/notificationsList.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/notifications/media/notificationsToasts.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/notifications/notificationsActions.ts (99%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/notifications/notificationsAlerts.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/notifications/notificationsCenter.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/notifications/notificationsCommands.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/notifications/notificationsList.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/notifications/notificationsStatus.ts (97%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/notifications/notificationsTelemetry.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/notifications/notificationsToasts.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/notifications/notificationsViewer.ts (96%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/panel/media/panelpart.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/panel/panelActions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/panel/panelPart.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/sidebar/media/sidebarpart.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/sidebar/sidebarPart.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/statusbar/media/statusbarpart.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/statusbar/statusbarPart.ts (87%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/titlebar/media/titlebarpart.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/titlebar/menubarControl.ts (87%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/titlebar/titlebarPart.ts (99%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/views/media/paneviewlet.css (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/views/media/views.css (95%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/views/treeView.ts (95%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/views/viewPane.ts (98%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/views/viewPaneContainer.ts (99%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/views/viewsService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/parts/views/viewsViewlet.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/quickaccess.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/style.ts (94%) rename {lib/vscode/src => src}/vs/workbench/browser/viewlet.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/web.main.ts (97%) rename {lib/vscode/src => src}/vs/workbench/browser/window.ts (91%) rename {lib/vscode/src => src}/vs/workbench/browser/workbench.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/browser/workbench.ts (95%) rename {lib/vscode/src => src}/vs/workbench/buildfile.desktop.js (100%) rename {lib/vscode/src => src}/vs/workbench/buildfile.web.js (100%) rename {lib/vscode/src => src}/vs/workbench/common/actions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/common/activity.ts (100%) rename {lib/vscode/src => src}/vs/workbench/common/component.ts (100%) rename {lib/vscode/src => src}/vs/workbench/common/composite.ts (100%) rename {lib/vscode/src => src}/vs/workbench/common/configuration.ts (100%) rename {lib/vscode/src => src}/vs/workbench/common/contributions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/common/dialogs.ts (100%) rename {lib/vscode/src => src}/vs/workbench/common/editor.ts (64%) rename {lib/vscode/src => src}/vs/workbench/common/editor/binaryEditorModel.ts (89%) rename {lib/vscode/src => src}/vs/workbench/common/editor/diffEditorInput.ts (73%) rename {lib/vscode/src => src}/vs/workbench/common/editor/diffEditorModel.ts (96%) rename {lib/vscode/src => src}/vs/workbench/common/editor/editorGroupModel.ts (96%) create mode 100644 src/vs/workbench/common/editor/editorInput.ts create mode 100644 src/vs/workbench/common/editor/editorModel.ts create mode 100644 src/vs/workbench/common/editor/editorOptions.ts rename lib/vscode/src/vs/workbench/common/editor/textResourceEditorInput.ts => src/vs/workbench/common/editor/resourceEditorInput.ts (50%) create mode 100644 src/vs/workbench/common/editor/sideBySideEditorInput.ts rename {lib/vscode/src => src}/vs/workbench/common/editor/textDiffEditorModel.ts (100%) rename {lib/vscode/src => src}/vs/workbench/common/editor/textEditorModel.ts (98%) create mode 100644 src/vs/workbench/common/editor/textResourceEditorInput.ts rename lib/vscode/src/vs/workbench/common/editor/resourceEditorModel.ts => src/vs/workbench/common/editor/textResourceEditorModel.ts (85%) rename {lib/vscode/src => src}/vs/workbench/common/memento.ts (100%) rename {lib/vscode/src => src}/vs/workbench/common/notifications.ts (99%) rename {lib/vscode/src => src}/vs/workbench/common/panecomposite.ts (100%) rename {lib/vscode/src => src}/vs/workbench/common/panel.ts (100%) rename {lib/vscode/src => src}/vs/workbench/common/resources.ts (97%) rename {lib/vscode/src => src}/vs/workbench/common/theme.ts (97%) rename {lib/vscode/src => src}/vs/workbench/common/viewlet.ts (100%) rename {lib/vscode/src => src}/vs/workbench/common/views.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/bulkEdit/browser/bulkCellEdits.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts (93%) rename {lib/vscode/src => src}/vs/workbench/contrib/bulkEdit/browser/bulkFileEdits.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts (94%) rename {lib/vscode/src => src}/vs/workbench/contrib/bulkEdit/browser/conflicts.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/bulkEdit/browser/preview/bulkEdit.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/bulkEdit/browser/preview/bulkEdit.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPreview.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditTree.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/bulkEdit/test/browser/bulkEditPreview.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/callHierarchy/browser/media/callHierarchy.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/callHierarchy/common/callHierarchy.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeActions/common/codeActions.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeActions/common/codeActionsContribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeActions/common/codeActionsExtensionPoint.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeActions/common/documentationContribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeActions/common/documentationExtensionPoint.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/codeEditor.contribution.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/diffEditorHelper.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/find/simpleFindReplaceWidget.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/find/simpleFindReplaceWidget.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts (93%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.ts (98%) create mode 100644 src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/largeFileOptimizations.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/menuPreventer.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsTree.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsTree.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoLineQuickAccess.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts (60%) create mode 100644 src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts (63%) create mode 100644 src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts create mode 100644 src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts (99%) rename lib/vscode/src/vs/workbench/browser/parts/editor/untitledHint.ts => src/vs/workbench/contrib/codeEditor/browser/untitledTextEditorHint.ts (85%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/browser/workbenchReferenceSearch.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/electron-sandbox/codeEditor.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/electron-sandbox/displayChangeRemeasureFonts.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/electron-sandbox/inputClipboardActions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/electron-sandbox/selectionClipboard.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/electron-sandbox/sleepResumeRepaintMinimap.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/electron-sandbox/startDebugTextMate.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/codeEditor/test/browser/saveParticipant.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/comments/browser/commentFormActions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/comments/browser/commentGlyphWidget.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/comments/browser/commentMenus.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/comments/browser/commentNode.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/comments/browser/commentService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/comments/browser/commentThreadWidget.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/comments/browser/comments.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/comments/browser/commentsView.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/comments/browser/media/panel.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/comments/browser/media/review.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/comments/browser/reactionsAction.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/comments/common/commentContextKeys.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/comments/common/commentModel.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/comments/common/commentThreadWidget.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/configExporter/electron-sandbox/configurationExportHelper.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/configExporter/electron-sandbox/configurationExportHelper.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/customEditor/browser/customEditor.contribution.ts (72%) rename {lib/vscode/src => src}/vs/workbench/contrib/customEditor/browser/customEditorInput.ts (63%) rename {lib/vscode/src => src}/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts (58%) rename {lib/vscode/src => src}/vs/workbench/contrib/customEditor/browser/customEditors.ts (95%) rename {lib/vscode/src => src}/vs/workbench/contrib/customEditor/common/contributedCustomEditors.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/customEditor/common/customEditor.ts (97%) rename {lib/vscode/src => src}/vs/workbench/contrib/customEditor/common/customEditorModelManager.ts (88%) rename {lib/vscode/src => src}/vs/workbench/contrib/customEditor/common/customTextEditorModel.ts (90%) rename {lib/vscode/src => src}/vs/workbench/contrib/customEditor/common/extensionPoint.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/baseDebugView.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/breakpointWidget.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/breakpointsView.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/callStackView.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debug.contribution.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugANSIHandling.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugActionViewItems.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugAdapterManager.ts (86%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugColors.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugCommands.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugEditorActions.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugEditorContribution.ts (95%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugHover.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugIcons.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugProgress.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugQuickAccess.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugService.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugSession.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugStatus.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugTaskRunner.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugTitle.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugToolBar.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/debugViewlet.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/exceptionWidget.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/linkDetector.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/loadedScriptsView.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/media/breakpointWidget.css (100%) create mode 100644 src/vs/workbench/contrib/debug/browser/media/continue-tb.png create mode 100644 src/vs/workbench/contrib/debug/browser/media/continue-without-debugging-tb.png rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/media/debug.contribution.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/media/debugHover.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/media/debugToolBar.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/media/debugViewlet.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/media/exceptionWidget.css (100%) create mode 100644 src/vs/workbench/contrib/debug/browser/media/pause-tb.png rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/media/repl.css (100%) create mode 100644 src/vs/workbench/contrib/debug/browser/media/restart-tb.png create mode 100644 src/vs/workbench/contrib/debug/browser/media/stepinto-tb.png create mode 100644 src/vs/workbench/contrib/debug/browser/media/stepout-tb.png create mode 100644 src/vs/workbench/contrib/debug/browser/media/stepover-tb.png create mode 100644 src/vs/workbench/contrib/debug/browser/media/stop-tb.png rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/rawDebugSession.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/repl.ts (97%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/replFilter.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/replViewer.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/variablesView.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/watchExpressionsView.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/browser/welcomeView.ts (97%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/common/debug.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/common/debugCompoundRoot.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/common/debugContentProvider.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/common/debugModel.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/common/debugProtocol.d.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/common/debugSchemas.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/common/debugSource.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/common/debugStorage.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/common/debugTelemetry.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/common/debugUtils.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/common/debugViewModel.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/common/debugger.ts (78%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/common/replModel.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/electron-sandbox/extensionHostDebugService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/node/debugAdapter.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/node/telemetryApp.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/node/terminals.ts (91%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/test/browser/breakpoints.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/test/browser/callStack.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/test/browser/debugHover.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/test/browser/debugSource.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/test/browser/debugUtils.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/test/browser/debugViewModel.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/test/browser/linkDetector.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/test/browser/mockDebug.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/test/browser/rawDebugSession.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/test/browser/repl.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/test/browser/watch.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/test/node/debugger.test.ts (87%) rename {lib/vscode/src => src}/vs/workbench/contrib/debug/test/node/streamDebugAdapter.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/emmet/browser/actions/expandAbbreviation.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/emmet/browser/emmet.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/emmet/browser/emmetActions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/emmet/test/browser/emmetAction.test.ts (86%) rename {lib/vscode/src => src}/vs/workbench/contrib/experiments/browser/experimentalPrompt.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/experiments/browser/experiments.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/experiments/common/experimentService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/experiments/test/electron-browser/experimentService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/experiments/test/electron-browser/experimentalPrompts.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/abstractRuntimeExtensionsEditor.ts (91%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/browserRuntimeExtensionsEditor.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/configBasedRecommendations.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/dynamicWorkspaceRecommendations.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/exeBasedRecommendations.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/experimentalRecommendations.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/extensionEditor.ts (99%) create mode 100644 src/vs/workbench/contrib/extensions/browser/extensionEnablementWorkspaceTrustTransitionParticipant.ts rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/extensionRecommendationNotificationService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/extensionRecommendations.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/extensionRecommendationsService.ts (94%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/extensions.contribution.ts (94%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/extensions.web.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/extensionsActions.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/extensionsActivationProgress.ts (100%) create mode 100644 src/vs/workbench/contrib/extensions/browser/extensionsCompletionItemsProvider.ts rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/extensionsDependencyChecker.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/extensionsIcons.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/extensionsList.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/extensionsQuickAccess.ts (93%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/extensionsViewer.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts (89%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/extensionsViews.ts (89%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/keymapRecommendations.ts (100%) create mode 100644 src/vs/workbench/contrib/extensions/browser/languageRecommendations.ts rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/media/extension.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/media/extensionActions.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/media/extensionEditor.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/media/extensionsWidgets.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/media/language-icon.svg (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/media/loading.svg (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/media/runtimeExtensionsEditor.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/media/theme-icon.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/browser/workspaceRecommendations.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/common/extensionQuery.ts (95%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/common/extensions.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/common/extensionsFileTemplate.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/common/extensionsInput.ts (83%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/common/extensionsUtils.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/common/runtimeExtensionsInput.ts (81%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts (96%) create mode 100644 src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts (98%) rename {lib/vscode/src/vs/workbench/contrib/extensions/electron-browser => src/vs/workbench/contrib/extensions/electron-sandbox}/debugExtensionHostAction.ts (97%) rename {lib/vscode/src/vs/workbench/contrib/extensions/electron-browser => src/vs/workbench/contrib/extensions/electron-sandbox}/extensions.contribution.ts (76%) create mode 100644 src/vs/workbench/contrib/extensions/electron-sandbox/extensionsActions.ts rename {lib/vscode/src/vs/workbench/contrib/extensions/electron-browser => src/vs/workbench/contrib/extensions/electron-sandbox}/extensionsSlowActions.ts (100%) rename {lib/vscode/src/vs/workbench/contrib/extensions/electron-browser => src/vs/workbench/contrib/extensions/electron-sandbox}/reportExtensionIssueAction.ts (100%) rename {lib/vscode/src/vs/workbench/contrib/extensions/electron-browser => src/vs/workbench/contrib/extensions/electron-sandbox}/runtimeExtensionsEditor.ts (95%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/test/common/extensionQuery.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts (98%) rename {lib/vscode/src/vs/workbench/contrib/externalTerminal/node => src/vs/workbench/contrib/externalTerminal/electron-sandbox}/externalTerminal.contribution.ts (50%) rename {lib/vscode/src => src}/vs/workbench/contrib/externalTerminal/node/TerminalHelper.scpt (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/externalTerminal/node/iTermHelper.scpt (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/externalUriOpener/common/configuration.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/externalUriOpener/common/contributedOpeners.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/externalUriOpener/common/externalUriOpener.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/externalUriOpener/common/externalUriOpenerService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/externalUriOpener/test/common/externalUriOpenerService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/feedback/browser/feedback.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/feedback/browser/feedback.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/feedback/browser/feedbackStatusbarItem.ts (95%) rename {lib/vscode/src => src}/vs/workbench/contrib/feedback/browser/media/feedback.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/feedback/browser/media/happy.svg (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/feedback/browser/media/sad.svg (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts (83%) create mode 100644 src/vs/workbench/contrib/files/browser/editors/fileEditorHandler.ts rename {lib/vscode/src/vs/workbench/contrib/files/common => src/vs/workbench/contrib/files/browser}/editors/fileEditorInput.ts (75%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/editors/textFileEditor.ts (81%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/editors/textFileEditorTracker.ts (86%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/explorerService.ts (92%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/explorerViewlet.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/fileActions.contribution.ts (97%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/fileActions.ts (77%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/fileCommands.ts (97%) create mode 100644 src/vs/workbench/contrib/files/browser/fileImportExport.ts rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/files.contribution.ts (87%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/files.ts (71%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/files.web.contribution.ts (73%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/media/explorerviewlet.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/views/emptyView.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/views/explorerDecorationsProvider.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/views/explorerView.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/views/explorerViewer.ts (70%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/views/media/openeditors.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/browser/views/openEditorsView.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/common/explorerModel.ts (97%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/common/files.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/common/workspaceWatcher.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/electron-sandbox/fileActions.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/electron-sandbox/fileCommands.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/electron-sandbox/files.contribution.ts (81%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/electron-sandbox/textFileEditor.ts (95%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/test/browser/editorAutoSave.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/test/browser/explorerModel.test.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/test/browser/explorerView.test.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/test/browser/fileActions.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts (74%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/test/browser/fileOnDiskProvider.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/files/test/browser/textFileEditorTracker.test.ts (92%) rename {lib/vscode/src => src}/vs/workbench/contrib/format/browser/format.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/format/browser/formatActionsMultiple.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/format/browser/formatActionsNone.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/format/browser/formatModified.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/issue/browser/issue.web.contribution.ts (65%) rename {lib/vscode/src => src}/vs/workbench/contrib/issue/browser/issueService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/issue/common/commands.ts (88%) create mode 100644 src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts create mode 100644 src/vs/workbench/contrib/issue/electron-sandbox/issueActions.ts rename {lib/vscode/src => src}/vs/workbench/contrib/keybindings/browser/keybindings.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/localizations/browser/localizations.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/localizations/browser/localizationsActions.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/localizations/browser/minimalTranslations.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/logs/common/logConstants.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/logs/common/logs.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/logs/common/logsActions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/logs/common/logsDataCleaner.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/logs/electron-sandbox/logsActions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/markdown/common/markdownDocumentRenderer.ts (93%) rename {lib/vscode/src => src}/vs/workbench/contrib/markers/browser/constants.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/markers/browser/markers.contribution.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/markers/browser/markers.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/markers/browser/markersFileDecorations.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/markers/browser/markersFilterOptions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/markers/browser/markersModel.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/markers/browser/markersTreeViewer.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/markers/browser/markersView.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/markers/browser/markersViewActions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/markers/browser/media/markers.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/markers/browser/messages.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/markers/test/browser/markersModel.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/cellOperations/cellOperations.ts (97%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/cellOperations/test/cellOperations.test.ts (94%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/clipboard/test/notebookClipboard.test.ts (86%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts (66%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/find/findController.ts (60%) create mode 100644 src/vs/workbench/contrib/notebook/browser/contrib/find/findModel.ts rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/find/media/notebookFind.css (100%) create mode 100644 src/vs/workbench/contrib/notebook/browser/contrib/find/test/find.test.ts rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/fold/folding.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/fold/foldingModel.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/fold/test/notebookFolding.test.ts (59%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/format/formatting.ts (100%) create mode 100644 src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/layout/layoutActions.ts (92%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/layout/test/layoutActions.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/marker/markerProvider.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/navigation/arrow.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/outline/test/notebookOutline.test.ts (94%) create mode 100644 src/vs/workbench/contrib/notebook/browser/contrib/profile/notebookProfile.ts rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/status/editorStatus.ts (66%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/statusBar/contributedStatusBarItemController.ts (88%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/statusBar/executionStatusBarItemController.ts (59%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/statusBar/notebookVisibleCellObserver.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/statusBar/statusBarProviders.ts (67%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/troubleshoot/layout.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/undoRedo/notebookUndoRedo.ts (77%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/undoRedo/test/notebookUndoRedo.test.ts (91%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/contrib/viewportCustomMarkdown/viewportCustomMarkdown.ts (80%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts (97%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts (97%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/diff/eventDispatcher.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts (95%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts (97%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts (94%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/extensionPoint.ts (63%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/media/notebook.css (81%) create mode 100644 src/vs/workbench/contrib/notebook/browser/media/notebookKernelActionViewItem.css rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/notebook.contribution.ts (58%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/notebookBrowser.ts (92%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/notebookCellStatusBarServiceImpl.ts (93%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/notebookDiffEditorInput.ts (81%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/notebookEditor.ts (84%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/notebookEditorDecorations.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/notebookEditorExtensions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/notebookEditorKernelManager.ts (81%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/notebookEditorService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/notebookEditorServiceImpl.ts (98%) create mode 100644 src/vs/workbench/contrib/notebook/browser/notebookEditorToolbar.ts rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts (77%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/notebookEditorWidgetContextKeys.ts (56%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/notebookIcons.ts (92%) create mode 100644 src/vs/workbench/contrib/notebook/browser/notebookKernelActionViewItem.ts rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/notebookKernelServiceImpl.ts (98%) create mode 100644 src/vs/workbench/contrib/notebook/browser/notebookRendererMessagingServiceImpl.ts rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts (80%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts (98%) create mode 100644 src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts rename lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookRegistry.ts => src/vs/workbench/contrib/notebook/browser/view/output/rendererRegistry.ts (66%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts (50%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/view/output/transforms/textHelper.ts (79%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts (77%) create mode 100644 src/vs/workbench/contrib/notebook/browser/view/renderers/cellActionView.ts rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys.ts (78%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/view/renderers/cellDnd.ts (85%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/view/renderers/cellEditorOptions.ts (60%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/view/renderers/cellMenus.ts (91%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/view/renderers/cellOutput.ts (79%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts (81%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts (90%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts (88%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts (56%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/view/renderers/webviewThemeMapping.ts (76%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel.ts (91%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/viewModel/cellEdit.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts (68%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/viewModel/cellSelectionCollection.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts (74%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel.ts (67%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel.ts (92%) create mode 100644 src/vs/workbench/contrib/notebook/browser/viewModel/viewContext.ts rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/model/cellEdit.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/model/notebookCellOutputTextModel.ts (72%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts (78%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts (93%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/notebookCellStatusBarService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/notebookCommon.ts (77%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/notebookEditorInput.ts (71%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/notebookEditorModel.ts (79%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/notebookEditorModelResolverService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts (87%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/notebookKernelService.ts (97%) create mode 100644 src/vs/workbench/contrib/notebook/common/notebookOptions.ts rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/notebookOutputRenderer.ts (78%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/notebookPerformance.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/notebookProvider.ts (76%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/notebookRange.ts (87%) create mode 100644 src/vs/workbench/contrib/notebook/common/notebookRendererMessagingService.ts rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/notebookService.ts (83%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/services/notebookSimpleWorker.ts (92%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/services/notebookWorkerService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/common/services/notebookWorkerServiceImpl.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/test/notebookBrowser.test.ts (90%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/test/notebookCellList.test.ts (83%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/test/notebookCommon.test.ts (94%) create mode 100644 src/vs/workbench/contrib/notebook/test/notebookDiff.test.ts rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/test/notebookEditor.test.ts (97%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/test/notebookEditorKernelManager.test.ts (99%) create mode 100644 src/vs/workbench/contrib/notebook/test/notebookEditorModel.test.ts rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/test/notebookKernelService.test.ts (96%) create mode 100644 src/vs/workbench/contrib/notebook/test/notebookRendererMessagingService.test.ts rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/test/notebookSelection.test.ts (92%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/test/notebookServiceImpl.test.ts (93%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/test/notebookTextModel.test.ts (90%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/test/notebookViewModel.test.ts (94%) rename {lib/vscode/src => src}/vs/workbench/contrib/notebook/test/testNotebookEditor.ts (89%) rename {lib/vscode/src => src}/vs/workbench/contrib/outline/browser/outline.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/outline/browser/outlinePane.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/outline/browser/outlinePane.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/outline/browser/outlineViewState.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/output/browser/logViewer.ts (87%) rename {lib/vscode/src => src}/vs/workbench/contrib/output/browser/media/output.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/output/browser/output.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/output/browser/outputServices.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/output/browser/outputView.ts (93%) rename {lib/vscode/src => src}/vs/workbench/contrib/output/common/output.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/output/common/outputChannelModel.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/output/common/outputChannelModelService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/output/common/outputLinkComputer.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/output/common/outputLinkProvider.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/output/electron-sandbox/outputChannelModelService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/output/test/browser/outputLinkProvider.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/performance/browser/performance.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/performance/browser/perfviewEditor.ts (94%) rename {lib/vscode/src => src}/vs/workbench/contrib/performance/electron-sandbox/performance.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/performance/electron-sandbox/startupProfiler.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/performance/electron-sandbox/startupTimings.ts (93%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/keyboardLayoutPicker.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/media/keybindings.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/media/keybindingsEditor.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/media/preferences.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/media/settingsWidgets.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/preferences.contribution.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/preferencesActions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/preferencesEditor.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/preferencesIcons.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/preferencesSearch.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/settingsEditor2.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/settingsLayout.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/settingsTree.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts (97%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/settingsWidgets.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/browser/tocTree.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/common/preferences.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/common/preferencesContribution.ts (70%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/common/smartSnippetInserter.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/test/browser/keybindingsEditorContribution.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/test/browser/settingsTreeModels.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/preferences/test/common/smartSnippetInserter.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/quickaccess/browser/commandsQuickAccess.ts (97%) rename {lib/vscode/src => src}/vs/workbench/contrib/quickaccess/browser/quickAccess.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/quickaccess/browser/viewQuickAccess.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/remote/browser/explorerViewItems.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/remote/browser/media/remoteViewlet.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/remote/browser/media/tunnelView.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/remote/browser/remote.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/remote/browser/remoteExplorer.ts (95%) rename {lib/vscode/src => src}/vs/workbench/contrib/remote/browser/remoteIcons.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/remote/browser/remoteIndicator.ts (71%) rename {lib/vscode/src => src}/vs/workbench/contrib/remote/browser/tunnelView.ts (90%) rename {lib/vscode/src => src}/vs/workbench/contrib/remote/browser/urlFinder.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/remote/common/remote.contribution.ts (91%) rename {lib/vscode/src => src}/vs/workbench/contrib/remote/common/showCandidate.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/remote/common/tunnelFactory.ts (90%) rename {lib/vscode/src => src}/vs/workbench/contrib/remote/electron-sandbox/remote.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/sash/browser/sash.contribution.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/sash/browser/sash.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/scm/browser/activity.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/scm/browser/media/dirtydiffDecorator.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/scm/browser/media/scm.css (93%) rename {lib/vscode/src => src}/vs/workbench/contrib/scm/browser/menus.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/scm/browser/scm.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/scm/browser/scmRepositoriesViewPane.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/scm/browser/scmRepositoryRenderer.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/scm/browser/scmViewPane.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/scm/browser/scmViewPaneContainer.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/scm/browser/scmViewService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/scm/browser/util.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/scm/common/scm.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/scm/common/scmService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/browser/anythingQuickAccess.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/browser/media/anythingQuickAccess.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/browser/media/searchEditor.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/browser/media/searchview.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/browser/patternInputWidget.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/browser/replaceContributions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/browser/replaceService.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/browser/search.contribution.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/browser/searchActions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/browser/searchIcons.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/browser/searchResultsView.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/browser/searchView.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/browser/searchWidget.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/browser/symbolsQuickAccess.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/common/cacheState.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/common/constants.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/common/queryBuilder.ts (95%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/common/replace.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/common/search.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/common/searchHistoryService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/common/searchModel.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/test/browser/mockSearchTree.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/test/browser/queryBuilder.test.ts (94%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/test/browser/searchActions.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/test/browser/searchViewlet.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/test/common/cacheState.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/test/common/extractRange.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/test/common/searchModel.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/test/common/searchResult.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/search/test/electron-browser/queryBuilder.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/searchEditor/browser/constants.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/searchEditor/browser/media/searchEditor.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts (89%) rename {lib/vscode/src => src}/vs/workbench/contrib/searchEditor/browser/searchEditor.ts (82%) rename {lib/vscode/src => src}/vs/workbench/contrib/searchEditor/browser/searchEditorActions.ts (95%) rename {lib/vscode/src => src}/vs/workbench/contrib/searchEditor/browser/searchEditorInput.ts (57%) create mode 100644 src/vs/workbench/contrib/searchEditor/browser/searchEditorModel.ts rename {lib/vscode/src => src}/vs/workbench/contrib/searchEditor/browser/searchEditorSerialization.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/snippets/browser/configureSnippets.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/snippets/browser/insertSnippet.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/snippets/browser/snippets.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/snippets/browser/snippetsFile.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/snippets/browser/snippetsService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/snippets/browser/tabCompletion.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/snippets/test/browser/snippetFile.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/snippets/test/browser/snippetsRegistry.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/snippets/test/browser/snippetsRewrite.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/snippets/test/browser/snippetsService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/surveys/browser/ces.contribution.ts (88%) rename {lib/vscode/src => src}/vs/workbench/contrib/surveys/browser/languageSurveys.contribution.ts (83%) rename {lib/vscode/src => src}/vs/workbench/contrib/surveys/browser/nps.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/tags/browser/workspaceTagsService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/tags/common/javaWorkspaceTags.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/tags/common/workspaceTags.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/tags/electron-sandbox/tags.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/tags/electron-sandbox/workspaceTags.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/tags/electron-sandbox/workspaceTagsService.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/tags/test/electron-browser/workspaceTags.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/browser/abstractTaskService.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts (90%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/browser/task.contribution.ts (97%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/browser/taskQuickPick.ts (80%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/browser/taskService.ts (100%) create mode 100644 src/vs/workbench/contrib/tasks/browser/taskTerminalStatus.ts rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/browser/tasksQuickAccess.ts (80%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts (97%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/common/jsonSchemaCommon.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/common/jsonSchema_v1.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/common/problemCollectors.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/common/problemMatcher.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/common/taskConfiguration.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/common/taskDefinitionRegistry.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/common/taskService.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/common/taskSystem.ts (97%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/common/taskTemplates.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/common/tasks.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/electron-sandbox/taskService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/test/common/configuration.test.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/tasks/test/common/problemMatcher.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/telemetry/browser/telemetry.contribution.ts (100%) create mode 100644 src/vs/workbench/contrib/terminal/.eslintrc.json rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/addons/commandTrackerAddon.ts (92%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/addons/navigationModeAddon.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/environmentVariableInfo.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/links/terminalBaseLinkProvider.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/links/terminalExternalLinkProviderAdapter.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/links/terminalLink.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/links/terminalLinkHelpers.ts (89%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/links/terminalLinkManager.ts (95%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/links/terminalProtocolLinkProvider.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/links/terminalValidatedLocalLinkProvider.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/links/terminalWordLinkProvider.ts (60%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/media/scrollbar.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/media/terminal.css (68%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/media/widgets.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/media/xterm.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/remotePty.ts (75%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/remoteTerminalService.ts (65%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminal.contribution.ts (89%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminal.ts (81%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminal.web.contribution.ts (60%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminalActions.ts (84%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminalCommands.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts (81%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminalDecorationsProvider.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts (92%) rename lib/vscode/src/vs/workbench/contrib/terminal/browser/terminalTab.ts => src/vs/workbench/contrib/terminal/browser/terminalGroup.ts (73%) create mode 100644 src/vs/workbench/contrib/terminal/browser/terminalIcon.ts rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminalIcons.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminalInstance.ts (74%) create mode 100644 src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts create mode 100644 src/vs/workbench/contrib/terminal/browser/terminalMenus.ts rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts (60%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts (79%) create mode 100644 src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts (59%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminalService.ts (52%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminalStatusList.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts (66%) create mode 100644 src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminalTypeAheadAddon.ts (63%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/terminalView.ts (54%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/widgets/environmentVariableInfoWidget.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/widgets/terminalHoverWidget.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/widgets/widgetManager.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/widgets/widgets.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/browser/xterm-private.d.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/common/environmentVariable.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/common/environmentVariable.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/common/environmentVariableCollection.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/common/environmentVariableService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/common/environmentVariableShared.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts (72%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/common/terminal.ts (66%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/common/terminalColorRegistry.ts (89%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/common/terminalConfiguration.ts (54%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/common/terminalEnvironment.ts (93%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/common/terminalExtensionPoints.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/common/terminalExtensionPoints.ts (68%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/common/terminalStrings.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/electron-sandbox/localPty.ts (81%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/electron-sandbox/localTerminalService.ts (68%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts (73%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/electron-sandbox/terminalProfileResolverService.ts (84%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts (83%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/test/browser/links/terminalLinkHelpers.test.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/test/browser/links/terminalProtocolLinkProvider.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/test/browser/links/terminalValidatedLocalLinkProvider.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/test/browser/links/terminalWordLinkProvider.test.ts (70%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/test/browser/terminalCommandTracker.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/test/browser/terminalConfigHelper.test.ts (81%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/test/browser/terminalProcessManager.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/test/browser/terminalStatusList.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/test/browser/terminalTypeahead.test.ts (95%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/test/common/environmentVariableCollection.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/test/common/environmentVariableService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/test/common/environmentVariableShared.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/test/common/terminalColorRegistry.test.ts (80%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/test/common/terminalDataBuffering.test.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/test/common/terminalEnvironment.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/terminal/test/node/terminalProfiles.test.ts (62%) rename lib/vscode/src/vs/workbench/contrib/externalTerminal/node/externalTerminal.ts => src/vs/workbench/contrib/testing/browser/explorerProjections/display.ts (87%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation.ts (80%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByName.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/browser/explorerProjections/hierarchalNodes.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/browser/explorerProjections/index.ts (93%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/browser/explorerProjections/nodeHelper.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/browser/icons.ts (72%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/browser/media/testing.css (76%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/browser/testExplorerActions.ts (68%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/browser/testing.contribution.ts (82%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/browser/testingDecorations.ts (97%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/browser/testingExplorerView.ts (81%) create mode 100644 src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts rename {lib/vscode/src => src}/vs/workbench/contrib/testing/browser/testingOutputTerminalService.ts (91%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/browser/testingProgressUiService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/browser/testingViewPaneContainer.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/browser/theme.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/configuration.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/constants.ts (100%) create mode 100644 src/vs/workbench/contrib/testing/common/getComputedState.ts rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/observableValue.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/ownedTestCollection.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/storedValue.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/testCollection.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/testResult.ts (95%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/testResultService.ts (97%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/testResultStorage.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/testService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/testServiceImpl.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/testStubs.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/testingAutoRun.ts (74%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/testingContentProvider.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/testingContextKeys.ts (71%) create mode 100644 src/vs/workbench/contrib/testing/common/testingPeekOpener.ts rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/testingStates.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/testingUri.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/common/workspaceTestCollectionService.ts (61%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/test/browser/explorerProjections/hierarchalByLocation.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/test/browser/explorerProjections/hierarchalByName.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/test/browser/testObjectTree.ts (92%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/test/common/ownedTestCollection.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/test/common/testResultService.test.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/test/common/testResultStorage.test.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/testing/test/common/testingUri.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/themes/browser/themes.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/themes/browser/themes.test.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/timeline/browser/media/timelinePane.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/timeline/browser/timeline.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/timeline/browser/timelinePane.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/timeline/common/timeline.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/timeline/common/timelineService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/update/browser/media/releasenoteseditor.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/update/browser/releaseNotesEditor.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/update/browser/update.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/update/browser/update.ts (95%) rename {lib/vscode/src => src}/vs/workbench/contrib/update/common/update.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/url/browser/externalUriResolver.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/url/browser/trustedDomains.ts (95%) rename {lib/vscode/src => src}/vs/workbench/contrib/url/browser/trustedDomainsFileSystemProvider.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/url/browser/trustedDomainsValidator.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/url/browser/url.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/url/common/urlGlob.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/url/test/browser/trustedDomains.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/userDataSync/browser/media/userDataSyncViews.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/userDataSync/browser/userDataSync.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/userDataSync/browser/userDataSync.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/userDataSync/browser/userDataSyncMergesView.ts (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/userDataSync/browser/userDataSyncTrigger.ts (92%) rename {lib/vscode/src => src}/vs/workbench/contrib/userDataSync/browser/userDataSyncViews.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/userDataSync/electron-sandbox/userDataSync.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/watermark/browser/watermark.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/watermark/browser/watermark.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/browser/baseWebviewElement.ts (83%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay.ts (84%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/browser/pre/fake.html (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/browser/pre/host.js (89%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/browser/pre/index.html (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/browser/pre/main.js (78%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/browser/pre/service-worker.js (75%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/browser/resourceLoading.ts (66%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/browser/themeing.ts (64%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/browser/webview.contribution.ts (59%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/browser/webview.ts (73%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/browser/webview.web.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/browser/webviewElement.ts (89%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/browser/webviewFindWidget.ts (91%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/browser/webviewService.ts (88%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/browser/webviewWindowDragMonitor.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/electron-browser/pre/electron-index.js (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/electron-browser/pre/index.html (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/electron-browser/webviewElement.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/electron-browser/webviewIgnoreMenuShortcutsManager.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/electron-browser/webviewService.ts (96%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/electron-sandbox/iframeWebviewElement.ts (81%) rename {lib/vscode/src => src}/vs/workbench/contrib/webview/electron-sandbox/windowIgnoreMenuShortcutsManager.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/webviewPanel/browser/webviewCommands.ts (92%) rename {lib/vscode/src => src}/vs/workbench/contrib/webviewPanel/browser/webviewEditor.ts (95%) rename {lib/vscode/src => src}/vs/workbench/contrib/webviewPanel/browser/webviewEditorInput.ts (88%) rename {lib/vscode/src => src}/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputSerializer.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/webviewPanel/browser/webviewIconManager.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/webviewPanel/browser/webviewPanel.contribution.ts (80%) rename {lib/vscode/src => src}/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/webviewView/browser/webviewView.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts (66%) rename {lib/vscode/src => src}/vs/workbench/contrib/webviewView/browser/webviewViewService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/common/viewsWelcome.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/common/viewsWelcomeContribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/common/viewsWelcomeExtensionPoint.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.contribution.ts (64%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.css (92%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts (78%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts (69%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedIcons.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedInput.ts (85%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedService.ts (58%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/gettingStartedContent.ts (67%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/colorTheme.png (100%) create mode 100644 src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark.png rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/commandPalette.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/debug.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/extensions.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/languageExtensions.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/openFolder.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/playground.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/scm.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/settings.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/settingsSync.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/shortcuts.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/splitview.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/tasks.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/terminal.png (100%) create mode 100644 src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/workspaceTrust.svg create mode 100644 src/vs/workbench/contrib/welcome/gettingStarted/common/media/example_markdown_media.ts rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/github.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/commandPalette.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/extensions.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/languageExtensions.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/openFolder.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/settings.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/settingsSync.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/terminal.png (100%) create mode 100644 src/vs/workbench/contrib/welcome/gettingStarted/common/media/light.png rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/light/commandPalette.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/light/debug.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/light/extensions.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/light/languageExtensions.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/light/openFolder.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/light/playground.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/light/scm.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/light/settings.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/light/settingsSync.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/light/shortcuts.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/light/splitview.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/light/tasks.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/light/terminal.png (100%) create mode 100644 src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/workspaceTrust.svg create mode 100644 src/vs/workbench/contrib/welcome/gettingStarted/common/media/monokai.png create mode 100644 src/vs/workbench/contrib/welcome/gettingStarted/common/media/more.png create mode 100644 src/vs/workbench/contrib/welcome/gettingStarted/common/media/notebookProfile.ts create mode 100644 src/vs/workbench/contrib/welcome/gettingStarted/common/media/notebookThemes/colab.png create mode 100644 src/vs/workbench/contrib/welcome/gettingStarted/common/media/notebookThemes/default.png create mode 100644 src/vs/workbench/contrib/welcome/gettingStarted/common/media/notebookThemes/jupyter.png create mode 100644 src/vs/workbench/contrib/welcome/gettingStarted/common/media/quiet-light.png rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/gettingStarted/common/media/tutorialVideo.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/overlay/browser/media/commandpalette-dark.svg (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/overlay/browser/media/commandpalette.svg (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/page/browser/vs_code_welcome_page.ts (87%) create mode 100644 src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/page/browser/welcomePage.css (99%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/page/browser/welcomePage.ts (80%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/page/browser/welcomePageColors.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/telemetryOptOut/electron-sandbox/telemetryOptOut.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/telemetryOptOut/electron-sandbox/telemetryOptOut.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/walkThrough/browser/editor/editorWalkThrough.ts (91%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/walkThrough/browser/editor/vs_code_editor_walkthrough.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughActions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput.ts (94%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.css (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts (98%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/walkThrough/common/walkThroughContentProvider.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils.ts (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/workspace/browser/media/trusted-badge.png (100%) rename {lib/vscode/src => src}/vs/workbench/contrib/workspace/browser/media/untrusted-status.png (100%) create mode 100644 src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts rename {lib/vscode/src => src}/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css (68%) create mode 100644 src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts rename {lib/vscode/src => src}/vs/workbench/contrib/workspaces/browser/workspaces.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/electron-browser/desktop.main.ts (100%) rename {lib/vscode/src => src}/vs/workbench/electron-sandbox/actions/developerActions.ts (100%) create mode 100644 src/vs/workbench/electron-sandbox/actions/installActions.ts rename {lib/vscode/src => src}/vs/workbench/electron-sandbox/actions/media/actions.css (100%) create mode 100644 src/vs/workbench/electron-sandbox/actions/windowActions.ts rename {lib/vscode/src => src}/vs/workbench/electron-sandbox/desktop.contribution.ts (66%) rename {lib/vscode/src => src}/vs/workbench/electron-sandbox/desktop.main.ts (100%) rename {lib/vscode/src => src}/vs/workbench/electron-sandbox/parts/dialogs/dialog.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts (100%) rename {lib/vscode/src => src}/vs/workbench/electron-sandbox/parts/titlebar/menubarControl.ts (95%) rename {lib/vscode/src => src}/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts (100%) rename {lib/vscode/src => src}/vs/workbench/electron-sandbox/sandbox.simpleservices.ts (78%) rename {lib/vscode/src => src}/vs/workbench/electron-sandbox/shared.desktop.main.ts (98%) create mode 100644 src/vs/workbench/electron-sandbox/splash.ts rename {lib/vscode/src => src}/vs/workbench/electron-sandbox/window.ts (94%) rename {lib/vscode/src => src}/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/activity/browser/activityService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/activity/common/activity.ts (85%) rename {lib/vscode/src => src}/vs/workbench/services/activityBar/browser/activityBarService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/authentication/browser/authenticationService.ts (97%) create mode 100644 src/vs/workbench/services/banner/browser/bannerService.ts rename {lib/vscode/src => src}/vs/workbench/services/clipboard/browser/clipboardService.ts (86%) rename {lib/vscode/src => src}/vs/workbench/services/clipboard/electron-sandbox/clipboardService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/commands/common/commandService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/commands/test/common/commandService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/configuration/browser/configuration.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/configuration/browser/configurationCache.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/configuration/browser/configurationService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/configuration/common/configuration.ts (86%) rename {lib/vscode/src => src}/vs/workbench/services/configuration/common/configurationEditingService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/configuration/common/configurationModels.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/configuration/common/jsonEditing.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/configuration/common/jsonEditingService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/configuration/electron-sandbox/configurationCache.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/configuration/test/browser/configurationEditingService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/configuration/test/browser/configurationService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/configuration/test/common/configurationModels.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/configuration/test/common/testServices.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/configurationResolver/common/configurationResolver.ts (89%) rename {lib/vscode/src => src}/vs/workbench/services/configurationResolver/common/configurationResolverSchema.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/configurationResolver/common/configurationResolverUtils.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/configurationResolver/common/variableResolver.ts (96%) rename {lib/vscode/src => src}/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts (96%) rename {lib/vscode/src => src}/vs/workbench/services/credentials/browser/credentialsService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/credentials/common/credentials.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/credentials/electron-sandbox/credentialsService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/decorations/browser/decorations.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/decorations/browser/decorationsService.ts (95%) rename {lib/vscode/src => src}/vs/workbench/services/decorations/test/browser/decorationsService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/dialogs/browser/fileDialogService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/dialogs/browser/simpleFileDialog.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/dialogs/common/dialogService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/dialogs/electron-sandbox/fileDialogService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/editor/browser/codeEditorService.ts (95%) rename {lib/vscode/src => src}/vs/workbench/services/editor/browser/editorDropService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/editor/browser/editorOverrideService.ts (73%) rename {lib/vscode/src => src}/vs/workbench/services/editor/browser/editorService.ts (77%) rename {lib/vscode/src => src}/vs/workbench/services/editor/common/editorGroupsService.ts (97%) rename {lib/vscode/src => src}/vs/workbench/services/editor/common/editorOverrideService.ts (64%) rename {lib/vscode/src => src}/vs/workbench/services/editor/common/editorService.ts (77%) rename {lib/vscode/src => src}/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts (94%) rename {lib/vscode/src => src}/vs/workbench/services/editor/test/browser/editorService.test.ts (79%) rename {lib/vscode/src => src}/vs/workbench/services/editor/test/browser/editorsObserver.test.ts (90%) rename {lib/vscode/src => src}/vs/workbench/services/encryption/browser/encryptionService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/encryption/common/encryptionService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/encryption/electron-sandbox/encryptionService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/environment/browser/environmentService.ts (86%) rename {lib/vscode/src => src}/vs/workbench/services/environment/common/environmentService.ts (96%) rename {lib/vscode/src => src}/vs/workbench/services/environment/electron-sandbox/environmentService.ts (87%) rename {lib/vscode/src => src}/vs/workbench/services/environment/electron-sandbox/shellEnvironmentService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/experiment/common/experimentService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensionManagement/browser/extensionBisect.ts (99%) rename {lib/vscode/src => src}/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts (93%) rename {lib/vscode/src => src}/vs/workbench/services/extensionManagement/browser/extensionUrlTrustService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensionManagement/common/extensionManagement.ts (95%) rename {lib/vscode/src => src}/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensionManagement/common/extensionManagementService.ts (96%) rename {lib/vscode/src => src}/vs/workbench/services/extensionManagement/common/remoteExtensionManagementService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensionManagement/common/webExtensionsScannerService.ts (95%) rename {lib/vscode/src => src}/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts (92%) rename {lib/vscode/src => src}/vs/workbench/services/extensionManagement/electron-sandbox/extensionTipsService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensionManagement/electron-sandbox/extensionUrlTrustService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts (97%) rename {lib/vscode/src => src}/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts (99%) rename {lib/vscode/src => src}/vs/workbench/services/extensionRecommendations/common/extensionIgnoredRecommendationsService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensionRecommendations/common/extensionRecommendations.ts (98%) rename {lib/vscode/src => src}/vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/browser/extensionService.ts (98%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/browser/extensionUrlHandler.ts (97%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts (99%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/browser/webWorkerFileSystemProvider.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/common/abstractExtensionService.ts (90%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/common/extensionDescriptionRegistry.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/common/extensionDevOptions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/common/extensionHostMain.ts (92%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/common/extensionHostManager.ts (97%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/common/extensionHostProtocol.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/common/extensionManifestPropertiesService.ts (92%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/common/extensionPoints.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/common/extensions.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/common/extensionsRegistry.ts (91%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/common/extensionsUtil.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/common/lazyPromise.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/common/polyfillNestedWorker.protocol.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/common/proxyIdentifier.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/common/remoteConsoleUtil.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/common/remoteExtensionHost.ts (98%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/common/rpcProtocol.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts (92%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/electron-browser/extensionService.ts (92%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts (99%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/node/extensionHostProcess.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts (95%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/node/extensionPoints.ts (90%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/node/proxyResolver.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/test/browser/extensionService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/test/common/extensionManifestPropertiesService.test.ts (80%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/test/common/rpcProtocol.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/worker/extensionHostWorker.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/worker/httpWebWorkerExtensionHostIframe.html (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/worker/httpsWebWorkerExtensionHostIframe.html (100%) rename {lib/vscode/src => src}/vs/workbench/services/extensions/worker/polyfillNestedWorker.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/files/browser/elevatedFileService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/files/common/elevatedFileService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/files/electron-sandbox/elevatedFileService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/filesConfiguration/common/filesConfigurationService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/history/browser/history.ts (99%) rename {lib/vscode/src => src}/vs/workbench/services/history/common/history.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/history/test/browser/history.test.ts (86%) rename {lib/vscode/src => src}/vs/workbench/services/host/browser/browserHostService.ts (98%) rename {lib/vscode/src => src}/vs/workbench/services/host/browser/host.ts (97%) rename {lib/vscode/src => src}/vs/workbench/services/host/electron-sandbox/nativeHostService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/hover/browser/hover.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/hover/browser/hoverService.ts (84%) rename {lib/vscode/src => src}/vs/workbench/services/hover/browser/hoverWidget.ts (98%) rename {lib/vscode/src => src}/vs/workbench/services/hover/browser/media/hover.css (100%) rename {lib/vscode/src => src}/vs/workbench/services/integrity/browser/integrityService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/integrity/common/integrity.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/integrity/electron-sandbox/integrityService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/ipc/electron-sandbox/sharedProcessService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/issue/common/issue.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/issue/electron-sandbox/issueService.ts (83%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keybindingService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/cz.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/de-swiss.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/de.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/de.linux.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/de.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/dk.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/dvorak.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/en-belgian.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/en-ext.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/en-in.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/en.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/en.linux.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/en.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/es-latin.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/es.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/es.linux.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/es.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.linux.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/hu.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/it.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/it.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/jp-roman.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/jp.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/ko.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.linux.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/no.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/pl.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/pl.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/pt-br.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/pt.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/pt.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.linux.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/sv.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/sv.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/thai.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/tr.win.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/keyboardLayouts/zh-hans.darwin.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/navigatorKeyboard.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/browser/unboundCommands.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/common/keybindingEditing.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/common/keybindingIO.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/common/keymapInfo.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts (99%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/common/windowsKeyboardMapper.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/electron-sandbox/nativeKeyboardLayout.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/browser/browserKeyboardMapper.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/browser/keybindingEditing.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/browser/keybindingIO.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/keyboardMapperTestUtils.ts (94%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/linux_de_ch.js (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/linux_de_ch.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/linux_en_uk.js (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/linux_en_uk.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/linux_en_us.js (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/linux_en_us.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/linux_ru.js (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/linux_ru.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/macLinuxFallbackKeyboardMapper.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/macLinuxKeyboardMapper.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/mac_de_ch.js (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/mac_de_ch.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/mac_en_us.js (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/mac_en_us.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/mac_zh_hant.js (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/mac_zh_hant.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/win_de_ch.js (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/win_de_ch.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/win_en_us.js (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/win_en_us.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/win_por_ptb.js (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/win_por_ptb.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/win_ru.js (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/win_ru.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/keybinding/test/electron-browser/windowsKeyboardMapper.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/label/common/labelService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/label/test/browser/label.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/label/test/electron-browser/label.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/layout/browser/layoutService.ts (98%) rename {lib/vscode/src => src}/vs/workbench/services/lifecycle/browser/lifecycleService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/lifecycle/common/lifecycle.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/lifecycle/common/lifecycleService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/lifecycle/electron-sandbox/lifecycleService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/localizations/electron-sandbox/localizationsService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/log/electron-sandbox/logService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/menubar/electron-sandbox/menubarService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/mode/common/workbenchModeService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/notification/common/notificationService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/outline/browser/outline.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/outline/browser/outlineService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/output/common/output.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/panel/common/panelService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/path/browser/pathService.ts (90%) rename {lib/vscode/src => src}/vs/workbench/services/path/common/pathService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/path/electron-sandbox/pathService.ts (56%) create mode 100644 src/vs/workbench/services/preferences/browser/keybindingsEditorInput.ts rename {lib/vscode/src => src}/vs/workbench/services/preferences/browser/keybindingsEditorModel.ts (99%) rename {lib/vscode/src => src}/vs/workbench/services/preferences/browser/preferencesService.ts (91%) rename {lib/vscode/src => src}/vs/workbench/services/preferences/common/preferences.ts (91%) rename {lib/vscode/src/vs/workbench/services/preferences/browser => src/vs/workbench/services/preferences/common}/preferencesEditorInput.ts (61%) rename {lib/vscode/src => src}/vs/workbench/services/preferences/common/preferencesModels.ts (99%) rename {lib/vscode/src => src}/vs/workbench/services/preferences/common/preferencesValidation.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/preferences/test/browser/keybindingsEditorModel.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/preferences/test/browser/preferencesService.test.ts (85%) rename {lib/vscode/src => src}/vs/workbench/services/preferences/test/common/preferencesValidation.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/progress/browser/media/progressService.css (100%) rename {lib/vscode/src => src}/vs/workbench/services/progress/browser/progressIndicator.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/progress/browser/progressService.ts (93%) rename {lib/vscode/src => src}/vs/workbench/services/progress/test/browser/progressIndicator.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/quickinput/browser/quickInputService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/remote/browser/remoteAgentServiceImpl.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/remote/browser/tunnelServiceImpl.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/remote/common/abstractRemoteAgentService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/remote/common/remoteAgentFileSystemChannel.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/remote/common/remoteAgentService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/remote/common/remoteExplorerService.ts (79%) rename {lib/vscode/src => src}/vs/workbench/services/remote/electron-browser/tunnelServiceImpl.ts (88%) rename {lib/vscode/src => src}/vs/workbench/services/remote/electron-sandbox/remoteAgentServiceImpl.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/remote/test/common/testServices.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/request/browser/requestService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/request/electron-sandbox/requestService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/browser/searchService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/common/fileSearchManager.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/common/replace.ts (99%) rename {lib/vscode/src => src}/vs/workbench/services/search/common/search.ts (98%) rename {lib/vscode/src => src}/vs/workbench/services/search/common/searchExtTypes.ts (96%) rename {lib/vscode/src => src}/vs/workbench/services/search/common/searchHelpers.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/common/searchService.ts (99%) rename {lib/vscode/src => src}/vs/workbench/services/search/common/textSearchManager.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/electron-browser/searchService.ts (97%) rename {lib/vscode/src => src}/vs/workbench/services/search/node/fileSearch.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/node/rawSearchService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/node/ripgrepFileSearch.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/node/ripgrepSearchProvider.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/node/ripgrepSearchUtils.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts (96%) rename {lib/vscode/src => src}/vs/workbench/services/search/node/searchApp.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/node/searchIpc.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/node/textSearchAdapter.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/node/textSearchManager.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/common/replace.test.ts (94%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/common/search.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/common/searchHelpers.test.ts (75%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/electron-browser/rawSearchService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/fileSearch.integrationTest.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/fixtures/binary.wuff (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/fixtures/examples/NullPoinderException.js (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/fixtures/examples/company.js (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/fixtures/examples/employee.js (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/fixtures/examples/small.js (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/fixtures/examples/subfolder/anotherfolder/anotherfile.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/fixtures/examples/subfolder/subfile.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/fixtures/index.html (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/fixtures/more/file.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/fixtures/site.css (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/fixtures/site.less (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/fixtures/some_utf16be.css (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/fixtures/some_utf16le.css (100%) rename "lib/vscode/src/vs/workbench/services/search/test/node/fixtures/\303\274m laut\346\261\211\350\257\255/\346\261\211\350\257\255.txt" => "src/vs/workbench/services/search/test/node/fixtures/\303\274m laut\346\261\211\350\257\255/\346\261\211\350\257\255.txt" (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/fixtures2/36438/modules/do-not-find.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/fixtures2/36438/more/modules/find.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/ripgrepFileSearch.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/ripgrepTextSearchEngine.test.ts (98%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/search.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/textSearch.integrationTest.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/search/test/node/textSearchManager.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/statusbar/common/statusbar.ts (90%) rename {lib/vscode/src => src}/vs/workbench/services/telemetry/browser/telemetryService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/telemetry/browser/workbenchCommonProperties.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/telemetry/electron-sandbox/telemetryService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/telemetry/electron-sandbox/workbenchCommonProperties.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/telemetry/test/browser/commonProperties.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/telemetry/test/electron-browser/commonProperties.test.ts (97%) rename {lib/vscode/src => src}/vs/workbench/services/textMate/browser/abstractTextMateService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/textMate/browser/textMateService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/textMate/common/TMGrammarFactory.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/textMate/common/TMGrammars.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/textMate/common/TMHelper.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/textMate/common/TMScopeRegistry.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/textMate/common/cgmanifest.json (100%) rename {lib/vscode/src => src}/vs/workbench/services/textMate/common/textMateService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/textMate/electron-sandbox/textMateService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/textMate/electron-sandbox/textMateWorker.ts (100%) create mode 100644 src/vs/workbench/services/textfile/browser/browserTextFileService.ts rename {lib/vscode/src => src}/vs/workbench/services/textfile/browser/textFileService.ts (99%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/common/encoding.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/common/textFileEditorModel.ts (97%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/common/textFileEditorModelManager.ts (91%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/common/textFileSaveParticipant.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/common/textfiles.ts (99%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/electron-sandbox/nativeTextFileService.ts (98%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/browser/browserTextFileService.io.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/browser/fixtures/files.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/browser/textFileEditorModel.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/browser/textFileEditorModelManager.test.ts (99%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/browser/textFileService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/common/textFileService.io.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/binary.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/index.html (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/lorem.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/lorem_big5.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/lorem_cp1252.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/lorem_cp866.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/lorem_gbk.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/lorem_shiftjis.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/lorem_utf16be.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/lorem_utf16le.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/lorem_utf8bom.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/small.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/small_umlaut.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/some.utf16le (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/some_big5.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/some_cp1252.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/some_cyrillic.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/some_gbk.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/some_shiftjis.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/some_small_cp1252.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/some_utf16le.css (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/some_utf8_bom.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/utf16_be_nobom.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/fixtures/utf16_le_nobom.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/nativeTextFileService.io.test.ts (95%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/electron-browser/nativeTextFileService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/encoding.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/empty.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/issue_102202.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/some.cp1252.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/some.css.qwoff (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/some.json.png (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/some.pdf (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/some.png.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/some.qwoff.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/some.shiftjis.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/some.xml.png (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/some_ansi.css (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/some_file.css (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/some_gbk.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/some_utf16be.css (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/some_utf16le.css (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/some_utf8.css (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/utf16_be_nobom.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textfile/test/node/encoding/fixtures/utf16_le_nobom.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts (96%) rename {lib/vscode/src => src}/vs/workbench/services/textmodelResolver/test/browser/textModelResolverService.test.ts (94%) rename {lib/vscode/src => src}/vs/workbench/services/textresourceProperties/common/textResourcePropertiesService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/browser/browserHostColorSchemeService.ts (91%) rename {lib/vscode/src => src}/vs/workbench/services/themes/browser/fileIconThemeData.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/browser/productIconThemeData.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/browser/workbenchThemeService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/common/colorExtensionPoint.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/common/colorThemeData.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/common/colorThemeSchema.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/common/fileIconThemeSchema.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/common/hostColorSchemeService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/common/iconExtensionPoint.ts (98%) rename {lib/vscode/src => src}/vs/workbench/services/themes/common/plistParser.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/common/productIconThemeSchema.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/common/textMateScopeMatcher.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/common/themeCompatibility.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/common/themeConfiguration.ts (99%) rename {lib/vscode/src => src}/vs/workbench/services/themes/common/themeExtensionPoints.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/common/tokenClassificationExtensionPoint.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/common/workbenchThemeService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/electron-sandbox/nativeHostColorSchemeService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/test/electron-browser/color-theme.json (100%) rename {lib/vscode/src => src}/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/timer/browser/timerService.ts (97%) rename {lib/vscode/src => src}/vs/workbench/services/timer/electron-sandbox/timerService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/title/common/titleService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/title/electron-sandbox/titleService.ts (100%) create mode 100644 src/vs/workbench/services/untitled/common/untitledTextEditorHandler.ts rename {lib/vscode/src => src}/vs/workbench/services/untitled/common/untitledTextEditorInput.ts (73%) rename {lib/vscode/src => src}/vs/workbench/services/untitled/common/untitledTextEditorModel.ts (91%) rename {lib/vscode/src => src}/vs/workbench/services/untitled/common/untitledTextEditorService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/untitled/test/browser/untitledTextEditor.test.ts (96%) rename {lib/vscode/src => src}/vs/workbench/services/update/browser/updateService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/update/electron-sandbox/updateService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/uriIdentity/common/uriIdentity.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/uriIdentity/common/uriIdentityService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/uriIdentity/test/common/uriIdentityService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/url/browser/urlService.ts (71%) rename {lib/vscode/src => src}/vs/workbench/services/url/electron-sandbox/urlService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/userData/browser/userDataInit.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/userData/common/fileUserDataProvider.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/userData/test/browser/fileUserDataProvider.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/userDataSync/browser/userDataAutoSyncEnablementService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/userDataSync/browser/userDataSyncResourceEnablementService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/userDataSync/common/userDataSync.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/userDataSync/common/userDataSyncUtil.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/userDataSync/electron-sandbox/userDataAutoSyncService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncAccountService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncMachinesService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/userDataSync/electron-sandbox/userDataSyncStoreManagementService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/viewlet/browser/viewlet.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/views/browser/viewDescriptorService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/views/common/viewContainerModel.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/views/test/browser/viewContainerModel.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/views/test/browser/viewDescriptorService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/browser/workingCopyBackupService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/browser/workingCopyBackupTracker.ts (100%) create mode 100644 src/vs/workbench/services/workingCopy/common/abstractFileWorkingCopyManager.ts create mode 100644 src/vs/workbench/services/workingCopy/common/fileWorkingCopy.ts create mode 100644 src/vs/workbench/services/workingCopy/common/fileWorkingCopyManager.ts create mode 100644 src/vs/workbench/services/workingCopy/common/resourceWorkingCopy.ts rename lib/vscode/src/vs/workbench/services/workingCopy/common/fileWorkingCopy.ts => src/vs/workbench/services/workingCopy/common/storedFileWorkingCopy.ts (71%) rename lib/vscode/src/vs/workbench/services/workingCopy/common/fileWorkingCopyManager.ts => src/vs/workbench/services/workingCopy/common/storedFileWorkingCopyManager.ts (54%) create mode 100644 src/vs/workbench/services/workingCopy/common/untitledFileWorkingCopy.ts create mode 100644 src/vs/workbench/services/workingCopy/common/untitledFileWorkingCopyManager.ts rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/common/workingCopy.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/common/workingCopyBackup.ts (93%) rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/common/workingCopyBackupService.ts (95%) rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/common/workingCopyBackupTracker.ts (95%) rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/common/workingCopyEditorService.ts (99%) rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/common/workingCopyFileOperationParticipant.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/common/workingCopyFileService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/common/workingCopyService.ts (86%) rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupTracker.ts (85%) create mode 100644 src/vs/workbench/services/workingCopy/test/browser/fileWorkingCopyManager.test.ts create mode 100644 src/vs/workbench/services/workingCopy/test/browser/resourceWorkingCopyTest.ts rename lib/vscode/src/vs/workbench/services/workingCopy/test/browser/fileWorkingCopy.test.ts => src/vs/workbench/services/workingCopy/test/browser/storedFileWorkingCopy.test.ts (69%) rename lib/vscode/src/vs/workbench/services/workingCopy/test/browser/fileWorkingCopyManager.test.ts => src/vs/workbench/services/workingCopy/test/browser/storedFileWorkingCopyManager.test.ts (67%) create mode 100644 src/vs/workbench/services/workingCopy/test/browser/untitledFileWorkingCopy.test.ts create mode 100644 src/vs/workbench/services/workingCopy/test/browser/untitledFileWorkingCopyManager.test.ts rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/test/browser/workingCopyBackupTracker.test.ts (95%) rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/test/browser/workingCopyEditorService.test.ts (91%) rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/test/browser/workingCopyFileService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts (93%) rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/test/electron-browser/fixtures/binary.txt (100%) rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/test/electron-browser/workingCopyBackupService.test.ts (98%) rename {lib/vscode/src => src}/vs/workbench/services/workingCopy/test/electron-browser/workingCopyBackupTracker.test.ts (93%) rename {lib/vscode/src => src}/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts (96%) rename {lib/vscode/src => src}/vs/workbench/services/workspaces/browser/workspaceEditingService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/workspaces/browser/workspaceTrustEditorInput.ts (93%) rename {lib/vscode/src => src}/vs/workbench/services/workspaces/browser/workspaces.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/workspaces/browser/workspacesService.ts (99%) rename {lib/vscode/src => src}/vs/workbench/services/workspaces/common/workspaceEditing.ts (100%) create mode 100644 src/vs/workbench/services/workspaces/common/workspaceTrust.ts rename {lib/vscode/src => src}/vs/workbench/services/workspaces/electron-sandbox/workspaceEditingService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/workspaces/electron-sandbox/workspacesService.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/workspaces/test/browser/workspaces.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/services/workspaces/test/common/testWorkspaceTrustService.ts (56%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHost.api.impl.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostApiCommands.test.ts (95%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostBulkEdits.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostCommands.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostConfiguration.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostDecorations.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostDiagnostics.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostDocumentData.test.perf-data.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostDocumentData.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostDocumentSaveParticipant.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostDocumentsAndEditors.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostFileSystemEventService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostLanguageFeatures.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostMessagerService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostNotebook.test.ts (93%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostNotebookConcatDocument.test.ts (99%) create mode 100644 src/vs/workbench/test/browser/api/extHostNotebookKernel2.test.ts rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostTesting.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostTextEditor.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostTreeViews.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostTypeConverter.test.ts (85%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostTypes.test.ts (91%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostWebview.test.ts (53%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/extHostWorkspace.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/mainThreadCommands.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/mainThreadConfiguration.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/mainThreadDiagnostics.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/mainThreadDocumentContentProviders.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/mainThreadDocuments.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/mainThreadDocumentsAndEditors.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/mainThreadEditors.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/mainThreadTreeViews.test.ts (98%) rename {lib/vscode/src => src}/vs/workbench/test/browser/api/testRPCProtocol.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/codeeditor.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/part.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/parts/editor/breadcrumbModel.test.ts (100%) rename lib/vscode/src/vs/workbench/test/browser/parts/editor/editorInput.test.ts => src/vs/workbench/test/browser/parts/editor/diffEditorInput.test.ts (78%) rename {lib/vscode/src => src}/vs/workbench/test/browser/parts/editor/editor.test.ts (77%) rename {lib/vscode/src => src}/vs/workbench/test/browser/parts/editor/editorDiffModel.test.ts (80%) rename {lib/vscode/src => src}/vs/workbench/test/browser/parts/editor/editorGroupModel.test.ts (99%) create mode 100644 src/vs/workbench/test/browser/parts/editor/editorInput.test.ts rename {lib/vscode/src => src}/vs/workbench/test/browser/parts/editor/editorModel.test.ts (96%) rename {lib/vscode/src => src}/vs/workbench/test/browser/parts/editor/editorPane.test.ts (61%) create mode 100644 src/vs/workbench/test/browser/parts/editor/resourceEditorInput.test.ts create mode 100644 src/vs/workbench/test/browser/parts/editor/sideBySideEditorInput.test.ts create mode 100644 src/vs/workbench/test/browser/parts/editor/textResourceEditorInput.test.ts rename {lib/vscode/src => src}/vs/workbench/test/browser/quickAccess.test.ts (92%) rename {lib/vscode/src => src}/vs/workbench/test/browser/viewlet.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/browser/workbenchTestServices.ts (92%) rename {lib/vscode/src => src}/vs/workbench/test/common/memento.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/common/notifications.test.ts (93%) rename {lib/vscode/src => src}/vs/workbench/test/common/workbenchTestServices.ts (98%) rename {lib/vscode/src => src}/vs/workbench/test/electron-browser/api/extHostSearch.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/electron-browser/api/mainThreadWorkspace.test.ts (96%) rename {lib/vscode/src => src}/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts (97%) create mode 100644 src/vs/workbench/test/electron-browser/colorRegistryExport.test.ts rename {lib/vscode/src => src}/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts (100%) rename {lib/vscode/src => src}/vs/workbench/test/electron-browser/workbenchTestServices.ts (97%) rename {lib/vscode/src => src}/vs/workbench/test/node/api/extHostTunnelService.test.ts (100%) rename {lib/vscode/src => src}/vs/workbench/workbench.common.main.ts (99%) rename {lib/vscode/src => src}/vs/workbench/workbench.desktop.main.css (100%) rename {lib/vscode/src => src}/vs/workbench/workbench.desktop.main.nls.js (100%) rename {lib/vscode/src => src}/vs/workbench/workbench.desktop.main.ts (84%) rename {lib/vscode/src => src}/vs/workbench/workbench.desktop.sandbox.main.ts (90%) rename {lib/vscode/src => src}/vs/workbench/workbench.sandbox.main.ts (96%) rename {lib/vscode/src => src}/vs/workbench/workbench.web.api.css (100%) rename {lib/vscode/src => src}/vs/workbench/workbench.web.api.nls.js (100%) rename {lib/vscode/src => src}/vs/workbench/workbench.web.api.ts (95%) rename {lib/vscode/src => src}/vs/workbench/workbench.web.main.ts (98%) rename {lib/vscode/test => test}/.mocharc.json (100%) rename {lib/vscode/test => test}/README.md (100%) rename {lib/vscode/test => test}/automation/.gitignore (100%) rename {lib/vscode/test => test}/automation/.npmignore (100%) rename {lib/vscode/test => test}/automation/README.md (100%) rename {lib/vscode/test => test}/automation/package.json (97%) rename {lib/vscode/test => test}/automation/src/activityBar.ts (100%) rename {lib/vscode/test => test}/automation/src/application.ts (90%) rename {lib/vscode/test => test}/automation/src/code.ts (99%) rename {lib/vscode/test => test}/automation/src/debug.ts (100%) rename {lib/vscode/test => test}/automation/src/driver.js (100%) rename {lib/vscode/test => test}/automation/src/editor.ts (100%) rename {lib/vscode/test => test}/automation/src/editors.ts (100%) rename {lib/vscode/test => test}/automation/src/explorer.ts (100%) rename {lib/vscode/test => test}/automation/src/extensions.ts (100%) rename {lib/vscode/test => test}/automation/src/index.ts (100%) rename {lib/vscode/test => test}/automation/src/keybindings.ts (100%) rename {lib/vscode/test => test}/automation/src/logger.ts (100%) rename {lib/vscode/test => test}/automation/src/notebook.ts (100%) rename {lib/vscode/test => test}/automation/src/peek.ts (100%) rename {lib/vscode/test => test}/automation/src/playwrightDriver.ts (100%) rename {lib/vscode/test => test}/automation/src/problems.ts (100%) rename {lib/vscode/test => test}/automation/src/quickaccess.ts (100%) rename {lib/vscode/test => test}/automation/src/quickinput.ts (100%) rename {lib/vscode/test => test}/automation/src/scm.ts (100%) rename {lib/vscode/test => test}/automation/src/search.ts (95%) rename {lib/vscode/test => test}/automation/src/settings.ts (100%) rename {lib/vscode/test => test}/automation/src/statusbar.ts (100%) rename {lib/vscode/test => test}/automation/src/terminal.ts (100%) rename {lib/vscode/test => test}/automation/src/viewlet.ts (100%) rename {lib/vscode/test => test}/automation/src/workbench.ts (100%) rename {lib/vscode/test => test}/automation/tools/copy-driver-definition.js (100%) rename {lib/vscode/test => test}/automation/tools/copy-package-version.js (100%) rename {lib/vscode/test => test}/automation/tsconfig.json (100%) rename {lib/vscode/test => test}/automation/yarn.lock (99%) rename {lib/vscode/test => test}/cgmanifest.json (100%) delete mode 100644 test/config.ts delete mode 100644 test/e2e/browser.test.ts delete mode 100644 test/e2e/codeServer.test.ts delete mode 100644 test/e2e/globalSetup.test.ts delete mode 100644 test/e2e/login.test.ts delete mode 100644 test/e2e/logout.test.ts delete mode 100644 test/e2e/models/CodeServer.ts delete mode 100644 test/e2e/openHelpAbout.test.ts delete mode 100644 test/e2e/terminal.test.ts rename {lib/vscode/test => test}/integration/browser/.gitignore (100%) rename {lib/vscode/test => test}/integration/browser/README.md (100%) rename {lib/vscode/test => test}/integration/browser/package.json (93%) rename {lib/vscode/test => test}/integration/browser/src/index.ts (95%) rename {lib/vscode/test => test}/integration/browser/tsconfig.json (100%) rename {lib/vscode/test => test}/integration/browser/yarn.lock (96%) rename {lib/vscode/test => test}/integration/electron/testrunner.js (100%) create mode 100644 test/leaks/index.html create mode 100644 test/leaks/package.json create mode 100644 test/leaks/server.js create mode 100644 test/leaks/yarn.lock rename {lib/vscode/test => test}/monaco/.gitignore (100%) rename {lib/vscode/test => test}/monaco/.mocharc.json (100%) rename {lib/vscode/test => test}/monaco/README.md (100%) rename {lib/vscode/test => test}/monaco/core.js (100%) rename {lib/vscode/test => test}/monaco/dist/core.html (100%) rename {lib/vscode/test => test}/monaco/monaco.test.ts (100%) rename {lib/vscode/test => test}/monaco/package.json (100%) rename {lib/vscode/test => test}/monaco/runner.js (100%) rename {lib/vscode/test => test}/monaco/tsconfig.json (100%) rename {lib/vscode/test => test}/monaco/webpack.config.js (100%) rename {lib/vscode/test => test}/monaco/yarn.lock (100%) delete mode 100644 test/package.json rename {lib/vscode/test => test}/smoke/.gitignore (100%) rename {lib/vscode/test => test}/smoke/Audit.md (100%) rename {lib/vscode/test => test}/smoke/README.md (100%) rename {lib/vscode/test => test}/smoke/package.json (96%) rename {lib/vscode/test => test}/smoke/src/areas/editor/editor.test.ts (100%) rename {lib/vscode/test => test}/smoke/src/areas/extensions/extensions.test.ts (100%) rename {lib/vscode/test => test}/smoke/src/areas/languages/languages.test.ts (100%) rename {lib/vscode/test => test}/smoke/src/areas/multiroot/multiroot.test.ts (95%) rename {lib/vscode/test => test}/smoke/src/areas/notebook/notebook.test.ts (100%) rename {lib/vscode/test => test}/smoke/src/areas/preferences/preferences.test.ts (100%) rename {lib/vscode/test => test}/smoke/src/areas/search/search.test.ts (89%) rename {lib/vscode/test => test}/smoke/src/areas/statusbar/statusbar.test.ts (100%) rename {lib/vscode/test => test}/smoke/src/areas/workbench/data-loss.test.ts (100%) rename {lib/vscode/test => test}/smoke/src/areas/workbench/data-migration.test.ts (100%) rename {lib/vscode/test => test}/smoke/src/areas/workbench/launch.test.ts (100%) rename {lib/vscode/test => test}/smoke/src/areas/workbench/localization.test.ts (91%) rename {lib/vscode/test => test}/smoke/src/main.ts (100%) rename {lib/vscode/test => test}/smoke/src/utils.ts (100%) rename {lib/vscode/test => test}/smoke/test/index.js (100%) rename {lib/vscode/test => test}/smoke/tsconfig.json (100%) rename {lib/vscode/test => test}/smoke/yarn.lock (98%) delete mode 100644 test/tsconfig.json rename {lib/vscode/test => test}/unit/README.md (100%) rename {lib/vscode/test => test}/unit/assert.js (100%) rename {lib/vscode/test => test}/unit/browser/index.js (98%) rename {lib/vscode/test => test}/unit/browser/renderer.html (100%) delete mode 100644 test/unit/cli.test.ts delete mode 100644 test/unit/constants.test.ts rename {lib/vscode/test => test}/unit/coverage.js (100%) rename {lib/vscode/test => test}/unit/electron/index.js (100%) rename {lib/vscode/test => test}/unit/electron/renderer.html (100%) rename {lib/vscode/test => test}/unit/electron/renderer.js (100%) delete mode 100644 test/unit/emitter.test.ts rename {lib/vscode/test => test}/unit/fullJsonStreamReporter.js (100%) delete mode 100644 test/unit/health.test.ts delete mode 100644 test/unit/http.test.ts rename {lib/vscode/test => test}/unit/node/all.js (100%) rename {lib/vscode/test => test}/unit/node/browser.js (100%) rename {lib/vscode/test => test}/unit/node/css.mock.js (100%) rename {lib/vscode/test => test}/unit/node/index.html (100%) delete mode 100644 test/unit/plugin.test.ts delete mode 100644 test/unit/proxy.test.ts delete mode 100644 test/unit/register.test.ts delete mode 100644 test/unit/routes/login.test.ts delete mode 100644 test/unit/serviceWorker.test.ts delete mode 100644 test/unit/socket.test.ts delete mode 100644 test/unit/test-plugin/.eslintrc.yaml delete mode 100644 test/unit/test-plugin/.gitignore delete mode 100644 test/unit/test-plugin/Makefile delete mode 100644 test/unit/test-plugin/package.json delete mode 100644 test/unit/test-plugin/public/icon.svg delete mode 100644 test/unit/test-plugin/public/index.html delete mode 100644 test/unit/test-plugin/src/index.ts delete mode 100644 test/unit/test-plugin/tsconfig.json delete mode 100644 test/unit/test-plugin/yarn.lock delete mode 100644 test/unit/update.test.ts delete mode 100644 test/unit/util.test.ts delete mode 100644 test/utils/constants.ts delete mode 100644 test/utils/cssStub.ts delete mode 100644 test/utils/globalSetup.ts delete mode 100644 test/utils/helpers.ts delete mode 100644 test/utils/httpserver.ts delete mode 100644 test/utils/integration.ts delete mode 100644 test/utils/wtfnode.ts delete mode 100644 test/yarn.lock delete mode 100644 tsconfig.json rename lib/vscode/tsfmt.json => tsfmt.json (100%) delete mode 100644 typings/httpolyglot/index.d.ts delete mode 100644 typings/ipc.d.ts delete mode 100644 typings/pluginapi.d.ts diff --git a/.devcontainer/README.md b/.devcontainer/README.md new file mode 100644 index 000000000000..827166823d73 --- /dev/null +++ b/.devcontainer/README.md @@ -0,0 +1,101 @@ +# Code - OSS Development Container + +This repository includes configuration for a development container for working with Code - OSS in a local container or using [GitHub Codespaces](https://github.com/features/codespaces). + +> **Tip:** The default VNC password is `vscode`. The VNC server runs on port `5901` and a web client is available on port `6080`. + +## Quick start - local + +1. Install Docker Desktop or Docker for Linux on your local machine. (See [docs](https://aka.ms/vscode-remote/containers/getting-started) for additional details.) + +2. **Important**: Docker needs at least **4 Cores and 6 GB of RAM (8 GB recommended)** to run a full build. If you are on macOS, or are using the old Hyper-V engine for Windows, update these values for Docker Desktop by right-clicking on the Docker status bar item and going to **Preferences/Settings > Resources > Advanced**. + + > **Note:** The [Resource Monitor](https://marketplace.visualstudio.com/items?itemName=mutantdino.resourcemonitor) extension is included in the container so you can keep an eye on CPU/Memory in the status bar. + +3. Install [Visual Studio Code Stable](https://code.visualstudio.com/) or [Insiders](https://code.visualstudio.com/insiders/) and the [Remote - Containers](https://aka.ms/vscode-remote/download/containers) extension. + + ![Image of Remote - Containers extension](https://microsoft.github.io/vscode-remote-release/images/remote-containers-extn.png) + + > **Note:** The Remote - Containers extension requires the Visual Studio Code distribution of Code - OSS. See the [FAQ](https://aka.ms/vscode-remote/faq/license) for details. + +4. Press Ctrl/Cmd + Shift + P or F1 and select **Remote-Containers: Clone Repository in Container Volume...**. + + > **Tip:** While you can use your local source tree instead, operations like `yarn install` can be slow on macOS or when using the Hyper-V engine on Windows. We recommend the "clone repository in container" approach instead since it uses "named volume" rather than the local filesystem. + +5. Type `https://github.com/microsoft/vscode` (or a branch or PR URL) in the input box and press Enter. + +6. After the container is running, open a web browser and go to [http://localhost:6080](http://localhost:6080), or use a [VNC Viewer](https://www.realvnc.com/en/connect/download/viewer/) to connect to `localhost:5901` and enter `vscode` as the password. + +Anything you start in VS Code, or the integrated terminal, will appear here. + +Next: **[Try it out!](#try-it)** + +## Quick start - GitHub Codespaces + +1. From the [microsoft/vscode GitHub repository](https://github.com/microsoft/vscode), click on the **Code** dropdown, select **Open with Codespaces**, and then click on **New codespace**. If prompted, select the **Standard** machine size (which is also the default). + + > **Note:** You will not see these options within GitHub if you are not in the Codespaces beta. + +2. After the codespace is up and running in your browser, press Ctrl/Cmd + Shift + P or F1 and select **Ports: Focus on Ports View**. + +3. You should see **VNC web client (6080)** under in the list of ports. Select the line and click on the globe icon to open it in a browser tab. + + > **Tip:** If you do not see the port, Ctrl/Cmd + Shift + P or F1, select **Forward a Port** and enter port `6080`. + +4. In the new tab, you should see noVNC. Click **Connect** and enter `vscode` as the password. + +Anything you start in VS Code, or the integrated terminal, will appear here. + +Next: **[Try it out!](#try-it)** + +### Using VS Code with GitHub Codespaces + +You may see improved VNC responsiveness when accessing a codespace from VS Code client since you can use a [VNC Viewer](https://www.realvnc.com/en/connect/download/viewer/). Here's how to do it. + +1. Install [Visual Studio Code Stable](https://code.visualstudio.com/) or [Insiders](https://code.visualstudio.com/insiders/) and the the [GitHub Codespaces extension](https://marketplace.visualstudio.com/items?itemName=GitHub.codespaces). + + > **Note:** The GitHub Codespaces extension requires the Visual Studio Code distribution of Code - OSS. + +2. After the VS Code is up and running, press Ctrl/Cmd + Shift + P or F1, choose **Codespaces: Create New Codespace**, and use the following settings: + - `microsoft/vscode` for the repository. + - Select any branch (e.g. **main**) - you select a different one later. + - Choose **Standard** (4-core, 8GB) as the size. + +4. After you have connected to the codespace, you can use a [VNC Viewer](https://www.realvnc.com/en/connect/download/viewer/) to connect to `localhost:5901` and enter `vscode` as the password. + + > **Tip:** You may also need change your VNC client's **Picture Quaility** setting to **High** to get a full color desktop. + +5. Anything you start in VS Code, or the integrated terminal, will appear here. + +Next: **[Try it out!](#try-it)** + +## Try it! + +This container uses the [Fluxbox](http://fluxbox.org/) window manager to keep things lean. **Right-click on the desktop** to see menu options. It works with GNOME and GTK applications, so other tools can be installed if needed. + +> **Note:** You can also set the resolution from the command line by typing `set-resolution`. + +To start working with Code - OSS, follow these steps: + +1. In your local VS Code client, open a terminal (Ctrl/Cmd + Shift + \`) and type the following commands: + + ```bash + yarn install + bash scripts/code.sh + ``` + +2. After the build is complete, open a web browser or a [VNC Viewer](https://www.realvnc.com/en/connect/download/viewer/) to connect to the desktop environment as described in the quick start and enter `vscode` as the password. + +3. You should now see Code - OSS! + +Next, let's try debugging. + +1. Shut down Code - OSS by clicking the box in the upper right corner of the Code - OSS window through your browser or VNC viewer. + +2. Go to your local VS Code client, and use the **Run / Debug** view to launch the **VS Code** configuration. (Typically the default, so you can likely just press F5). + + > **Note:** If launching times out, you can increase the value of `timeout` in the "VS Code", "Attach Main Process", "Attach Extension Host", and "Attach to Shared Process" configurations in [launch.json](../.vscode/launch.json). However, running `scripts/code.sh` first will set up Electron which will usually solve timeout issues. + +3. After a bit, Code - OSS will appear with the debugger attached! + +Enjoy! diff --git a/lib/vscode/.devcontainer/cache/.gitignore b/.devcontainer/cache/.gitignore similarity index 100% rename from lib/vscode/.devcontainer/cache/.gitignore rename to .devcontainer/cache/.gitignore diff --git a/lib/vscode/.devcontainer/cache/before-cache.sh b/.devcontainer/cache/before-cache.sh similarity index 100% rename from lib/vscode/.devcontainer/cache/before-cache.sh rename to .devcontainer/cache/before-cache.sh diff --git a/lib/vscode/.devcontainer/cache/build-cache-image.sh b/.devcontainer/cache/build-cache-image.sh similarity index 100% rename from lib/vscode/.devcontainer/cache/build-cache-image.sh rename to .devcontainer/cache/build-cache-image.sh diff --git a/lib/vscode/.devcontainer/cache/cache-diff.sh b/.devcontainer/cache/cache-diff.sh similarity index 100% rename from lib/vscode/.devcontainer/cache/cache-diff.sh rename to .devcontainer/cache/cache-diff.sh diff --git a/lib/vscode/.devcontainer/cache/cache.Dockerfile b/.devcontainer/cache/cache.Dockerfile similarity index 100% rename from lib/vscode/.devcontainer/cache/cache.Dockerfile rename to .devcontainer/cache/cache.Dockerfile diff --git a/lib/vscode/.devcontainer/cache/restore-diff.sh b/.devcontainer/cache/restore-diff.sh similarity index 100% rename from lib/vscode/.devcontainer/cache/restore-diff.sh rename to .devcontainer/cache/restore-diff.sh diff --git a/lib/vscode/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json similarity index 70% rename from lib/vscode/.devcontainer/devcontainer.json rename to .devcontainer/devcontainer.json index 3b82cd9028d2..d66344eccf65 100644 --- a/lib/vscode/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -3,20 +3,26 @@ // Image contents: https://github.com/microsoft/vscode-dev-containers/blob/master/repository-containers/images/github.com/microsoft/vscode/.devcontainer/base.Dockerfile "image": "mcr.microsoft.com/vscode/devcontainers/repos/microsoft/vscode:branch-main", - - "workspaceMount": "source=${localWorkspaceFolder},target=/home/node/workspace/vscode,type=bind,consistency=cached", - "workspaceFolder": "/home/node/workspace/vscode", "overrideCommand": false, "runArgs": [ "--init", "--security-opt", "seccomp=unconfined"], "settings": { - "terminal.integrated.shell.linux": "/bin/bash", "resmon.show.battery": false, "resmon.show.cpufreq": false }, - // noVNC, VNC, debug ports - "forwardPorts": [6080, 5901, 9222], + // noVNC, VNC + "forwardPorts": [6080, 5901], + "portsAttributes": { + "6080": { + "label": "VNC web client (noVNC)", + "onAutoForward": "silent" + }, + "5901": { + "label": "VNC TCP port", + "onAutoForward": "silent" + } + }, "extensions": [ "dbaeumer.vscode-eslint", diff --git a/lib/vscode/.devcontainer/prepare.sh b/.devcontainer/prepare.sh similarity index 100% rename from lib/vscode/.devcontainer/prepare.sh rename to .devcontainer/prepare.sh diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 9bcce7a80897..000000000000 --- a/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -** -!release-packages -!ci diff --git a/.editorconfig b/.editorconfig index 65705d954568..e7e99b5bcb52 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,15 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file root = true +# Tab indentation [*] -indent_style = space +indent_style = tab trim_trailing_whitespace = true + +# The indent size used in the `package.json` file cannot be changed +# https://github.com/npm/npm/pull/3180#issuecomment-16336516 +[{*.yml,*.yaml,package.json}] +indent_style = space indent_size = 2 diff --git a/lib/vscode/.eslintignore b/.eslintignore similarity index 80% rename from lib/vscode/.eslintignore rename to .eslintignore index b67a816156a4..8b93a4199e5d 100644 --- a/lib/vscode/.eslintignore +++ b/.eslintignore @@ -16,7 +16,3 @@ **/extensions/markdown-language-features/notebook-out/** **/extensions/typescript-basics/test/colorize-fixtures/** **/extensions/**/dist/** -# These are code-server code symlinks. -src/vs/base/node/proxy_agent.ts -src/vs/ipc.d.ts -src/vs/server/common/util.ts diff --git a/lib/vscode/.eslintrc.json b/.eslintrc.json similarity index 99% rename from lib/vscode/.eslintrc.json rename to .eslintrc.json index e7ff9be00a1f..a54964c17b67 100644 --- a/lib/vscode/.eslintrc.json +++ b/.eslintrc.json @@ -62,7 +62,7 @@ "code-no-standalone-editor": "warn", "code-no-unexternalized-strings": "warn", "code-layering": [ - "off", + "warn", { "common": [], "node": [ @@ -88,7 +88,7 @@ } ], "code-import-patterns": [ - "off", + "warn", // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // !!! Do not relax these rules !!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -501,7 +501,7 @@ "**/vs/platform/**", "**/vs/editor/**", "**/vs/workbench/{common,browser,node,electron-sandbox,electron-browser}/**", - "vs/workbench/contrib/files/common/editors/fileEditorInput", + "vs/workbench/contrib/files/browser/editors/fileEditorInput", "**/vs/workbench/services/**", "**/vs/workbench/test/**", "*" // node modules diff --git a/.eslintrc.yaml b/.eslintrc.yaml deleted file mode 100644 index b579a9a24671..000000000000 --- a/.eslintrc.yaml +++ /dev/null @@ -1,46 +0,0 @@ -parser: "@typescript-eslint/parser" -env: - browser: true - es6: true # Map, etc. - jest: true - node: true - -parserOptions: - ecmaVersion: 2018 - sourceType: module - -extends: - - eslint:recommended - - plugin:@typescript-eslint/recommended - - plugin:import/recommended - - plugin:import/typescript - - plugin:prettier/recommended - # Prettier should always be last - # Removes eslint rules that conflict with prettier. - - prettier - -rules: - # Sometimes you need to add args to implement a function signature even - # if they are unused. - "@typescript-eslint/no-unused-vars": ["error", { "args": "none" }] - # For overloads. - no-dupe-class-members: off - "@typescript-eslint/no-use-before-define": off - "@typescript-eslint/no-non-null-assertion": off - "@typescript-eslint/ban-types": off - "@typescript-eslint/no-var-requires": off - "@typescript-eslint/explicit-module-boundary-types": off - "@typescript-eslint/no-explicit-any": off - "@typescript-eslint/no-extra-semi": off - eqeqeq: error - import/order: - [error, { alphabetize: { order: "asc" }, groups: [["builtin", "external", "internal"], "parent", "sibling"] }] - no-async-promise-executor: off - # This isn't a real module, just types, which apparently doesn't resolve. - import/no-unresolved: [error, { ignore: ["express-serve-static-core"] }] - -settings: - # Does not work with CommonJS unfortunately. - import/ignore: - - env-paths - - xdg-basedir diff --git a/.gitattributes b/.gitattributes index dc5caf936908..5a817c30b6d7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,10 @@ -*.afdesign filter=lfs diff=lfs merge=lfs -text +* text=auto + +LICENSE.txt eol=crlf +ThirdPartyNotices.txt eol=crlf + +*.bat eol=crlf +*.cmd eol=crlf +*.ps1 eol=lf +*.sh eol=lf +*.rtf -text \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index b7e6805b7f29..000000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,3 +0,0 @@ -* @cdr/code-server-reviewers - -ci/helm-chart @Matthew-Beckett @alexgorbatchev diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md deleted file mode 100644 index 4ec82a898d65..000000000000 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -name: Bug report -about: Report a bug and help us improve -title: "" -labels: "" -assignees: "" ---- - - - -## OS/Web Information - -- Web Browser: -- Local OS: -- Remote OS: -- Remote Architecture: -- `code-server --version`: - -## Steps to Reproduce - -1. -2. -3. - -## Expected - - - -## Actual - - - -## Logs - - - -## Screenshot - - - -## Notes - - - -This issue can be reproduced in VS Code: Yes/No diff --git a/lib/vscode/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md similarity index 99% rename from lib/vscode/.github/ISSUE_TEMPLATE/bug_report.md rename to .github/ISSUE_TEMPLATE/bug_report.md index b40ba5ddd483..8a44ce8c7ac1 100644 --- a/lib/vscode/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -8,6 +8,11 @@ about: Create a report to help us improve + +Does this issue occur when all extensions are disabled?: Yes/No + + + - VS Code Version: - OS Version: @@ -15,9 +20,3 @@ Steps to Reproduce: 1. 2. - - -Does this issue occur when all extensions are disabled?: Yes/No - - - diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 2f567fce310b..51e7f3660431 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,5 @@ blank_issues_enabled: false contact_links: - name: Question - url: https://github.com/cdr/code-server/discussions/new?category_id=22503114 - about: Ask the community for help on our GitHub Discussions board - - name: Chat - about: Need immediate help or just want to talk? Hop in our Slack - url: https://cdr.co/join-community + url: https://stackoverflow.com/questions/tagged/visual-studio-code + about: Please ask and answer questions here. diff --git a/.github/ISSUE_TEMPLATE/doc.md b/.github/ISSUE_TEMPLATE/doc.md deleted file mode 100644 index ba63b11bdf8f..000000000000 --- a/.github/ISSUE_TEMPLATE/doc.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -name: Documentation improvement -about: Suggest a documentation improvement -title: "" -labels: "docs" -assignees: "" ---- diff --git a/.github/ISSUE_TEMPLATE/extension-request.md b/.github/ISSUE_TEMPLATE/extension-request.md deleted file mode 100644 index 97f6059ae045..000000000000 --- a/.github/ISSUE_TEMPLATE/extension-request.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -name: Extension request -about: Request an extension missing from the code-server marketplace -title: "" -labels: extension-request -assignees: "" ---- - - - -- [ ] Extension name: -- [ ] Extension GitHub or homepage: diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md deleted file mode 100644 index 3f7411eefb6b..000000000000 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: Feature request -about: Suggest an idea -title: "" -labels: feature -assignees: "" ---- - - diff --git a/lib/vscode/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md similarity index 100% rename from lib/vscode/.github/ISSUE_TEMPLATE/feature_request.md rename to .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md deleted file mode 100644 index 4cdeac9f7b66..000000000000 --- a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/.github/PULL_REQUEST_TEMPLATE/release_template.md b/.github/PULL_REQUEST_TEMPLATE/release_template.md deleted file mode 100644 index a88b6de174b6..000000000000 --- a/.github/PULL_REQUEST_TEMPLATE/release_template.md +++ /dev/null @@ -1,18 +0,0 @@ - - -This PR is to generate a new release of `code-server` at `$CODE_SERVER_VERSION_TO_UPDATE` - -## Screenshot - -TODO - -## TODOs - -- [ ] test locally -- [ ] upload assets to draft release -- [ ] test one of the release packages locally -- [ ] double-check github release tag is the commit with artifacts (_note gets messed up after uploading assets_) -- [ ] publish release -- [ ] merge PR -- [ ] update the homebrew package -- [ ] update the AUR package diff --git a/lib/vscode/.github/calendar.yml b/.github/calendar.yml similarity index 100% rename from lib/vscode/.github/calendar.yml rename to .github/calendar.yml diff --git a/lib/vscode/.github/classifier.json b/.github/classifier.json similarity index 93% rename from lib/vscode/.github/classifier.json rename to .github/classifier.json index 5adabb9aa9c9..1783b82c8797 100644 --- a/lib/vscode/.github/classifier.json +++ b/.github/classifier.json @@ -1,16 +1,17 @@ { "$schema": "https://raw.githubusercontent.com/microsoft/vscode-github-triage-actions/master/classifier-deep/apply/apply-labels/deep-classifier-config.schema.json", - "vacation": [], + "vacation": ["RMacfarlane"], "assignees": { "JacksonKearl": {"accuracy": 0.5} }, "labels": { "L10N": {"assign": []}, "VIM": {"assign": []}, + "accessibility": { "assign": ["isidorn"]}, "api": {"assign": ["jrieken"]}, "api-finalization": {"assign": []}, "api-proposal": {"assign": ["jrieken"]}, - "authentication": {"assign": ["RMacfarlane"]}, + "authentication": {"assign": ["TylerLeonhardt"]}, "breadcrumbs": {"assign": ["jrieken"]}, "callhierarchy": {"assign": ["jrieken"]}, "code-lens": {"assign": ["jrieken"]}, @@ -20,8 +21,7 @@ "context-keys": {"assign": []}, "css-less-scss": {"assign": ["aeschli"]}, "custom-editors": {"assign": ["mjbvz"]}, - "debug": {"assign": ["isidorn"]}, - "debug-console": {"assign": ["isidorn"]}, + "debug": {"assign": ["weinand"]}, "dialogs": {"assign": ["sbatten"]}, "diff-editor": {"assign": []}, "dropdown": {"assign": []}, @@ -81,14 +81,15 @@ "icon-brand": {"assign": []}, "icons-product": {"assign": ["misolori"]}, "install-update": {"assign": []}, - "integrated-terminal": {"assign": ["meganrogge"]}, - "integrated-terminal-conpty": {"assign": ["meganrogge"]}, - "integrated-terminal-links": {"assign": ["meganrogge"]}, + "terminal": {"assign": ["meganrogge"]}, + "terminal-conpty": {"assign": ["meganrogge"]}, + "terminal-links": {"assign": ["meganrogge"]}, + "terminal-external": {"assign": ["meganrogge"]}, "integration-test": {"assign": []}, "intellisense-config": {"assign": []}, "ipc": {"assign": ["joaomoreno"]}, "issue-bot": {"assign": ["chrmarti"]}, - "issue-reporter": {"assign": ["RMacfarlane"]}, + "issue-reporter": {"assign": ["TylerLeonhardt"]}, "javascript": {"assign": ["mjbvz"]}, "json": {"assign": ["aeschli"]}, "keybindings": {"assign": []}, @@ -113,7 +114,7 @@ "php": {"assign": ["roblourens"]}, "portable-mode": {"assign": ["joaomoreno"]}, "proxy": {"assign": []}, - "quick-pick": {"assign": ["chrmarti"]}, + "quick-pick": {"assign": ["TylerLeonhardt"]}, "references-viewlet": {"assign": ["jrieken"]}, "release-notes": {"assign": []}, "remote": {"assign": []}, @@ -152,7 +153,7 @@ "web": {"assign": ["bpasero"]}, "webview": {"assign": ["mjbvz"]}, "workbench-cli": {"assign": []}, - "workbench-diagnostics": {"assign": ["RMacfarlane"]}, + "workbench-diagnostics": {"assign": ["Tyriar"]}, "workbench-dnd": {"assign": ["bpasero"]}, "workbench-editor-grid": {"assign": ["sbatten"]}, "workbench-editors": {"assign": ["bpasero"]}, diff --git a/.github/codeql-config.yml b/.github/codeql-config.yml deleted file mode 100644 index 690b8e5a92e0..000000000000 --- a/.github/codeql-config.yml +++ /dev/null @@ -1,4 +0,0 @@ -name: "code-server CodeQL config" - -paths-ignore: - - lib/vscode diff --git a/lib/vscode/.github/commands.json b/.github/commands.json similarity index 97% rename from lib/vscode/.github/commands.json rename to .github/commands.json index de0643d56c92..388a9c3dbb33 100644 --- a/lib/vscode/.github/commands.json +++ b/.github/commands.json @@ -90,7 +90,7 @@ "@author" ], "action": "updateLabels", - "addLabel": "z-author-verified", + "addLabel": "verified", "removeLabel": "author-verification-requested", "requireLabel": "author-verification-requested", "disallowLabel": "unreleased" @@ -133,6 +133,18 @@ "action": "updateLabels", "addLabel": "~needs more info" }, + { + "type": "comment", + "name": "needsPerfInfo", + "allowUsers": [ + "cleidigh", + "usernamehw", + "gjsjohnmurray", + "IllusionMH" + ], + "addLabel": "needs more info", + "comment": "Thanks for creating this issue regarding performance! Please follow this guide to help us diagnose performance issues: https://github.com/microsoft/vscode/wiki/Performance-Issues \n\nHappy Coding!" + }, { "type": "comment", "name": "jsDebugLogs", diff --git a/lib/vscode/.github/commands.yml b/.github/commands.yml similarity index 100% rename from lib/vscode/.github/commands.yml rename to .github/commands.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 4ec51d013758..000000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,27 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "daily" - time: "11:00" - ignore: - # GitHub always delivers the latest versions for each major - # release tag, so handle updates manually - - dependency-name: "actions/*" - - dependency-name: "github/codeql-action/*" - - - package-ecosystem: "npm" - directory: "/" - schedule: - interval: "daily" - time: "11:00" - ignore: - - dependency-name: "@types/node" - versions: ["15.x", "14.x", "13.x"] - - dependency-name: "xdg-basedir" - # 5.0.0 has breaking changes as they switch to named exports - # and convert the module to ESM - # We can't use it until we switch to ESM across the project - # See release notes: https://github.com/sindresorhus/xdg-basedir/releases/tag/v5.0.0 - versions: ["5.x"] diff --git a/lib/vscode/.github/endgame/insiders.yml b/.github/endgame/insiders.yml similarity index 100% rename from lib/vscode/.github/endgame/insiders.yml rename to .github/endgame/insiders.yml diff --git a/lib/vscode/.github/insiders.yml b/.github/insiders.yml similarity index 100% rename from lib/vscode/.github/insiders.yml rename to .github/insiders.yml diff --git a/.github/lock.yml b/.github/lock.yml deleted file mode 100644 index 2dfb6cf38862..000000000000 --- a/.github/lock.yml +++ /dev/null @@ -1,37 +0,0 @@ -# Configuration for Lock Threads - https://github.com/dessant/lock-threads-app - -# Number of days of inactivity before a closed issue or pull request is locked -daysUntilLock: 90 - -# Skip issues and pull requests created before a given timestamp. Timestamp must -# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable -skipCreatedBefore: false - -# Issues and pull requests with these labels will be ignored. Set to `[]` to disable -exemptLabels: [] - -# Label to add before locking, such as `outdated`. Set to `false` to disable -lockLabel: false - -# Comment to post before locking. Set to `false` to disable -lockComment: > - This thread has been automatically locked since there has not been - any recent activity after it was closed. Please open a new issue for - related bugs. - -# Assign `resolved` as the reason for locking. Set to `false` to disable -setLockReason: true -# Limit to only `issues` or `pulls` -# only: issues - -# Optionally, specify configuration settings just for `issues` or `pulls` -# issues: -# exemptLabels: -# - help-wanted -# lockLabel: outdated - -# pulls: -# daysUntilLock: 30 - -# Repository to extend settings from -# _extends: repo diff --git a/lib/vscode/.github/pull_request_template.md b/.github/pull_request_template.md similarity index 100% rename from lib/vscode/.github/pull_request_template.md rename to .github/pull_request_template.md diff --git a/.github/ranger.yml b/.github/ranger.yml deleted file mode 100644 index ec029b19c261..000000000000 --- a/.github/ranger.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Configuration for the repo ranger bot -# See docs: https://www.notion.so/Documentation-8d7627bb1f3c42b7b1820e8d6f157a57#9879d1374fab4d1f9c607c230fd5123d -default: - close: - # Default time to wait before closing the label. Can either be a number in milliseconds - # or a string specified by the `ms` package (https://www.npmjs.com/package/ms) - delay: "2 days" - - # Default comment to post when an issue is first marked with a closing label - comment: "⚠️ This issue has been marked $LABEL and will be closed in $DELAY." - -labels: - duplicate: close - wontfix: close - "squash when passing": merge - "rebase when passing": merge - "merge when passing": merge - stale: - action: close - delay: 7 days - comment: "⚠️ This issue has been marked stale and will automatically be closed in $DELAY." - "new contributor": - action: comment - delay: 5s - message: "Thanks for making your first contribution! :slightly_smiling_face:" - extension-request: - action: close - delay: 5s - comment: > - Thanks for opening an extension request! - We are currently in the process of switching extension - marketplaces and transitioning over to [Open VSX](https://open-vsx.org/). - Once https://github.com/eclipse/openvsx/issues/249 is implemented, we - can fully make this transition. Therefore, we are no longer accepting - new requests for extension requests. We suggest installing the VSIX - file and then installing into code-server as a temporary workaround. - See [docs](https://github.com/cdr/code-server/blob/main/docs/FAQ.md#installing-vsix-extensions-via-the-command-line) for more info. - "upstream:vscode": - action: close - delay: 5s - comment: > - This issue has been marked as 'upstream:vscode'. - Please file this upstream: [link to open issue](https://github.com/microsoft/vscode/issues/new/choose) - - This issue will automatically close in $DELAY. diff --git a/lib/vscode/.github/similarity.yml b/.github/similarity.yml similarity index 100% rename from lib/vscode/.github/similarity.yml rename to .github/similarity.yml diff --git a/lib/vscode/.github/subscribers.json b/.github/subscribers.json similarity index 72% rename from lib/vscode/.github/subscribers.json rename to .github/subscribers.json index 7ee6e5cdadd3..25c676a47c74 100644 --- a/lib/vscode/.github/subscribers.json +++ b/.github/subscribers.json @@ -4,6 +4,7 @@ "rchiodo", "greazer", "donjayamanne", - "jilljac" + "jilljac", + "IanMatthewHuff" ] } diff --git a/lib/vscode/.github/workflows/author-verified.yml b/.github/workflows/author-verified.yml similarity index 100% rename from lib/vscode/.github/workflows/author-verified.yml rename to .github/workflows/author-verified.yml diff --git a/lib/vscode/.github/workflows/build-chat.yml b/.github/workflows/build-chat.yml similarity index 100% rename from lib/vscode/.github/workflows/build-chat.yml rename to .github/workflows/build-chat.yml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml deleted file mode 100644 index 8e6344db09e4..000000000000 --- a/.github/workflows/ci.yaml +++ /dev/null @@ -1,466 +0,0 @@ -name: ci - -on: - push: - branches: - - main - pull_request: - branches: - - main - -# Note: if: success() is used in several jobs - -# this ensures that it only executes if all previous jobs succeeded. - -# if: steps.cache-yarn.outputs.cache-hit != 'true' -# will skip running `yarn install` if it successfully fetched from cache - -jobs: - prebuild: - name: Pre-build checks - runs-on: ubuntu-latest - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - steps: - - name: Checkout repo - uses: actions/checkout@v2 - - - name: Install Node.js v12 - uses: actions/setup-node@v2 - with: - node-version: "12" - - - name: Install helm - uses: azure/setup-helm@v1.1 - - - name: Fetch dependencies from cache - id: cache-yarn - uses: actions/cache@v2 - with: - path: "**/node_modules" - key: yarn-build-${{ hashFiles('**/yarn.lock') }} - - - name: Install dependencies - if: steps.cache-yarn.outputs.cache-hit != 'true' - run: yarn --frozen-lockfile - - - name: Audit for vulnerabilities - run: yarn _audit - if: success() - - - name: Run yarn fmt - run: yarn fmt - if: success() - - - name: Run yarn lint - run: yarn lint - if: success() - - - name: Run code-server unit tests - run: yarn test:unit - if: success() - - - name: Upload coverage report to Codecov - run: yarn coverage - if: success() - - build: - name: Build - needs: prebuild - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Install Node.js v12 - uses: actions/setup-node@v2 - with: - node-version: "12" - - - name: Fetch dependencies from cache - id: cache-yarn - uses: actions/cache@v2 - with: - path: "**/node_modules" - key: yarn-build-${{ hashFiles('**/yarn.lock') }} - - - name: Install dependencies - if: steps.cache-yarn.outputs.cache-hit != 'true' - run: yarn --frozen-lockfile - - - name: Build code-server - run: yarn build - - # Parse the hash of the latest commit inside lib/vscode - # use this to avoid rebuilding it if nothing changed - # How it works: the `git log` command fetches the hash of the last commit - # that changed a file inside `lib/vscode`. If a commit changes any file in there, - # the hash returned will change, and we rebuild vscode. If the hash did not change, - # (for example, a change to `src/` or `docs/`), we reuse the same build as last time. - # This saves a lot of time in CI, as compiling VSCode can take anywhere from 5-10 minutes. - - name: Get latest lib/vscode rev - id: vscode-rev - run: echo "::set-output name=rev::$(git log -1 --format='%H' ./lib/vscode)" - - - name: Attempt to fetch vscode build from cache - id: cache-vscode - uses: actions/cache@v2 - with: - path: | - lib/vscode/.build - lib/vscode/out-build - lib/vscode/out-vscode - lib/vscode/out-vscode-min - key: vscode-build-${{ steps.vscode-rev.outputs.rev }} - - - name: Build vscode - if: steps.cache-vscode.outputs.cache-hit != 'true' - run: yarn build:vscode - - # The release package does not contain any native modules - # and is neutral to architecture/os/libc version. - - name: Create release package - run: yarn release - if: success() - - # https://github.com/actions/upload-artifact/issues/38 - - name: Compress release package - run: tar -czf package.tar.gz release - - - name: Upload npm package artifact - uses: actions/upload-artifact@v2 - with: - name: npm-package - path: ./package.tar.gz - - # TODO: cache building yarn --production - # possibly 2m30s of savings(?) - # this requires refactoring our release scripts - package-linux-amd64: - name: x86-64 Linux build - needs: build - runs-on: ubuntu-latest - container: "centos:7" - - steps: - - uses: actions/checkout@v2 - - - name: Install Node.js v12 - uses: actions/setup-node@v2 - with: - node-version: "12" - - - name: Install development tools - run: | - yum install -y epel-release centos-release-scl - yum install -y devtoolset-9-{make,gcc,gcc-c++} jq rsync - - - name: Install nfpm and envsubst - run: | - curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh -s -- -b ~/.local/bin v2.3.1 - curl -L https://github.com/a8m/envsubst/releases/download/v1.1.0/envsubst-`uname -s`-`uname -m` -o envsubst - chmod +x envsubst - mv envsubst ~/.local/bin - echo "$HOME/.local/bin" >> $GITHUB_PATH - - - name: Install yarn - run: npm install -g yarn - - - name: Download npm package - uses: actions/download-artifact@v2 - with: - name: npm-package - - - name: Decompress npm package - run: tar -xzf package.tar.gz - - # NOTE: && here is deliberate - GitHub puts each line in its own `.sh` - # file when running inside a docker container. - - name: Build standalone release - run: source scl_source enable devtoolset-9 && yarn release:standalone - - - name: Sanity test standalone release - run: yarn test:standalone-release - - - name: Build packages with nfpm - run: yarn package - - - name: Upload release artifacts - uses: actions/upload-artifact@v2 - with: - name: release-packages - path: ./release-packages - - # NOTE@oxy: - # We use Ubuntu 16.04 here, so that our build is more compatible - # with older libc versions. We used to (Q1'20) use CentOS 7 here, - # but it has a full update EOL of Q4'20 and a 'critical security' - # update EOL of 2024. We're dropping full support a few years before - # the final EOL, but I don't believe CentOS 7 has a large arm64 userbase. - # It is not feasible to cross-compile with CentOS. - - # Cross-compile notes: To compile native dependencies for arm64, - # we install the aarch64 cross toolchain and then set it as the default - # compiler/linker/etc. with the AR/CC/CXX/LINK environment variables. - # qemu-user-static on ubuntu-16.04 currently doesn't run Node correctly, - # so we just build with "native"/x86_64 node, then download arm64 node - # and then put it in our release. We can't smoke test the arm64 build this way, - # but this means we don't need to maintain a self-hosted runner! - package-linux-arm64: - name: Linux ARM64 cross-compile build - needs: build - runs-on: ubuntu-16.04 - env: - AR: aarch64-linux-gnu-ar - CC: aarch64-linux-gnu-gcc - CXX: aarch64-linux-gnu-g++ - LINK: aarch64-linux-gnu-g++ - NPM_CONFIG_ARCH: arm64 - - steps: - - uses: actions/checkout@v2 - - - name: Install Node.js v12 - uses: actions/setup-node@v2 - with: - node-version: "12" - - - name: Install nfpm - run: | - curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh -s -- -b ~/.local/bin v2.3.1 - echo "$HOME/.local/bin" >> $GITHUB_PATH - - - name: Install cross-compiler - run: sudo apt install g++-aarch64-linux-gnu - - - name: Download npm package - uses: actions/download-artifact@v2 - with: - name: npm-package - - - name: Decompress npm package - run: tar -xzf package.tar.gz - - - name: Build standalone release - run: yarn release:standalone - - - name: Replace node with arm64 equivalent - run: | - wget https://nodejs.org/dist/v12.18.4/node-v12.18.4-linux-arm64.tar.gz - tar -xzf node-v12.18.4-linux-arm64.tar.gz node-v12.18.4-linux-arm64/bin/node --strip-components=2 - mv ./node ./release-standalone/lib/node - - - name: Build packages with nfpm - run: yarn package arm64 - - - name: Upload release artifacts - uses: actions/upload-artifact@v2 - with: - name: release-packages - path: ./release-packages - - package-macos-amd64: - name: x86-64 macOS build - needs: build - runs-on: macos-latest - steps: - - uses: actions/checkout@v2 - - - name: Install Node.js v12 - uses: actions/setup-node@v2 - with: - node-version: "12" - - - name: Install nfpm - run: | - curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh -s -- -b ~/.local/bin v2.3.1 - echo "$HOME/.local/bin" >> $GITHUB_PATH - - - name: Download npm package - uses: actions/download-artifact@v2 - with: - name: npm-package - - - name: Decompress npm package - run: tar -xzf package.tar.gz - - - name: Build standalone release - run: yarn release:standalone - - - name: Sanity test standalone release - run: yarn test:standalone-release - - - name: Build packages with nfpm - run: yarn package - - - name: Upload release artifacts - uses: actions/upload-artifact@v2 - with: - name: release-packages - path: ./release-packages - - test-e2e: - name: End-to-end tests - needs: package-linux-amd64 - runs-on: ubuntu-latest - env: - PASSWORD: e45432jklfdsab - CODE_SERVER_ADDRESS: http://localhost:8080 - steps: - - uses: actions/checkout@v2 - - - name: Install Node.js v12 - uses: actions/setup-node@v2 - with: - node-version: "12" - - - name: Install playwright - uses: microsoft/playwright-github-action@v1 - - - name: Fetch dependencies from cache - id: cache-yarn - uses: actions/cache@v2 - with: - path: "**/node_modules" - key: yarn-build-${{ hashFiles('**/yarn.lock') }} - - - name: Download release packages - uses: actions/download-artifact@v2 - with: - name: release-packages - path: ./release-packages - - - name: Untar code-server file - run: | - cd release-packages && tar -xzf code-server*-linux-amd64.tar.gz - - - name: Install dependencies - if: steps.cache-yarn.outputs.cache-hit != 'true' - run: yarn --frozen-lockfile - - # HACK: this shouldn't need to exist, but put it here anyway - # in an attempt to solve Playwright cache failures. - - name: Reinstall playwright - if: steps.cache-yarn.outputs.cache-hit == 'true' - run: | - cd test/ - rm -r node_modules/playwright - yarn install --check-files - - - name: Run end-to-end tests - run: | - ./release-packages/code-server*-linux-amd64/bin/code-server --log trace & - yarn test:e2e - - - name: Upload test artifacts - if: always() - uses: actions/upload-artifact@v2 - with: - name: failed-test-videos - path: ./test/test-results - - - name: Remove release packages and test artifacts - run: rm -rf ./release-packages ./test/test-results - - docker-amd64: - runs-on: ubuntu-latest - needs: package-linux-amd64 - steps: - - uses: actions/checkout@v2 - - - name: Download release package - uses: actions/download-artifact@v2 - with: - name: release-packages - path: ./release-packages - - - name: Run ./ci/steps/build-docker-image.sh - run: ./ci/steps/build-docker-image.sh - - - name: Upload release image - uses: actions/upload-artifact@v2 - with: - name: release-images - path: ./release-images - - # TODO: this is the last place where we use our self-hosted arm64 runner. - # In the future, consider switching to docker buildx + qemu, - # thus removing the requirement for us to maintain the runner. - docker-arm64: - runs-on: ubuntu-arm64-latest - needs: package-linux-arm64 - steps: - - uses: actions/checkout@v2 - - - name: Download release package - uses: actions/download-artifact@v2 - with: - name: release-packages - path: ./release-packages - - - name: Run ./ci/steps/build-docker-image.sh - run: ./ci/steps/build-docker-image.sh - - - name: Upload release image - uses: actions/upload-artifact@v2 - with: - name: release-images - path: ./release-images - - trivy-scan-image: - runs-on: ubuntu-20.04 - needs: docker-amd64 - - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Download release images - uses: actions/download-artifact@v2 - with: - name: release-images - path: ./release-images - - - name: Run Trivy vulnerability scanner in image mode - # Commit SHA for v0.0.14 - uses: aquasecurity/trivy-action@b38389f8efef9798810fe0c5b5096ac198cffd54 - with: - input: "./release-images/code-server-amd64-*.tar" - scan-type: "image" - ignore-unfixed: true - format: "template" - template: "@/contrib/sarif.tpl" - output: "trivy-image-results.sarif" - severity: "HIGH,CRITICAL" - - - name: Upload Trivy scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@v1 - with: - sarif_file: "trivy-image-results.sarif" - - # We have to use two trivy jobs - # because GitHub only allows - # codeql/upload-sarif action per job - trivy-scan-repo: - runs-on: ubuntu-20.04 - - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Run Trivy vulnerability scanner in repo mode - # Commit SHA for v0.0.14 - uses: aquasecurity/trivy-action@b38389f8efef9798810fe0c5b5096ac198cffd54 - with: - scan-type: "fs" - scan-ref: "." - ignore-unfixed: true - format: "template" - template: "@/contrib/sarif.tpl" - output: "trivy-repo-results.sarif" - severity: "HIGH,CRITICAL" - - - name: Upload Trivy scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@v1 - with: - sarif_file: "trivy-repo-results.sarif" diff --git a/lib/vscode/.github/workflows/ci.yml b/.github/workflows/ci.yml similarity index 99% rename from lib/vscode/.github/workflows/ci.yml rename to .github/workflows/ci.yml index d08dac3c03b9..faac7802508d 100644 --- a/lib/vscode/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -244,6 +244,9 @@ jobs: - name: Run Valid Layers Checks run: yarn valid-layers-check + - name: Compile /build/ + run: yarn --cwd build compile + - name: Run Monaco Editor Checks run: yarn monaco-compile-check diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 3b41e3d9b2ad..000000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: "Code Scanning" - -on: - push: - branches: [main] - pull_request: - # The branches below must be a subset of the branches above - branches: [main] - schedule: - # Runs every Monday morning PST - - cron: "17 15 * * 1" - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-20.04 - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - config-file: ./.github/codeql-config.yml - languages: javascript - - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 diff --git a/lib/vscode/.github/workflows/codeql.yml b/.github/workflows/codeql.yml similarity index 100% rename from lib/vscode/.github/workflows/codeql.yml rename to .github/workflows/codeql.yml diff --git a/lib/vscode/.github/workflows/deep-classifier-monitor.yml b/.github/workflows/deep-classifier-monitor.yml similarity index 100% rename from lib/vscode/.github/workflows/deep-classifier-monitor.yml rename to .github/workflows/deep-classifier-monitor.yml diff --git a/lib/vscode/.github/workflows/deep-classifier-runner.yml b/.github/workflows/deep-classifier-runner.yml similarity index 100% rename from lib/vscode/.github/workflows/deep-classifier-runner.yml rename to .github/workflows/deep-classifier-runner.yml diff --git a/lib/vscode/.github/workflows/deep-classifier-scraper.yml b/.github/workflows/deep-classifier-scraper.yml similarity index 100% rename from lib/vscode/.github/workflows/deep-classifier-scraper.yml rename to .github/workflows/deep-classifier-scraper.yml diff --git a/lib/vscode/.github/workflows/devcontainer-cache.yml b/.github/workflows/devcontainer-cache.yml similarity index 100% rename from lib/vscode/.github/workflows/devcontainer-cache.yml rename to .github/workflows/devcontainer-cache.yml diff --git a/lib/vscode/.github/workflows/english-please.yml b/.github/workflows/english-please.yml similarity index 100% rename from lib/vscode/.github/workflows/english-please.yml rename to .github/workflows/english-please.yml diff --git a/lib/vscode/.github/workflows/feature-request.yml b/.github/workflows/feature-request.yml similarity index 100% rename from lib/vscode/.github/workflows/feature-request.yml rename to .github/workflows/feature-request.yml diff --git a/lib/vscode/.github/workflows/latest-release-monitor.yml b/.github/workflows/latest-release-monitor.yml similarity index 100% rename from lib/vscode/.github/workflows/latest-release-monitor.yml rename to .github/workflows/latest-release-monitor.yml diff --git a/lib/vscode/.github/workflows/locker.yml b/.github/workflows/locker.yml similarity index 100% rename from lib/vscode/.github/workflows/locker.yml rename to .github/workflows/locker.yml diff --git a/lib/vscode/.github/workflows/needs-more-info-closer.yml b/.github/workflows/needs-more-info-closer.yml similarity index 100% rename from lib/vscode/.github/workflows/needs-more-info-closer.yml rename to .github/workflows/needs-more-info-closer.yml diff --git a/lib/vscode/.github/workflows/no-yarn-lock-changes.yml b/.github/workflows/no-yarn-lock-changes.yml similarity index 100% rename from lib/vscode/.github/workflows/no-yarn-lock-changes.yml rename to .github/workflows/no-yarn-lock-changes.yml diff --git a/lib/vscode/.github/workflows/on-comment.yml b/.github/workflows/on-comment.yml similarity index 100% rename from lib/vscode/.github/workflows/on-comment.yml rename to .github/workflows/on-comment.yml diff --git a/lib/vscode/.github/workflows/on-label.yml b/.github/workflows/on-label.yml similarity index 100% rename from lib/vscode/.github/workflows/on-label.yml rename to .github/workflows/on-label.yml diff --git a/lib/vscode/.github/workflows/on-open.yml b/.github/workflows/on-open.yml similarity index 100% rename from lib/vscode/.github/workflows/on-open.yml rename to .github/workflows/on-open.yml diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml deleted file mode 100644 index 361c47ae7c33..000000000000 --- a/.github/workflows/publish.yaml +++ /dev/null @@ -1,53 +0,0 @@ -name: publish - -on: - # Shows the manual trigger in GitHub UI - # helpful as a back-up in case the GitHub Actions Workflow fails - workflow_dispatch: - - release: - types: [published] - -jobs: - # NOTE: this job requires curl, jq and yarn - # All of them are included in ubuntu-latest. - npm: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Run ./ci/steps/publish-npm.sh - run: ./ci/steps/publish-npm.sh - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - - # NOTE: this job requires curl, jq and docker - # All of them are included in ubuntu-latest. - docker: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Run ./ci/steps/push-docker-manifest.sh - run: ./ci/steps/push-docker-manifest.sh - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} - DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} - - homebrew: - # The newest version of code-server needs to be available on npm when this runs - # otherwise, it will 404 and won't open a PR to bump version on homebrew/homebrew-core - needs: npm - runs-on: macos-latest - steps: - - uses: actions/checkout@v2 - - name: Configure git - run: | - git config user.name github-actions - git config user.email github-actions@github.com - - name: Bump code-server homebrew version - env: - HOMEBREW_GITHUB_API_TOKEN: ${{secrets.HOMEBREW_GITHUB_API_TOKEN}} - run: ./ci/steps/brew-bump.sh diff --git a/lib/vscode/.github/workflows/release-pipeline-labeler.yml b/.github/workflows/release-pipeline-labeler.yml similarity index 100% rename from lib/vscode/.github/workflows/release-pipeline-labeler.yml rename to .github/workflows/release-pipeline-labeler.yml diff --git a/lib/vscode/.github/workflows/rich-navigation.yml b/.github/workflows/rich-navigation.yml similarity index 100% rename from lib/vscode/.github/workflows/rich-navigation.yml rename to .github/workflows/rich-navigation.yml diff --git a/lib/vscode/.github/workflows/test-plan-item-validator.yml b/.github/workflows/test-plan-item-validator.yml similarity index 100% rename from lib/vscode/.github/workflows/test-plan-item-validator.yml rename to .github/workflows/test-plan-item-validator.yml diff --git a/.gitignore b/.gitignore index 736e30c59648..11a7486bf533 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,18 @@ -.tsbuildinfo +.DS_Store .cache -dist* -out* -release/ -release-npm-package/ -release-standalone/ -release-packages/ -release-gcp/ -release-images/ -node_modules -/lib/vscode/node_modules.asar -node-* -/plugins -/lib/coder-cloud-agent -.home -coverage -**/.DS_Store -# Failed e2e test videos are saved here -test/test-results +npm-debug.log +Thumbs.db +node_modules/ +.build/ +extensions/**/dist/ +/out*/ +/extensions/**/out/ +src/vs/server +resources/server +build/node_modules +coverage/ +test_data/ +test-results/ +yarn-error.log +vscode.lsif +vscode.db diff --git a/lib/vscode/.mailmap b/.mailmap similarity index 100% rename from lib/vscode/.mailmap rename to .mailmap diff --git a/lib/vscode/.mention-bot b/.mention-bot similarity index 100% rename from lib/vscode/.mention-bot rename to .mention-bot diff --git a/.prettierrc.yaml b/.prettierrc.yaml deleted file mode 100644 index a0634116d20d..000000000000 --- a/.prettierrc.yaml +++ /dev/null @@ -1,4 +0,0 @@ -printWidth: 120 -semi: false -trailingComma: all -arrowParens: always diff --git a/.stylelintrc.yaml b/.stylelintrc.yaml deleted file mode 100644 index af5c94bc4f3e..000000000000 --- a/.stylelintrc.yaml +++ /dev/null @@ -1,2 +0,0 @@ -extends: - - stylelint-config-recommended diff --git a/.tours/contributing.tour b/.tours/contributing.tour deleted file mode 100644 index 1dd8e6b2ab8e..000000000000 --- a/.tours/contributing.tour +++ /dev/null @@ -1,151 +0,0 @@ -{ - "$schema": "https://aka.ms/codetour-schema", - "title": "Contributing", - "steps": [ - { - "directory": "src", - "line": 1, - "description": "Hello world! code-server's source code lives here in `src` (see the explorer). It's broadly arranged into browser code, Node code, and code shared between both." - }, - { - "file": "src/node/entry.ts", - "line": 157, - "description": "code-server begins execution here. CLI arguments are parsed, special flags like --help are handled, then the HTTP server is started." - }, - { - "file": "src/node/cli.ts", - "line": 28, - "description": "This describes all of the code-server CLI options and how they will be parsed." - }, - { - "file": "src/node/cli.ts", - "line": 233, - "description": "Here's the actual CLI parser." - }, - { - "file": "src/node/settings.ts", - "line": 1, - "description": "code-server maintains a settings file that is read and written here." - }, - { - "file": "src/node/app.ts", - "line": 11, - "description": "The core of code-server are HTTP and web socket servers which are created here. They provide authentication, file access, an API, and serve web-based applications like VS Code." - }, - { - "file": "src/node/wsRouter.ts", - "line": 38, - "description": "This is an analog to Express's Router that handles web socket routes." - }, - { - "file": "src/node/http.ts", - "line": 1, - "description": "This file provides various HTTP utility functions." - }, - { - "file": "src/node/coder_cloud.ts", - "line": 9, - "description": "The cloud agent spawned here provides the --link functionality." - }, - { - "file": "src/node/heart.ts", - "line": 7, - "description": "code-server's heart beats to indicate recent activity.\n\nAlso documented here: [https://github.com/cdr/code-server/blob/master/docs/FAQ.md#heartbeat-file](https://github.com/cdr/code-server/blob/master/docs/FAQ.md#heartbeat-file)" - }, - { - "file": "src/node/socket.ts", - "line": 13, - "description": "We pass sockets to child processes, however we can't pass TLS sockets so when code-server is handling TLS (via --cert) we use this to create a proxy that can be passed to the child." - }, - { - "directory": "src/node/routes", - "line": 1, - "description": "code-server's routes live here in `src/node/routes` (see the explorer)." - }, - { - "file": "src/node/routes/index.ts", - "line": 123, - "description": "The architecture of code-server allows it to be extended with applications via plugins. Each application is registered at its own route and handles requests at and below that route. Currently we have only VS Code (although it is not yet actually split out into a plugin)." - }, - { - "file": "src/node/plugin.ts", - "line": 103, - "description": "The previously mentioned plugins are loaded here." - }, - { - "file": "src/node/routes/apps.ts", - "line": 12, - "description": "This provides a list of the applications registered with code-server." - }, - { - "file": "src/node/routes/domainProxy.ts", - "line": 18, - "description": "code-server provides a built-in proxy to help in developing web-based applications. This is the code for the domain-based proxy.\n\nAlso documented here: [https://github.com/cdr/code-server/blob/master/docs/FAQ.md#how-do-i-securely-access-web-services](https://github.com/cdr/code-server/blob/master/docs/FAQ.md#how-do-i-securely-access-web-services)" - }, - { - "file": "src/node/routes/pathProxy.ts", - "line": 19, - "description": "Here is the path-based version of the proxy.\n\nAlso documented here: [https://github.com/cdr/code-server/blob/master/docs/FAQ.md#how-do-i-securely-access-web-services](https://github.com/cdr/code-server/blob/master/docs/FAQ.md#how-do-i-securely-access-web-services)" - }, - { - "file": "src/node/proxy.ts", - "line": 4, - "description": "Both the domain and path proxy use the single proxy instance created here." - }, - { - "file": "src/node/routes/health.ts", - "line": 5, - "description": "A simple endpoint that lets you see if code-server is up.\n\nAlso documented here: [https://github.com/cdr/code-server/blob/master/docs/FAQ.md#healthz-endpoint](https://github.com/cdr/code-server/blob/master/docs/FAQ.md#healthz-endpoint)" - }, - { - "file": "src/node/routes/login.ts", - "line": 46, - "description": "code-server supports a password-based login here." - }, - { - "file": "src/node/routes/static.ts", - "line": 16, - "description": "This serves static assets. Anything under the code-server directory can be fetched. Anything outside requires authentication." - }, - { - "file": "src/node/routes/update.ts", - "line": 10, - "description": "This endpoint lets you query for the latest code-server version. It's used to power the update popup you see in VS Code." - }, - { - "file": "src/node/routes/vscode.ts", - "line": 15, - "description": "This is the endpoint that serves VS Code's HTML, handles VS Code's websockets, and handles a few VS Code-specific endpoints for fetching static files." - }, - { - "file": "src/node/vscode.ts", - "line": 13, - "description": "The actual VS Code spawn and initialization is handled here. VS Code runs in a separate child process. We communicate via IPC and by passing it web sockets." - }, - { - "file": "src/browser/serviceWorker.ts", - "line": 1, - "description": "The service worker only exists to provide PWA functionality." - }, - { - "directory": "src/browser/pages", - "line": 1, - "description": "HTML, CSS, and JavaScript for each page lives in here `src/browser/pages` (see the explorer). Currently our HTML uses a simple search and replace template system with variables that {{LOOK_LIKE_THIS}}." - }, - { - "file": "src/browser/pages/vscode.html", - "line": 1, - "description": "The VS Code HTML is based off VS Code's own `workbench.html`." - }, - { - "directory": "src/browser/media", - "line": 1, - "description": "Static images and the manifest live here in `src/browser/media` (see the explorer)." - }, - { - "directory": "lib/vscode", - "line": 1, - "description": "code-server makes use of VS Code's frontend web/remote support. Most of the modifications implement the remote server since that portion of the code is closed source and not released with VS Code.\n\nWe also have a few bug fixes and have added some features (like client-side extensions). See [https://github.com/cdr/code-server/blob/master/docs/CONTRIBUTING.md#modifications-to-vs-code](https://github.com/cdr/code-server/blob/master/docs/CONTRIBUTING.md#modifications-to-vs-code) for a list.\n\nWe make an effort to keep the modifications as few as possible." - } - ] -} \ No newline at end of file diff --git a/.tours/start-development.tour b/.tours/start-development.tour deleted file mode 100644 index 4df15077d36f..000000000000 --- a/.tours/start-development.tour +++ /dev/null @@ -1,26 +0,0 @@ -{ - "$schema": "https://aka.ms/codetour-schema", - "title": "Start Development", - "steps": [ - { - "file": "package.json", - "line": 31, - "description": "## Commands\n\nTo start developing, make sure you have Node 12+ and the [required dependencies](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites) installed. Then, run the following commands:\n\n1. Install dependencies:\n>> yarn\n\n3. Start development mode (and watch for changes):\n>> yarn watch" - }, - { - "file": "src/node/app.ts", - "line": 68, - "description": "## Visit the web server\n\nIf all goes well, you should see something like this in your terminal. code-server should be live in development mode.\n\n---\n```bash\n[2020-12-09T21:03:37.156Z] info code-server 3.7.4 development\n[2020-12-09T21:03:37.157Z] info Using user-data-dir ~/.local/share/code-server\n[2020-12-09T21:03:37.165Z] info Using config file ~/.config/code-server/config.yaml\n[2020-12-09T21:03:37.165Z] info HTTP server listening on http://127.0.0.1:8080 \n[2020-12-09T21:03:37.165Z] info - Authentication is enabled\n[2020-12-09T21:03:37.165Z] info - Using password from ~/.config/code-server/config.yaml\n[2020-12-09T21:03:37.165Z] info - Not serving HTTPS\n```\n\n---\n\nIf you have the default configuration, you can access it at [http://localhost:8080](http://localhost:8080)." - }, - { - "file": "src/browser/pages/login.html", - "line": 26, - "description": "## Make a change\n\nThis is the login page, let's make a change and see it update on our web server! Perhaps change the text :)\n\n```html\n
Modifying the login page 👨🏼‍💻
\n```\n\nReminder, you can likely preview at [http://localhost:8080](http://localhost:8080)" - }, - { - "file": "src/node/app.ts", - "line": 62, - "description": "## That's it!\n\n\nThat's all there is to it! When this tour ends, your terminal session may stop, but just use `yarn watch` to start developing from here on out!\n\n\nIf you haven't already, be sure to check out these resources:\n- [Tour: Contributing](command:codetour.startTourByTitle?[\"Contributing\")\n- [Docs: FAQ.md](https://github.com/cdr/code-server/blob/master/docs/FAQ.md)\n- [Docs: CONTRIBUTING.md](https://github.com/cdr/code-server/blob/master/docs/CONTRIBUTING.md)\n- [Community: GitHub Discussions](https://github.com/cdr/code-server/discussions)\n- [Community: Slack](https://community.coder.com)" - } - ] -} diff --git a/lib/vscode/.vscode/cglicenses.schema.json b/.vscode/cglicenses.schema.json similarity index 100% rename from lib/vscode/.vscode/cglicenses.schema.json rename to .vscode/cglicenses.schema.json diff --git a/lib/vscode/.vscode/cgmanifest.schema.json b/.vscode/cgmanifest.schema.json similarity index 100% rename from lib/vscode/.vscode/cgmanifest.schema.json rename to .vscode/cgmanifest.schema.json diff --git a/lib/vscode/.vscode/extensions.json b/.vscode/extensions.json similarity index 100% rename from lib/vscode/.vscode/extensions.json rename to .vscode/extensions.json diff --git a/lib/vscode/.vscode/launch.json b/.vscode/launch.json similarity index 100% rename from lib/vscode/.vscode/launch.json rename to .vscode/launch.json diff --git a/lib/vscode/.vscode/notebooks/api.github-issues b/.vscode/notebooks/api.github-issues similarity index 52% rename from lib/vscode/.vscode/notebooks/api.github-issues rename to .vscode/notebooks/api.github-issues index b9e25a7c914f..112920287601 100644 --- a/lib/vscode/.vscode/notebooks/api.github-issues +++ b/.vscode/notebooks/api.github-issues @@ -2,37 +2,31 @@ { "kind": 1, "language": "markdown", - "value": "#### Config", - "editable": true + "value": "#### Config" }, { "kind": 2, "language": "github-issues", - "value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"April 2021\"", - "editable": true + "value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"May 2021\"" }, { "kind": 1, "language": "markdown", - "value": "### Finalization", - "editable": true + "value": "### Finalization" }, { "kind": 2, "language": "github-issues", - "value": "$repo $milestone label:api-finalization", - "editable": true + "value": "$repo $milestone label:api-finalization" }, { "kind": 1, "language": "markdown", - "value": "### Proposals", - "editable": true + "value": "### Proposals" }, { "kind": 2, "language": "github-issues", - "value": "$repo $milestone is:open label:api-proposal ", - "editable": true + "value": "$repo $milestone is:open label:api-proposal " } ] \ No newline at end of file diff --git a/lib/vscode/.vscode/notebooks/endgame.github-issues b/.vscode/notebooks/endgame.github-issues similarity index 99% rename from lib/vscode/.vscode/notebooks/endgame.github-issues rename to .vscode/notebooks/endgame.github-issues index 881af2c14b43..bc2fba29ddf1 100644 --- a/lib/vscode/.vscode/notebooks/endgame.github-issues +++ b/.vscode/notebooks/endgame.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-remotehub\n\n$MILESTONE=milestone:\"April 2021\"" + "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-remotehub\n\n$MILESTONE=milestone:\"May 2021\"" }, { "kind": 1, diff --git a/lib/vscode/.vscode/notebooks/grooming-delta.github-issues b/.vscode/notebooks/grooming-delta.github-issues similarity index 100% rename from lib/vscode/.vscode/notebooks/grooming-delta.github-issues rename to .vscode/notebooks/grooming-delta.github-issues diff --git a/lib/vscode/.vscode/notebooks/grooming.github-issues b/.vscode/notebooks/grooming.github-issues similarity index 100% rename from lib/vscode/.vscode/notebooks/grooming.github-issues rename to .vscode/notebooks/grooming.github-issues diff --git a/lib/vscode/.vscode/notebooks/inbox.github-issues b/.vscode/notebooks/inbox.github-issues similarity index 100% rename from lib/vscode/.vscode/notebooks/inbox.github-issues rename to .vscode/notebooks/inbox.github-issues diff --git a/lib/vscode/.vscode/notebooks/my-endgame.github-issues b/.vscode/notebooks/my-endgame.github-issues similarity index 98% rename from lib/vscode/.vscode/notebooks/my-endgame.github-issues rename to .vscode/notebooks/my-endgame.github-issues index c435ee77500b..aad3a8db3a90 100644 --- a/lib/vscode/.vscode/notebooks/my-endgame.github-issues +++ b/.vscode/notebooks/my-endgame.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remotehub\n\n$MILESTONE=milestone:\"April 2021\"\n\n$MINE=assignee:@me" + "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remotehub\n\n$MILESTONE=milestone:\"May 2021\"\n\n$MINE=assignee:@me" }, { "kind": 1, @@ -157,7 +157,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS $MILESTONE -$MINE is:issue is:closed sort:updated-asc label:bug -label:verified -label:z-author-verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found -author:aeschli -author:alexdima -author:alexr00 -author:AmandaSilver -author:bamurtaugh -author:bpasero -author:btholt -author:chrisdias -author:chrmarti -author:Chuxel -author:connor4312 -author:dbaeumer -author:deepak1556 -author:devinvalenciano -author:digitarald -author:eamodio -author:egamma -author:fiveisprime -author:gregvanl -author:isidorn -author:ItalyPaleAle -author:JacksonKearl -author:joaomoreno -author:jrieken -author:kieferrm -author:lszomoru -author:meganrogge -author:misolori -author:mjbvz -author:ornellaalt -author:orta -author:rebornix -author:RMacfarlane -author:roblourens -author:rzhao271 -author:sana-ajani -author:sandy081 -author:sbatten -author:stevencl -author:Tyriar -author:weinand -author:TylerLeonhardt -author:lramos15" + "value": "$REPOS $MILESTONE -$MINE is:issue is:closed sort:updated-asc label:bug -label:verified -label:z-author-verified -label:on-testplan -label:*duplicate -label:duplicate -label:invalid -label:*as-designed -label:error-telemetry -label:verification-steps-needed -label:verification-found -author:aeschli -author:alexdima -author:alexr00 -author:AmandaSilver -author:bamurtaugh -author:bpasero -author:btholt -author:chrisdias -author:chrmarti -author:Chuxel -author:connor4312 -author:dbaeumer -author:deepak1556 -author:devinvalenciano -author:digitarald -author:eamodio -author:egamma -author:fiveisprime -author:gregvanl -author:isidorn -author:ItalyPaleAle -author:JacksonKearl -author:joaomoreno -author:jrieken -author:kieferrm -author:lszomoru -author:meganrogge -author:misolori -author:mjbvz -author:ornellaalt -author:orta -author:rebornix -author:RMacfarlane -author:roblourens -author:rzhao271 -author:sana-ajani -author:sandy081 -author:sbatten -author:stevencl -author:Tyriar -author:weinand -author:TylerLeonhardt -author:lramos15 -author:hediet" }, { "kind": 1, diff --git a/lib/vscode/.vscode/notebooks/my-work.github-issues b/.vscode/notebooks/my-work.github-issues similarity index 63% rename from lib/vscode/.vscode/notebooks/my-work.github-issues rename to .vscode/notebooks/my-work.github-issues index 4e288133b7a2..77ca0e0443b5 100644 --- a/lib/vscode/.vscode/notebooks/my-work.github-issues +++ b/.vscode/notebooks/my-work.github-issues @@ -2,115 +2,96 @@ { "kind": 1, "language": "markdown", - "value": "##### `Config`: This should be changed every month/milestone", - "editable": true + "value": "##### `Config`: This should be changed every month/milestone" }, { "kind": 2, "language": "github-issues", - "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog\n\n// current milestone name\n$milestone=milestone:\"April 2021\"", - "editable": true + "value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog\n\n// current milestone name\n$milestone=milestone:\"May 2021\"" }, { "kind": 1, "language": "github-issues", - "value": "## Milestone Work", - "editable": true + "value": "## Milestone Work" }, { "kind": 2, "language": "github-issues", - "value": "$repos $milestone assignee:@me is:open", - "editable": true + "value": "$repos $milestone assignee:@me is:open" }, { "kind": 1, "language": "github-issues", - "value": "## Bugs, Debt, Features...", - "editable": true + "value": "## Bugs, Debt, Features..." }, { "kind": 1, "language": "markdown", - "value": "#### My Bugs", - "editable": true + "value": "#### My Bugs" }, { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open label:bug", - "editable": true + "value": "$repos assignee:@me is:open label:bug" }, { "kind": 1, "language": "markdown", - "value": "#### Debt & Engineering", - "editable": true + "value": "#### Debt & Engineering" }, { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open label:debt OR $repos assignee:@me is:open label:engineering", - "editable": true + "value": "$repos assignee:@me is:open label:debt OR $repos assignee:@me is:open label:engineering" }, { "kind": 1, "language": "markdown", - "value": "#### Performance 🐌 🔜 🏎", - "editable": true + "value": "#### Performance 🐌 🔜 🏎" }, { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open label:perf OR $repos assignee:@me is:open label:perf-startup OR $repos assignee:@me is:open label:perf-bloat OR $repos assignee:@me is:open label:freeze-slow-crash-leak", - "editable": true + "value": "$repos assignee:@me is:open label:perf OR $repos assignee:@me is:open label:perf-startup OR $repos assignee:@me is:open label:perf-bloat OR $repos assignee:@me is:open label:freeze-slow-crash-leak" }, { "kind": 1, "language": "markdown", - "value": "#### Feature Requests", - "editable": true + "value": "#### Feature Requests" }, { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open label:feature-request milestone:Backlog sort:reactions-+1-desc", - "editable": true + "value": "$repos assignee:@me is:open label:feature-request milestone:Backlog sort:reactions-+1-desc" }, { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open milestone:\"Backlog Candidates\"", - "editable": true + "value": "$repos assignee:@me is:open milestone:\"Backlog Candidates\"" }, { "kind": 1, "language": "markdown", - "value": "### Personal Inbox\n", - "editable": true + "value": "### Personal Inbox\n" }, { "kind": 1, "language": "markdown", - "value": "\n#### Missing Type label", - "editable": true + "value": "\n#### Missing Type label" }, { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open type:issue -label:bug -label:\"needs more info\" -label:feature-request -label:under-discussion -label:debt -label:plan-item -label:upstream", - "editable": true + "value": "$repos assignee:@me is:open type:issue -label:bug -label:\"needs more info\" -label:feature-request -label:under-discussion -label:debt -label:plan-item -label:upstream" }, { "kind": 1, "language": "markdown", - "value": "#### Not Actionable", - "editable": true + "value": "#### Not Actionable" }, { "kind": 2, "language": "github-issues", - "value": "$repos assignee:@me is:open label:\"needs more info\"", - "editable": true + "value": "$repos assignee:@me is:open label:\"needs more info\"" } ] \ No newline at end of file diff --git a/lib/vscode/.vscode/notebooks/papercuts.github-issues b/.vscode/notebooks/papercuts.github-issues similarity index 100% rename from lib/vscode/.vscode/notebooks/papercuts.github-issues rename to .vscode/notebooks/papercuts.github-issues diff --git a/lib/vscode/.vscode/notebooks/verification.github-issues b/.vscode/notebooks/verification.github-issues similarity index 100% rename from lib/vscode/.vscode/notebooks/verification.github-issues rename to .vscode/notebooks/verification.github-issues diff --git a/lib/vscode/.vscode/searches/TrustedTypes.code-search b/.vscode/searches/TrustedTypes.code-search similarity index 100% rename from lib/vscode/.vscode/searches/TrustedTypes.code-search rename to .vscode/searches/TrustedTypes.code-search diff --git a/lib/vscode/.vscode/searches/ts36031.code-search b/.vscode/searches/ts36031.code-search similarity index 100% rename from lib/vscode/.vscode/searches/ts36031.code-search rename to .vscode/searches/ts36031.code-search diff --git a/lib/vscode/.vscode/settings.json b/.vscode/settings.json similarity index 100% rename from lib/vscode/.vscode/settings.json rename to .vscode/settings.json diff --git a/lib/vscode/.vscode/shared.code-snippets b/.vscode/shared.code-snippets similarity index 100% rename from lib/vscode/.vscode/shared.code-snippets rename to .vscode/shared.code-snippets diff --git a/lib/vscode/.vscode/tasks.json b/.vscode/tasks.json similarity index 80% rename from lib/vscode/.vscode/tasks.json rename to .vscode/tasks.json index 8fb5cb440b79..c0b290afa729 100644 --- a/lib/vscode/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -55,39 +55,11 @@ } } }, - { - "type": "npm", - "script": "watch-extension-mediad", - "label": "Ext Media - Build", - "isBackground": true, - "presentation": { - "reveal": "never", - "group": "buildWatchers" - }, - "problemMatcher": { - "owner": "typescript", - "applyTo": "closedDocuments", - "fileLocation": [ - "absolute" - ], - "pattern": { - "regexp": "Error: ([^(]+)\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\): (.*)$", - "file": 1, - "location": 2, - "message": 3 - }, - "background": { - "beginsPattern": "Starting compilation", - "endsPattern": "Finished compilation" - } - } - }, { "label": "VS Code - Build", "dependsOn": [ "Core - Build", - "Ext - Build", - "Ext Media - Build", + "Ext - Build" ], "group": { "kind": "build", @@ -102,7 +74,8 @@ "group": "build", "presentation": { "reveal": "never", - "group": "buildKillers" + "group": "buildKillers", + "close": true }, "problemMatcher": "$tsc" }, @@ -113,18 +86,8 @@ "group": "build", "presentation": { "reveal": "never", - "group": "buildKillers" - }, - "problemMatcher": "$tsc" - }, - { - "type": "npm", - "script": "kill-watch-extension-mediad", - "label": "Kill Ext Media - Build", - "group": "build", - "presentation": { - "reveal": "never", - "group": "buildKillers" + "group": "buildKillers", + "close": true }, "problemMatcher": "$tsc" }, @@ -132,8 +95,7 @@ "label": "Kill VS Code - Build", "dependsOn": [ "Kill Core - Build", - "Kill Ext - Build", - "Kill Ext Media - Build", + "Kill Ext - Build" ], "group": "build", "problemMatcher": [] @@ -238,7 +200,8 @@ "command": "node build/lib/preLaunch.js", "label": "Ensure Prelaunch Dependencies", "presentation": { - "reveal": "silent" + "reveal": "silent", + "close": true } }, { diff --git a/lib/vscode/.yarnrc b/.yarnrc similarity index 78% rename from lib/vscode/.yarnrc rename to .yarnrc index 1965e671993f..ba290809667b 100644 --- a/lib/vscode/.yarnrc +++ b/.yarnrc @@ -1,3 +1,3 @@ disturl "https://electronjs.org/headers" -target "12.0.4" +target "12.0.9" runtime "electron" diff --git a/lib/vscode/CONTRIBUTING.md b/CONTRIBUTING.md similarity index 100% rename from lib/vscode/CONTRIBUTING.md rename to CONTRIBUTING.md diff --git a/LICENSE.txt b/LICENSE.txt index 0270469f3670..0ac28ee234d2 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,20 +1,21 @@ -The MIT License +MIT License -Copyright (c) 2019 Coder Technologies Inc. +Copyright (c) 2015 - present Microsoft Corporation -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index d472c33f8322..ac7f2194233f 100644 --- a/README.md +++ b/README.md @@ -1,77 +1,75 @@ -# code-server · [!["GitHub Discussions"](https://img.shields.io/badge/%20GitHub-%20Discussions-gray.svg?longCache=true&logo=github&colorB=purple)](https://github.com/cdr/code-server/discussions) [!["Join us on Slack"](https://img.shields.io/badge/join-us%20on%20slack-gray.svg?longCache=true&logo=slack&colorB=brightgreen)](https://cdr.co/join-community) [![Twitter Follow](https://img.shields.io/twitter/follow/CoderHQ?label=%40CoderHQ&style=social)](https://twitter.com/coderhq) +# Visual Studio Code - Open Source ("Code - OSS") +[![Feature Requests](https://img.shields.io/github/issues/microsoft/vscode/feature-request.svg)](https://github.com/microsoft/vscode/issues?q=is%3Aopen+is%3Aissue+label%3Afeature-request+sort%3Areactions-%2B1-desc) +[![Bugs](https://img.shields.io/github/issues/microsoft/vscode/bug.svg)](https://github.com/microsoft/vscode/issues?utf8=✓&q=is%3Aissue+is%3Aopen+label%3Abug) +[![Gitter](https://img.shields.io/badge/chat-on%20gitter-yellow.svg)](https://gitter.im/Microsoft/vscode) -[![codecov](https://codecov.io/gh/cdr/code-server/branch/main/graph/badge.svg?token=5iM9farjnC)](https://codecov.io/gh/cdr/code-server) -[![See latest docs](https://img.shields.io/static/v1?label=Docs&message=see%20latest%20&color=blue)](https://github.com/cdr/code-server/tree/v3.9.3/docs) +## The Repository -Run [VS Code](https://github.com/Microsoft/vscode) on any machine anywhere and access it in the browser. +This repository ("`Code - OSS`") is where we (Microsoft) develop the [Visual Studio Code](https://code.visualstudio.com) product together with the community. Not only do we work on code and issues here, we also publish our [roadmap](https://github.com/microsoft/vscode/wiki/Roadmap), [monthly iteration plans](https://github.com/microsoft/vscode/wiki/Iteration-Plans), and our [endgame plans](https://github.com/microsoft/vscode/wiki/Running-the-Endgame). This source code is available to everyone under the standard [MIT license](https://github.com/microsoft/vscode/blob/main/LICENSE.txt). -![Screenshot](./docs/assets/screenshot.png) +## Visual Studio Code -## Highlights +

+ VS Code in action +

-- Code on any device with a consistent development environment -- Use cloud servers to speed up tests, compilations, downloads, and more -- Preserve battery life when you're on the go; all intensive tasks run on your server +[Visual Studio Code](https://code.visualstudio.com) is a distribution of the `Code - OSS` repository with Microsoft specific customizations released under a traditional [Microsoft product license](https://code.visualstudio.com/License/). -## Requirements +[Visual Studio Code](https://code.visualstudio.com) combines the simplicity of a code editor with what developers need for their core edit-build-debug cycle. It provides comprehensive code editing, navigation, and understanding support along with lightweight debugging, a rich extensibility model, and lightweight integration with existing tools. -For a good experience, we recommend at least: +Visual Studio Code is updated monthly with new features and bug fixes. You can download it for Windows, macOS, and Linux on [Visual Studio Code's website](https://code.visualstudio.com/Download). To get the latest releases every day, install the [Insiders build](https://code.visualstudio.com/insiders). -- 1 GB of RAM -- 2 cores +## Contributing -You can use whatever linux distribution floats your boat but in our [guide](./docs/guide.md) we assume Debian on Google Cloud. +There are many ways in which you can participate in this project, for example: -## Getting Started +* [Submit bugs and feature requests](https://github.com/microsoft/vscode/issues), and help us verify as they are checked in +* Review [source code changes](https://github.com/microsoft/vscode/pulls) +* Review the [documentation](https://github.com/microsoft/vscode-docs) and make pull requests for anything from typos to additional and new content -There are three ways you can get started: +If you are interested in fixing issues and contributing directly to the code base, +please see the document [How to Contribute](https://github.com/microsoft/vscode/wiki/How-to-Contribute), which covers the following: -1. Using the [install script](./install.sh), which automates most of the process. The script uses the system package manager (if possible) -2. Manually installing code-server; see [Installation](./docs/install.md) for instructions applicable to most use cases -3. Use our one-click buttons and guides to [deploy code-server to a popular cloud provider](https://github.com/cdr/deploy-code-server) ⚡ +* [How to build and run from source](https://github.com/microsoft/vscode/wiki/How-to-Contribute) +* [The development workflow, including debugging and running tests](https://github.com/microsoft/vscode/wiki/How-to-Contribute#debugging) +* [Coding guidelines](https://github.com/microsoft/vscode/wiki/Coding-Guidelines) +* [Submitting pull requests](https://github.com/microsoft/vscode/wiki/How-to-Contribute#pull-requests) +* [Finding an issue to work on](https://github.com/microsoft/vscode/wiki/How-to-Contribute#where-to-contribute) +* [Contributing to translations](https://aka.ms/vscodeloc) -If you choose to use the install script, you can preview what occurs during the install process: +## Feedback -```bash -curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run -``` +* Ask a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/vscode) +* [Request a new feature](CONTRIBUTING.md) +* Upvote [popular feature requests](https://github.com/microsoft/vscode/issues?q=is%3Aopen+is%3Aissue+label%3Afeature-request+sort%3Areactions-%2B1-desc) +* [File an issue](https://github.com/microsoft/vscode/issues) +* Follow [@code](https://twitter.com/code) and let us know what you think! -To install, run: +See our [wiki](https://github.com/microsoft/vscode/wiki/Feedback-Channels) for a description of each of these channels and information on some other available community-driven channels. -```bash -curl -fsSL https://code-server.dev/install.sh | sh -``` +## Related Projects -When done, the install script prints out instructions for running and starting code-server. +Many of the core components and extensions to VS Code live in their own repositories on GitHub. For example, the [node debug adapter](https://github.com/microsoft/vscode-node-debug) and the [mono debug adapter](https://github.com/microsoft/vscode-mono-debug) have their own repositories. For a complete list, please visit the [Related Projects](https://github.com/microsoft/vscode/wiki/Related-Projects) page on our [wiki](https://github.com/microsoft/vscode/wiki). -We also have an in-depth [setup and configuration](./docs/guide.md) guide. +## Bundled Extensions -### code-server --link +VS Code includes a set of built-in extensions located in the [extensions](extensions) folder, including grammars and snippets for many languages. Extensions that provide rich language support (code completion, Go to Definition) for a language have the suffix `language-features`. For example, the `json` extension provides coloring for `JSON` and the `json-language-features` provides rich language support for `JSON`. -We're working on a cloud platform that makes deploying and managing code-server easier. -Consider running code-server with the beta flag `--link` if you don't want to worry about +## Development Container -- TLS -- Authentication -- Port Forwarding +This repository includes a Visual Studio Code Remote - Containers / GitHub Codespaces development container. -```bash -$ code-server --link -Proxying code-server, you can access your IDE at https://valmar-jon.cdr.co -``` +- For [Remote - Containers](https://aka.ms/vscode-remote/download/containers), use the **Remote-Containers: Clone Repository in Container Volume...** command which creates a Docker volume for better disk I/O on macOS and Windows. +- For Codespaces, install the [Github Codespaces](https://marketplace.visualstudio.com/items?itemName=GitHub.codespacese) extension in VS Code, and use the **Codespaces: Create New Codespace** command. -## FAQ +Docker / the Codespace should have at least **4 Cores and 6 GB of RAM (8 GB recommended)** to run full build. See the [development container README](.devcontainer/README.md) for more information. -See [./docs/FAQ.md](./docs/FAQ.md). +## Code of Conduct -## Want to help? +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. -See [CONTRIBUTING](./docs/CONTRIBUTING.md) for details. +## License -## Hiring +Copyright (c) Microsoft Corporation. All rights reserved. -Interested in [working at Coder](https://coder.com)? Check out [our open positions](https://jobs.lever.co/coder)! - -## For Organizations - -Visit [our website](https://coder.com) for more information about remote development for your organization or enterprise. +Licensed under the [MIT](LICENSE.txt) license. diff --git a/lib/vscode/SECURITY.md b/SECURITY.md similarity index 100% rename from lib/vscode/SECURITY.md rename to SECURITY.md diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index fd6f420e235e..d929c6b59e78 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -1,22 +1,2886 @@ -code-server +microsoft-vscode THIRD-PARTY SOFTWARE NOTICES AND INFORMATION Do Not Translate or Localize -1. Microsoft/vscode version 1.47.0 (https://github.com/Microsoft/vscode) +This project incorporates components from the projects listed below. The original copyright notices and the licenses under which Microsoft received such components are set forth below. Microsoft reserves all rights not expressly granted herein, whether by implication, estoppel or otherwise. -%% Microsoft/vscode NOTICES AND INFORMATION BEGIN HERE +1. atom/language-clojure version 0.22.7 (https://github.com/atom/language-clojure) +2. atom/language-coffee-script version 0.49.3 (https://github.com/atom/language-coffee-script) +3. atom/language-css version 0.44.4 (https://github.com/atom/language-css) +4. atom/language-java version 0.32.1 (https://github.com/atom/language-java) +5. atom/language-sass version 0.62.1 (https://github.com/atom/language-sass) +6. atom/language-shellscript version 0.26.0 (https://github.com/atom/language-shellscript) +7. atom/language-xml version 0.35.2 (https://github.com/atom/language-xml) +8. better-go-syntax version 1.0.0 (https://github.com/jeff-hykin/better-go-syntax/ ) +9. Colorsublime-Themes version 0.1.0 (https://github.com/Colorsublime/Colorsublime-Themes) +10. daaain/Handlebars version 1.8.0 (https://github.com/daaain/Handlebars) +11. dart-lang/dart-syntax-highlight (https://github.com/dart-lang/dart-syntax-highlight) +12. davidrios/pug-tmbundle (https://github.com/davidrios/pug-tmbundle) +13. definitelytyped (https://github.com/DefinitelyTyped/DefinitelyTyped) +14. demyte/language-cshtml version 0.3.0 (https://github.com/demyte/language-cshtml) +15. Document Object Model version 4.0.0 (https://www.w3.org/DOM/) +16. dotnet/csharp-tmLanguage version 0.1.0 (https://github.com/dotnet/csharp-tmLanguage) +17. expand-abbreviation version 0.5.8 (https://github.com/emmetio/expand-abbreviation) +18. fadeevab/make.tmbundle (https://github.com/fadeevab/make.tmbundle) +19. freebroccolo/atom-language-swift (https://github.com/freebroccolo/atom-language-swift) +20. HTML 5.1 W3C Working Draft version 08 October 2015 (http://www.w3.org/TR/2015/WD-html51-20151008/) +21. Ikuyadeu/vscode-R version 1.3.0 (https://github.com/Ikuyadeu/vscode-R) +22. insane version 2.6.2 (https://github.com/bevacqua/insane) +23. Ionic documentation version 1.2.4 (https://github.com/ionic-team/ionic-site) +24. ionide/ionide-fsgrammar (https://github.com/ionide/ionide-fsgrammar) +25. jeff-hykin/cpp-textmate-grammar version 1.12.11 (https://github.com/jeff-hykin/cpp-textmate-grammar) +26. jeff-hykin/cpp-textmate-grammar version 1.15.5 (https://github.com/jeff-hykin/cpp-textmate-grammar) +27. js-beautify version 1.6.8 (https://github.com/beautify-web/js-beautify) +28. JuliaEditorSupport/atom-language-julia version 0.21.0 (https://github.com/JuliaEditorSupport/atom-language-julia) +29. Jxck/assert version 1.0.0 (https://github.com/Jxck/assert) +30. language-docker (https://github.com/moby/moby) +31. language-less version 0.34.2 (https://github.com/atom/language-less) +32. language-php version 0.46.2 (https://github.com/atom/language-php) +33. MagicStack/MagicPython version 1.1.1 (https://github.com/MagicStack/MagicPython) +34. marked version 1.1.0 (https://github.com/markedjs/marked) +35. mdn-data version 1.1.12 (https://github.com/mdn/data) +36. microsoft/TypeScript-TmLanguage version 0.0.1 (https://github.com/microsoft/TypeScript-TmLanguage) +37. microsoft/vscode-JSON.tmLanguage (https://github.com/microsoft/vscode-JSON.tmLanguage) +38. microsoft/vscode-markdown-tm-grammar version 1.0.0 (https://github.com/microsoft/vscode-markdown-tm-grammar) +39. microsoft/vscode-mssql version 1.9.0 (https://github.com/microsoft/vscode-mssql) +40. mmims/language-batchfile version 0.7.6 (https://github.com/mmims/language-batchfile) +41. NVIDIA/cuda-cpp-grammar (https://github.com/NVIDIA/cuda-cpp-grammar) +42. PowerShell/EditorSyntax version 1.0.0 (https://github.com/PowerShell/EditorSyntax) +43. rust-syntax version 0.4.3 (https://github.com/dustypomerleau/rust-syntax) +44. seti-ui version 0.1.0 (https://github.com/jesseweed/seti-ui) +45. shaders-tmLanguage version 0.1.0 (https://github.com/tgjones/shaders-tmLanguage) +46. textmate/asp.vb.net.tmbundle (https://github.com/textmate/asp.vb.net.tmbundle) +47. textmate/c.tmbundle (https://github.com/textmate/c.tmbundle) +48. textmate/diff.tmbundle (https://github.com/textmate/diff.tmbundle) +49. textmate/git.tmbundle (https://github.com/textmate/git.tmbundle) +50. textmate/groovy.tmbundle (https://github.com/textmate/groovy.tmbundle) +51. textmate/html.tmbundle (https://github.com/textmate/html.tmbundle) +52. textmate/ini.tmbundle (https://github.com/textmate/ini.tmbundle) +53. textmate/javascript.tmbundle (https://github.com/textmate/javascript.tmbundle) +54. textmate/lua.tmbundle (https://github.com/textmate/lua.tmbundle) +55. textmate/markdown.tmbundle (https://github.com/textmate/markdown.tmbundle) +56. textmate/perl.tmbundle (https://github.com/textmate/perl.tmbundle) +57. textmate/ruby.tmbundle (https://github.com/textmate/ruby.tmbundle) +58. textmate/yaml.tmbundle (https://github.com/textmate/yaml.tmbundle) +59. TypeScript-TmLanguage version 0.1.8 (https://github.com/microsoft/TypeScript-TmLanguage) +60. TypeScript-TmLanguage version 1.0.0 (https://github.com/microsoft/TypeScript-TmLanguage) +61. Unicode version 12.0.0 (https://home.unicode.org/) +62. vscode-codicons version 0.0.14 (https://github.com/microsoft/vscode-codicons) +63. vscode-logfile-highlighter version 2.11.0 (https://github.com/emilast/vscode-logfile-highlighter) +64. vscode-swift version 0.0.1 (https://github.com/owensd/vscode-swift) +65. Web Background Synchronization (https://github.com/WICG/background-sync) + + +%% atom/language-clojure NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) 2014 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +This package was derived from a TextMate bundle located at +https://github.com/mmcgrana/textmate-clojure and distributed under the +following license, located in `LICENSE.md`: + +The MIT License (MIT) + +Copyright (c) 2010- Mark McGranaghan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +========================================= +END OF atom/language-clojure NOTICES AND INFORMATION + +%% atom/language-coffee-script NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2014 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +This package was derived from a TextMate bundle located at +https://github.com/jashkenas/coffee-script-tmbundle and distributed under the +following license, located in `LICENSE`: + +Copyright (c) 2009-2014 Jeremy Ashkenas + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF atom/language-coffee-script NOTICES AND INFORMATION + +%% atom/language-css NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) 2014 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +-------------------------------------------------------------------- + +This package was derived from a TextMate bundle located at +https://github.com/textmate/css.tmbundle and distributed under the following +license, located in `README.mdown`: + +Permission to copy, use, modify, sell and distribute this +software is granted. This software is provided "as is" without +express or implied warranty, and with no claim as to its +suitability for any purpose. +========================================= +END OF atom/language-css NOTICES AND INFORMATION + +%% atom/language-java NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2014 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +This package was derived from a TextMate bundle located at +https://github.com/textmate/java.tmbundle and distributed under the following +license, located in `README.mdown`: + +Permission to copy, use, modify, sell and distribute this +software is granted. This software is provided "as is" without +express or implied warranty, and with no claim as to its +suitability for any purpose. +========================================= +END OF atom/language-java NOTICES AND INFORMATION + +%% atom/language-sass NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2014 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +This package was derived from a TextMate bundle located at +https://github.com/alexsancho/Sass.tmbundle and distributed under the following +license, located in `LICENSE.md`: + +Copyright (c) 2012 Alex Sancho, http://alexsancho.name/ + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF atom/language-sass NOTICES AND INFORMATION + +%% atom/language-shellscript NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2014 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +This package was derived from a TextMate bundle located at +https://github.com/textmate/shellscript.tmbundle and distributed under the +following license, located in `README.mdown`: + +Permission to copy, use, modify, sell and distribute this +software is granted. This software is provided "as is" without +express or implied warranty, and with no claim as to its +suitability for any purpose. +========================================= +END OF atom/language-shellscript NOTICES AND INFORMATION + +%% atom/language-xml NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2014 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +This package was derived from a TextMate bundle located at +https://github.com/textmate/xml.tmbundle and distributed under the following +license, located in `README.mdown`: + +Permission to copy, use, modify, sell and distribute this +software is granted. This software is provided "as is" without +express or implied warranty, and with no claim as to its +suitability for any purpose. +========================================= +END OF atom/language-xml NOTICES AND INFORMATION + +%% better-go-syntax NOTICES AND INFORMATION BEGIN HERE +========================================= +MIT License + +Copyright (c) 2019 Jeff Hykin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +========================================= +END OF better-go-syntax NOTICES AND INFORMATION + +%% Colorsublime-Themes NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) 2015 Colorsublime.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +========================================= +END OF Colorsublime-Themes NOTICES AND INFORMATION + +%% daaain/Handlebars NOTICES AND INFORMATION BEGIN HERE +========================================= +-- Credits + +Adapted from the great sublime-text-handlebars package by Nicholas Westlake. + +Thanks a lot to all the generous contributors (in alphabetical order): @bittersweetryan, @bradcliffe, @calumbrodie, @duncanbeevers, @hlvnst, @jonschlinkert, @Krutius, @samselikoff, @utkarshkukreti, @zeppelin + +-- License + +(The MIT License) + +Copyright (c) daaain/Handlebars project authors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF daaain/Handlebars NOTICES AND INFORMATION + +%% dart-lang/dart-syntax-highlight NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright 2020, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +========================================= +END OF dart-lang/dart-syntax-highlight NOTICES AND INFORMATION + +%% davidrios/pug-tmbundle NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2016 David Rios + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF davidrios/pug-tmbundle NOTICES AND INFORMATION + +%% definitelytyped NOTICES AND INFORMATION BEGIN HERE +========================================= +This project is licensed under the MIT license. +Copyrights are respective of each contributor listed at the beginning of each definition file. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF definitelytyped NOTICES AND INFORMATION + +%% demyte/language-cshtml NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2014 James Summerton + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF demyte/language-cshtml NOTICES AND INFORMATION + +%% Document Object Model NOTICES AND INFORMATION BEGIN HERE +========================================= +W3C License +This work is being provided by the copyright holders under the following license. +By obtaining and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions. +Permission to copy, modify, and distribute this work, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following +on ALL copies of the work or portions thereof, including modifications: +* The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. +* Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the W3C Software and Document Short Notice should be included. +* Notice of any changes or modifications, through a copyright statement on the new code or document such as "This software or document includes material copied from or derived +from Document Object Model. Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang)." +Disclaimers +THIS WORK IS PROVIDED "AS IS + AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR +FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. +COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. +The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the work without specific, written prior permission. +Title to copyright in this work will at all times remain with copyright holders. +========================================= +END OF Document Object Model NOTICES AND INFORMATION + +%% dotnet/csharp-tmLanguage NOTICES AND INFORMATION BEGIN HERE +========================================= +MIT License + +Copyright (c) 2016 .NET Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +========================================= +END OF dotnet/csharp-tmLanguage NOTICES AND INFORMATION + +%% expand-abbreviation NOTICES AND INFORMATION BEGIN HERE +========================================= +MIT License + +Copyright (c) 2017 Emmet.io + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +========================================= +END OF expand-abbreviation NOTICES AND INFORMATION + +%% fadeevab/make.tmbundle NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) textmate-make.tmbundle project authors + +If not otherwise specified (see below), files in this repository fall under the following license: + +Permission to copy, use, modify, sell and distribute this +software is granted. This software is provided "as is" without +express or implied warranty, and with no claim as to its +suitability for any purpose. + +An exception is made for files in readable text which contain their own license information, +or files where an accompanying file exists (in the same directory) with a "-license" suffix added +to the base-name name of the original file, and an extension of txt, html, or similar. For example +"tidy" is accompanied by "tidy-license.txt". +========================================= +END OF fadeevab/make.tmbundle NOTICES AND INFORMATION + +%% freebroccolo/atom-language-swift NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2014 Darin Morrison + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF freebroccolo/atom-language-swift NOTICES AND INFORMATION + +%% HTML 5.1 W3C Working Draft NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang). This software or document includes material copied +from or derived from HTML 5.1 W3C Working Draft (http://www.w3.org/TR/2015/WD-html51-20151008/.) + +THIS DOCUMENT IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT +NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE CONTENTS OF +THE DOCUMENT ARE SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF SUCH CONTENTS WILL NOT INFRINGE ANY THIRD PARTY +PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + +COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE +DOCUMENT OR THE PERFORMANCE OR IMPLEMENTATION OF THE CONTENTS THEREOF. + +The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to this document or its contents +without specific, written prior permission. Title to copyright in this document will at all times remain with copyright holders. +========================================= +END OF HTML 5.1 W3C Working Draft NOTICES AND INFORMATION + +%% Ikuyadeu/vscode-R NOTICES AND INFORMATION BEGIN HERE +========================================= +MIT License + +Copyright (c) 2019 Yuki Ueda + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +========================================= +END OF Ikuyadeu/vscode-R NOTICES AND INFORMATION + +%% insane NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright © 2015 Nicolas Bevacqua + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF insane NOTICES AND INFORMATION + +%% Ionic documentation NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright Drifty Co. http://drifty.com/. + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of this License; and + +You must cause any modified files to carry prominent notices stating that You changed the files; and + +You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS +========================================= +END OF Ionic documentation NOTICES AND INFORMATION + +%% ionide/ionide-fsgrammar NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2015 Krzysztof Cieslak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +========================================= +END OF ionide/ionide-fsgrammar NOTICES AND INFORMATION + +%% jeff-hykin/cpp-textmate-grammar NOTICES AND INFORMATION BEGIN HERE +========================================= +MIT License + +Copyright (c) 2019 Jeff Hykin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +========================================= +END OF jeff-hykin/cpp-textmate-grammar NOTICES AND INFORMATION + +%% js-beautify NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF js-beautify NOTICES AND INFORMATION + +%% JuliaEditorSupport/atom-language-julia NOTICES AND INFORMATION BEGIN HERE +========================================= +The atom-language-julia package is licensed under the MIT "Expat" License: + +> Copyright (c) 2015 +> +> Permission is hereby granted, free of charge, to any person obtaining +> a copy of this software and associated documentation files (the +> "Software"), to deal in the Software without restriction, including +> without limitation the rights to use, copy, modify, merge, publish, +> distribute, sublicense, and/or sell copies of the Software, and to +> permit persons to whom the Software is furnished to do so, subject to +> the following conditions: +> +> The above copyright notice and this permission notice shall be +> included in all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +> IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +> CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +> TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +> SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF JuliaEditorSupport/atom-language-julia NOTICES AND INFORMATION + +%% Jxck/assert NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2011 Jxck + +Originally from node.js (http://nodejs.org) +Copyright Joyent, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF Jxck/assert NOTICES AND INFORMATION + +%% language-docker NOTICES AND INFORMATION BEGIN HERE +========================================= +Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2013-2018 Docker, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +========================================= +END OF language-docker NOTICES AND INFORMATION + +%% language-less NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2014 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +This package was derived from a TextMate bundle located at +https://github.com/textmate/less.tmbundle and distributed under the following +license, located in `LICENSE.md`: + +Copyright (c) 2010 Scott Kyle and Rasmus Andersson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +========================================= +END OF language-less NOTICES AND INFORMATION + +%% language-php NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2014 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +This package was derived from a TextMate bundle located at +https://github.com/textmate/php.tmbundle and distributed under the following +license, located in `README.mdown`: + +Permission to copy, use, modify, sell and distribute this +software is granted. This software is provided "as is" without +express or implied warranty, and with no claim as to its +suitability for any purpose. +========================================= +END OF language-php NOTICES AND INFORMATION + +%% MagicStack/MagicPython NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License + +Copyright (c) 2015-present MagicStack Inc. http://magic.io + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +========================================= +END OF MagicStack/MagicPython NOTICES AND INFORMATION + +%% marked NOTICES AND INFORMATION BEGIN HERE +========================================= +information + +## Contribution License Agreement + +If you contribute code to this project, you are implicitly allowing your code +to be distributed under the MIT license. You are also implicitly verifying that +all code is your original work. `` + +## Marked + +Copyright (c) 2018+, MarkedJS (https://github.com/markedjs/) +Copyright (c) 2011-2018, Christopher Jeffrey (https://github.com/chjj/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +## Markdown + +Copyright © 2004, John Gruber +http://daringfireball.net/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +* Neither the name "Markdown" nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +This software is provided by the copyright holders and contributors "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright owner or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. +========================================= +END OF marked NOTICES AND INFORMATION + +%% mdn-data NOTICES AND INFORMATION BEGIN HERE +========================================= +Mozilla Public License Version 2.0 + +Copyright (c) 2018 Mozilla Corporation + +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. +========================================= +END OF mdn-data NOTICES AND INFORMATION + +%% microsoft/TypeScript-TmLanguage NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +========================================= +END OF microsoft/TypeScript-TmLanguage NOTICES AND INFORMATION + +%% microsoft/vscode-JSON.tmLanguage NOTICES AND INFORMATION BEGIN HERE +========================================= +vscode-JSON.tmLanguage + +Copyright (c) Microsoft Corporation + +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the ""Software""), to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF microsoft/vscode-JSON.tmLanguage NOTICES AND INFORMATION + +%% microsoft/vscode-markdown-tm-grammar NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) Microsoft 2018 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +========================================= +END OF microsoft/vscode-markdown-tm-grammar NOTICES AND INFORMATION + +%% microsoft/vscode-mssql NOTICES AND INFORMATION BEGIN HERE +========================================= +------------------------------------------ START OF LICENSE ----------------------------------------- +vscode-mssql +Copyright (c) Microsoft Corporation +All rights reserved. +MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +Copyright (c) 2016 Microsoft +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +----------------------------------------------- END OF LICENSE ----------------------------------------- +========================================= +END OF microsoft/vscode-mssql NOTICES AND INFORMATION + +%% mmims/language-batchfile NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2021 Michael Mims + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +========================================= +END OF mmims/language-batchfile NOTICES AND INFORMATION + +%% NVIDIA/cuda-cpp-grammar NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright 2021 NVIDIA Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF NVIDIA/cuda-cpp-grammar NOTICES AND INFORMATION + +%% PowerShell/EditorSyntax NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) Microsoft Corporation + +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +========================================= +END OF PowerShell/EditorSyntax NOTICES AND INFORMATION + +%% rust-syntax NOTICES AND INFORMATION BEGIN HERE +========================================= +MIT License + +Copyright (c) 2020 Dustin Pomerleau + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +========================================= +END OF rust-syntax NOTICES AND INFORMATION + +%% seti-ui NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) 2014 Jesse Weed + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF seti-ui NOTICES AND INFORMATION + +%% shaders-tmLanguage NOTICES AND INFORMATION BEGIN HERE +========================================= +MIT License + +Copyright (c) 2017 Tim Jones + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +========================================= +END OF shaders-tmLanguage NOTICES AND INFORMATION + +%% textmate/asp.vb.net.tmbundle NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) textmate-asp.vb.net.tmbundle project authors + +If not otherwise specified (see below), files in this folder fall under the following license: + +Permission to copy, use, modify, sell and distribute this +software is granted. This software is provided "as is" without +express or implied warranty, and with no claim as to its +suitability for any purpose. + +An exception is made for files in readable text which contain their own license information, +or files where an accompanying file exists (in the same directory) with a "-license" suffix added +to the base-name name of the original file, and an extension of txt, html, or similar. For example +"tidy" is accompanied by "tidy-license.txt". +========================================= +END OF textmate/asp.vb.net.tmbundle NOTICES AND INFORMATION + +%% textmate/c.tmbundle NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) textmate-c.tmbundle authors + +If not otherwise specified (see below), files in this repository fall under the following license: + +Permission to copy, use, modify, sell and distribute this +software is granted. This software is provided "as is" without +express or implied warranty, and with no claim as to its +suitability for any purpose. + +An exception is made for files in readable text which contain their own license information, +or files where an accompanying file exists (in the same directory) with a "-license" suffix added +to the base-name name of the original file, and an extension of txt, html, or similar. For example +"tidy" is accompanied by "tidy-license.txt". +========================================= +END OF textmate/c.tmbundle NOTICES AND INFORMATION + +%% textmate/diff.tmbundle NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) textmate-diff.tmbundle project authors + +If not otherwise specified (see below), files in this repository fall under the following license: + +Permission to copy, use, modify, sell and distribute this +software is granted. This software is provided "as is" without +express or implied warranty, and with no claim as to its +suitability for any purpose. + +An exception is made for files in readable text which contain their own license information, +or files where an accompanying file exists (in the same directory) with a "-license" suffix added +to the base-name name of the original file, and an extension of txt, html, or similar. For example +"tidy" is accompanied by "tidy-license.txt". +========================================= +END OF textmate/diff.tmbundle NOTICES AND INFORMATION + +%% textmate/git.tmbundle NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2008 Tim Harper + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the" +Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF textmate/git.tmbundle NOTICES AND INFORMATION + +%% textmate/groovy.tmbundle NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) textmate-groovy.tmbundle project authors + +If not otherwise specified (see below), files in this repository fall under the following license: + +Permission to copy, use, modify, sell and distribute this +software is granted. This software is provided "as is" without +express or implied warranty, and with no claim as to its +suitability for any purpose. + +An exception is made for files in readable text which contain their own license information, +or files where an accompanying file exists (in the same directory) with a "-license" suffix added +to the base-name name of the original file, and an extension of txt, html, or similar. For example +"tidy" is accompanied by "tidy-license.txt". +========================================= +END OF textmate/groovy.tmbundle NOTICES AND INFORMATION + +%% textmate/html.tmbundle NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) textmate-html.tmbundle project authors + +If not otherwise specified (see below), files in this repository fall under the following license: + +Permission to copy, use, modify, sell and distribute this +software is granted. This software is provided "as is" without +express or implied warranty, and with no claim as to its +suitability for any purpose. + +An exception is made for files in readable text which contain their own license information, +or files where an accompanying file exists (in the same directory) with a "-license" suffix added +to the base-name name of the original file, and an extension of txt, html, or similar. For example +"tidy" is accompanied by "tidy-license.txt". +========================================= +END OF textmate/html.tmbundle NOTICES AND INFORMATION + +%% textmate/ini.tmbundle NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) textmate-ini.tmbundle project authors + +If not otherwise specified (see below), files in this folder fall under the following license: + +Permission to copy, use, modify, sell and distribute this +software is granted. This software is provided "as is" without +express or implied warranty, and with no claim as to its +suitability for any purpose. + +An exception is made for files in readable text which contain their own license information, +or files where an accompanying file exists (in the same directory) with a "-license" suffix added +to the base-name name of the original file, and an extension of txt, html, or similar. For example +"tidy" is accompanied by "tidy-license.txt". +========================================= +END OF textmate/ini.tmbundle NOTICES AND INFORMATION + +%% textmate/javascript.tmbundle NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) textmate-javascript.tmbundle project authors + +If not otherwise specified (see below), files in this repository fall under the following license: + +Permission to copy, use, modify, sell and distribute this +software is granted. This software is provided "as is" without +express or implied warranty, and with no claim as to its +suitability for any purpose. + +An exception is made for files in readable text which contain their own license information, +or files where an accompanying file exists (in the same directory) with a "-license" suffix added +to the base-name name of the original file, and an extension of txt, html, or similar. For example +"tidy" is accompanied by "tidy-license.txt". +========================================= +END OF textmate/javascript.tmbundle NOTICES AND INFORMATION + +%% textmate/lua.tmbundle NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) textmate-lua.tmbundle project authors + +If not otherwise specified (see below), files in this repository fall under the following license: + +Permission to copy, use, modify, sell and distribute this +software is granted. This software is provided "as is" without +express or implied warranty, and with no claim as to its +suitability for any purpose. + +An exception is made for files in readable text which contain their own license information, +or files where an accompanying file exists (in the same directory) with a "-license" suffix added +to the base-name name of the original file, and an extension of txt, html, or similar. For example +"tidy" is accompanied by "tidy-license.txt". +========================================= +END OF textmate/lua.tmbundle NOTICES AND INFORMATION + +%% textmate/markdown.tmbundle NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) markdown.tmbundle authors + +If not otherwise specified (see below), files in this repository fall under the following license: + +Permission to copy, use, modify, sell and distribute this +software is granted. This software is provided "as is" without +express or implied warranty, and with no claim as to its +suitability for any purpose. + +An exception is made for files in readable text which contain their own license information, +or files where an accompanying file exists (in the same directory) with a "-license" suffix added +to the base-name name of the original file, and an extension of txt, html, or similar. For example +"tidy" is accompanied by "tidy-license.txt". +========================================= +END OF textmate/markdown.tmbundle NOTICES AND INFORMATION + +%% textmate/perl.tmbundle NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) textmate-perl.tmbundle project authors + +If not otherwise specified (see below), files in this repository fall under the following license: + +Permission to copy, use, modify, sell and distribute this +software is granted. This software is provided "as is" without +express or implied warranty, and with no claim as to its +suitability for any purpose. + +An exception is made for files in readable text which contain their own license information, +or files where an accompanying file exists (in the same directory) with a "-license" suffix added +to the base-name name of the original file, and an extension of txt, html, or similar. For example +"tidy" is accompanied by "tidy-license.txt". +========================================= +END OF textmate/perl.tmbundle NOTICES AND INFORMATION + +%% textmate/ruby.tmbundle NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) textmate-ruby.tmbundle project authors + +If not otherwise specified (see below), files in this folder fall under the following license: + +Permission to copy, use, modify, sell and distribute this +software is granted. This software is provided "as is" without +express or implied warranty, and with no claim as to its +suitability for any purpose. + +An exception is made for files in readable text which contain their own license information, +or files where an accompanying file exists (in the same directory) with a "-license" suffix added +to the base-name name of the original file, and an extension of txt, html, or similar. For example +"tidy" is accompanied by "tidy-license.txt". +========================================= +END OF textmate/ruby.tmbundle NOTICES AND INFORMATION + +%% textmate/yaml.tmbundle NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) 2015 FichteFoll + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF textmate/yaml.tmbundle NOTICES AND INFORMATION + +%% TypeScript-TmLanguage NOTICES AND INFORMATION BEGIN HERE +========================================= +Copyright (c) Microsoft Corporation +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +========================================= +END OF TypeScript-TmLanguage NOTICES AND INFORMATION + +%% Unicode NOTICES AND INFORMATION BEGIN HERE +========================================= +Unicode Data Files include all data files under the directories +http://www.unicode.org/Public/, http://www.unicode.org/reports/, +http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and +http://www.unicode.org/utility/trac/browser/. + +Unicode Data Files do not include PDF online code charts under the +directory http://www.unicode.org/Public/. + +Software includes any source code published in the Unicode Standard +or under the directories +http://www.unicode.org/Public/, http://www.unicode.org/reports/, +http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and +http://www.unicode.org/utility/trac/browser/. + +NOTICE TO USER: Carefully read the following legal agreement. +BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S +DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), +YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. +IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE +THE DATA FILES OR SOFTWARE. + +COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 1991-2017 Unicode, Inc. All rights reserved. +Distributed under the Terms of Use in http://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation +(the "Data Files") or Unicode software and any associated documentation +(the "Software") to deal in the Data Files or Software +without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, and/or sell copies of +the Data Files or Software, and to permit persons to whom the Data Files +or Software are furnished to do so, provided that either +(a) this copyright and permission notice appear with all copies +of the Data Files or Software, or +(b) this copyright and permission notice appear in associated +Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT OF THIRD PARTY RIGHTS. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in these Data Files or Software without prior +written authorization of the copyright holder. +========================================= +END OF Unicode NOTICES AND INFORMATION + +%% vscode-codicons NOTICES AND INFORMATION BEGIN HERE +========================================= +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the "Licensor." The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. +========================================= +END OF vscode-codicons NOTICES AND INFORMATION + +%% vscode-logfile-highlighter NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2015 emilast + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +========================================= +END OF vscode-logfile-highlighter NOTICES AND INFORMATION + +%% vscode-swift NOTICES AND INFORMATION BEGIN HERE ========================================= -MIT License +The MIT License (MIT) +Copyright (c) 2015 David Owens II -Copyright (c) 2015 - present Microsoft Corporation +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +========================================= +END OF vscode-swift NOTICES AND INFORMATION + +%% Web Background Synchronization NOTICES AND INFORMATION BEGIN HERE +========================================= +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +========================================= +END OF Web Background Synchronization NOTICES AND INFORMATION \ No newline at end of file diff --git a/lib/vscode/build/.cachesalt b/build/.cachesalt similarity index 100% rename from lib/vscode/build/.cachesalt rename to build/.cachesalt diff --git a/lib/vscode/build/.gitattributes b/build/.gitattributes similarity index 100% rename from lib/vscode/build/.gitattributes rename to build/.gitattributes diff --git a/lib/vscode/build/.moduleignore b/build/.moduleignore similarity index 100% rename from lib/vscode/build/.moduleignore rename to build/.moduleignore diff --git a/lib/vscode/build/.webignore b/build/.webignore similarity index 100% rename from lib/vscode/build/.webignore rename to build/.webignore diff --git a/lib/vscode/build/azure-pipelines/common/computeNodeModulesCacheKey.js b/build/azure-pipelines/common/computeNodeModulesCacheKey.js similarity index 100% rename from lib/vscode/build/azure-pipelines/common/computeNodeModulesCacheKey.js rename to build/azure-pipelines/common/computeNodeModulesCacheKey.js diff --git a/lib/vscode/build/azure-pipelines/common/computeNodeModulesCacheKey.ts b/build/azure-pipelines/common/computeNodeModulesCacheKey.ts similarity index 100% rename from lib/vscode/build/azure-pipelines/common/computeNodeModulesCacheKey.ts rename to build/azure-pipelines/common/computeNodeModulesCacheKey.ts diff --git a/build/azure-pipelines/common/createAsset.js b/build/azure-pipelines/common/createAsset.js new file mode 100644 index 000000000000..340c6fd7e5d9 --- /dev/null +++ b/build/azure-pipelines/common/createAsset.js @@ -0,0 +1,197 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = require("fs"); +const url = require("url"); +const crypto = require("crypto"); +const azure = require("azure-storage"); +const mime = require("mime"); +const cosmos_1 = require("@azure/cosmos"); +const retry_1 = require("./retry"); +if (process.argv.length !== 8) { + console.error('Usage: node createAsset.js PRODUCT OS ARCH TYPE NAME FILE'); + process.exit(-1); +} +// Contains all of the logic for mapping details to our actual product names in CosmosDB +function getPlatform(product, os, arch, type) { + switch (os) { + case 'win32': + switch (product) { + case 'client': + const asset = arch === 'ia32' ? 'win32' : `win32-${arch}`; + switch (type) { + case 'archive': + return `${asset}-archive`; + case 'setup': + return asset; + case 'user-setup': + return `${asset}-user`; + default: + throw `Unrecognized: ${product} ${os} ${arch} ${type}`; + } + case 'server': + if (arch === 'arm64') { + throw `Unrecognized: ${product} ${os} ${arch} ${type}`; + } + return arch === 'ia32' ? 'server-win32' : `server-win32-${arch}`; + case 'web': + if (arch === 'arm64') { + throw `Unrecognized: ${product} ${os} ${arch} ${type}`; + } + return arch === 'ia32' ? 'server-win32-web' : `server-win32-${arch}-web`; + default: + throw `Unrecognized: ${product} ${os} ${arch} ${type}`; + } + case 'linux': + switch (type) { + case 'snap': + return `linux-snap-${arch}`; + case 'archive-unsigned': + switch (product) { + case 'client': + return `linux-${arch}`; + case 'server': + return `server-linux-${arch}`; + case 'web': + return arch === 'standalone' ? 'web-standalone' : `server-linux-${arch}-web`; + default: + throw `Unrecognized: ${product} ${os} ${arch} ${type}`; + } + case 'deb-package': + return `linux-deb-${arch}`; + case 'rpm-package': + return `linux-rpm-${arch}`; + default: + throw `Unrecognized: ${product} ${os} ${arch} ${type}`; + } + case 'darwin': + switch (product) { + case 'client': + if (arch === 'x64') { + return 'darwin'; + } + return `darwin-${arch}`; + case 'server': + return 'server-darwin'; + case 'web': + if (arch !== 'x64') { + throw `What should the platform be?: ${product} ${os} ${arch} ${type}`; + } + return 'server-darwin-web'; + default: + throw `Unrecognized: ${product} ${os} ${arch} ${type}`; + } + default: + throw `Unrecognized: ${product} ${os} ${arch} ${type}`; + } +} +// Contains all of the logic for mapping types to our actual types in CosmosDB +function getRealType(type) { + switch (type) { + case 'user-setup': + return 'setup'; + case 'deb-package': + case 'rpm-package': + return 'package'; + default: + return type; + } +} +function hashStream(hashName, stream) { + return new Promise((c, e) => { + const shasum = crypto.createHash(hashName); + stream + .on('data', shasum.update.bind(shasum)) + .on('error', e) + .on('close', () => c(shasum.digest('hex'))); + }); +} +async function doesAssetExist(blobService, quality, blobName) { + const existsResult = await new Promise((c, e) => blobService.doesBlobExist(quality, blobName, (err, r) => err ? e(err) : c(r))); + return existsResult.exists; +} +async function uploadBlob(blobService, quality, blobName, filePath, fileName) { + const blobOptions = { + contentSettings: { + contentType: mime.lookup(filePath), + contentDisposition: `attachment; filename="${fileName}"`, + cacheControl: 'max-age=31536000, public' + } + }; + await new Promise((c, e) => blobService.createBlockBlobFromLocalFile(quality, blobName, filePath, blobOptions, err => err ? e(err) : c())); +} +function getEnv(name) { + const result = process.env[name]; + if (typeof result === 'undefined') { + throw new Error('Missing env: ' + name); + } + return result; +} +async function main() { + const [, , product, os, arch, unprocessedType, fileName, filePath] = process.argv; + // getPlatform needs the unprocessedType + const platform = getPlatform(product, os, arch, unprocessedType); + const type = getRealType(unprocessedType); + const quality = getEnv('VSCODE_QUALITY'); + const commit = getEnv('BUILD_SOURCEVERSION'); + console.log('Creating asset...'); + const stat = await new Promise((c, e) => fs.stat(filePath, (err, stat) => err ? e(err) : c(stat))); + const size = stat.size; + console.log('Size:', size); + const stream = fs.createReadStream(filePath); + const [sha1hash, sha256hash] = await Promise.all([hashStream('sha1', stream), hashStream('sha256', stream)]); + console.log('SHA1:', sha1hash); + console.log('SHA256:', sha256hash); + const blobName = commit + '/' + fileName; + const storageAccount = process.env['AZURE_STORAGE_ACCOUNT_2']; + const blobService = azure.createBlobService(storageAccount, process.env['AZURE_STORAGE_ACCESS_KEY_2']) + .withFilter(new azure.ExponentialRetryPolicyFilter(20)); + const blobExists = await doesAssetExist(blobService, quality, blobName); + if (blobExists) { + console.log(`Blob ${quality}, ${blobName} already exists, not publishing again.`); + return; + } + const mooncakeBlobService = azure.createBlobService(storageAccount, process.env['MOONCAKE_STORAGE_ACCESS_KEY'], `${storageAccount}.blob.core.chinacloudapi.cn`) + .withFilter(new azure.ExponentialRetryPolicyFilter(20)); + // mooncake is fussy and far away, this is needed! + blobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000; + mooncakeBlobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000; + console.log('Uploading blobs to Azure storage and Mooncake Azure storage...'); + await retry_1.retry(() => Promise.all([ + uploadBlob(blobService, quality, blobName, filePath, fileName), + uploadBlob(mooncakeBlobService, quality, blobName, filePath, fileName) + ])); + console.log('Blobs successfully uploaded.'); + // TODO: Understand if blobName and blobPath are the same and replace blobPath with blobName if so. + const assetUrl = `${process.env['AZURE_CDN_URL']}/${quality}/${blobName}`; + const blobPath = url.parse(assetUrl).path; + const mooncakeUrl = `${process.env['MOONCAKE_CDN_URL']}${blobPath}`; + const asset = { + platform, + type, + url: assetUrl, + hash: sha1hash, + mooncakeUrl, + sha256hash, + size + }; + // Remove this if we ever need to rollback fast updates for windows + if (/win32/.test(platform)) { + asset.supportsFastUpdate = true; + } + console.log('Asset:', JSON.stringify(asset, null, ' ')); + const client = new cosmos_1.CosmosClient({ endpoint: process.env['AZURE_DOCUMENTDB_ENDPOINT'], key: process.env['AZURE_DOCUMENTDB_MASTERKEY'] }); + const scripts = client.database('builds').container(quality).scripts; + await retry_1.retry(() => scripts.storedProcedure('createAsset').execute('', [commit, asset, true])); + console.log(` Done ✔️`); +} +main().then(() => { + console.log('Asset successfully created'); + process.exit(0); +}, err => { + console.error(err); + process.exit(1); +}); diff --git a/lib/vscode/build/azure-pipelines/common/createAsset.ts b/build/azure-pipelines/common/createAsset.ts similarity index 50% rename from lib/vscode/build/azure-pipelines/common/createAsset.ts rename to build/azure-pipelines/common/createAsset.ts index daf60d710eec..5fe93c566bb1 100644 --- a/lib/vscode/build/azure-pipelines/common/createAsset.ts +++ b/build/azure-pipelines/common/createAsset.ts @@ -6,6 +6,7 @@ 'use strict'; import * as fs from 'fs'; +import * as url from 'url'; import { Readable } from 'stream'; import * as crypto from 'crypto'; import * as azure from 'azure-storage'; @@ -24,11 +25,98 @@ interface Asset { supportsFastUpdate?: boolean; } -if (process.argv.length !== 6) { - console.error('Usage: node createAsset.js PLATFORM TYPE NAME FILE'); +if (process.argv.length !== 8) { + console.error('Usage: node createAsset.js PRODUCT OS ARCH TYPE NAME FILE'); process.exit(-1); } +// Contains all of the logic for mapping details to our actual product names in CosmosDB +function getPlatform(product: string, os: string, arch: string, type: string): string { + switch (os) { + case 'win32': + switch (product) { + case 'client': + const asset = arch === 'ia32' ? 'win32' : `win32-${arch}`; + switch (type) { + case 'archive': + return `${asset}-archive`; + case 'setup': + return asset; + case 'user-setup': + return `${asset}-user`; + default: + throw `Unrecognized: ${product} ${os} ${arch} ${type}`; + } + case 'server': + if (arch === 'arm64') { + throw `Unrecognized: ${product} ${os} ${arch} ${type}`; + } + return arch === 'ia32' ? 'server-win32' : `server-win32-${arch}`; + case 'web': + if (arch === 'arm64') { + throw `Unrecognized: ${product} ${os} ${arch} ${type}`; + } + return arch === 'ia32' ? 'server-win32-web' : `server-win32-${arch}-web`; + default: + throw `Unrecognized: ${product} ${os} ${arch} ${type}`; + } + case 'linux': + switch (type) { + case 'snap': + return `linux-snap-${arch}`; + case 'archive-unsigned': + switch (product) { + case 'client': + return `linux-${arch}`; + case 'server': + return `server-linux-${arch}`; + case 'web': + return arch === 'standalone' ? 'web-standalone' : `server-linux-${arch}-web`; + default: + throw `Unrecognized: ${product} ${os} ${arch} ${type}`; + } + case 'deb-package': + return `linux-deb-${arch}`; + case 'rpm-package': + return `linux-rpm-${arch}`; + default: + throw `Unrecognized: ${product} ${os} ${arch} ${type}`; + } + case 'darwin': + switch (product) { + case 'client': + if (arch === 'x64') { + return 'darwin'; + } + return `darwin-${arch}`; + case 'server': + return 'server-darwin'; + case 'web': + if (arch !== 'x64') { + throw `What should the platform be?: ${product} ${os} ${arch} ${type}`; + } + return 'server-darwin-web'; + default: + throw `Unrecognized: ${product} ${os} ${arch} ${type}`; + } + default: + throw `Unrecognized: ${product} ${os} ${arch} ${type}`; + } +} + +// Contains all of the logic for mapping types to our actual types in CosmosDB +function getRealType(type: string) { + switch (type) { + case 'user-setup': + return 'setup'; + case 'deb-package': + case 'rpm-package': + return 'package'; + default: + return type; + } +} + function hashStream(hashName: string, stream: Readable): Promise { return new Promise((c, e) => { const shasum = crypto.createHash(hashName); @@ -68,7 +156,10 @@ function getEnv(name: string): string { } async function main(): Promise { - const [, , platform, type, fileName, filePath] = process.argv; + const [, , product, os, arch, unprocessedType, fileName, filePath] = process.argv; + // getPlatform needs the unprocessedType + const platform = getPlatform(product, os, arch, unprocessedType); + const type = getRealType(unprocessedType); const quality = getEnv('VSCODE_QUALITY'); const commit = getEnv('BUILD_SOURCEVERSION'); @@ -98,17 +189,33 @@ async function main(): Promise { return; } - console.log('Uploading blobs to Azure storage...'); + const mooncakeBlobService = azure.createBlobService(storageAccount, process.env['MOONCAKE_STORAGE_ACCESS_KEY']!, `${storageAccount}.blob.core.chinacloudapi.cn`) + .withFilter(new azure.ExponentialRetryPolicyFilter(20)); + + // mooncake is fussy and far away, this is needed! + blobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000; + mooncakeBlobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000; + + console.log('Uploading blobs to Azure storage and Mooncake Azure storage...'); - await uploadBlob(blobService, quality, blobName, filePath, fileName); + await retry(() => Promise.all([ + uploadBlob(blobService, quality, blobName, filePath, fileName), + uploadBlob(mooncakeBlobService, quality, blobName, filePath, fileName) + ])); console.log('Blobs successfully uploaded.'); + // TODO: Understand if blobName and blobPath are the same and replace blobPath with blobName if so. + const assetUrl = `${process.env['AZURE_CDN_URL']}/${quality}/${blobName}`; + const blobPath = url.parse(assetUrl).path; + const mooncakeUrl = `${process.env['MOONCAKE_CDN_URL']}${blobPath}`; + const asset: Asset = { platform, type, - url: `${process.env['AZURE_CDN_URL']}/${quality}/${blobName}`, + url: assetUrl, hash: sha1hash, + mooncakeUrl, sha256hash, size }; @@ -123,6 +230,8 @@ async function main(): Promise { const client = new CosmosClient({ endpoint: process.env['AZURE_DOCUMENTDB_ENDPOINT']!, key: process.env['AZURE_DOCUMENTDB_MASTERKEY'] }); const scripts = client.database('builds').container(quality).scripts; await retry(() => scripts.storedProcedure('createAsset').execute('', [commit, asset, true])); + + console.log(` Done ✔️`); } main().then(() => { diff --git a/lib/vscode/build/azure-pipelines/common/createBuild.js b/build/azure-pipelines/common/createBuild.js similarity index 100% rename from lib/vscode/build/azure-pipelines/common/createBuild.js rename to build/azure-pipelines/common/createBuild.js diff --git a/lib/vscode/build/azure-pipelines/common/createBuild.ts b/build/azure-pipelines/common/createBuild.ts similarity index 100% rename from lib/vscode/build/azure-pipelines/common/createBuild.ts rename to build/azure-pipelines/common/createBuild.ts diff --git a/lib/vscode/build/azure-pipelines/common/extract-telemetry.sh b/build/azure-pipelines/common/extract-telemetry.sh similarity index 100% rename from lib/vscode/build/azure-pipelines/common/extract-telemetry.sh rename to build/azure-pipelines/common/extract-telemetry.sh diff --git a/lib/vscode/build/azure-pipelines/common/installPlaywright.js b/build/azure-pipelines/common/installPlaywright.js similarity index 100% rename from lib/vscode/build/azure-pipelines/common/installPlaywright.js rename to build/azure-pipelines/common/installPlaywright.js diff --git a/lib/vscode/build/azure-pipelines/common/installPlaywright.ts b/build/azure-pipelines/common/installPlaywright.ts similarity index 100% rename from lib/vscode/build/azure-pipelines/common/installPlaywright.ts rename to build/azure-pipelines/common/installPlaywright.ts diff --git a/lib/vscode/build/azure-pipelines/common/listNodeModules.js b/build/azure-pipelines/common/listNodeModules.js similarity index 100% rename from lib/vscode/build/azure-pipelines/common/listNodeModules.js rename to build/azure-pipelines/common/listNodeModules.js diff --git a/lib/vscode/build/azure-pipelines/common/listNodeModules.ts b/build/azure-pipelines/common/listNodeModules.ts similarity index 100% rename from lib/vscode/build/azure-pipelines/common/listNodeModules.ts rename to build/azure-pipelines/common/listNodeModules.ts diff --git a/lib/vscode/build/azure-pipelines/common/publish-webview.js b/build/azure-pipelines/common/publish-webview.js similarity index 100% rename from lib/vscode/build/azure-pipelines/common/publish-webview.js rename to build/azure-pipelines/common/publish-webview.js diff --git a/lib/vscode/build/azure-pipelines/common/publish-webview.sh b/build/azure-pipelines/common/publish-webview.sh similarity index 100% rename from lib/vscode/build/azure-pipelines/common/publish-webview.sh rename to build/azure-pipelines/common/publish-webview.sh diff --git a/lib/vscode/build/azure-pipelines/common/publish-webview.ts b/build/azure-pipelines/common/publish-webview.ts similarity index 100% rename from lib/vscode/build/azure-pipelines/common/publish-webview.ts rename to build/azure-pipelines/common/publish-webview.ts diff --git a/lib/vscode/build/azure-pipelines/common/releaseBuild.js b/build/azure-pipelines/common/releaseBuild.js similarity index 100% rename from lib/vscode/build/azure-pipelines/common/releaseBuild.js rename to build/azure-pipelines/common/releaseBuild.js diff --git a/lib/vscode/build/azure-pipelines/common/releaseBuild.ts b/build/azure-pipelines/common/releaseBuild.ts similarity index 100% rename from lib/vscode/build/azure-pipelines/common/releaseBuild.ts rename to build/azure-pipelines/common/releaseBuild.ts diff --git a/lib/vscode/build/azure-pipelines/common/retry.js b/build/azure-pipelines/common/retry.js similarity index 100% rename from lib/vscode/build/azure-pipelines/common/retry.js rename to build/azure-pipelines/common/retry.js diff --git a/lib/vscode/build/azure-pipelines/common/retry.ts b/build/azure-pipelines/common/retry.ts similarity index 100% rename from lib/vscode/build/azure-pipelines/common/retry.ts rename to build/azure-pipelines/common/retry.ts diff --git a/lib/vscode/build/azure-pipelines/common/telemetry-config.json b/build/azure-pipelines/common/telemetry-config.json similarity index 100% rename from lib/vscode/build/azure-pipelines/common/telemetry-config.json rename to build/azure-pipelines/common/telemetry-config.json diff --git a/lib/vscode/build/azure-pipelines/darwin/app-entitlements.plist b/build/azure-pipelines/darwin/app-entitlements.plist similarity index 100% rename from lib/vscode/build/azure-pipelines/darwin/app-entitlements.plist rename to build/azure-pipelines/darwin/app-entitlements.plist diff --git a/lib/vscode/build/azure-pipelines/darwin/helper-gpu-entitlements.plist b/build/azure-pipelines/darwin/helper-gpu-entitlements.plist similarity index 100% rename from lib/vscode/build/azure-pipelines/darwin/helper-gpu-entitlements.plist rename to build/azure-pipelines/darwin/helper-gpu-entitlements.plist diff --git a/lib/vscode/build/azure-pipelines/darwin/helper-renderer-entitlements.plist b/build/azure-pipelines/darwin/helper-renderer-entitlements.plist similarity index 100% rename from lib/vscode/build/azure-pipelines/darwin/helper-renderer-entitlements.plist rename to build/azure-pipelines/darwin/helper-renderer-entitlements.plist diff --git a/lib/vscode/build/azure-pipelines/darwin/product-build-darwin-sign.yml b/build/azure-pipelines/darwin/product-build-darwin-sign.yml similarity index 80% rename from lib/vscode/build/azure-pipelines/darwin/product-build-darwin-sign.yml rename to build/azure-pipelines/darwin/product-build-darwin-sign.yml index 4ad8349c51a8..49f74b55c933 100644 --- a/lib/vscode/build/azure-pipelines/darwin/product-build-darwin-sign.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-sign.yml @@ -35,13 +35,13 @@ steps: displayName: Restore modules for just build folder and compile it - download: current - artifact: vscode-darwin-$(VSCODE_ARCH) + artifact: unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive displayName: Download $(VSCODE_ARCH) artifact - script: | set -e - unzip $(Pipeline.Workspace)/vscode-darwin-$(VSCODE_ARCH)/VSCode-darwin-$(VSCODE_ARCH).zip -d $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) - mv $(Pipeline.Workspace)/vscode-darwin-$(VSCODE_ARCH)/VSCode-darwin-$(VSCODE_ARCH).zip $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH).zip + unzip $(Pipeline.Workspace)/unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive/VSCode-darwin-$(VSCODE_ARCH).zip -d $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH) + mv $(Pipeline.Workspace)/unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive/VSCode-darwin-$(VSCODE_ARCH).zip $(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH).zip displayName: Unzip & move - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 @@ -108,22 +108,18 @@ steps: condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64')) - script: | - set -e - # For legacy purposes, arch for x64 is just 'darwin' case $VSCODE_ARCH in x64) ASSET_ID="darwin" ;; arm64) ASSET_ID="darwin-arm64" ;; universal) ASSET_ID="darwin-universal" ;; esac + echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID" + displayName: Set asset id variable + + - script: mv $(agent.builddirectory)/VSCode-darwin-x64.zip $(agent.builddirectory)/VSCode-darwin.zip + displayName: Rename x64 build to it's legacy name + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - node build/azure-pipelines/common/createAsset.js \ - "$ASSET_ID" \ - archive \ - "VSCode-$ASSET_ID.zip" \ - ../VSCode-darwin-$(VSCODE_ARCH).zip - displayName: Publish Clients + - publish: $(Agent.BuildDirectory)/VSCode-$(ASSET_ID).zip + artifact: vscode_client_darwin_$(VSCODE_ARCH)_archive diff --git a/lib/vscode/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml similarity index 92% rename from lib/vscode/build/azure-pipelines/darwin/product-build-darwin.yml rename to build/azure-pipelines/darwin/product-build-darwin.yml index 186920fe96d6..566eeb805229 100644 --- a/lib/vscode/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -138,19 +138,19 @@ steps: condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'universal'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - download: current - artifact: vscode-darwin-x64 + artifact: unsigned_vscode_client_darwin_x64_archive displayName: Download x64 artifact condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'universal')) - download: current - artifact: vscode-darwin-arm64 + artifact: unsigned_vscode_client_darwin_arm64_archive displayName: Download arm64 artifact condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'universal')) - script: | set -e - cp $(Pipeline.Workspace)/vscode-darwin-x64/VSCode-darwin-x64.zip $(agent.builddirectory)/VSCode-darwin-x64.zip - cp $(Pipeline.Workspace)/vscode-darwin-arm64/VSCode-darwin-arm64.zip $(agent.builddirectory)/VSCode-darwin-arm64.zip + cp $(Pipeline.Workspace)/unsigned_vscode_client_darwin_x64_archive/VSCode-darwin-x64.zip $(agent.builddirectory)/VSCode-darwin-x64.zip + cp $(Pipeline.Workspace)/unsigned_vscode_client_darwin_arm64_archive/VSCode-darwin-arm64.zip $(agent.builddirectory)/VSCode-darwin-arm64.zip unzip $(agent.builddirectory)/VSCode-darwin-x64.zip -d $(agent.builddirectory)/VSCode-darwin-x64 unzip $(agent.builddirectory)/VSCode-darwin-arm64.zip -d $(agent.builddirectory)/VSCode-darwin-arm64 DEBUG=* node build/darwin/create-universal-app.js @@ -280,26 +280,27 @@ steps: - script: | set -e - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - VSCODE_ARCH="$(VSCODE_ARCH)" ./build/azure-pipelines/darwin/publish-server.sh - displayName: Publish Servers + + # package Remote Extension Host + pushd .. && mv vscode-reh-darwin vscode-server-darwin && zip -Xry vscode-server-darwin.zip vscode-server-darwin && popd + + # package Remote Extension Host (Web) + pushd .. && mv vscode-reh-web-darwin vscode-server-darwin-web && zip -Xry vscode-server-darwin-web.zip vscode-server-darwin-web && popd + displayName: Prepare to publish servers condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), ne(variables['VSCODE_PUBLISH'], 'false')) - publish: $(Agent.BuildDirectory)/VSCode-darwin-$(VSCODE_ARCH).zip - artifact: vscode-darwin-$(VSCODE_ARCH) + artifact: unsigned_vscode_client_darwin_$(VSCODE_ARCH)_archive displayName: Publish client archive condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) - publish: $(Agent.BuildDirectory)/vscode-server-darwin.zip - artifact: vscode-server-darwin-$(VSCODE_ARCH) + artifact: vscode_server_darwin_$(VSCODE_ARCH)_archive-unsigned displayName: Publish server archive condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), ne(variables['VSCODE_PUBLISH'], 'false')) - publish: $(Agent.BuildDirectory)/vscode-server-darwin-web.zip - artifact: vscode-server-darwin-$(VSCODE_ARCH)-web + artifact: vscode_web_darwin_$(VSCODE_ARCH)_archive-unsigned displayName: Publish web server archive condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), ne(variables['VSCODE_PUBLISH'], 'false')) @@ -308,5 +309,5 @@ steps: VSCODE_ARCH="$(VSCODE_ARCH)" \ yarn gulp upload-vscode-configuration displayName: Upload configuration (for Bing settings search) - condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64')) + condition: and(succeeded(), eq(variables['VSCODE_ARCH'], 'x64'), ne(variables['VSCODE_PUBLISH'], 'false')) continueOnError: true diff --git a/lib/vscode/build/azure-pipelines/distro-build.yml b/build/azure-pipelines/distro-build.yml similarity index 100% rename from lib/vscode/build/azure-pipelines/distro-build.yml rename to build/azure-pipelines/distro-build.yml diff --git a/lib/vscode/build/azure-pipelines/exploration-build.yml b/build/azure-pipelines/exploration-build.yml similarity index 100% rename from lib/vscode/build/azure-pipelines/exploration-build.yml rename to build/azure-pipelines/exploration-build.yml diff --git a/lib/vscode/build/azure-pipelines/linux/.gitignore b/build/azure-pipelines/linux/.gitignore similarity index 100% rename from lib/vscode/build/azure-pipelines/linux/.gitignore rename to build/azure-pipelines/linux/.gitignore diff --git a/lib/vscode/build/azure-pipelines/linux/alpine/install-dependencies.sh b/build/azure-pipelines/linux/alpine/install-dependencies.sh similarity index 100% rename from lib/vscode/build/azure-pipelines/linux/alpine/install-dependencies.sh rename to build/azure-pipelines/linux/alpine/install-dependencies.sh diff --git a/lib/vscode/build/azure-pipelines/linux/publish.sh b/build/azure-pipelines/linux/prepare-publish.sh similarity index 79% rename from lib/vscode/build/azure-pipelines/linux/publish.sh rename to build/azure-pipelines/linux/prepare-publish.sh index 6d748c6e340d..891fa8024ef5 100755 --- a/lib/vscode/build/azure-pipelines/linux/publish.sh +++ b/build/azure-pipelines/linux/prepare-publish.sh @@ -13,8 +13,6 @@ TARBALL_PATH="$ROOT/$TARBALL_FILENAME" rm -rf $ROOT/code-*.tar.* (cd $ROOT && tar -czf $TARBALL_PATH $BUILDNAME) -node build/azure-pipelines/common/createAsset.js "$PLATFORM_LINUX" archive-unsigned "$TARBALL_FILENAME" "$TARBALL_PATH" - # Publish Remote Extension Host LEGACY_SERVER_BUILD_NAME="vscode-reh-$PLATFORM_LINUX" SERVER_BUILD_NAME="vscode-server-$PLATFORM_LINUX" @@ -24,8 +22,6 @@ SERVER_TARBALL_PATH="$ROOT/$SERVER_TARBALL_FILENAME" rm -rf $ROOT/vscode-server-*.tar.* (cd $ROOT && mv $LEGACY_SERVER_BUILD_NAME $SERVER_BUILD_NAME && tar --owner=0 --group=0 -czf $SERVER_TARBALL_PATH $SERVER_BUILD_NAME) -node build/azure-pipelines/common/createAsset.js "server-$PLATFORM_LINUX" archive-unsigned "$SERVER_TARBALL_FILENAME" "$SERVER_TARBALL_PATH" - # Publish Remote Extension Host (Web) LEGACY_SERVER_BUILD_NAME="vscode-reh-web-$PLATFORM_LINUX" SERVER_BUILD_NAME="vscode-server-$PLATFORM_LINUX-web" @@ -35,8 +31,6 @@ SERVER_TARBALL_PATH="$ROOT/$SERVER_TARBALL_FILENAME" rm -rf $ROOT/vscode-server-*-web.tar.* (cd $ROOT && mv $LEGACY_SERVER_BUILD_NAME $SERVER_BUILD_NAME && tar --owner=0 --group=0 -czf $SERVER_TARBALL_PATH $SERVER_BUILD_NAME) -node build/azure-pipelines/common/createAsset.js "server-$PLATFORM_LINUX-web" archive-unsigned "$SERVER_TARBALL_FILENAME" "$SERVER_TARBALL_PATH" - # Publish DEB case $VSCODE_ARCH in x64) DEB_ARCH="amd64" ;; @@ -47,8 +41,6 @@ PLATFORM_DEB="linux-deb-$VSCODE_ARCH" DEB_FILENAME="$(ls $REPO/.build/linux/deb/$DEB_ARCH/deb/)" DEB_PATH="$REPO/.build/linux/deb/$DEB_ARCH/deb/$DEB_FILENAME" -node build/azure-pipelines/common/createAsset.js "$PLATFORM_DEB" package "$DEB_FILENAME" "$DEB_PATH" - # Publish RPM case $VSCODE_ARCH in x64) RPM_ARCH="x86_64" ;; @@ -61,8 +53,6 @@ PLATFORM_RPM="linux-rpm-$VSCODE_ARCH" RPM_FILENAME="$(ls $REPO/.build/linux/rpm/$RPM_ARCH/ | grep .rpm)" RPM_PATH="$REPO/.build/linux/rpm/$RPM_ARCH/$RPM_FILENAME" -node build/azure-pipelines/common/createAsset.js "$PLATFORM_RPM" package "$RPM_FILENAME" "$RPM_PATH" - # Publish Snap # Pack snap tarball artifact, in order to preserve file perms mkdir -p $REPO/.build/linux/snap-tarball @@ -73,3 +63,4 @@ rm -rf $SNAP_TARBALL_PATH # Export DEB_PATH, RPM_PATH echo "##vso[task.setvariable variable=DEB_PATH]$DEB_PATH" echo "##vso[task.setvariable variable=RPM_PATH]$RPM_PATH" +echo "##vso[task.setvariable variable=TARBALL_PATH]$TARBALL_PATH" diff --git a/lib/vscode/build/azure-pipelines/linux/product-build-alpine.yml b/build/azure-pipelines/linux/product-build-alpine.yml similarity index 77% rename from lib/vscode/build/azure-pipelines/linux/product-build-alpine.yml rename to build/azure-pipelines/linux/product-build-alpine.yml index 8376c079ce88..ed0c35346c70 100644 --- a/lib/vscode/build/azure-pipelines/linux/product-build-alpine.yml +++ b/build/azure-pipelines/linux/product-build-alpine.yml @@ -117,19 +117,37 @@ steps: - script: | set -e - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - ./build/azure-pipelines/linux/alpine/publish.sh - displayName: Publish + REPO="$(pwd)" + ROOT="$REPO/.." + + PLATFORM_LINUX="linux-alpine" + + # Publish Remote Extension Host + LEGACY_SERVER_BUILD_NAME="vscode-reh-$PLATFORM_LINUX" + SERVER_BUILD_NAME="vscode-server-$PLATFORM_LINUX" + SERVER_TARBALL_FILENAME="vscode-server-$PLATFORM_LINUX.tar.gz" + SERVER_TARBALL_PATH="$ROOT/$SERVER_TARBALL_FILENAME" + + rm -rf $ROOT/vscode-server-*.tar.* + (cd $ROOT && mv $LEGACY_SERVER_BUILD_NAME $SERVER_BUILD_NAME && tar --owner=0 --group=0 -czf $SERVER_TARBALL_PATH $SERVER_BUILD_NAME) + + # Publish Remote Extension Host (Web) + LEGACY_SERVER_BUILD_NAME="vscode-reh-web-$PLATFORM_LINUX" + SERVER_BUILD_NAME="vscode-server-$PLATFORM_LINUX-web" + SERVER_TARBALL_FILENAME="vscode-server-$PLATFORM_LINUX-web.tar.gz" + SERVER_TARBALL_PATH="$ROOT/$SERVER_TARBALL_FILENAME" + + rm -rf $ROOT/vscode-server-*-web.tar.* + (cd $ROOT && mv $LEGACY_SERVER_BUILD_NAME $SERVER_BUILD_NAME && tar --owner=0 --group=0 -czf $SERVER_TARBALL_PATH $SERVER_BUILD_NAME) + displayName: Prepare for publish condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) - publish: $(Agent.BuildDirectory)/vscode-server-linux-alpine.tar.gz - artifact: vscode-server-linux-alpine + artifact: vscode_server_linux_alpine_archive-unsigned displayName: Publish server archive condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) - publish: $(Agent.BuildDirectory)/vscode-server-linux-alpine-web.tar.gz - artifact: vscode-server-linux-alpine-web + artifact: vscode_web_linux_alpine_archive-unsigned displayName: Publish web server archive condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) diff --git a/lib/vscode/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml similarity index 94% rename from lib/vscode/build/azure-pipelines/linux/product-build-linux.yml rename to build/azure-pipelines/linux/product-build-linux.yml index cb06bf6a7249..8181083d1f25 100644 --- a/lib/vscode/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -245,27 +245,32 @@ steps: AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ VSCODE_ARCH="$(VSCODE_ARCH)" \ - ./build/azure-pipelines/linux/publish.sh - displayName: Publish + ./build/azure-pipelines/linux/prepare-publish.sh + displayName: Prepare for Publish condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) - publish: $(DEB_PATH) - artifact: vscode-linux-deb-$(VSCODE_ARCH) + artifact: vscode_client_linux_$(VSCODE_ARCH)_deb-package displayName: Publish deb package condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) - publish: $(RPM_PATH) - artifact: vscode-linux-rpm-$(VSCODE_ARCH) + artifact: vscode_client_linux_$(VSCODE_ARCH)_rpm-package displayName: Publish rpm package condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - publish: $(TARBALL_PATH) + artifact: vscode_client_linux_$(VSCODE_ARCH)_archive-unsigned + displayName: Publish client archive + condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) + - publish: $(Agent.BuildDirectory)/vscode-server-linux-$(VSCODE_ARCH).tar.gz - artifact: vscode-server-linux-$(VSCODE_ARCH) + artifact: vscode_server_linux_$(VSCODE_ARCH)_archive-unsigned displayName: Publish server archive condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) - publish: $(Agent.BuildDirectory)/vscode-server-linux-$(VSCODE_ARCH)-web.tar.gz - artifact: vscode-server-linux-$(VSCODE_ARCH)-web + artifact: vscode_web_linux_$(VSCODE_ARCH)_archive-unsigned displayName: Publish web server archive condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) diff --git a/lib/vscode/build/azure-pipelines/linux/snap-build-linux.yml b/build/azure-pipelines/linux/snap-build-linux.yml similarity index 84% rename from lib/vscode/build/azure-pipelines/linux/snap-build-linux.yml rename to build/azure-pipelines/linux/snap-build-linux.yml index f5e0288f0b92..f7af900e1d0d 100644 --- a/lib/vscode/build/azure-pipelines/linux/snap-build-linux.yml +++ b/build/azure-pipelines/linux/snap-build-linux.yml @@ -50,15 +50,11 @@ steps: esac (cd $SNAP_ROOT/code-* && sudo --preserve-env snapcraft prime $SNAPCRAFT_TARGET_ARGS && snap pack prime --compression=lzo --filename="$SNAP_PATH") - # Publish snap package - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - node build/azure-pipelines/common/createAsset.js "linux-snap-$(VSCODE_ARCH)" package "$SNAP_FILENAME" "$SNAP_PATH" - # Export SNAP_PATH echo "##vso[task.setvariable variable=SNAP_PATH]$SNAP_PATH" + displayName: Prepare for publish - publish: $(SNAP_PATH) - artifact: vscode-linux-snap-$(VSCODE_ARCH) + artifact: vscode_client_linux_$(VSCODE_ARCH)_snap displayName: Publish snap package condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) diff --git a/lib/vscode/build/azure-pipelines/linux/xvfb.init b/build/azure-pipelines/linux/xvfb.init similarity index 100% rename from lib/vscode/build/azure-pipelines/linux/xvfb.init rename to build/azure-pipelines/linux/xvfb.init diff --git a/lib/vscode/build/azure-pipelines/mixin.js b/build/azure-pipelines/mixin.js similarity index 100% rename from lib/vscode/build/azure-pipelines/mixin.js rename to build/azure-pipelines/mixin.js diff --git a/lib/vscode/build/azure-pipelines/mixin.ts b/build/azure-pipelines/mixin.ts similarity index 100% rename from lib/vscode/build/azure-pipelines/mixin.ts rename to build/azure-pipelines/mixin.ts diff --git a/lib/vscode/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml similarity index 89% rename from lib/vscode/build/azure-pipelines/product-build.yml rename to build/azure-pipelines/product-build.yml index fd698a0e7dfc..2c475b9deddd 100644 --- a/lib/vscode/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -86,6 +86,8 @@ variables: value: ${{ eq(parameters.ENABLE_TERRAPIN, true) }} - name: VSCODE_QUALITY value: ${{ parameters.VSCODE_QUALITY }} + - name: VSCODE_RELEASE + value: ${{ parameters.VSCODE_RELEASE }} - name: VSCODE_BUILD_STAGE_WINDOWS value: ${{ or(eq(parameters.VSCODE_BUILD_WIN32, true), eq(parameters.VSCODE_BUILD_WIN32_32BIT, true), eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }} - name: VSCODE_BUILD_STAGE_LINUX @@ -301,37 +303,30 @@ stages: steps: - template: darwin/product-build-darwin-sign.yml - - ${{ if and(eq(variables['VSCODE_PUBLISH'], true), eq(parameters.VSCODE_COMPILE_ONLY, false)) }}: - - stage: Mooncake + - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), ne(variables['VSCODE_PUBLISH'], 'false')) }}: + - stage: Publish dependsOn: - - ${{ if eq(variables['VSCODE_BUILD_STAGE_WINDOWS'], true) }}: - - Windows - - ${{ if eq(variables['VSCODE_BUILD_STAGE_LINUX'], true) }}: - - Linux - - ${{ if eq(variables['VSCODE_BUILD_STAGE_MACOS'], true) }}: - - macOS - condition: succeededOrFailed() + - Compile pool: vmImage: "Ubuntu-18.04" + variables: + - name: BUILDS_API_URL + value: $(System.CollectionUri)$(System.TeamProject)/_apis/build/builds/$(Build.BuildId)/ jobs: - - job: SyncMooncake - displayName: Sync Mooncake + - job: PublishBuild + timeoutInMinutes: 180 + displayName: Publish Build steps: - - template: sync-mooncake.yml + - template: product-publish.yml - - ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), or(eq(parameters.VSCODE_RELEASE, true), and(in(parameters.VSCODE_QUALITY, 'insider', 'exploration'), eq(variables['VSCODE_SCHEDULEDBUILD'], true)))) }}: - - stage: Release - dependsOn: - - ${{ if eq(variables['VSCODE_BUILD_STAGE_WINDOWS'], true) }}: - - Windows - - ${{ if eq(variables['VSCODE_BUILD_STAGE_LINUX'], true) }}: - - Linux - - ${{ if eq(variables['VSCODE_BUILD_STAGE_MACOS'], true) }}: - - macOS - pool: - vmImage: "Ubuntu-18.04" - jobs: - - job: ReleaseBuild - displayName: Release Build - steps: - - template: release.yml + - ${{ if or(eq(parameters.VSCODE_RELEASE, true), and(in(parameters.VSCODE_QUALITY, 'insider', 'exploration'), eq(variables['VSCODE_SCHEDULEDBUILD'], true))) }}: + - stage: Release + dependsOn: + - Publish + pool: + vmImage: "Ubuntu-18.04" + jobs: + - job: ReleaseBuild + displayName: Release Build + steps: + - template: product-release.yml diff --git a/lib/vscode/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml similarity index 93% rename from lib/vscode/build/azure-pipelines/product-compile.yml rename to build/azure-pipelines/product-compile.yml index 52c7758cfdee..18c17639b830 100644 --- a/lib/vscode/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -118,14 +118,6 @@ steps: displayName: Publish Webview condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) - - script: | - set -e - VERSION=`node -p "require(\"./package.json\").version"` - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - node build/azure-pipelines/common/createBuild.js $VERSION - displayName: Create build - condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) - # we gotta tarball everything in order to preserve file permissions - script: | set -e diff --git a/build/azure-pipelines/product-publish.ps1 b/build/azure-pipelines/product-publish.ps1 new file mode 100644 index 000000000000..339002ab0c17 --- /dev/null +++ b/build/azure-pipelines/product-publish.ps1 @@ -0,0 +1,114 @@ +. build/azure-pipelines/win32/exec.ps1 +$ErrorActionPreference = 'Stop' +$ProgressPreference = 'SilentlyContinue' +$ARTIFACT_PROCESSED_WILDCARD_PATH = "$env:PIPELINE_WORKSPACE/artifacts_processed_*/artifacts_processed_*" +$ARTIFACT_PROCESSED_FILE_PATH = "$env:PIPELINE_WORKSPACE/artifacts_processed_$env:SYSTEM_STAGEATTEMPT/artifacts_processed_$env:SYSTEM_STAGEATTEMPT.txt" + +function Get-PipelineArtifact { + param($Name = '*') + try { + $res = Invoke-RestMethod "$($env:BUILDS_API_URL)artifacts?api-version=6.0" -Headers @{ + Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" + } -MaximumRetryCount 5 -RetryIntervalSec 1 + + if (!$res) { + return + } + + $res.value | Where-Object { $_.name -Like $Name } + } catch { + Write-Warning $_ + } +} + +# This set will keep track of which artifacts have already been processed +$set = [System.Collections.Generic.HashSet[string]]::new() + +if (Test-Path $ARTIFACT_PROCESSED_WILDCARD_PATH) { + # Grab the latest artifact_processed text file and load all assets already processed from that. + # This means that the latest artifact_processed_*.txt file has all of the contents of the previous ones. + # Note: The kusto-like syntax only works in PS7+ and only in scripts, not at the REPL. + Get-ChildItem $ARTIFACT_PROCESSED_WILDCARD_PATH + | Sort-Object + | Select-Object -Last 1 + | Get-Content + | ForEach-Object { + $set.Add($_) | Out-Null + Write-Host "Already processed artifact: $_" + } +} + +# Create the artifact file that will be used for this run +New-Item -Path $ARTIFACT_PROCESSED_FILE_PATH -Force | Out-Null + +# Determine which stages we need to watch +$stages = @( + if ($env:VSCODE_BUILD_STAGE_WINDOWS -eq 'True') { 'Windows' } + if ($env:VSCODE_BUILD_STAGE_LINUX -eq 'True') { 'Linux' } + if ($env:VSCODE_BUILD_STAGE_MACOS -eq 'True') { 'macOS' } +) + +do { + Start-Sleep -Seconds 10 + + $artifacts = Get-PipelineArtifact -Name 'vscode_*' + if (!$artifacts) { + continue + } + + $artifacts | ForEach-Object { + $artifactName = $_.name + if($set.Add($artifactName)) { + Write-Host "Processing artifact: '$artifactName. Downloading from: $($_.resource.downloadUrl)" + + try { + Invoke-RestMethod $_.resource.downloadUrl -OutFile "$env:AGENT_TEMPDIRECTORY/$artifactName.zip" -Headers @{ + Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" + } -MaximumRetryCount 5 -RetryIntervalSec 1 | Out-Null + + Expand-Archive -Path "$env:AGENT_TEMPDIRECTORY/$artifactName.zip" -DestinationPath $env:AGENT_TEMPDIRECTORY | Out-Null + } catch { + Write-Warning $_ + $set.Remove($artifactName) | Out-Null + continue + } + + $null,$product,$os,$arch,$type = $artifactName -split '_' + $asset = Get-ChildItem -rec "$env:AGENT_TEMPDIRECTORY/$artifactName" + Write-Host "Processing artifact with the following values:" + # turning in into an object just to log nicely + @{ + product = $product + os = $os + arch = $arch + type = $type + asset = $asset.Name + } | Format-Table + + exec { node build/azure-pipelines/common/createAsset.js $product $os $arch $type $asset.Name $asset.FullName } + $artifactName >> $ARTIFACT_PROCESSED_FILE_PATH + } + } + + # Get the timeline and see if it says the other stage completed + try { + $timeline = Invoke-RestMethod "$($env:BUILDS_API_URL)timeline?api-version=6.0" -Headers @{ + Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" + } -MaximumRetryCount 5 -RetryIntervalSec 1 + } catch { + Write-Warning $_ + continue + } + + foreach ($stage in $stages) { + $otherStageFinished = $timeline.records | Where-Object { $_.name -eq $stage -and $_.type -eq 'stage' -and $_.state -eq 'completed' } + if (!$otherStageFinished) { + break + } + } + + $artifacts = Get-PipelineArtifact -Name 'vscode_*' + $artifactsStillToProcess = $artifacts.Count -ne $set.Count +} while (!$otherStageFinished -or $artifactsStillToProcess) + +Write-Host "Processed $($set.Count) artifacts." diff --git a/build/azure-pipelines/product-publish.yml b/build/azure-pipelines/product-publish.yml new file mode 100644 index 000000000000..de8cb216b8a1 --- /dev/null +++ b/build/azure-pipelines/product-publish.yml @@ -0,0 +1,89 @@ +steps: + - task: NodeTool@0 + inputs: + versionSpec: "12.x" + + - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.x" + + - task: AzureKeyVault@1 + displayName: "Azure Key Vault: Get Secrets" + inputs: + azureSubscription: "vscode-builds-subscription" + KeyVaultName: vscode + + - pwsh: | + . build/azure-pipelines/win32/exec.ps1 + cd build + exec { yarn } + displayName: Install dependencies + + - download: current + patterns: '**/artifacts_processed_*.txt' + displayName: Download all artifacts_processed text files + + - pwsh: | + . build/azure-pipelines/win32/exec.ps1 + + if (Test-Path "$(Pipeline.Workspace)/artifacts_processed_*/artifacts_processed_*.txt") { + Write-Host "Artifacts already processed so a build must have already been created." + return + } + + $env:AZURE_DOCUMENTDB_MASTERKEY = "$(builds-docdb-key-readwrite)" + $VERSION = node -p "require('./package.json').version" + Write-Host "Creating build with version: $VERSION" + exec { node build/azure-pipelines/common/createBuild.js $VERSION } + displayName: Create build if it hasn't been created before + + - pwsh: | + $env:VSCODE_MIXIN_PASSWORD = "$(github-distro-mixin-password)" + $env:AZURE_DOCUMENTDB_MASTERKEY = "$(builds-docdb-key-readwrite)" + $env:AZURE_STORAGE_ACCESS_KEY = "$(ticino-storage-key)" + $env:AZURE_STORAGE_ACCESS_KEY_2 = "$(vscode-storage-key)" + $env:MOONCAKE_STORAGE_ACCESS_KEY = "$(vscode-mooncake-storage-key)" + build/azure-pipelines/product-publish.ps1 + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) + displayName: Process artifacts + + - publish: $(Pipeline.Workspace)/artifacts_processed_$(System.StageAttempt)/artifacts_processed_$(System.StageAttempt).txt + artifact: artifacts_processed_$(System.StageAttempt) + displayName: Publish what artifacts were published for this stage attempt + + - pwsh: | + $ErrorActionPreference = 'Stop' + + # Determine which stages we need to watch + $stages = @( + if ($env:VSCODE_BUILD_STAGE_WINDOWS -eq 'True') { 'Windows' } + if ($env:VSCODE_BUILD_STAGE_LINUX -eq 'True') { 'Linux' } + if ($env:VSCODE_BUILD_STAGE_MACOS -eq 'True') { 'macOS' } + ) + Write-Host "Stages to check: $stages" + + # Get the timeline and see if it says the other stage completed + $timeline = Invoke-RestMethod "$($env:BUILDS_API_URL)timeline?api-version=6.0" -Headers @{ + Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN" + } -MaximumRetryCount 5 -RetryIntervalSec 1 + + $failedStages = @() + foreach ($stage in $stages) { + $didStageFail = $timeline.records | Where-Object { + $_.name -eq $stage -and $_.type -eq 'stage' -and $_.result -ne 'succeeded' -and $_.result -ne 'succeededWithIssues' + } + + if($didStageFail) { + $failedStages += $stage + } else { + Write-Host "'$stage' did not fail." + } + } + + if ($failedStages.Length) { + throw "Failed stages: $($failedStages -join ', '). This stage will now fail so that it is easier to retry failed jobs." + } + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) + displayName: Determine if stage should succeed diff --git a/lib/vscode/build/azure-pipelines/release.yml b/build/azure-pipelines/product-release.yml similarity index 100% rename from lib/vscode/build/azure-pipelines/release.yml rename to build/azure-pipelines/product-release.yml diff --git a/lib/vscode/build/azure-pipelines/publish-types/check-version.js b/build/azure-pipelines/publish-types/check-version.js similarity index 100% rename from lib/vscode/build/azure-pipelines/publish-types/check-version.js rename to build/azure-pipelines/publish-types/check-version.js diff --git a/lib/vscode/build/azure-pipelines/publish-types/check-version.ts b/build/azure-pipelines/publish-types/check-version.ts similarity index 100% rename from lib/vscode/build/azure-pipelines/publish-types/check-version.ts rename to build/azure-pipelines/publish-types/check-version.ts diff --git a/lib/vscode/build/azure-pipelines/publish-types/publish-types.yml b/build/azure-pipelines/publish-types/publish-types.yml similarity index 100% rename from lib/vscode/build/azure-pipelines/publish-types/publish-types.yml rename to build/azure-pipelines/publish-types/publish-types.yml diff --git a/lib/vscode/build/azure-pipelines/publish-types/update-types.js b/build/azure-pipelines/publish-types/update-types.js similarity index 100% rename from lib/vscode/build/azure-pipelines/publish-types/update-types.js rename to build/azure-pipelines/publish-types/update-types.js diff --git a/lib/vscode/build/azure-pipelines/publish-types/update-types.ts b/build/azure-pipelines/publish-types/update-types.ts similarity index 100% rename from lib/vscode/build/azure-pipelines/publish-types/update-types.ts rename to build/azure-pipelines/publish-types/update-types.ts diff --git a/lib/vscode/build/azure-pipelines/upload-cdn.js b/build/azure-pipelines/upload-cdn.js similarity index 100% rename from lib/vscode/build/azure-pipelines/upload-cdn.js rename to build/azure-pipelines/upload-cdn.js diff --git a/lib/vscode/build/azure-pipelines/upload-cdn.ts b/build/azure-pipelines/upload-cdn.ts similarity index 100% rename from lib/vscode/build/azure-pipelines/upload-cdn.ts rename to build/azure-pipelines/upload-cdn.ts diff --git a/lib/vscode/build/azure-pipelines/upload-sourcemaps.js b/build/azure-pipelines/upload-sourcemaps.js similarity index 100% rename from lib/vscode/build/azure-pipelines/upload-sourcemaps.js rename to build/azure-pipelines/upload-sourcemaps.js diff --git a/lib/vscode/build/azure-pipelines/upload-sourcemaps.ts b/build/azure-pipelines/upload-sourcemaps.ts similarity index 100% rename from lib/vscode/build/azure-pipelines/upload-sourcemaps.ts rename to build/azure-pipelines/upload-sourcemaps.ts diff --git a/lib/vscode/build/azure-pipelines/web/product-build-web.yml b/build/azure-pipelines/web/product-build-web.yml similarity index 90% rename from lib/vscode/build/azure-pipelines/web/product-build-web.yml rename to build/azure-pipelines/web/product-build-web.yml index 772fe1c05abd..45dedea1b4c6 100644 --- a/lib/vscode/build/azure-pipelines/web/product-build-web.yml +++ b/build/azure-pipelines/web/product-build-web.yml @@ -119,13 +119,19 @@ steps: - script: | set -e - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - ./build/azure-pipelines/web/publish.sh - displayName: Publish + REPO="$(pwd)" + ROOT="$REPO/.." + + WEB_BUILD_NAME="vscode-web" + WEB_TARBALL_FILENAME="vscode-web.tar.gz" + WEB_TARBALL_PATH="$ROOT/$WEB_TARBALL_FILENAME" + + rm -rf $ROOT/vscode-web.tar.* + + cd $ROOT && tar --owner=0 --group=0 -czf $WEB_TARBALL_PATH $WEB_BUILD_NAME + displayName: Prepare for publish - publish: $(Agent.BuildDirectory)/vscode-web.tar.gz - artifact: vscode-web-standalone + artifact: vscode_web_linux_standalone_archive-unsigned displayName: Publish web archive condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) diff --git a/lib/vscode/build/azure-pipelines/win32/ESRPClient/NuGet.config b/build/azure-pipelines/win32/ESRPClient/NuGet.config similarity index 100% rename from lib/vscode/build/azure-pipelines/win32/ESRPClient/NuGet.config rename to build/azure-pipelines/win32/ESRPClient/NuGet.config diff --git a/lib/vscode/build/azure-pipelines/win32/ESRPClient/packages.config b/build/azure-pipelines/win32/ESRPClient/packages.config similarity index 100% rename from lib/vscode/build/azure-pipelines/win32/ESRPClient/packages.config rename to build/azure-pipelines/win32/ESRPClient/packages.config diff --git a/lib/vscode/build/azure-pipelines/win32/exec.ps1 b/build/azure-pipelines/win32/exec.ps1 similarity index 100% rename from lib/vscode/build/azure-pipelines/win32/exec.ps1 rename to build/azure-pipelines/win32/exec.ps1 diff --git a/lib/vscode/build/azure-pipelines/win32/import-esrp-auth-cert.ps1 b/build/azure-pipelines/win32/import-esrp-auth-cert.ps1 similarity index 100% rename from lib/vscode/build/azure-pipelines/win32/import-esrp-auth-cert.ps1 rename to build/azure-pipelines/win32/import-esrp-auth-cert.ps1 diff --git a/lib/vscode/build/azure-pipelines/win32/publish.ps1 b/build/azure-pipelines/win32/prepare-publish.ps1 similarity index 51% rename from lib/vscode/build/azure-pipelines/win32/publish.ps1 rename to build/azure-pipelines/win32/prepare-publish.ps1 index a225f9d5fdf9..f80e1ca0ce9a 100644 --- a/lib/vscode/build/azure-pipelines/win32/publish.ps1 +++ b/build/azure-pipelines/win32/prepare-publish.ps1 @@ -13,24 +13,31 @@ $Zip = "$Repo\.build\win32-$Arch\archive\VSCode-win32-$Arch.zip" $LegacyServer = "$Root\vscode-reh-win32-$Arch" $Server = "$Root\vscode-server-win32-$Arch" $ServerZip = "$Repo\.build\vscode-server-win32-$Arch.zip" +$LegacyWeb = "$Root\vscode-reh-web-win32-$Arch" +$Web = "$Root\vscode-server-win32-$Arch-web" +$WebZip = "$Repo\.build\vscode-server-win32-$Arch-web.zip" $Build = "$Root\VSCode-win32-$Arch" # Create server archive if ("$Arch" -ne "arm64") { exec { xcopy $LegacyServer $Server /H /E /I } exec { .\node_modules\7zip\7zip-lite\7z.exe a -tzip $ServerZip $Server -r } + exec { xcopy $LegacyWeb $Web /H /E /I } + exec { .\node_modules\7zip\7zip-lite\7z.exe a -tzip $WebZip $Web -r } } # get version $PackageJson = Get-Content -Raw -Path "$Build\resources\app\package.json" | ConvertFrom-Json $Version = $PackageJson.version -$AssetPlatform = if ("$Arch" -eq "ia32") { "win32" } else { "win32-$Arch" } - -exec { node build/azure-pipelines/common/createAsset.js "$AssetPlatform-archive" archive "VSCode-win32-$Arch-$Version.zip" $Zip } -exec { node build/azure-pipelines/common/createAsset.js "$AssetPlatform" setup "VSCodeSetup-$Arch-$Version.exe" $SystemExe } -exec { node build/azure-pipelines/common/createAsset.js "$AssetPlatform-user" setup "VSCodeUserSetup-$Arch-$Version.exe" $UserExe } - -if ("$Arch" -ne "arm64") { - exec { node build/azure-pipelines/common/createAsset.js "server-$AssetPlatform" archive "vscode-server-win32-$Arch.zip" $ServerZip } -} +$ARCHIVE_NAME = "VSCode-win32-$Arch-$Version.zip" +$SYSTEM_SETUP_NAME = "VSCodeSetup-$Arch-$Version.exe" +$USER_SETUP_NAME = "VSCodeUserSetup-$Arch-$Version.exe" + +# Set variables for upload +Move-Item $Zip "$Repo\.build\win32-$Arch\archive\$ARCHIVE_NAME" +Write-Host "##vso[task.setvariable variable=ARCHIVE_NAME]$ARCHIVE_NAME" +Move-Item $SystemExe "$Repo\.build\win32-$Arch\system-setup\$SYSTEM_SETUP_NAME" +Write-Host "##vso[task.setvariable variable=SYSTEM_SETUP_NAME]$SYSTEM_SETUP_NAME" +Move-Item $UserExe "$Repo\.build\win32-$Arch\user-setup\$USER_SETUP_NAME" +Write-Host "##vso[task.setvariable variable=USER_SETUP_NAME]$USER_SETUP_NAME" diff --git a/lib/vscode/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml similarity index 96% rename from lib/vscode/build/azure-pipelines/win32/product-build-win32.yml rename to build/azure-pipelines/win32/product-build-win32.yml index 2dcaf8b2e010..1f8514ae7e3e 100644 --- a/lib/vscode/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -295,31 +295,31 @@ steps: $env:AZURE_STORAGE_ACCESS_KEY_2 = "$(vscode-storage-key)" $env:AZURE_DOCUMENTDB_MASTERKEY = "$(builds-docdb-key-readwrite)" $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" - .\build\azure-pipelines\win32\publish.ps1 + .\build\azure-pipelines\win32\prepare-publish.ps1 displayName: Publish condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) - - publish: $(System.DefaultWorkingDirectory)\.build\win32-$(VSCODE_ARCH)\archive\VSCode-win32-$(VSCODE_ARCH).zip - artifact: vscode-win32-$(VSCODE_ARCH) + - publish: $(System.DefaultWorkingDirectory)\.build\win32-$(VSCODE_ARCH)\archive\$(ARCHIVE_NAME) + artifact: vscode_client_win32_$(VSCODE_ARCH)_archive displayName: Publish archive condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) - - publish: $(System.DefaultWorkingDirectory)\.build\win32-$(VSCODE_ARCH)\system-setup\VSCodeSetup.exe - artifact: vscode-win32-$(VSCODE_ARCH)-setup + - publish: $(System.DefaultWorkingDirectory)\.build\win32-$(VSCODE_ARCH)\system-setup\$(SYSTEM_SETUP_NAME) + artifact: vscode_client_win32_$(VSCODE_ARCH)_setup displayName: Publish system setup condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) - - publish: $(System.DefaultWorkingDirectory)\.build\win32-$(VSCODE_ARCH)\user-setup\VSCodeSetup.exe - artifact: vscode-win32-$(VSCODE_ARCH)-user-setup + - publish: $(System.DefaultWorkingDirectory)\.build\win32-$(VSCODE_ARCH)\user-setup\$(USER_SETUP_NAME) + artifact: vscode_client_win32_$(VSCODE_ARCH)_user-setup displayName: Publish user setup condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false')) - publish: $(System.DefaultWorkingDirectory)\.build\vscode-server-win32-$(VSCODE_ARCH).zip - artifact: vscode-server-win32-$(VSCODE_ARCH) + artifact: vscode_server_win32_$(VSCODE_ARCH)_archive displayName: Publish server archive condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) - publish: $(System.DefaultWorkingDirectory)\.build\vscode-server-win32-$(VSCODE_ARCH)-web.zip - artifact: vscode-server-win32-$(VSCODE_ARCH)-web + artifact: vscode_web_win32_$(VSCODE_ARCH)_archive displayName: Publish web server archive condition: and(succeeded(), ne(variables['VSCODE_PUBLISH'], 'false'), ne(variables['VSCODE_ARCH'], 'arm64')) diff --git a/lib/vscode/build/azure-pipelines/win32/retry.ps1 b/build/azure-pipelines/win32/retry.ps1 similarity index 100% rename from lib/vscode/build/azure-pipelines/win32/retry.ps1 rename to build/azure-pipelines/win32/retry.ps1 diff --git a/lib/vscode/build/azure-pipelines/win32/sign.ps1 b/build/azure-pipelines/win32/sign.ps1 similarity index 100% rename from lib/vscode/build/azure-pipelines/win32/sign.ps1 rename to build/azure-pipelines/win32/sign.ps1 diff --git a/lib/vscode/build/builtin/.eslintrc b/build/builtin/.eslintrc similarity index 100% rename from lib/vscode/build/builtin/.eslintrc rename to build/builtin/.eslintrc diff --git a/lib/vscode/build/builtin/browser-main.js b/build/builtin/browser-main.js similarity index 100% rename from lib/vscode/build/builtin/browser-main.js rename to build/builtin/browser-main.js diff --git a/lib/vscode/build/builtin/index.html b/build/builtin/index.html similarity index 100% rename from lib/vscode/build/builtin/index.html rename to build/builtin/index.html diff --git a/lib/vscode/build/builtin/main.js b/build/builtin/main.js similarity index 100% rename from lib/vscode/build/builtin/main.js rename to build/builtin/main.js diff --git a/lib/vscode/build/builtin/package.json b/build/builtin/package.json similarity index 100% rename from lib/vscode/build/builtin/package.json rename to build/builtin/package.json diff --git a/lib/vscode/build/darwin/create-universal-app.js b/build/darwin/create-universal-app.js similarity index 96% rename from lib/vscode/build/darwin/create-universal-app.js rename to build/darwin/create-universal-app.js index d455a5cef703..d91064d41a60 100644 --- a/lib/vscode/build/darwin/create-universal-app.js +++ b/build/darwin/create-universal-app.js @@ -33,7 +33,7 @@ async function main() { 'Credits.rtf', 'CodeResources', 'fsevents.node', - 'Info.plist', // TODO@deepak1556: regressed with 11.4.2 internal builds + 'Info.plist', '.npmrc' ], outAppPath, diff --git a/lib/vscode/build/darwin/create-universal-app.ts b/build/darwin/create-universal-app.ts similarity index 100% rename from lib/vscode/build/darwin/create-universal-app.ts rename to build/darwin/create-universal-app.ts diff --git a/lib/vscode/build/darwin/sign.js b/build/darwin/sign.js similarity index 100% rename from lib/vscode/build/darwin/sign.js rename to build/darwin/sign.js diff --git a/lib/vscode/build/darwin/sign.ts b/build/darwin/sign.ts similarity index 100% rename from lib/vscode/build/darwin/sign.ts rename to build/darwin/sign.ts diff --git a/lib/vscode/build/eslint.js b/build/eslint.js similarity index 100% rename from lib/vscode/build/eslint.js rename to build/eslint.js diff --git a/lib/vscode/build/filters.js b/build/filters.js similarity index 100% rename from lib/vscode/build/filters.js rename to build/filters.js diff --git a/lib/vscode/build/gulpfile.compile.js b/build/gulpfile.compile.js similarity index 100% rename from lib/vscode/build/gulpfile.compile.js rename to build/gulpfile.compile.js diff --git a/lib/vscode/build/gulpfile.editor.js b/build/gulpfile.editor.js similarity index 100% rename from lib/vscode/build/gulpfile.editor.js rename to build/gulpfile.editor.js diff --git a/lib/vscode/build/gulpfile.extensions.js b/build/gulpfile.extensions.js similarity index 66% rename from lib/vscode/build/gulpfile.extensions.js rename to build/gulpfile.extensions.js index 9312f6c930a2..cbb7c486b13d 100644 --- a/lib/vscode/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -8,7 +8,6 @@ require('events').EventEmitter.defaultMaxListeners = 100; const gulp = require('gulp'); const path = require('path'); -const child_process = require('child_process'); const nodeUtil = require('util'); const es = require('event-stream'); const filter = require('gulp-filter'); @@ -20,8 +19,6 @@ const glob = require('glob'); const root = path.dirname(__dirname); const commit = util.getVersion(root); const plumber = require('gulp-plumber'); -const fancyLog = require('fancy-log'); -const ansiColors = require('ansi-colors'); const ext = require('./lib/extensions'); const extensionsPath = path.join(path.dirname(__dirname), 'extensions'); @@ -201,45 +198,17 @@ gulp.task(compileExtensionsBuildLegacyTask); //#region Extension media -// Additional projects to webpack. These typically build code for webviews -const webpackMediaConfigFiles = [ - 'markdown-language-features/webpack.config.js', - 'simple-browser/webpack.config.js', -]; - -// Additional projects to run esbuild on. These typically build code for webviews -const esbuildMediaScripts = [ - 'markdown-language-features/esbuild.js', - 'notebook-markdown-extensions/esbuild.js', -]; - -const compileExtensionMediaTask = task.define('compile-extension-media', () => buildExtensionMedia(false)); +const compileExtensionMediaTask = task.define('compile-extension-media', () => ext.buildExtensionMedia(false)); gulp.task(compileExtensionMediaTask); exports.compileExtensionMediaTask = compileExtensionMediaTask; -const watchExtensionMedia = task.define('watch-extension-media', () => buildExtensionMedia(true)); +const watchExtensionMedia = task.define('watch-extension-media', () => ext.buildExtensionMedia(true)); gulp.task(watchExtensionMedia); exports.watchExtensionMedia = watchExtensionMedia; -const compileExtensionMediaBuildTask = task.define('compile-extension-media-build', () => buildExtensionMedia(false, '.build/extensions')); +const compileExtensionMediaBuildTask = task.define('compile-extension-media-build', () => ext.buildExtensionMedia(false, '.build/extensions')); gulp.task(compileExtensionMediaBuildTask); -async function buildExtensionMedia(isWatch, outputRoot) { - const webpackConfigLocations = webpackMediaConfigFiles.map(p => { - return { - configPath: path.join(extensionsPath, p), - outputRoot: outputRoot ? path.join(root, outputRoot, path.dirname(p)) : undefined - }; - }); - return Promise.all([ - webpackExtensions('webpacking extension media', isWatch, webpackConfigLocations), - esbuildExtensions('esbuilding extension media', isWatch, esbuildMediaScripts.map(p => ({ - script: path.join(extensionsPath, p), - outputRoot: outputRoot ? path.join(root, outputRoot, path.dirname(p)) : undefined - }))), - ]); -} - //#endregion //#region Azure Pipelines @@ -271,121 +240,5 @@ async function buildWebExtensions(isWatch) { path.join(extensionsPath, '**', 'extension-browser.webpack.config.js'), { ignore: ['**/node_modules'] } ); - return webpackExtensions('packaging web extension', isWatch, webpackConfigLocations.map(configPath => ({ configPath }))); -} - -/** - * @param {string} taskName - * @param {boolean} isWatch - * @param {{ configPath: string, outputRoot?: boolean}} webpackConfigLocations - */ -async function webpackExtensions(taskName, isWatch, webpackConfigLocations) { - const webpack = require('webpack'); - - const webpackConfigs = []; - - for (const { configPath, outputRoot } of webpackConfigLocations) { - const configOrFnOrArray = require(configPath); - function addConfig(configOrFn) { - let config; - if (typeof configOrFn === 'function') { - config = configOrFn({}, {}); - webpackConfigs.push(config); - } else { - config = configOrFn; - } - - if (outputRoot) { - config.output.path = path.join(outputRoot, path.relative(path.dirname(configPath), config.output.path)); - } - - webpackConfigs.push(configOrFn); - } - addConfig(configOrFnOrArray); - } - function reporter(fullStats) { - if (Array.isArray(fullStats.children)) { - for (const stats of fullStats.children) { - const outputPath = stats.outputPath; - if (outputPath) { - const relativePath = path.relative(extensionsPath, outputPath).replace(/\\/g, '/'); - const match = relativePath.match(/[^\/]+(\/server|\/client)?/); - fancyLog(`Finished ${ansiColors.green(taskName)} ${ansiColors.cyan(match[0])} with ${stats.errors.length} errors.`); - } - if (Array.isArray(stats.errors)) { - stats.errors.forEach(error => { - fancyLog.error(error); - }); - } - if (Array.isArray(stats.warnings)) { - stats.warnings.forEach(warning => { - fancyLog.warn(warning); - }); - } - } - } - } - return new Promise((resolve, reject) => { - if (isWatch) { - webpack(webpackConfigs).watch({}, (err, stats) => { - if (err) { - reject(); - } else { - reporter(stats.toJson()); - } - }); - } else { - webpack(webpackConfigs).run((err, stats) => { - if (err) { - fancyLog.error(err); - reject(); - } else { - reporter(stats.toJson()); - resolve(); - } - }); - } - }); -} - -/** - * @param {string} taskName - * @param {boolean} isWatch - * @param {{ script: string, outputRoot?: string }}} scripts - */ -async function esbuildExtensions(taskName, isWatch, scripts) { - function reporter(/** @type {string} */ stdError, /** @type {string} */script) { - const matches = (stdError || '').match(/\> (.+): error: (.+)?/g); - fancyLog(`Finished ${ansiColors.green(taskName)} ${script} with ${matches ? matches.length : 0} errors.`); - for (const match of matches || []) { - fancyLog.error(match); - } - } - - const tasks = scripts.map(({ script, outputRoot }) => { - return new Promise((resolve, reject) => { - const args = [script]; - if (isWatch) { - args.push('--watch'); - } - if (outputRoot) { - args.push('--outputRoot', outputRoot); - } - const proc = child_process.execFile(process.argv[0], args, {}, (error, _stdout, stderr) => { - if (error) { - return reject(error); - } - reporter(stderr, script); - if (stderr) { - return reject(); - } - return resolve(); - }); - - proc.stdout.on('data', (data) => { - fancyLog(`${ansiColors.green(taskName)}: ${data.toString('utf8')}`); - }); - }); - }); - return Promise.all(tasks); + return ext.webpackExtensions('packaging web extension', isWatch, webpackConfigLocations.map(configPath => ({ configPath }))); } diff --git a/lib/vscode/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js similarity index 100% rename from lib/vscode/build/gulpfile.hygiene.js rename to build/gulpfile.hygiene.js diff --git a/lib/vscode/build/gulpfile.js b/build/gulpfile.js similarity index 100% rename from lib/vscode/build/gulpfile.js rename to build/gulpfile.js diff --git a/lib/vscode/build/gulpfile.reh.js b/build/gulpfile.reh.js similarity index 99% rename from lib/vscode/build/gulpfile.reh.js rename to build/gulpfile.reh.js index 6230916a1dc8..387a54cbbfea 100644 --- a/lib/vscode/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js @@ -42,7 +42,6 @@ BUILD_TARGETS.forEach(({ platform, arch }) => { }); function getNodeVersion() { - return process.versions.node; const yarnrc = fs.readFileSync(path.join(REPO_ROOT, 'remote', '.yarnrc'), 'utf8'); const target = /^target "(.*)"$/m.exec(yarnrc)[1]; return target; diff --git a/lib/vscode/build/gulpfile.vscode.js b/build/gulpfile.vscode.js similarity index 97% rename from lib/vscode/build/gulpfile.vscode.js rename to build/gulpfile.vscode.js index 3eeba69d2581..a6e043f122cb 100644 --- a/lib/vscode/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -228,7 +228,14 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op .pipe(jsFilter) .pipe(util.rewriteSourceMappingURL(sourceMappingURLBase)) .pipe(jsFilter.restore) - .pipe(createAsar(path.join(process.cwd(), 'node_modules'), ['**/*.node', '**/vscode-ripgrep/bin/*', '**/node-pty/build/Release/*', '**/*.wasm'], 'node_modules.asar')); + .pipe(createAsar(path.join(process.cwd(), 'node_modules'), [ + '**/*.node', + '**/vscode-ripgrep/bin/*', + '**/node-pty/build/Release/*', + '**/node-pty/lib/worker/conoutSocketWorker.js', + '**/node-pty/lib/shared/conout.js', + '**/*.wasm' + ], 'node_modules.asar')); let all = es.merge( packageJsonStream, @@ -383,8 +390,6 @@ BUILD_TARGETS.forEach(buildTarget => { } }); -// Transifex Localizations - const innoSetupConfig = { 'zh-cn': { codePage: 'CP936', defaultInfo: { name: 'Simplified Chinese', id: '$0804', } }, 'zh-tw': { codePage: 'CP950', defaultInfo: { name: 'Traditional Chinese', id: '$0404' } }, @@ -400,6 +405,8 @@ const innoSetupConfig = { 'tr': { codePage: 'CP1254' } }; +// Transifex Localizations + const apiHostname = process.env.TRANSIFEX_API_URL; const apiName = process.env.TRANSIFEX_API_NAME; const apiToken = process.env.TRANSIFEX_API_TOKEN; @@ -434,7 +441,7 @@ gulp.task(task.define( function () { const pathToMetadata = './out-vscode/nls.metadata.json'; const pathToExtensions = '.build/extensions/*'; - const pathToSetup = 'build/win32/**/{Default.isl,messages.en.isl}'; + const pathToSetup = 'build/win32/i18n/messages.en.isl'; return es.merge( gulp.src(pathToMetadata).pipe(i18n.createXlfFilesForCoreBundle()), @@ -460,8 +467,8 @@ gulp.task('vscode-translations-import', function () { } }); return es.merge([...i18n.defaultLanguages, ...i18n.extraLanguages].map(language => { - let id = language.transifexId || language.id; - return gulp.src(`${options.location}/${id}/setup/*/*.xlf`) + let id = language.id; + return gulp.src(`${options.location}/${id}/vscode-setup/messages.xlf`) .pipe(i18n.prepareIslFiles(language, innoSetupConfig[language.id])) .pipe(vfs.dest(`./build/win32/i18n`)); })); diff --git a/lib/vscode/build/gulpfile.vscode.linux.js b/build/gulpfile.vscode.linux.js similarity index 100% rename from lib/vscode/build/gulpfile.vscode.linux.js rename to build/gulpfile.vscode.linux.js diff --git a/lib/vscode/build/gulpfile.vscode.web.js b/build/gulpfile.vscode.web.js similarity index 100% rename from lib/vscode/build/gulpfile.vscode.web.js rename to build/gulpfile.vscode.web.js diff --git a/lib/vscode/build/gulpfile.vscode.win32.js b/build/gulpfile.vscode.win32.js similarity index 100% rename from lib/vscode/build/gulpfile.vscode.win32.js rename to build/gulpfile.vscode.win32.js diff --git a/lib/vscode/build/hygiene.js b/build/hygiene.js similarity index 100% rename from lib/vscode/build/hygiene.js rename to build/hygiene.js diff --git a/lib/vscode/build/jsconfig.json b/build/jsconfig.json similarity index 100% rename from lib/vscode/build/jsconfig.json rename to build/jsconfig.json diff --git a/lib/vscode/build/lib/asar.js b/build/lib/asar.js similarity index 100% rename from lib/vscode/build/lib/asar.js rename to build/lib/asar.js diff --git a/lib/vscode/build/lib/asar.ts b/build/lib/asar.ts similarity index 100% rename from lib/vscode/build/lib/asar.ts rename to build/lib/asar.ts diff --git a/lib/vscode/build/lib/builtInExtensions.js b/build/lib/builtInExtensions.js similarity index 97% rename from lib/vscode/build/lib/builtInExtensions.js rename to build/lib/builtInExtensions.js index 9b8bcc9e0009..d851a6ee5f9a 100644 --- a/lib/vscode/build/lib/builtInExtensions.js +++ b/build/lib/builtInExtensions.js @@ -18,8 +18,8 @@ const ansiColors = require("ansi-colors"); const mkdirp = require('mkdirp'); const root = path.dirname(path.dirname(__dirname)); const productjson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8')); -const builtInExtensions = productjson.builtInExtensions; -const webBuiltInExtensions = productjson.webBuiltInExtensions; +const builtInExtensions = productjson.builtInExtensions || []; +const webBuiltInExtensions = productjson.webBuiltInExtensions || []; const controlFilePath = path.join(os.homedir(), '.vscode-oss-dev', 'extensions', 'control.json'); const ENABLE_LOGGING = !process.env['VSCODE_BUILD_BUILTIN_EXTENSIONS_SILENCE_PLEASE']; function log(...messages) { diff --git a/lib/vscode/build/lib/builtInExtensions.ts b/build/lib/builtInExtensions.ts similarity index 99% rename from lib/vscode/build/lib/builtInExtensions.ts rename to build/lib/builtInExtensions.ts index af444defab88..2c1cb3abba2c 100644 --- a/lib/vscode/build/lib/builtInExtensions.ts +++ b/build/lib/builtInExtensions.ts @@ -36,8 +36,8 @@ export interface IExtensionDefinition { const root = path.dirname(path.dirname(__dirname)); const productjson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8')); -const builtInExtensions = productjson.builtInExtensions; -const webBuiltInExtensions = productjson.webBuiltInExtensions; +const builtInExtensions = productjson.builtInExtensions || []; +const webBuiltInExtensions = productjson.webBuiltInExtensions || []; const controlFilePath = path.join(os.homedir(), '.vscode-oss-dev', 'extensions', 'control.json'); const ENABLE_LOGGING = !process.env['VSCODE_BUILD_BUILTIN_EXTENSIONS_SILENCE_PLEASE']; diff --git a/lib/vscode/build/lib/builtInExtensionsCG.js b/build/lib/builtInExtensionsCG.js similarity index 96% rename from lib/vscode/build/lib/builtInExtensionsCG.js rename to build/lib/builtInExtensionsCG.js index 10bf38f8c8e2..679663724c8b 100644 --- a/lib/vscode/build/lib/builtInExtensionsCG.js +++ b/build/lib/builtInExtensionsCG.js @@ -12,8 +12,8 @@ const ansiColors = require("ansi-colors"); const root = path.dirname(path.dirname(__dirname)); const rootCG = path.join(root, 'extensionsCG'); const productjson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8')); -const builtInExtensions = productjson.builtInExtensions; -const webBuiltInExtensions = productjson.webBuiltInExtensions; +const builtInExtensions = productjson.builtInExtensions || []; +const webBuiltInExtensions = productjson.webBuiltInExtensions || []; const token = process.env['VSCODE_MIXIN_PASSWORD'] || process.env['GITHUB_TOKEN'] || undefined; const contentBasePath = 'raw.githubusercontent.com'; const contentFileNames = ['package.json', 'package-lock.json', 'yarn.lock']; diff --git a/lib/vscode/build/lib/builtInExtensionsCG.ts b/build/lib/builtInExtensionsCG.ts similarity index 98% rename from lib/vscode/build/lib/builtInExtensionsCG.ts rename to build/lib/builtInExtensionsCG.ts index 45785529b66d..2b758da5c912 100644 --- a/lib/vscode/build/lib/builtInExtensionsCG.ts +++ b/build/lib/builtInExtensionsCG.ts @@ -13,8 +13,8 @@ import { IExtensionDefinition } from './builtInExtensions'; const root = path.dirname(path.dirname(__dirname)); const rootCG = path.join(root, 'extensionsCG'); const productjson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8')); -const builtInExtensions = productjson.builtInExtensions; -const webBuiltInExtensions = productjson.webBuiltInExtensions; +const builtInExtensions = productjson.builtInExtensions || []; +const webBuiltInExtensions = productjson.webBuiltInExtensions || []; const token = process.env['VSCODE_MIXIN_PASSWORD'] || process.env['GITHUB_TOKEN'] || undefined; const contentBasePath = 'raw.githubusercontent.com'; diff --git a/lib/vscode/build/lib/bundle.js b/build/lib/bundle.js similarity index 100% rename from lib/vscode/build/lib/bundle.js rename to build/lib/bundle.js diff --git a/lib/vscode/build/lib/bundle.ts b/build/lib/bundle.ts similarity index 100% rename from lib/vscode/build/lib/bundle.ts rename to build/lib/bundle.ts diff --git a/lib/vscode/build/lib/compilation.js b/build/lib/compilation.js similarity index 100% rename from lib/vscode/build/lib/compilation.js rename to build/lib/compilation.js diff --git a/lib/vscode/build/lib/compilation.ts b/build/lib/compilation.ts similarity index 100% rename from lib/vscode/build/lib/compilation.ts rename to build/lib/compilation.ts diff --git a/lib/vscode/build/lib/dependencies.js b/build/lib/dependencies.js similarity index 100% rename from lib/vscode/build/lib/dependencies.js rename to build/lib/dependencies.js diff --git a/lib/vscode/build/lib/dependencies.ts b/build/lib/dependencies.ts similarity index 100% rename from lib/vscode/build/lib/dependencies.ts rename to build/lib/dependencies.ts diff --git a/lib/vscode/build/lib/electron.js b/build/lib/electron.js similarity index 100% rename from lib/vscode/build/lib/electron.js rename to build/lib/electron.js diff --git a/lib/vscode/build/lib/electron.ts b/build/lib/electron.ts similarity index 100% rename from lib/vscode/build/lib/electron.ts rename to build/lib/electron.ts diff --git a/lib/vscode/build/lib/eslint/code-import-patterns.js b/build/lib/eslint/code-import-patterns.js similarity index 100% rename from lib/vscode/build/lib/eslint/code-import-patterns.js rename to build/lib/eslint/code-import-patterns.js diff --git a/lib/vscode/build/lib/eslint/code-import-patterns.ts b/build/lib/eslint/code-import-patterns.ts similarity index 100% rename from lib/vscode/build/lib/eslint/code-import-patterns.ts rename to build/lib/eslint/code-import-patterns.ts diff --git a/lib/vscode/build/lib/eslint/code-layering.js b/build/lib/eslint/code-layering.js similarity index 100% rename from lib/vscode/build/lib/eslint/code-layering.js rename to build/lib/eslint/code-layering.js diff --git a/lib/vscode/build/lib/eslint/code-layering.ts b/build/lib/eslint/code-layering.ts similarity index 100% rename from lib/vscode/build/lib/eslint/code-layering.ts rename to build/lib/eslint/code-layering.ts diff --git a/lib/vscode/build/lib/eslint/code-no-nls-in-standalone-editor.js b/build/lib/eslint/code-no-nls-in-standalone-editor.js similarity index 100% rename from lib/vscode/build/lib/eslint/code-no-nls-in-standalone-editor.js rename to build/lib/eslint/code-no-nls-in-standalone-editor.js diff --git a/lib/vscode/build/lib/eslint/code-no-nls-in-standalone-editor.ts b/build/lib/eslint/code-no-nls-in-standalone-editor.ts similarity index 100% rename from lib/vscode/build/lib/eslint/code-no-nls-in-standalone-editor.ts rename to build/lib/eslint/code-no-nls-in-standalone-editor.ts diff --git a/lib/vscode/build/lib/eslint/code-no-standalone-editor.js b/build/lib/eslint/code-no-standalone-editor.js similarity index 100% rename from lib/vscode/build/lib/eslint/code-no-standalone-editor.js rename to build/lib/eslint/code-no-standalone-editor.js diff --git a/lib/vscode/build/lib/eslint/code-no-standalone-editor.ts b/build/lib/eslint/code-no-standalone-editor.ts similarity index 100% rename from lib/vscode/build/lib/eslint/code-no-standalone-editor.ts rename to build/lib/eslint/code-no-standalone-editor.ts diff --git a/lib/vscode/build/lib/eslint/code-no-unexternalized-strings.js b/build/lib/eslint/code-no-unexternalized-strings.js similarity index 100% rename from lib/vscode/build/lib/eslint/code-no-unexternalized-strings.js rename to build/lib/eslint/code-no-unexternalized-strings.js diff --git a/lib/vscode/build/lib/eslint/code-no-unexternalized-strings.ts b/build/lib/eslint/code-no-unexternalized-strings.ts similarity index 100% rename from lib/vscode/build/lib/eslint/code-no-unexternalized-strings.ts rename to build/lib/eslint/code-no-unexternalized-strings.ts diff --git a/lib/vscode/build/lib/eslint/code-no-unused-expressions.js b/build/lib/eslint/code-no-unused-expressions.js similarity index 100% rename from lib/vscode/build/lib/eslint/code-no-unused-expressions.js rename to build/lib/eslint/code-no-unused-expressions.js diff --git a/lib/vscode/build/lib/eslint/code-no-unused-expressions.ts b/build/lib/eslint/code-no-unused-expressions.ts similarity index 100% rename from lib/vscode/build/lib/eslint/code-no-unused-expressions.ts rename to build/lib/eslint/code-no-unused-expressions.ts diff --git a/lib/vscode/build/lib/eslint/code-translation-remind.js b/build/lib/eslint/code-translation-remind.js similarity index 100% rename from lib/vscode/build/lib/eslint/code-translation-remind.js rename to build/lib/eslint/code-translation-remind.js diff --git a/lib/vscode/build/lib/eslint/code-translation-remind.ts b/build/lib/eslint/code-translation-remind.ts similarity index 100% rename from lib/vscode/build/lib/eslint/code-translation-remind.ts rename to build/lib/eslint/code-translation-remind.ts diff --git a/lib/vscode/build/lib/eslint/utils.js b/build/lib/eslint/utils.js similarity index 100% rename from lib/vscode/build/lib/eslint/utils.js rename to build/lib/eslint/utils.js diff --git a/lib/vscode/build/lib/eslint/utils.ts b/build/lib/eslint/utils.ts similarity index 100% rename from lib/vscode/build/lib/eslint/utils.ts rename to build/lib/eslint/utils.ts diff --git a/lib/vscode/build/lib/eslint/vscode-dts-cancellation.js b/build/lib/eslint/vscode-dts-cancellation.js similarity index 100% rename from lib/vscode/build/lib/eslint/vscode-dts-cancellation.js rename to build/lib/eslint/vscode-dts-cancellation.js diff --git a/lib/vscode/build/lib/eslint/vscode-dts-cancellation.ts b/build/lib/eslint/vscode-dts-cancellation.ts similarity index 100% rename from lib/vscode/build/lib/eslint/vscode-dts-cancellation.ts rename to build/lib/eslint/vscode-dts-cancellation.ts diff --git a/lib/vscode/build/lib/eslint/vscode-dts-create-func.js b/build/lib/eslint/vscode-dts-create-func.js similarity index 100% rename from lib/vscode/build/lib/eslint/vscode-dts-create-func.js rename to build/lib/eslint/vscode-dts-create-func.js diff --git a/lib/vscode/build/lib/eslint/vscode-dts-create-func.ts b/build/lib/eslint/vscode-dts-create-func.ts similarity index 100% rename from lib/vscode/build/lib/eslint/vscode-dts-create-func.ts rename to build/lib/eslint/vscode-dts-create-func.ts diff --git a/lib/vscode/build/lib/eslint/vscode-dts-event-naming.js b/build/lib/eslint/vscode-dts-event-naming.js similarity index 100% rename from lib/vscode/build/lib/eslint/vscode-dts-event-naming.js rename to build/lib/eslint/vscode-dts-event-naming.js diff --git a/lib/vscode/build/lib/eslint/vscode-dts-event-naming.ts b/build/lib/eslint/vscode-dts-event-naming.ts similarity index 100% rename from lib/vscode/build/lib/eslint/vscode-dts-event-naming.ts rename to build/lib/eslint/vscode-dts-event-naming.ts diff --git a/lib/vscode/build/lib/eslint/vscode-dts-interface-naming.js b/build/lib/eslint/vscode-dts-interface-naming.js similarity index 100% rename from lib/vscode/build/lib/eslint/vscode-dts-interface-naming.js rename to build/lib/eslint/vscode-dts-interface-naming.js diff --git a/lib/vscode/build/lib/eslint/vscode-dts-interface-naming.ts b/build/lib/eslint/vscode-dts-interface-naming.ts similarity index 100% rename from lib/vscode/build/lib/eslint/vscode-dts-interface-naming.ts rename to build/lib/eslint/vscode-dts-interface-naming.ts diff --git a/lib/vscode/build/lib/eslint/vscode-dts-literal-or-types.js b/build/lib/eslint/vscode-dts-literal-or-types.js similarity index 100% rename from lib/vscode/build/lib/eslint/vscode-dts-literal-or-types.js rename to build/lib/eslint/vscode-dts-literal-or-types.js diff --git a/lib/vscode/build/lib/eslint/vscode-dts-literal-or-types.ts b/build/lib/eslint/vscode-dts-literal-or-types.ts similarity index 100% rename from lib/vscode/build/lib/eslint/vscode-dts-literal-or-types.ts rename to build/lib/eslint/vscode-dts-literal-or-types.ts diff --git a/lib/vscode/build/lib/eslint/vscode-dts-provider-naming.js b/build/lib/eslint/vscode-dts-provider-naming.js similarity index 100% rename from lib/vscode/build/lib/eslint/vscode-dts-provider-naming.js rename to build/lib/eslint/vscode-dts-provider-naming.js diff --git a/lib/vscode/build/lib/eslint/vscode-dts-provider-naming.ts b/build/lib/eslint/vscode-dts-provider-naming.ts similarity index 100% rename from lib/vscode/build/lib/eslint/vscode-dts-provider-naming.ts rename to build/lib/eslint/vscode-dts-provider-naming.ts diff --git a/lib/vscode/build/lib/eslint/vscode-dts-region-comments.js b/build/lib/eslint/vscode-dts-region-comments.js similarity index 100% rename from lib/vscode/build/lib/eslint/vscode-dts-region-comments.js rename to build/lib/eslint/vscode-dts-region-comments.js diff --git a/lib/vscode/build/lib/eslint/vscode-dts-region-comments.ts b/build/lib/eslint/vscode-dts-region-comments.ts similarity index 100% rename from lib/vscode/build/lib/eslint/vscode-dts-region-comments.ts rename to build/lib/eslint/vscode-dts-region-comments.ts diff --git a/lib/vscode/build/lib/eslint/vscode-dts-use-thenable.js b/build/lib/eslint/vscode-dts-use-thenable.js similarity index 100% rename from lib/vscode/build/lib/eslint/vscode-dts-use-thenable.js rename to build/lib/eslint/vscode-dts-use-thenable.js diff --git a/lib/vscode/build/lib/eslint/vscode-dts-use-thenable.ts b/build/lib/eslint/vscode-dts-use-thenable.ts similarity index 100% rename from lib/vscode/build/lib/eslint/vscode-dts-use-thenable.ts rename to build/lib/eslint/vscode-dts-use-thenable.ts diff --git a/lib/vscode/build/lib/extensions.js b/build/lib/extensions.js similarity index 73% rename from lib/vscode/build/lib/extensions.js rename to build/lib/extensions.js index b25c3713ea83..3d6a2906178c 100644 --- a/lib/vscode/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -4,9 +4,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); -exports.translatePackageJSON = exports.scanBuiltinExtensions = exports.packageMarketplaceExtensionsStream = exports.packageLocalExtensionsStream = exports.fromMarketplace = void 0; +exports.buildExtensionMedia = exports.webpackExtensions = exports.translatePackageJSON = exports.scanBuiltinExtensions = exports.packageMarketplaceExtensionsStream = exports.packageLocalExtensionsStream = exports.fromMarketplace = void 0; const es = require("event-stream"); const fs = require("fs"); +const cp = require("child_process"); const glob = require("glob"); const gulp = require("gulp"); const path = require("path"); @@ -328,3 +329,132 @@ function translatePackageJSON(packageJSON, packageNLSPath) { return packageJSON; } exports.translatePackageJSON = translatePackageJSON; +const extensionsPath = path.join(root, 'extensions'); +// Additional projects to webpack. These typically build code for webviews +const webpackMediaConfigFiles = [ + 'markdown-language-features/webpack.config.js', + 'simple-browser/webpack.config.js', +]; +// Additional projects to run esbuild on. These typically build code for webviews +const esbuildMediaScripts = [ + 'markdown-language-features/esbuild.js', + 'notebook-markdown-extensions/esbuild.js', +]; +async function webpackExtensions(taskName, isWatch, webpackConfigLocations) { + const webpack = require('webpack'); + const webpackConfigs = []; + for (const { configPath, outputRoot } of webpackConfigLocations) { + const configOrFnOrArray = require(configPath); + function addConfig(configOrFn) { + let config; + if (typeof configOrFn === 'function') { + config = configOrFn({}, {}); + webpackConfigs.push(config); + } + else { + config = configOrFn; + } + if (outputRoot) { + config.output.path = path.join(outputRoot, path.relative(path.dirname(configPath), config.output.path)); + } + webpackConfigs.push(configOrFn); + } + addConfig(configOrFnOrArray); + } + function reporter(fullStats) { + if (Array.isArray(fullStats.children)) { + for (const stats of fullStats.children) { + const outputPath = stats.outputPath; + if (outputPath) { + const relativePath = path.relative(extensionsPath, outputPath).replace(/\\/g, '/'); + const match = relativePath.match(/[^\/]+(\/server|\/client)?/); + fancyLog(`Finished ${ansiColors.green(taskName)} ${ansiColors.cyan(match[0])} with ${stats.errors.length} errors.`); + } + if (Array.isArray(stats.errors)) { + stats.errors.forEach((error) => { + fancyLog.error(error); + }); + } + if (Array.isArray(stats.warnings)) { + stats.warnings.forEach((warning) => { + fancyLog.warn(warning); + }); + } + } + } + } + return new Promise((resolve, reject) => { + if (isWatch) { + webpack(webpackConfigs).watch({}, (err, stats) => { + if (err) { + reject(); + } + else { + reporter(stats.toJson()); + } + }); + } + else { + webpack(webpackConfigs).run((err, stats) => { + if (err) { + fancyLog.error(err); + reject(); + } + else { + reporter(stats.toJson()); + resolve(); + } + }); + } + }); +} +exports.webpackExtensions = webpackExtensions; +async function esbuildExtensions(taskName, isWatch, scripts) { + function reporter(stdError, script) { + const matches = (stdError || '').match(/\> (.+): error: (.+)?/g); + fancyLog(`Finished ${ansiColors.green(taskName)} ${script} with ${matches ? matches.length : 0} errors.`); + for (const match of matches || []) { + fancyLog.error(match); + } + } + const tasks = scripts.map(({ script, outputRoot }) => { + return new Promise((resolve, reject) => { + const args = [script]; + if (isWatch) { + args.push('--watch'); + } + if (outputRoot) { + args.push('--outputRoot', outputRoot); + } + const proc = cp.execFile(process.argv[0], args, {}, (error, _stdout, stderr) => { + if (error) { + return reject(error); + } + reporter(stderr, script); + if (stderr) { + return reject(); + } + return resolve(); + }); + proc.stdout.on('data', (data) => { + fancyLog(`${ansiColors.green(taskName)}: ${data.toString('utf8')}`); + }); + }); + }); + return Promise.all(tasks); +} +async function buildExtensionMedia(isWatch, outputRoot) { + return Promise.all([ + webpackExtensions('webpacking extension media', isWatch, webpackMediaConfigFiles.map(p => { + return { + configPath: path.join(extensionsPath, p), + outputRoot: outputRoot ? path.join(root, outputRoot, path.dirname(p)) : undefined + }; + })), + esbuildExtensions('esbuilding extension media', isWatch, esbuildMediaScripts.map(p => ({ + script: path.join(extensionsPath, p), + outputRoot: outputRoot ? path.join(root, outputRoot, path.dirname(p)) : undefined + }))), + ]); +} +exports.buildExtensionMedia = buildExtensionMedia; diff --git a/lib/vscode/build/lib/extensions.ts b/build/lib/extensions.ts similarity index 76% rename from lib/vscode/build/lib/extensions.ts rename to build/lib/extensions.ts index ec5c7d03b101..6c55569b9731 100644 --- a/lib/vscode/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -5,6 +5,7 @@ import * as es from 'event-stream'; import * as fs from 'fs'; +import * as cp from 'child_process'; import * as glob from 'glob'; import * as gulp from 'gulp'; import * as path from 'path'; @@ -19,6 +20,7 @@ import * as fancyLog from 'fancy-log'; import * as ansiColors from 'ansi-colors'; const buffer = require('gulp-buffer'); import * as jsoncParser from 'jsonc-parser'; +import webpack = require('webpack'); const util = require('./util'); const root = path.dirname(path.dirname(__dirname)); const commit = util.getVersion(root); @@ -65,7 +67,7 @@ function fromLocal(extensionPath: string, forWeb: boolean): Stream { if (isWebPacked) { input = updateExtensionPackageJSON(input, (data: any) => { delete data.scripts; - // https://github.com/cdr/code-server/pull/2041#issuecomment-685910322 + delete data.dependencies; delete data.devDependencies; if (data.main) { data.main = data.main.replace('/out/', /dist/); @@ -403,3 +405,138 @@ export function translatePackageJSON(packageJSON: string, packageNLSPath: string translate(packageJSON); return packageJSON; } + +const extensionsPath = path.join(root, 'extensions'); + +// Additional projects to webpack. These typically build code for webviews +const webpackMediaConfigFiles = [ + 'markdown-language-features/webpack.config.js', + 'simple-browser/webpack.config.js', +]; + +// Additional projects to run esbuild on. These typically build code for webviews +const esbuildMediaScripts = [ + 'markdown-language-features/esbuild.js', + 'notebook-markdown-extensions/esbuild.js', +]; + +export async function webpackExtensions(taskName: string, isWatch: boolean, webpackConfigLocations: { configPath: string, outputRoot?: string }[]) { + const webpack = require('webpack') as typeof import('webpack'); + + const webpackConfigs: webpack.Configuration[] = []; + + for (const { configPath, outputRoot } of webpackConfigLocations) { + const configOrFnOrArray = require(configPath); + function addConfig(configOrFn: webpack.Configuration | Function) { + let config; + if (typeof configOrFn === 'function') { + config = configOrFn({}, {}); + webpackConfigs.push(config); + } else { + config = configOrFn; + } + + if (outputRoot) { + config.output.path = path.join(outputRoot, path.relative(path.dirname(configPath), config.output.path)); + } + + webpackConfigs.push(configOrFn); + } + addConfig(configOrFnOrArray); + } + function reporter(fullStats: any) { + if (Array.isArray(fullStats.children)) { + for (const stats of fullStats.children) { + const outputPath = stats.outputPath; + if (outputPath) { + const relativePath = path.relative(extensionsPath, outputPath).replace(/\\/g, '/'); + const match = relativePath.match(/[^\/]+(\/server|\/client)?/); + fancyLog(`Finished ${ansiColors.green(taskName)} ${ansiColors.cyan(match![0])} with ${stats.errors.length} errors.`); + } + if (Array.isArray(stats.errors)) { + stats.errors.forEach((error: any) => { + fancyLog.error(error); + }); + } + if (Array.isArray(stats.warnings)) { + stats.warnings.forEach((warning: any) => { + fancyLog.warn(warning); + }); + } + } + } + } + return new Promise((resolve, reject) => { + if (isWatch) { + webpack(webpackConfigs).watch({}, (err, stats) => { + if (err) { + reject(); + } else { + reporter(stats.toJson()); + } + }); + } else { + webpack(webpackConfigs).run((err, stats) => { + if (err) { + fancyLog.error(err); + reject(); + } else { + reporter(stats.toJson()); + resolve(); + } + }); + } + }); +} + +async function esbuildExtensions(taskName: string, isWatch: boolean, scripts: { script: string, outputRoot?: string }[]) { + function reporter(stdError: string, script: string) { + const matches = (stdError || '').match(/\> (.+): error: (.+)?/g); + fancyLog(`Finished ${ansiColors.green(taskName)} ${script} with ${matches ? matches.length : 0} errors.`); + for (const match of matches || []) { + fancyLog.error(match); + } + } + + const tasks = scripts.map(({ script, outputRoot }) => { + return new Promise((resolve, reject) => { + const args = [script]; + if (isWatch) { + args.push('--watch'); + } + if (outputRoot) { + args.push('--outputRoot', outputRoot); + } + const proc = cp.execFile(process.argv[0], args, {}, (error, _stdout, stderr) => { + if (error) { + return reject(error); + } + reporter(stderr, script); + if (stderr) { + return reject(); + } + return resolve(); + }); + + proc.stdout!.on('data', (data) => { + fancyLog(`${ansiColors.green(taskName)}: ${data.toString('utf8')}`); + }); + }); + }); + return Promise.all(tasks); +} + +export async function buildExtensionMedia(isWatch: boolean, outputRoot?: string) { + return Promise.all([ + webpackExtensions('webpacking extension media', isWatch, webpackMediaConfigFiles.map(p => { + return { + configPath: path.join(extensionsPath, p), + outputRoot: outputRoot ? path.join(root, outputRoot, path.dirname(p)) : undefined + }; + })), + esbuildExtensions('esbuilding extension media', isWatch, esbuildMediaScripts.map(p => ({ + script: path.join(extensionsPath, p), + outputRoot: outputRoot ? path.join(root, outputRoot, path.dirname(p)) : undefined + }))), + ]); +} diff --git a/lib/vscode/build/lib/git.js b/build/lib/git.js similarity index 100% rename from lib/vscode/build/lib/git.js rename to build/lib/git.js diff --git a/lib/vscode/build/lib/git.ts b/build/lib/git.ts similarity index 100% rename from lib/vscode/build/lib/git.ts rename to build/lib/git.ts diff --git a/build/lib/i18n.js b/build/lib/i18n.js new file mode 100644 index 000000000000..4c7c5c32eb44 --- /dev/null +++ b/build/lib/i18n.js @@ -0,0 +1,1163 @@ +"use strict"; +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.prepareIslFiles = exports.prepareI18nPackFiles = exports.prepareI18nFiles = exports.pullSetupXlfFiles = exports.findObsoleteResources = exports.pushXlfFiles = exports.createXlfFilesForIsl = exports.createXlfFilesForExtensions = exports.createXlfFilesForCoreBundle = exports.getResource = exports.processNlsFiles = exports.Limiter = exports.XLF = exports.Line = exports.externalExtensionsWithTranslations = exports.extraLanguages = exports.defaultLanguages = void 0; +const path = require("path"); +const fs = require("fs"); +const event_stream_1 = require("event-stream"); +const File = require("vinyl"); +const Is = require("is"); +const xml2js = require("xml2js"); +const https = require("https"); +const gulp = require("gulp"); +const fancyLog = require("fancy-log"); +const ansiColors = require("ansi-colors"); +const iconv = require("iconv-lite-umd"); +const NUMBER_OF_CONCURRENT_DOWNLOADS = 4; +function log(message, ...rest) { + fancyLog(ansiColors.green('[i18n]'), message, ...rest); +} +exports.defaultLanguages = [ + { id: 'zh-tw', folderName: 'cht', translationId: 'zh-hant' }, + { id: 'zh-cn', folderName: 'chs', translationId: 'zh-hans' }, + { id: 'ja', folderName: 'jpn' }, + { id: 'ko', folderName: 'kor' }, + { id: 'de', folderName: 'deu' }, + { id: 'fr', folderName: 'fra' }, + { id: 'es', folderName: 'esn' }, + { id: 'ru', folderName: 'rus' }, + { id: 'it', folderName: 'ita' } +]; +// languages requested by the community to non-stable builds +exports.extraLanguages = [ + { id: 'pt-br', folderName: 'ptb' }, + { id: 'hu', folderName: 'hun' }, + { id: 'tr', folderName: 'trk' } +]; +// non built-in extensions also that are transifex and need to be part of the language packs +exports.externalExtensionsWithTranslations = { + 'vscode-chrome-debug': 'msjsdiag.debugger-for-chrome', + 'vscode-node-debug': 'ms-vscode.node-debug', + 'vscode-node-debug2': 'ms-vscode.node-debug2' +}; +var LocalizeInfo; +(function (LocalizeInfo) { + function is(value) { + let candidate = value; + return Is.defined(candidate) && Is.string(candidate.key) && (Is.undef(candidate.comment) || (Is.array(candidate.comment) && candidate.comment.every(element => Is.string(element)))); + } + LocalizeInfo.is = is; +})(LocalizeInfo || (LocalizeInfo = {})); +var BundledFormat; +(function (BundledFormat) { + function is(value) { + if (Is.undef(value)) { + return false; + } + let candidate = value; + let length = Object.keys(value).length; + return length === 3 && Is.defined(candidate.keys) && Is.defined(candidate.messages) && Is.defined(candidate.bundles); + } + BundledFormat.is = is; +})(BundledFormat || (BundledFormat = {})); +var PackageJsonFormat; +(function (PackageJsonFormat) { + function is(value) { + if (Is.undef(value) || !Is.object(value)) { + return false; + } + return Object.keys(value).every(key => { + let element = value[key]; + return Is.string(element) || (Is.object(element) && Is.defined(element.message) && Is.defined(element.comment)); + }); + } + PackageJsonFormat.is = is; +})(PackageJsonFormat || (PackageJsonFormat = {})); +class Line { + constructor(indent = 0) { + this.buffer = []; + if (indent > 0) { + this.buffer.push(new Array(indent + 1).join(' ')); + } + } + append(value) { + this.buffer.push(value); + return this; + } + toString() { + return this.buffer.join(''); + } +} +exports.Line = Line; +class TextModel { + constructor(contents) { + this._lines = contents.split(/\r\n|\r|\n/); + } + get lines() { + return this._lines; + } +} +class XLF { + constructor(project) { + this.project = project; + this.buffer = []; + this.files = Object.create(null); + this.numberOfMessages = 0; + } + toString() { + this.appendHeader(); + const files = Object.keys(this.files).sort(); + for (const file of files) { + this.appendNewLine(``, 2); + const items = this.files[file].sort((a, b) => { + return a.id < b.id ? -1 : a.id > b.id ? 1 : 0; + }); + for (const item of items) { + this.addStringItem(file, item); + } + this.appendNewLine(''); + } + this.appendFooter(); + return this.buffer.join('\r\n'); + } + addFile(original, keys, messages) { + if (keys.length === 0) { + console.log('No keys in ' + original); + return; + } + if (keys.length !== messages.length) { + throw new Error(`Unmatching keys(${keys.length}) and messages(${messages.length}).`); + } + this.numberOfMessages += keys.length; + this.files[original] = []; + let existingKeys = new Set(); + for (let i = 0; i < keys.length; i++) { + let key = keys[i]; + let realKey; + let comment; + if (Is.string(key)) { + realKey = key; + comment = undefined; + } + else if (LocalizeInfo.is(key)) { + realKey = key.key; + if (key.comment && key.comment.length > 0) { + comment = key.comment.map(comment => encodeEntities(comment)).join('\r\n'); + } + } + if (!realKey || existingKeys.has(realKey)) { + continue; + } + existingKeys.add(realKey); + let message = encodeEntities(messages[i]); + this.files[original].push({ id: realKey, message: message, comment: comment }); + } + } + addStringItem(file, item) { + if (!item.id || item.message === undefined || item.message === null) { + throw new Error(`No item ID or value specified: ${JSON.stringify(item)}. File: ${file}`); + } + if (item.message.length === 0) { + log(`Item with id ${item.id} in file ${file} has an empty message.`); + } + this.appendNewLine(``, 4); + this.appendNewLine(`${item.message}`, 6); + if (item.comment) { + this.appendNewLine(`${item.comment}`, 6); + } + this.appendNewLine('', 4); + } + appendHeader() { + this.appendNewLine('', 0); + this.appendNewLine('', 0); + } + appendFooter() { + this.appendNewLine('', 0); + } + appendNewLine(content, indent) { + let line = new Line(indent); + line.append(content); + this.buffer.push(line.toString()); + } +} +exports.XLF = XLF; +XLF.parsePseudo = function (xlfString) { + return new Promise((resolve) => { + let parser = new xml2js.Parser(); + let files = []; + parser.parseString(xlfString, function (_err, result) { + const fileNodes = result['xliff']['file']; + fileNodes.forEach(file => { + const originalFilePath = file.$.original; + const messages = {}; + const transUnits = file.body[0]['trans-unit']; + if (transUnits) { + transUnits.forEach((unit) => { + const key = unit.$.id; + const val = pseudify(unit.source[0]['_'].toString()); + if (key && val) { + messages[key] = decodeEntities(val); + } + }); + files.push({ messages: messages, originalFilePath: originalFilePath, language: 'ps' }); + } + }); + resolve(files); + }); + }); +}; +XLF.parse = function (xlfString) { + return new Promise((resolve, reject) => { + let parser = new xml2js.Parser(); + let files = []; + parser.parseString(xlfString, function (err, result) { + if (err) { + reject(new Error(`XLF parsing error: Failed to parse XLIFF string. ${err}`)); + } + const fileNodes = result['xliff']['file']; + if (!fileNodes) { + reject(new Error(`XLF parsing error: XLIFF file does not contain "xliff" or "file" node(s) required for parsing.`)); + } + fileNodes.forEach((file) => { + const originalFilePath = file.$.original; + if (!originalFilePath) { + reject(new Error(`XLF parsing error: XLIFF file node does not contain original attribute to determine the original location of the resource file.`)); + } + let language = file.$['target-language']; + if (!language) { + reject(new Error(`XLF parsing error: XLIFF file node does not contain target-language attribute to determine translated language.`)); + } + const messages = {}; + const transUnits = file.body[0]['trans-unit']; + if (transUnits) { + transUnits.forEach((unit) => { + const key = unit.$.id; + if (!unit.target) { + return; // No translation available + } + let val = unit.target[0]; + if (typeof val !== 'string') { + // We allow empty source values so support them for translations as well. + val = val._ ? val._ : ''; + } + if (!key) { + reject(new Error(`XLF parsing error: trans-unit ${JSON.stringify(unit, undefined, 0)} defined in file ${originalFilePath} is missing the ID attribute.`)); + return; + } + messages[key] = decodeEntities(val); + }); + files.push({ messages: messages, originalFilePath: originalFilePath, language: language.toLowerCase() }); + } + }); + resolve(files); + }); + }); +}; +class Limiter { + constructor(maxDegreeOfParalellism) { + this.maxDegreeOfParalellism = maxDegreeOfParalellism; + this.outstandingPromises = []; + this.runningPromises = 0; + } + queue(factory) { + return new Promise((c, e) => { + this.outstandingPromises.push({ factory, c, e }); + this.consume(); + }); + } + consume() { + while (this.outstandingPromises.length && this.runningPromises < this.maxDegreeOfParalellism) { + const iLimitedTask = this.outstandingPromises.shift(); + this.runningPromises++; + const promise = iLimitedTask.factory(); + promise.then(iLimitedTask.c).catch(iLimitedTask.e); + promise.then(() => this.consumed()).catch(() => this.consumed()); + } + } + consumed() { + this.runningPromises--; + this.consume(); + } +} +exports.Limiter = Limiter; +function sortLanguages(languages) { + return languages.sort((a, b) => { + return a.id < b.id ? -1 : (a.id > b.id ? 1 : 0); + }); +} +function stripComments(content) { + /** + * First capturing group matches double quoted string + * Second matches single quotes string + * Third matches block comments + * Fourth matches line comments + */ + const regexp = /("(?:[^\\\"]*(?:\\.)?)*")|('(?:[^\\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g; + let result = content.replace(regexp, (match, _m1, _m2, m3, m4) => { + // Only one of m1, m2, m3, m4 matches + if (m3) { + // A block comment. Replace with nothing + return ''; + } + else if (m4) { + // A line comment. If it ends in \r?\n then keep it. + let length = m4.length; + if (length > 2 && m4[length - 1] === '\n') { + return m4[length - 2] === '\r' ? '\r\n' : '\n'; + } + else { + return ''; + } + } + else { + // We match a string + return match; + } + }); + return result; +} +function escapeCharacters(value) { + const result = []; + for (let i = 0; i < value.length; i++) { + const ch = value.charAt(i); + switch (ch) { + case '\'': + result.push('\\\''); + break; + case '"': + result.push('\\"'); + break; + case '\\': + result.push('\\\\'); + break; + case '\n': + result.push('\\n'); + break; + case '\r': + result.push('\\r'); + break; + case '\t': + result.push('\\t'); + break; + case '\b': + result.push('\\b'); + break; + case '\f': + result.push('\\f'); + break; + default: + result.push(ch); + } + } + return result.join(''); +} +function processCoreBundleFormat(fileHeader, languages, json, emitter) { + let keysSection = json.keys; + let messageSection = json.messages; + let bundleSection = json.bundles; + let statistics = Object.create(null); + let defaultMessages = Object.create(null); + let modules = Object.keys(keysSection); + modules.forEach((module) => { + let keys = keysSection[module]; + let messages = messageSection[module]; + if (!messages || keys.length !== messages.length) { + emitter.emit('error', `Message for module ${module} corrupted. Mismatch in number of keys and messages.`); + return; + } + let messageMap = Object.create(null); + defaultMessages[module] = messageMap; + keys.map((key, i) => { + if (typeof key === 'string') { + messageMap[key] = messages[i]; + } + else { + messageMap[key.key] = messages[i]; + } + }); + }); + let languageDirectory = path.join(__dirname, '..', '..', '..', 'vscode-loc', 'i18n'); + if (!fs.existsSync(languageDirectory)) { + log(`No VS Code localization repository found. Looking at ${languageDirectory}`); + log(`To bundle translations please check out the vscode-loc repository as a sibling of the vscode repository.`); + } + let sortedLanguages = sortLanguages(languages); + sortedLanguages.forEach((language) => { + if (process.env['VSCODE_BUILD_VERBOSE']) { + log(`Generating nls bundles for: ${language.id}`); + } + statistics[language.id] = 0; + let localizedModules = Object.create(null); + let languageFolderName = language.translationId || language.id; + let i18nFile = path.join(languageDirectory, `vscode-language-pack-${languageFolderName}`, 'translations', 'main.i18n.json'); + let allMessages; + if (fs.existsSync(i18nFile)) { + let content = stripComments(fs.readFileSync(i18nFile, 'utf8')); + allMessages = JSON.parse(content); + } + modules.forEach((module) => { + let order = keysSection[module]; + let moduleMessage; + if (allMessages) { + moduleMessage = allMessages.contents[module]; + } + if (!moduleMessage) { + if (process.env['VSCODE_BUILD_VERBOSE']) { + log(`No localized messages found for module ${module}. Using default messages.`); + } + moduleMessage = defaultMessages[module]; + statistics[language.id] = statistics[language.id] + Object.keys(moduleMessage).length; + } + let localizedMessages = []; + order.forEach((keyInfo) => { + let key = null; + if (typeof keyInfo === 'string') { + key = keyInfo; + } + else { + key = keyInfo.key; + } + let message = moduleMessage[key]; + if (!message) { + if (process.env['VSCODE_BUILD_VERBOSE']) { + log(`No localized message found for key ${key} in module ${module}. Using default message.`); + } + message = defaultMessages[module][key]; + statistics[language.id] = statistics[language.id] + 1; + } + localizedMessages.push(message); + }); + localizedModules[module] = localizedMessages; + }); + Object.keys(bundleSection).forEach((bundle) => { + let modules = bundleSection[bundle]; + let contents = [ + fileHeader, + `define("${bundle}.nls.${language.id}", {` + ]; + modules.forEach((module, index) => { + contents.push(`\t"${module}": [`); + let messages = localizedModules[module]; + if (!messages) { + emitter.emit('error', `Didn't find messages for module ${module}.`); + return; + } + messages.forEach((message, index) => { + contents.push(`\t\t"${escapeCharacters(message)}${index < messages.length ? '",' : '"'}`); + }); + contents.push(index < modules.length - 1 ? '\t],' : '\t]'); + }); + contents.push('});'); + emitter.queue(new File({ path: bundle + '.nls.' + language.id + '.js', contents: Buffer.from(contents.join('\n'), 'utf-8') })); + }); + }); + Object.keys(statistics).forEach(key => { + let value = statistics[key]; + log(`${key} has ${value} untranslated strings.`); + }); + sortedLanguages.forEach(language => { + let stats = statistics[language.id]; + if (Is.undef(stats)) { + log(`\tNo translations found for language ${language.id}. Using default language instead.`); + } + }); +} +function processNlsFiles(opts) { + return event_stream_1.through(function (file) { + let fileName = path.basename(file.path); + if (fileName === 'nls.metadata.json') { + let json = null; + if (file.isBuffer()) { + json = JSON.parse(file.contents.toString('utf8')); + } + else { + this.emit('error', `Failed to read component file: ${file.relative}`); + return; + } + if (BundledFormat.is(json)) { + processCoreBundleFormat(opts.fileHeader, opts.languages, json, this); + } + } + this.queue(file); + }); +} +exports.processNlsFiles = processNlsFiles; +const editorProject = 'vscode-editor', workbenchProject = 'vscode-workbench', extensionsProject = 'vscode-extensions', setupProject = 'vscode-setup'; +function getResource(sourceFile) { + let resource; + if (/^vs\/platform/.test(sourceFile)) { + return { name: 'vs/platform', project: editorProject }; + } + else if (/^vs\/editor\/contrib/.test(sourceFile)) { + return { name: 'vs/editor/contrib', project: editorProject }; + } + else if (/^vs\/editor/.test(sourceFile)) { + return { name: 'vs/editor', project: editorProject }; + } + else if (/^vs\/base/.test(sourceFile)) { + return { name: 'vs/base', project: editorProject }; + } + else if (/^vs\/code/.test(sourceFile)) { + return { name: 'vs/code', project: workbenchProject }; + } + else if (/^vs\/workbench\/contrib/.test(sourceFile)) { + resource = sourceFile.split('/', 4).join('/'); + return { name: resource, project: workbenchProject }; + } + else if (/^vs\/workbench\/services/.test(sourceFile)) { + resource = sourceFile.split('/', 4).join('/'); + return { name: resource, project: workbenchProject }; + } + else if (/^vs\/workbench/.test(sourceFile)) { + return { name: 'vs/workbench', project: workbenchProject }; + } + throw new Error(`Could not identify the XLF bundle for ${sourceFile}`); +} +exports.getResource = getResource; +function createXlfFilesForCoreBundle() { + return event_stream_1.through(function (file) { + const basename = path.basename(file.path); + if (basename === 'nls.metadata.json') { + if (file.isBuffer()) { + const xlfs = Object.create(null); + const json = JSON.parse(file.contents.toString('utf8')); + for (let coreModule in json.keys) { + const projectResource = getResource(coreModule); + const resource = projectResource.name; + const project = projectResource.project; + const keys = json.keys[coreModule]; + const messages = json.messages[coreModule]; + if (keys.length !== messages.length) { + this.emit('error', `There is a mismatch between keys and messages in ${file.relative} for module ${coreModule}`); + return; + } + else { + let xlf = xlfs[resource]; + if (!xlf) { + xlf = new XLF(project); + xlfs[resource] = xlf; + } + xlf.addFile(`src/${coreModule}`, keys, messages); + } + } + for (let resource in xlfs) { + const xlf = xlfs[resource]; + const filePath = `${xlf.project}/${resource.replace(/\//g, '_')}.xlf`; + const xlfFile = new File({ + path: filePath, + contents: Buffer.from(xlf.toString(), 'utf8') + }); + this.queue(xlfFile); + } + } + else { + this.emit('error', new Error(`File ${file.relative} is not using a buffer content`)); + return; + } + } + else { + this.emit('error', new Error(`File ${file.relative} is not a core meta data file.`)); + return; + } + }); +} +exports.createXlfFilesForCoreBundle = createXlfFilesForCoreBundle; +function createXlfFilesForExtensions() { + let counter = 0; + let folderStreamEnded = false; + let folderStreamEndEmitted = false; + return event_stream_1.through(function (extensionFolder) { + const folderStream = this; + const stat = fs.statSync(extensionFolder.path); + if (!stat.isDirectory()) { + return; + } + let extensionName = path.basename(extensionFolder.path); + if (extensionName === 'node_modules') { + return; + } + counter++; + let _xlf; + function getXlf() { + if (!_xlf) { + _xlf = new XLF(extensionsProject); + } + return _xlf; + } + gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe(event_stream_1.through(function (file) { + if (file.isBuffer()) { + const buffer = file.contents; + const basename = path.basename(file.path); + if (basename === 'package.nls.json') { + const json = JSON.parse(buffer.toString('utf8')); + const keys = Object.keys(json); + const messages = keys.map((key) => { + const value = json[key]; + if (Is.string(value)) { + return value; + } + else if (value) { + return value.message; + } + else { + return `Unknown message for key: ${key}`; + } + }); + getXlf().addFile(`extensions/${extensionName}/package`, keys, messages); + } + else if (basename === 'nls.metadata.json') { + const json = JSON.parse(buffer.toString('utf8')); + const relPath = path.relative(`.build/extensions/${extensionName}`, path.dirname(file.path)); + for (let file in json) { + const fileContent = json[file]; + getXlf().addFile(`extensions/${extensionName}/${relPath}/${file}`, fileContent.keys, fileContent.messages); + } + } + else { + this.emit('error', new Error(`${file.path} is not a valid extension nls file`)); + return; + } + } + }, function () { + if (_xlf) { + let xlfFile = new File({ + path: path.join(extensionsProject, extensionName + '.xlf'), + contents: Buffer.from(_xlf.toString(), 'utf8') + }); + folderStream.queue(xlfFile); + } + this.queue(null); + counter--; + if (counter === 0 && folderStreamEnded && !folderStreamEndEmitted) { + folderStreamEndEmitted = true; + folderStream.queue(null); + } + })); + }, function () { + folderStreamEnded = true; + if (counter === 0) { + folderStreamEndEmitted = true; + this.queue(null); + } + }); +} +exports.createXlfFilesForExtensions = createXlfFilesForExtensions; +function createXlfFilesForIsl() { + return event_stream_1.through(function (file) { + let projectName, resourceFile; + if (path.basename(file.path) === 'messages.en.isl') { + projectName = setupProject; + resourceFile = 'messages.xlf'; + } + else { + throw new Error(`Unknown input file ${file.path}`); + } + let xlf = new XLF(projectName), keys = [], messages = []; + let model = new TextModel(file.contents.toString()); + let inMessageSection = false; + model.lines.forEach(line => { + if (line.length === 0) { + return; + } + let firstChar = line.charAt(0); + switch (firstChar) { + case ';': + // Comment line; + return; + case '[': + inMessageSection = '[Messages]' === line || '[CustomMessages]' === line; + return; + } + if (!inMessageSection) { + return; + } + let sections = line.split('='); + if (sections.length !== 2) { + throw new Error(`Badly formatted message found: ${line}`); + } + else { + let key = sections[0]; + let value = sections[1]; + if (key.length > 0 && value.length > 0) { + keys.push(key); + messages.push(value); + } + } + }); + const originalPath = file.path.substring(file.cwd.length + 1, file.path.split('.')[0].length).replace(/\\/g, '/'); + xlf.addFile(originalPath, keys, messages); + // Emit only upon all ISL files combined into single XLF instance + const newFilePath = path.join(projectName, resourceFile); + const xlfFile = new File({ path: newFilePath, contents: Buffer.from(xlf.toString(), 'utf-8') }); + this.queue(xlfFile); + }); +} +exports.createXlfFilesForIsl = createXlfFilesForIsl; +function pushXlfFiles(apiHostname, username, password) { + let tryGetPromises = []; + let updateCreatePromises = []; + return event_stream_1.through(function (file) { + const project = path.dirname(file.relative); + const fileName = path.basename(file.path); + const slug = fileName.substr(0, fileName.length - '.xlf'.length); + const credentials = `${username}:${password}`; + // Check if resource already exists, if not, then create it. + let promise = tryGetResource(project, slug, apiHostname, credentials); + tryGetPromises.push(promise); + promise.then(exists => { + if (exists) { + promise = updateResource(project, slug, file, apiHostname, credentials); + } + else { + promise = createResource(project, slug, file, apiHostname, credentials); + } + updateCreatePromises.push(promise); + }); + }, function () { + // End the pipe only after all the communication with Transifex API happened + Promise.all(tryGetPromises).then(() => { + Promise.all(updateCreatePromises).then(() => { + this.queue(null); + }).catch((reason) => { throw new Error(reason); }); + }).catch((reason) => { throw new Error(reason); }); + }); +} +exports.pushXlfFiles = pushXlfFiles; +function getAllResources(project, apiHostname, username, password) { + return new Promise((resolve, reject) => { + const credentials = `${username}:${password}`; + const options = { + hostname: apiHostname, + path: `/api/2/project/${project}/resources`, + auth: credentials, + method: 'GET' + }; + const request = https.request(options, (res) => { + let buffer = []; + res.on('data', (chunk) => buffer.push(chunk)); + res.on('end', () => { + if (res.statusCode === 200) { + let json = JSON.parse(Buffer.concat(buffer).toString()); + if (Array.isArray(json)) { + resolve(json.map(o => o.slug)); + return; + } + reject(`Unexpected data format. Response code: ${res.statusCode}.`); + } + else { + reject(`No resources in ${project} returned no data. Response code: ${res.statusCode}.`); + } + }); + }); + request.on('error', (err) => { + reject(`Failed to query resources in ${project} with the following error: ${err}. ${options.path}`); + }); + request.end(); + }); +} +function findObsoleteResources(apiHostname, username, password) { + let resourcesByProject = Object.create(null); + resourcesByProject[extensionsProject] = [].concat(exports.externalExtensionsWithTranslations); // clone + return event_stream_1.through(function (file) { + const project = path.dirname(file.relative); + const fileName = path.basename(file.path); + const slug = fileName.substr(0, fileName.length - '.xlf'.length); + let slugs = resourcesByProject[project]; + if (!slugs) { + resourcesByProject[project] = slugs = []; + } + slugs.push(slug); + this.push(file); + }, function () { + const json = JSON.parse(fs.readFileSync('./build/lib/i18n.resources.json', 'utf8')); + let i18Resources = [...json.editor, ...json.workbench].map((r) => r.project + '/' + r.name.replace(/\//g, '_')); + let extractedResources = []; + for (let project of [workbenchProject, editorProject]) { + for (let resource of resourcesByProject[project]) { + if (resource !== 'setup_messages') { + extractedResources.push(project + '/' + resource); + } + } + } + if (i18Resources.length !== extractedResources.length) { + console.log(`[i18n] Obsolete resources in file 'build/lib/i18n.resources.json': JSON.stringify(${i18Resources.filter(p => extractedResources.indexOf(p) === -1)})`); + console.log(`[i18n] Missing resources in file 'build/lib/i18n.resources.json': JSON.stringify(${extractedResources.filter(p => i18Resources.indexOf(p) === -1)})`); + } + let promises = []; + for (let project in resourcesByProject) { + promises.push(getAllResources(project, apiHostname, username, password).then(resources => { + let expectedResources = resourcesByProject[project]; + let unusedResources = resources.filter(resource => resource && expectedResources.indexOf(resource) === -1); + if (unusedResources.length) { + console.log(`[transifex] Obsolete resources in project '${project}': ${unusedResources.join(', ')}`); + } + })); + } + return Promise.all(promises).then(_ => { + this.push(null); + }).catch((reason) => { throw new Error(reason); }); + }); +} +exports.findObsoleteResources = findObsoleteResources; +function tryGetResource(project, slug, apiHostname, credentials) { + return new Promise((resolve, reject) => { + const options = { + hostname: apiHostname, + path: `/api/2/project/${project}/resource/${slug}/?details`, + auth: credentials, + method: 'GET' + }; + const request = https.request(options, (response) => { + if (response.statusCode === 404) { + resolve(false); + } + else if (response.statusCode === 200) { + resolve(true); + } + else { + reject(`Failed to query resource ${project}/${slug}. Response: ${response.statusCode} ${response.statusMessage}`); + } + }); + request.on('error', (err) => { + reject(`Failed to get ${project}/${slug} on Transifex: ${err}`); + }); + request.end(); + }); +} +function createResource(project, slug, xlfFile, apiHostname, credentials) { + return new Promise((_resolve, reject) => { + const data = JSON.stringify({ + 'content': xlfFile.contents.toString(), + 'name': slug, + 'slug': slug, + 'i18n_type': 'XLIFF' + }); + const options = { + hostname: apiHostname, + path: `/api/2/project/${project}/resources`, + headers: { + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(data) + }, + auth: credentials, + method: 'POST' + }; + let request = https.request(options, (res) => { + if (res.statusCode === 201) { + log(`Resource ${project}/${slug} successfully created on Transifex.`); + } + else { + reject(`Something went wrong in the request creating ${slug} in ${project}. ${res.statusCode}`); + } + }); + request.on('error', (err) => { + reject(`Failed to create ${project}/${slug} on Transifex: ${err}`); + }); + request.write(data); + request.end(); + }); +} +/** + * The following link provides information about how Transifex handles updates of a resource file: + * https://dev.befoolish.co/tx-docs/public/projects/updating-content#what-happens-when-you-update-files + */ +function updateResource(project, slug, xlfFile, apiHostname, credentials) { + return new Promise((resolve, reject) => { + const data = JSON.stringify({ content: xlfFile.contents.toString() }); + const options = { + hostname: apiHostname, + path: `/api/2/project/${project}/resource/${slug}/content`, + headers: { + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(data) + }, + auth: credentials, + method: 'PUT' + }; + let request = https.request(options, (res) => { + if (res.statusCode === 200) { + res.setEncoding('utf8'); + let responseBuffer = ''; + res.on('data', function (chunk) { + responseBuffer += chunk; + }); + res.on('end', () => { + const response = JSON.parse(responseBuffer); + log(`Resource ${project}/${slug} successfully updated on Transifex. Strings added: ${response.strings_added}, updated: ${response.strings_added}, deleted: ${response.strings_added}`); + resolve(); + }); + } + else { + reject(`Something went wrong in the request updating ${slug} in ${project}. ${res.statusCode}`); + } + }); + request.on('error', (err) => { + reject(`Failed to update ${project}/${slug} on Transifex: ${err}`); + }); + request.write(data); + request.end(); + }); +} +function pullSetupXlfFiles(apiHostname, username, password, language, includeDefault) { + let setupResources = [{ name: 'setup_messages', project: workbenchProject }]; + if (includeDefault) { + setupResources.push({ name: 'setup_default', project: setupProject }); + } + return pullXlfFiles(apiHostname, username, password, language, setupResources); +} +exports.pullSetupXlfFiles = pullSetupXlfFiles; +function pullXlfFiles(apiHostname, username, password, language, resources) { + const credentials = `${username}:${password}`; + let expectedTranslationsCount = resources.length; + let translationsRetrieved = 0, called = false; + return event_stream_1.readable(function (_count, callback) { + // Mark end of stream when all resources were retrieved + if (translationsRetrieved === expectedTranslationsCount) { + return this.emit('end'); + } + if (!called) { + called = true; + const stream = this; + resources.map(function (resource) { + retrieveResource(language, resource, apiHostname, credentials).then((file) => { + if (file) { + stream.emit('data', file); + } + translationsRetrieved++; + }).catch(error => { throw new Error(error); }); + }); + } + callback(); + }); +} +const limiter = new Limiter(NUMBER_OF_CONCURRENT_DOWNLOADS); +function retrieveResource(language, resource, apiHostname, credentials) { + return limiter.queue(() => new Promise((resolve, reject) => { + const slug = resource.name.replace(/\//g, '_'); + const project = resource.project; + let transifexLanguageId = language.id === 'ps' ? 'en' : language.translationId || language.id; + const options = { + hostname: apiHostname, + path: `/api/2/project/${project}/resource/${slug}/translation/${transifexLanguageId}?file&mode=onlyreviewed`, + auth: credentials, + port: 443, + method: 'GET' + }; + console.log('[transifex] Fetching ' + options.path); + let request = https.request(options, (res) => { + let xlfBuffer = []; + res.on('data', (chunk) => xlfBuffer.push(chunk)); + res.on('end', () => { + if (res.statusCode === 200) { + resolve(new File({ contents: Buffer.concat(xlfBuffer), path: `${project}/${slug}.xlf` })); + } + else if (res.statusCode === 404) { + console.log(`[transifex] ${slug} in ${project} returned no data.`); + resolve(null); + } + else { + reject(`${slug} in ${project} returned no data. Response code: ${res.statusCode}.`); + } + }); + }); + request.on('error', (err) => { + reject(`Failed to query resource ${slug} with the following error: ${err}. ${options.path}`); + }); + request.end(); + })); +} +function prepareI18nFiles() { + let parsePromises = []; + return event_stream_1.through(function (xlf) { + let stream = this; + let parsePromise = XLF.parse(xlf.contents.toString()); + parsePromises.push(parsePromise); + parsePromise.then(resolvedFiles => { + resolvedFiles.forEach(file => { + let translatedFile = createI18nFile(file.originalFilePath, file.messages); + stream.queue(translatedFile); + }); + }); + }, function () { + Promise.all(parsePromises) + .then(() => { this.queue(null); }) + .catch(reason => { throw new Error(reason); }); + }); +} +exports.prepareI18nFiles = prepareI18nFiles; +function createI18nFile(originalFilePath, messages) { + let result = Object.create(null); + result[''] = [ + '--------------------------------------------------------------------------------------------', + 'Copyright (c) Microsoft Corporation. All rights reserved.', + 'Licensed under the MIT License. See License.txt in the project root for license information.', + '--------------------------------------------------------------------------------------------', + 'Do not edit this file. It is machine generated.' + ]; + for (let key of Object.keys(messages)) { + result[key] = messages[key]; + } + let content = JSON.stringify(result, null, '\t'); + if (process.platform === 'win32') { + content = content.replace(/\n/g, '\r\n'); + } + return new File({ + path: path.join(originalFilePath + '.i18n.json'), + contents: Buffer.from(content, 'utf8') + }); +} +const i18nPackVersion = '1.0.0'; +function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths, pseudo = false) { + let parsePromises = []; + let mainPack = { version: i18nPackVersion, contents: {} }; + let extensionsPacks = {}; + let errors = []; + return event_stream_1.through(function (xlf) { + let project = path.basename(path.dirname(path.dirname(xlf.relative))); + let resource = path.basename(xlf.relative, '.xlf'); + let contents = xlf.contents.toString(); + log(`Found ${project}: ${resource}`); + let parsePromise = pseudo ? XLF.parsePseudo(contents) : XLF.parse(contents); + parsePromises.push(parsePromise); + parsePromise.then(resolvedFiles => { + resolvedFiles.forEach(file => { + const path = file.originalFilePath; + const firstSlash = path.indexOf('/'); + if (project === extensionsProject) { + let extPack = extensionsPacks[resource]; + if (!extPack) { + extPack = extensionsPacks[resource] = { version: i18nPackVersion, contents: {} }; + } + const externalId = externalExtensions[resource]; + if (!externalId) { // internal extension: remove 'extensions/extensionId/' segnent + const secondSlash = path.indexOf('/', firstSlash + 1); + extPack.contents[path.substr(secondSlash + 1)] = file.messages; + } + else { + extPack.contents[path] = file.messages; + } + } + else { + mainPack.contents[path.substr(firstSlash + 1)] = file.messages; + } + }); + }).catch(reason => { + errors.push(reason); + }); + }, function () { + Promise.all(parsePromises) + .then(() => { + if (errors.length > 0) { + throw errors; + } + const translatedMainFile = createI18nFile('./main', mainPack); + resultingTranslationPaths.push({ id: 'vscode', resourceName: 'main.i18n.json' }); + this.queue(translatedMainFile); + for (let extension in extensionsPacks) { + const translatedExtFile = createI18nFile(`extensions/${extension}`, extensionsPacks[extension]); + this.queue(translatedExtFile); + const externalExtensionId = externalExtensions[extension]; + if (externalExtensionId) { + resultingTranslationPaths.push({ id: externalExtensionId, resourceName: `extensions/${extension}.i18n.json` }); + } + else { + resultingTranslationPaths.push({ id: `vscode.${extension}`, resourceName: `extensions/${extension}.i18n.json` }); + } + } + this.queue(null); + }) + .catch((reason) => { + this.emit('error', reason); + }); + }); +} +exports.prepareI18nPackFiles = prepareI18nPackFiles; +function prepareIslFiles(language, innoSetupConfig) { + let parsePromises = []; + return event_stream_1.through(function (xlf) { + let stream = this; + let parsePromise = XLF.parse(xlf.contents.toString()); + parsePromises.push(parsePromise); + parsePromise.then(resolvedFiles => { + resolvedFiles.forEach(file => { + let translatedFile = createIslFile(file.originalFilePath, file.messages, language, innoSetupConfig); + stream.queue(translatedFile); + }); + }).catch(reason => { + this.emit('error', reason); + }); + }, function () { + Promise.all(parsePromises) + .then(() => { this.queue(null); }) + .catch(reason => { + this.emit('error', reason); + }); + }); +} +exports.prepareIslFiles = prepareIslFiles; +function createIslFile(originalFilePath, messages, language, innoSetup) { + let content = []; + let originalContent; + if (path.basename(originalFilePath) === 'Default') { + originalContent = new TextModel(fs.readFileSync(originalFilePath + '.isl', 'utf8')); + } + else { + originalContent = new TextModel(fs.readFileSync(originalFilePath + '.en.isl', 'utf8')); + } + originalContent.lines.forEach(line => { + if (line.length > 0) { + let firstChar = line.charAt(0); + if (firstChar === '[' || firstChar === ';') { + content.push(line); + } + else { + let sections = line.split('='); + let key = sections[0]; + let translated = line; + if (key) { + let translatedMessage = messages[key]; + if (translatedMessage) { + translated = `${key}=${translatedMessage}`; + } + } + content.push(translated); + } + } + }); + const basename = path.basename(originalFilePath); + const filePath = `${basename}.${language.id}.isl`; + const encoded = iconv.encode(Buffer.from(content.join('\r\n'), 'utf8').toString(), innoSetup.codePage); + return new File({ + path: filePath, + contents: Buffer.from(encoded), + }); +} +function encodeEntities(value) { + let result = []; + for (let i = 0; i < value.length; i++) { + let ch = value[i]; + switch (ch) { + case '<': + result.push('<'); + break; + case '>': + result.push('>'); + break; + case '&': + result.push('&'); + break; + default: + result.push(ch); + } + } + return result.join(''); +} +function decodeEntities(value) { + return value.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); +} +function pseudify(message) { + return '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D'; +} diff --git a/lib/vscode/build/lib/i18n.resources.json b/build/lib/i18n.resources.json similarity index 100% rename from lib/vscode/build/lib/i18n.resources.json rename to build/lib/i18n.resources.json diff --git a/lib/vscode/build/lib/i18n.ts b/build/lib/i18n.ts similarity index 93% rename from lib/vscode/build/lib/i18n.ts rename to build/lib/i18n.ts index 746c481b262d..5e00e9d6c6e6 100644 --- a/lib/vscode/build/lib/i18n.ts +++ b/build/lib/i18n.ts @@ -10,7 +10,6 @@ import { through, readable, ThroughStream } from 'event-stream'; import * as File from 'vinyl'; import * as Is from 'is'; import * as xml2js from 'xml2js'; -import * as glob from 'glob'; import * as https from 'https'; import * as gulp from 'gulp'; import * as fancyLog from 'fancy-log'; @@ -31,10 +30,6 @@ export interface Language { export interface InnoSetup { codePage: string; //code page for encoding (http://www.jrsoftware.org/ishelp/index.php?topic=langoptionssection) - defaultInfo?: { - name: string; // inno setup language name - id: string; // locale identifier (https://msdn.microsoft.com/en-us/library/dd318693.aspx) - }; } export const defaultLanguages: Language[] = [ @@ -198,14 +193,17 @@ export class XLF { public toString(): string { this.appendHeader(); - for (let file in this.files) { + const files = Object.keys(this.files).sort(); + for (const file of files) { this.appendNewLine(``, 2); - for (let item of this.files[file]) { + const items = this.files[file].sort((a: Item, b: Item) => { + return a.id < b.id ? -1 : a.id > b.id ? 1 : 0; + }); + for (const item of items) { this.addStringItem(file, item); } - this.appendNewLine('', 2); + this.appendNewLine(''); } - this.appendFooter(); return this.buffer.join('\r\n'); } @@ -763,12 +761,11 @@ export function createXlfFilesForIsl(): ThroughStream { return through(function (this: ThroughStream, file: File) { let projectName: string, resourceFile: string; - if (path.basename(file.path) === 'Default.isl') { + if (path.basename(file.path) === 'messages.en.isl') { projectName = setupProject; - resourceFile = 'setup_default.xlf'; + resourceFile = 'messages.xlf'; } else { - projectName = workbenchProject; - resourceFile = 'setup_messages.xlf'; + throw new Error(`Unknown input file ${file.path}`); } let xlf = new XLF(projectName), @@ -1036,35 +1033,6 @@ function updateResource(project: string, slug: string, xlfFile: File, apiHostnam }); } -// cache resources -let _coreAndExtensionResources: Resource[]; - -export function pullCoreAndExtensionsXlfFiles(apiHostname: string, username: string, password: string, language: Language, externalExtensions?: Map): NodeJS.ReadableStream { - if (!_coreAndExtensionResources) { - _coreAndExtensionResources = []; - // editor and workbench - const json = JSON.parse(fs.readFileSync('./build/lib/i18n.resources.json', 'utf8')); - _coreAndExtensionResources.push(...json.editor); - _coreAndExtensionResources.push(...json.workbench); - - // extensions - let extensionsToLocalize = Object.create(null); - glob.sync('.build/extensions/**/*.nls.json').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); - glob.sync('.build/extensions/*/node_modules/vscode-nls').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); - - Object.keys(extensionsToLocalize).forEach(extension => { - _coreAndExtensionResources.push({ name: extension, project: extensionsProject }); - }); - - if (externalExtensions) { - for (let resourceName in externalExtensions) { - _coreAndExtensionResources.push({ name: resourceName, project: extensionsProject }); - } - } - } - return pullXlfFiles(apiHostname, username, password, language, _coreAndExtensionResources); -} - export function pullSetupXlfFiles(apiHostname: string, username: string, password: string, language: Language, includeDefault: boolean): NodeJS.ReadableStream { let setupResources = [{ name: 'setup_messages', project: workbenchProject }]; if (includeDefault) { @@ -1196,20 +1164,16 @@ export interface TranslationPath { resourceName: string; } -export function pullI18nPackFiles(apiHostname: string, username: string, password: string, language: Language, resultingTranslationPaths: TranslationPath[]): NodeJS.ReadableStream { - return pullCoreAndExtensionsXlfFiles(apiHostname, username, password, language, externalExtensionsWithTranslations) - .pipe(prepareI18nPackFiles(externalExtensionsWithTranslations, resultingTranslationPaths, language.id === 'ps')); -} - export function prepareI18nPackFiles(externalExtensions: Map, resultingTranslationPaths: TranslationPath[], pseudo = false): NodeJS.ReadWriteStream { let parsePromises: Promise[] = []; let mainPack: I18nPack = { version: i18nPackVersion, contents: {} }; let extensionsPacks: Map = {}; let errors: any[] = []; return through(function (this: ThroughStream, xlf: File) { - let project = path.basename(path.dirname(xlf.relative)); + let project = path.basename(path.dirname(path.dirname(xlf.relative))); let resource = path.basename(xlf.relative, '.xlf'); let contents = xlf.contents.toString(); + log(`Found ${project}: ${resource}`); let parsePromise = pseudo ? XLF.parsePseudo(contents) : XLF.parse(contents); parsePromises.push(parsePromise); parsePromise.then( @@ -1278,9 +1242,6 @@ export function prepareIslFiles(language: Language, innoSetupConfig: InnoSetup): parsePromise.then( resolvedFiles => { resolvedFiles.forEach(file => { - if (path.basename(file.originalFilePath) === 'Default' && !innoSetupConfig.defaultInfo) { - return; - } let translatedFile = createIslFile(file.originalFilePath, file.messages, language, innoSetupConfig); stream.queue(translatedFile); }); @@ -1315,17 +1276,9 @@ function createIslFile(originalFilePath: string, messages: Map, language let key = sections[0]; let translated = line; if (key) { - if (key === 'LanguageName') { - translated = `${key}=${innoSetup.defaultInfo!.name}`; - } else if (key === 'LanguageID') { - translated = `${key}=${innoSetup.defaultInfo!.id}`; - } else if (key === 'LanguageCodePage') { - translated = `${key}=${innoSetup.codePage.substr(2)}`; - } else { - let translatedMessage = messages[key]; - if (translatedMessage) { - translated = `${key}=${translatedMessage}`; - } + let translatedMessage = messages[key]; + if (translatedMessage) { + translated = `${key}=${translatedMessage}`; } } diff --git a/lib/vscode/build/lib/layersChecker.js b/build/lib/layersChecker.js similarity index 100% rename from lib/vscode/build/lib/layersChecker.js rename to build/lib/layersChecker.js diff --git a/lib/vscode/build/lib/layersChecker.ts b/build/lib/layersChecker.ts similarity index 100% rename from lib/vscode/build/lib/layersChecker.ts rename to build/lib/layersChecker.ts diff --git a/lib/vscode/build/lib/monaco-api.js b/build/lib/monaco-api.js similarity index 100% rename from lib/vscode/build/lib/monaco-api.js rename to build/lib/monaco-api.js diff --git a/lib/vscode/build/lib/monaco-api.ts b/build/lib/monaco-api.ts similarity index 100% rename from lib/vscode/build/lib/monaco-api.ts rename to build/lib/monaco-api.ts diff --git a/lib/vscode/build/lib/nls.js b/build/lib/nls.js similarity index 100% rename from lib/vscode/build/lib/nls.js rename to build/lib/nls.js diff --git a/lib/vscode/build/lib/nls.ts b/build/lib/nls.ts similarity index 100% rename from lib/vscode/build/lib/nls.ts rename to build/lib/nls.ts diff --git a/lib/vscode/build/lib/node.js b/build/lib/node.js similarity index 100% rename from lib/vscode/build/lib/node.js rename to build/lib/node.js diff --git a/lib/vscode/build/lib/node.ts b/build/lib/node.ts similarity index 78% rename from lib/vscode/build/lib/node.ts rename to build/lib/node.ts index 20389c69445b..6ac45ebb1f89 100644 --- a/lib/vscode/build/lib/node.ts +++ b/build/lib/node.ts @@ -4,11 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import * as path from 'path'; +import * as fs from 'fs'; const root = path.dirname(path.dirname(__dirname)); -const version = process.versions.node; -const platform = process.platform; +const yarnrcPath = path.join(root, 'remote', '.yarnrc'); +const yarnrc = fs.readFileSync(yarnrcPath, 'utf8'); +const version = /^target\s+"([^"]+)"$/m.exec(yarnrc)![1]; +const platform = process.platform; const arch = platform === 'darwin' ? 'x64' : process.arch; const node = platform === 'win32' ? 'node.exe' : 'node'; diff --git a/lib/vscode/build/lib/optimize.js b/build/lib/optimize.js similarity index 99% rename from lib/vscode/build/lib/optimize.js rename to build/lib/optimize.js index 1cfca357f7c8..762a1ac2b4f1 100644 --- a/lib/vscode/build/lib/optimize.js +++ b/build/lib/optimize.js @@ -177,7 +177,7 @@ function minifyTask(src, sourceMapBaseUrl) { sourcemap: 'external', outdir: '.', platform: 'node', - target: ['node12.18'], + target: ['node14.16'], write: false }).then(res => { const jsFile = res.outputFiles.find(f => /\.js$/.test(f.path)); diff --git a/lib/vscode/build/lib/optimize.ts b/build/lib/optimize.ts similarity index 99% rename from lib/vscode/build/lib/optimize.ts rename to build/lib/optimize.ts index c3c29e4a7004..b613416cab2f 100644 --- a/lib/vscode/build/lib/optimize.ts +++ b/build/lib/optimize.ts @@ -254,7 +254,7 @@ export function minifyTask(src: string, sourceMapBaseUrl?: string): (cb: any) => sourcemap: 'external', outdir: '.', platform: 'node', - target: ['node12.18'], + target: ['node14.16'], write: false }).then(res => { const jsFile = res.outputFiles.find(f => /\.js$/.test(f.path))!; diff --git a/lib/vscode/build/lib/preLaunch.js b/build/lib/preLaunch.js similarity index 100% rename from lib/vscode/build/lib/preLaunch.js rename to build/lib/preLaunch.js diff --git a/lib/vscode/build/lib/preLaunch.ts b/build/lib/preLaunch.ts similarity index 100% rename from lib/vscode/build/lib/preLaunch.ts rename to build/lib/preLaunch.ts diff --git a/lib/vscode/build/lib/reporter.js b/build/lib/reporter.js similarity index 100% rename from lib/vscode/build/lib/reporter.js rename to build/lib/reporter.js diff --git a/lib/vscode/build/lib/reporter.ts b/build/lib/reporter.ts similarity index 100% rename from lib/vscode/build/lib/reporter.ts rename to build/lib/reporter.ts diff --git a/lib/vscode/build/lib/snapshotLoader.js b/build/lib/snapshotLoader.js similarity index 100% rename from lib/vscode/build/lib/snapshotLoader.js rename to build/lib/snapshotLoader.js diff --git a/lib/vscode/build/lib/snapshotLoader.ts b/build/lib/snapshotLoader.ts similarity index 100% rename from lib/vscode/build/lib/snapshotLoader.ts rename to build/lib/snapshotLoader.ts diff --git a/lib/vscode/build/lib/standalone.js b/build/lib/standalone.js similarity index 100% rename from lib/vscode/build/lib/standalone.js rename to build/lib/standalone.js diff --git a/lib/vscode/build/lib/standalone.ts b/build/lib/standalone.ts similarity index 100% rename from lib/vscode/build/lib/standalone.ts rename to build/lib/standalone.ts diff --git a/lib/vscode/build/lib/stats.js b/build/lib/stats.js similarity index 100% rename from lib/vscode/build/lib/stats.js rename to build/lib/stats.js diff --git a/lib/vscode/build/lib/stats.ts b/build/lib/stats.ts similarity index 100% rename from lib/vscode/build/lib/stats.ts rename to build/lib/stats.ts diff --git a/lib/vscode/build/lib/task.js b/build/lib/task.js similarity index 100% rename from lib/vscode/build/lib/task.js rename to build/lib/task.js diff --git a/lib/vscode/build/lib/task.ts b/build/lib/task.ts similarity index 100% rename from lib/vscode/build/lib/task.ts rename to build/lib/task.ts diff --git a/lib/vscode/build/lib/test/i18n.test.js b/build/lib/test/i18n.test.js similarity index 100% rename from lib/vscode/build/lib/test/i18n.test.js rename to build/lib/test/i18n.test.js diff --git a/lib/vscode/build/lib/test/i18n.test.ts b/build/lib/test/i18n.test.ts similarity index 100% rename from lib/vscode/build/lib/test/i18n.test.ts rename to build/lib/test/i18n.test.ts diff --git a/lib/vscode/build/lib/treeshaking.js b/build/lib/treeshaking.js similarity index 99% rename from lib/vscode/build/lib/treeshaking.js rename to build/lib/treeshaking.js index 3abe020882bc..41cb33809b04 100644 --- a/lib/vscode/build/lib/treeshaking.js +++ b/build/lib/treeshaking.js @@ -241,6 +241,9 @@ function nodeOrChildIsBlack(node) { } return false; } +function isSymbolWithDeclarations(symbol) { + return !!(symbol && symbol.declarations); +} function markNodes(ts, languageService, options) { const program = languageService.getProgram(); if (!program) { @@ -413,7 +416,7 @@ function markNodes(ts, languageService, options) { if (symbolImportNode) { setColor(symbolImportNode, 2 /* Black */); } - if (symbol && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) { + if (isSymbolWithDeclarations(symbol) && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) { for (let i = 0, len = symbol.declarations.length; i < len; i++) { const declaration = symbol.declarations[i]; if (ts.isSourceFile(declaration)) { @@ -686,7 +689,7 @@ function getRealNodeSymbol(ts, checker, node) { // get the aliased symbol instead. This allows for goto def on an import e.g. // import {A, B} from "mod"; // to jump to the implementation directly. - if (symbol && symbol.flags & ts.SymbolFlags.Alias && shouldSkipAlias(node, symbol.declarations[0])) { + if (symbol && symbol.flags & ts.SymbolFlags.Alias && symbol.declarations && shouldSkipAlias(node, symbol.declarations[0])) { const aliased = checker.getAliasedSymbol(symbol); if (aliased.declarations) { // We should mark the import as visited diff --git a/lib/vscode/build/lib/treeshaking.ts b/build/lib/treeshaking.ts similarity index 98% rename from lib/vscode/build/lib/treeshaking.ts rename to build/lib/treeshaking.ts index f941e9791a76..f24b31e26ac9 100644 --- a/lib/vscode/build/lib/treeshaking.ts +++ b/build/lib/treeshaking.ts @@ -323,6 +323,10 @@ function nodeOrChildIsBlack(node: ts.Node): boolean { return false; } +function isSymbolWithDeclarations(symbol: ts.Symbol | undefined | null): symbol is ts.Symbol & { declarations: ts.Declaration[] } { + return !!(symbol && symbol.declarations); +} + function markNodes(ts: typeof import('typescript'), languageService: ts.LanguageService, options: ITreeShakingOptions) { const program = languageService.getProgram(); if (!program) { @@ -530,7 +534,7 @@ function markNodes(ts: typeof import('typescript'), languageService: ts.Language setColor(symbolImportNode, NodeColor.Black); } - if (symbol && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) { + if (isSymbolWithDeclarations(symbol) && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) { for (let i = 0, len = symbol.declarations.length; i < len; i++) { const declaration = symbol.declarations[i]; if (ts.isSourceFile(declaration)) { @@ -595,7 +599,7 @@ function markNodes(ts: typeof import('typescript'), languageService: ts.Language } } -function nodeIsInItsOwnDeclaration(nodeSourceFile: ts.SourceFile, node: ts.Node, symbol: ts.Symbol): boolean { +function nodeIsInItsOwnDeclaration(nodeSourceFile: ts.SourceFile, node: ts.Node, symbol: ts.Symbol & { declarations: ts.Declaration[] }): boolean { for (let i = 0, len = symbol.declarations.length; i < len; i++) { const declaration = symbol.declarations[i]; const declarationSourceFile = declaration.getSourceFile(); @@ -838,7 +842,7 @@ function getRealNodeSymbol(ts: typeof import('typescript'), checker: ts.TypeChec // get the aliased symbol instead. This allows for goto def on an import e.g. // import {A, B} from "mod"; // to jump to the implementation directly. - if (symbol && symbol.flags & ts.SymbolFlags.Alias && shouldSkipAlias(node, symbol.declarations[0])) { + if (symbol && symbol.flags & ts.SymbolFlags.Alias && symbol.declarations && shouldSkipAlias(node, symbol.declarations[0])) { const aliased = checker.getAliasedSymbol(symbol); if (aliased.declarations) { // We should mark the import as visited diff --git a/lib/vscode/build/lib/typings/cgmanifest.json b/build/lib/typings/cgmanifest.json similarity index 100% rename from lib/vscode/build/lib/typings/cgmanifest.json rename to build/lib/typings/cgmanifest.json diff --git a/lib/vscode/build/lib/typings/event-stream.d.ts b/build/lib/typings/event-stream.d.ts similarity index 100% rename from lib/vscode/build/lib/typings/event-stream.d.ts rename to build/lib/typings/event-stream.d.ts diff --git a/lib/vscode/build/lib/typings/github-releases.d.ts b/build/lib/typings/github-releases.d.ts similarity index 100% rename from lib/vscode/build/lib/typings/github-releases.d.ts rename to build/lib/typings/github-releases.d.ts diff --git a/lib/vscode/build/lib/typings/gulp-bom.d.ts b/build/lib/typings/gulp-bom.d.ts similarity index 100% rename from lib/vscode/build/lib/typings/gulp-bom.d.ts rename to build/lib/typings/gulp-bom.d.ts diff --git a/lib/vscode/build/lib/typings/gulp-flatmap.d.ts b/build/lib/typings/gulp-flatmap.d.ts similarity index 100% rename from lib/vscode/build/lib/typings/gulp-flatmap.d.ts rename to build/lib/typings/gulp-flatmap.d.ts diff --git a/lib/vscode/build/lib/typings/gulp-remote-src.d.ts b/build/lib/typings/gulp-remote-src.d.ts similarity index 100% rename from lib/vscode/build/lib/typings/gulp-remote-src.d.ts rename to build/lib/typings/gulp-remote-src.d.ts diff --git a/lib/vscode/build/lib/typings/gulp-tsb.d.ts b/build/lib/typings/gulp-tsb.d.ts similarity index 100% rename from lib/vscode/build/lib/typings/gulp-tsb.d.ts rename to build/lib/typings/gulp-tsb.d.ts diff --git a/lib/vscode/build/lib/typings/is.d.ts b/build/lib/typings/is.d.ts similarity index 100% rename from lib/vscode/build/lib/typings/is.d.ts rename to build/lib/typings/is.d.ts diff --git a/lib/vscode/build/lib/typings/lazy.js.d.ts b/build/lib/typings/lazy.js.d.ts similarity index 100% rename from lib/vscode/build/lib/typings/lazy.js.d.ts rename to build/lib/typings/lazy.js.d.ts diff --git a/lib/vscode/build/lib/typings/vinyl.d.ts b/build/lib/typings/vinyl.d.ts similarity index 100% rename from lib/vscode/build/lib/typings/vinyl.d.ts rename to build/lib/typings/vinyl.d.ts diff --git a/lib/vscode/build/lib/util.js b/build/lib/util.js similarity index 100% rename from lib/vscode/build/lib/util.js rename to build/lib/util.js diff --git a/lib/vscode/build/lib/util.ts b/build/lib/util.ts similarity index 99% rename from lib/vscode/build/lib/util.ts rename to build/lib/util.ts index 48853bc6201a..c0a0d9619d73 100644 --- a/lib/vscode/build/lib/util.ts +++ b/build/lib/util.ts @@ -336,7 +336,6 @@ export function streamToPromise(stream: NodeJS.ReadWriteStream): Promise { } export function getElectronVersion(): string { - return process.versions.node; const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8'); const target = /^target "(.*)"$/m.exec(yarnrc)![1]; return target; diff --git a/lib/vscode/build/lib/watch/.gitignore b/build/lib/watch/.gitignore similarity index 100% rename from lib/vscode/build/lib/watch/.gitignore rename to build/lib/watch/.gitignore diff --git a/lib/vscode/build/lib/watch/index.js b/build/lib/watch/index.js similarity index 100% rename from lib/vscode/build/lib/watch/index.js rename to build/lib/watch/index.js diff --git a/lib/vscode/build/lib/watch/index.ts b/build/lib/watch/index.ts similarity index 100% rename from lib/vscode/build/lib/watch/index.ts rename to build/lib/watch/index.ts diff --git a/lib/vscode/build/lib/watch/package.json b/build/lib/watch/package.json similarity index 100% rename from lib/vscode/build/lib/watch/package.json rename to build/lib/watch/package.json diff --git a/lib/vscode/build/lib/watch/watch-win32.js b/build/lib/watch/watch-win32.js similarity index 100% rename from lib/vscode/build/lib/watch/watch-win32.js rename to build/lib/watch/watch-win32.js diff --git a/lib/vscode/build/lib/watch/watch-win32.ts b/build/lib/watch/watch-win32.ts similarity index 100% rename from lib/vscode/build/lib/watch/watch-win32.ts rename to build/lib/watch/watch-win32.ts diff --git a/lib/vscode/build/lib/watch/watcher.exe b/build/lib/watch/watcher.exe similarity index 100% rename from lib/vscode/build/lib/watch/watcher.exe rename to build/lib/watch/watcher.exe diff --git a/lib/vscode/build/lib/watch/yarn.lock b/build/lib/watch/yarn.lock similarity index 100% rename from lib/vscode/build/lib/watch/yarn.lock rename to build/lib/watch/yarn.lock diff --git a/lib/vscode/build/monaco/LICENSE b/build/monaco/LICENSE similarity index 100% rename from lib/vscode/build/monaco/LICENSE rename to build/monaco/LICENSE diff --git a/lib/vscode/build/monaco/README-npm.md b/build/monaco/README-npm.md similarity index 100% rename from lib/vscode/build/monaco/README-npm.md rename to build/monaco/README-npm.md diff --git a/lib/vscode/build/monaco/README.md b/build/monaco/README.md similarity index 100% rename from lib/vscode/build/monaco/README.md rename to build/monaco/README.md diff --git a/lib/vscode/build/monaco/ThirdPartyNotices.txt b/build/monaco/ThirdPartyNotices.txt similarity index 100% rename from lib/vscode/build/monaco/ThirdPartyNotices.txt rename to build/monaco/ThirdPartyNotices.txt diff --git a/lib/vscode/build/monaco/esm.core.js b/build/monaco/esm.core.js similarity index 100% rename from lib/vscode/build/monaco/esm.core.js rename to build/monaco/esm.core.js diff --git a/lib/vscode/build/monaco/monaco.d.ts.recipe b/build/monaco/monaco.d.ts.recipe similarity index 100% rename from lib/vscode/build/monaco/monaco.d.ts.recipe rename to build/monaco/monaco.d.ts.recipe diff --git a/lib/vscode/build/monaco/monaco.usage.recipe b/build/monaco/monaco.usage.recipe similarity index 100% rename from lib/vscode/build/monaco/monaco.usage.recipe rename to build/monaco/monaco.usage.recipe diff --git a/lib/vscode/build/monaco/monaco.webpack.config.js b/build/monaco/monaco.webpack.config.js similarity index 100% rename from lib/vscode/build/monaco/monaco.webpack.config.js rename to build/monaco/monaco.webpack.config.js diff --git a/lib/vscode/build/monaco/package.json b/build/monaco/package.json similarity index 100% rename from lib/vscode/build/monaco/package.json rename to build/monaco/package.json diff --git a/lib/vscode/build/monaco/version.txt b/build/monaco/version.txt similarity index 100% rename from lib/vscode/build/monaco/version.txt rename to build/monaco/version.txt diff --git a/lib/vscode/build/npm/dirs.js b/build/npm/dirs.js similarity index 100% rename from lib/vscode/build/npm/dirs.js rename to build/npm/dirs.js diff --git a/lib/vscode/build/npm/postinstall.js b/build/npm/postinstall.js similarity index 100% rename from lib/vscode/build/npm/postinstall.js rename to build/npm/postinstall.js diff --git a/lib/vscode/build/npm/preinstall.js b/build/npm/preinstall.js similarity index 100% rename from lib/vscode/build/npm/preinstall.js rename to build/npm/preinstall.js diff --git a/lib/vscode/build/npm/update-all-grammars.js b/build/npm/update-all-grammars.js similarity index 100% rename from lib/vscode/build/npm/update-all-grammars.js rename to build/npm/update-all-grammars.js diff --git a/lib/vscode/build/npm/update-distro.js b/build/npm/update-distro.js similarity index 100% rename from lib/vscode/build/npm/update-distro.js rename to build/npm/update-distro.js diff --git a/build/npm/update-localization-extension.js b/build/npm/update-localization-extension.js new file mode 100644 index 000000000000..43bc792d9f84 --- /dev/null +++ b/build/npm/update-localization-extension.js @@ -0,0 +1,101 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +let i18n = require("../lib/i18n"); + +let fs = require("fs"); +let path = require("path"); + +let gulp = require('gulp'); +let vfs = require("vinyl-fs"); +let rimraf = require('rimraf'); +let minimist = require('minimist'); + +function update(options) { + let idOrPath = options._; + if (!idOrPath) { + throw new Error('Argument must be the location of the localization extension.'); + } + let location = options.location; + if (location !== undefined && !fs.existsSync(location)) { + throw new Error(`${location} doesn't exist.`); + } + let locExtFolder = idOrPath; + if (/^\w{2}(-\w+)?$/.test(idOrPath)) { + locExtFolder = path.join('..', 'vscode-loc', 'i18n', `vscode-language-pack-${idOrPath}`); + } + let locExtStat = fs.statSync(locExtFolder); + if (!locExtStat || !locExtStat.isDirectory) { + throw new Error('No directory found at ' + idOrPath); + } + let packageJSON = JSON.parse(fs.readFileSync(path.join(locExtFolder, 'package.json')).toString()); + let contributes = packageJSON['contributes']; + if (!contributes) { + throw new Error('The extension must define a "localizations" contribution in the "package.json"'); + } + let localizations = contributes['localizations']; + if (!localizations) { + throw new Error('The extension must define a "localizations" contribution of type array in the "package.json"'); + } + + localizations.forEach(function (localization) { + if (!localization.languageId || !localization.languageName || !localization.localizedLanguageName) { + throw new Error('Each localization contribution must define "languageId", "languageName" and "localizedLanguageName" properties.'); + } + let languageId = localization.languageId; + let translationDataFolder = path.join(locExtFolder, 'translations'); + + switch (languageId) { + case 'zh-cn': + languageId = 'zh-Hans'; + break; + case 'zh-tw': + languageId = 'zh-Hant'; + break; + case 'pt-br': + languageId = 'pt-BR'; + break; + } + + if (fs.existsSync(translationDataFolder) && fs.existsSync(path.join(translationDataFolder, 'main.i18n.json'))) { + console.log('Clearing \'' + translationDataFolder + '\'...'); + rimraf.sync(translationDataFolder); + } + + console.log(`Importing translations for ${languageId} form '${location}' to '${translationDataFolder}' ...`); + let translationPaths = []; + gulp.src(path.join(location, '**', languageId, '*.xlf'), { silent: false }) + .pipe(i18n.prepareI18nPackFiles(i18n.externalExtensionsWithTranslations, translationPaths, languageId === 'ps')) + .on('error', (error) => { + console.log(`Error occurred while importing translations:`); + translationPaths = undefined; + if (Array.isArray(error)) { + error.forEach(console.log); + } else if (error) { + console.log(error); + } else { + console.log('Unknown error'); + } + }) + .pipe(vfs.dest(translationDataFolder)) + .on('end', function () { + if (translationPaths !== undefined) { + localization.translations = []; + for (let tp of translationPaths) { + localization.translations.push({ id: tp.id, path: `./translations/${tp.resourceName}` }); + } + fs.writeFileSync(path.join(locExtFolder, 'package.json'), JSON.stringify(packageJSON, null, '\t')); + } + }); + }); +} +if (path.basename(process.argv[1]) === 'update-localization-extension.js') { + var options = minimist(process.argv.slice(2), { + string: 'location' + }); + update(options); +} diff --git a/lib/vscode/build/package.json b/build/package.json similarity index 95% rename from lib/vscode/build/package.json rename to build/package.json index cd119a5f7a52..f683c3241dc1 100644 --- a/lib/vscode/build/package.json +++ b/build/package.json @@ -24,7 +24,7 @@ "@types/minimist": "^1.2.1", "@types/mkdirp": "^1.0.1", "@types/mocha": "^8.2.0", - "@types/node": "^14.14.37", + "@types/node": "14.x", "@types/p-limit": "^2.2.0", "@types/plist": "^3.0.2", "@types/pump": "^1.0.1", @@ -42,7 +42,7 @@ "colors": "^1.4.0", "commander": "^7.0.0", "electron-osx-sign": "^0.4.16", - "esbuild": "^0.8.30", + "esbuild": "^0.12.6", "fs-extra": "^9.1.0", "got": "11.8.1", "iconv-lite-umd": "0.6.8", @@ -52,7 +52,7 @@ "p-limit": "^3.1.0", "plist": "^3.0.1", "source-map": "0.6.1", - "typescript": "^4.3.0-dev.20210426", + "typescript": "^4.4.0-dev.20210528", "vsce": "1.48.0", "vscode-universal": "deepak1556/universal#61454d96223b774c53cda10f72c2098c0ce02d58" }, diff --git a/lib/vscode/build/polyfills/vscode-extension-telemetry.js b/build/polyfills/vscode-extension-telemetry.js similarity index 100% rename from lib/vscode/build/polyfills/vscode-extension-telemetry.js rename to build/polyfills/vscode-extension-telemetry.js diff --git a/lib/vscode/build/polyfills/vscode-nls.js b/build/polyfills/vscode-nls.js similarity index 100% rename from lib/vscode/build/polyfills/vscode-nls.js rename to build/polyfills/vscode-nls.js diff --git a/lib/vscode/build/tsconfig.build.json b/build/tsconfig.build.json similarity index 100% rename from lib/vscode/build/tsconfig.build.json rename to build/tsconfig.build.json diff --git a/lib/vscode/build/tsconfig.json b/build/tsconfig.json similarity index 100% rename from lib/vscode/build/tsconfig.json rename to build/tsconfig.json diff --git a/lib/vscode/build/win32/.gitignore b/build/win32/.gitignore similarity index 100% rename from lib/vscode/build/win32/.gitignore rename to build/win32/.gitignore diff --git a/lib/vscode/build/win32/Cargo.lock b/build/win32/Cargo.lock similarity index 100% rename from lib/vscode/build/win32/Cargo.lock rename to build/win32/Cargo.lock diff --git a/lib/vscode/build/win32/code.iss b/build/win32/code.iss similarity index 100% rename from lib/vscode/build/win32/code.iss rename to build/win32/code.iss diff --git a/lib/vscode/build/win32/i18n/Default.hu.isl b/build/win32/i18n/Default.hu.isl similarity index 100% rename from lib/vscode/build/win32/i18n/Default.hu.isl rename to build/win32/i18n/Default.hu.isl diff --git a/lib/vscode/build/win32/i18n/Default.ko.isl b/build/win32/i18n/Default.ko.isl similarity index 100% rename from lib/vscode/build/win32/i18n/Default.ko.isl rename to build/win32/i18n/Default.ko.isl diff --git a/lib/vscode/build/win32/i18n/Default.zh-cn.isl b/build/win32/i18n/Default.zh-cn.isl similarity index 100% rename from lib/vscode/build/win32/i18n/Default.zh-cn.isl rename to build/win32/i18n/Default.zh-cn.isl diff --git a/lib/vscode/build/win32/i18n/Default.zh-tw.isl b/build/win32/i18n/Default.zh-tw.isl similarity index 100% rename from lib/vscode/build/win32/i18n/Default.zh-tw.isl rename to build/win32/i18n/Default.zh-tw.isl diff --git a/lib/vscode/build/win32/i18n/messages.de.isl b/build/win32/i18n/messages.de.isl similarity index 100% rename from lib/vscode/build/win32/i18n/messages.de.isl rename to build/win32/i18n/messages.de.isl diff --git a/lib/vscode/build/win32/i18n/messages.en.isl b/build/win32/i18n/messages.en.isl similarity index 100% rename from lib/vscode/build/win32/i18n/messages.en.isl rename to build/win32/i18n/messages.en.isl diff --git a/lib/vscode/build/win32/i18n/messages.es.isl b/build/win32/i18n/messages.es.isl similarity index 100% rename from lib/vscode/build/win32/i18n/messages.es.isl rename to build/win32/i18n/messages.es.isl diff --git a/lib/vscode/build/win32/i18n/messages.fr.isl b/build/win32/i18n/messages.fr.isl similarity index 100% rename from lib/vscode/build/win32/i18n/messages.fr.isl rename to build/win32/i18n/messages.fr.isl diff --git a/lib/vscode/build/win32/i18n/messages.hu.isl b/build/win32/i18n/messages.hu.isl similarity index 100% rename from lib/vscode/build/win32/i18n/messages.hu.isl rename to build/win32/i18n/messages.hu.isl diff --git a/lib/vscode/build/win32/i18n/messages.it.isl b/build/win32/i18n/messages.it.isl similarity index 100% rename from lib/vscode/build/win32/i18n/messages.it.isl rename to build/win32/i18n/messages.it.isl diff --git a/lib/vscode/build/win32/i18n/messages.ja.isl b/build/win32/i18n/messages.ja.isl similarity index 100% rename from lib/vscode/build/win32/i18n/messages.ja.isl rename to build/win32/i18n/messages.ja.isl diff --git a/lib/vscode/build/win32/i18n/messages.ko.isl b/build/win32/i18n/messages.ko.isl similarity index 100% rename from lib/vscode/build/win32/i18n/messages.ko.isl rename to build/win32/i18n/messages.ko.isl diff --git a/lib/vscode/build/win32/i18n/messages.pt-br.isl b/build/win32/i18n/messages.pt-br.isl similarity index 100% rename from lib/vscode/build/win32/i18n/messages.pt-br.isl rename to build/win32/i18n/messages.pt-br.isl diff --git a/lib/vscode/build/win32/i18n/messages.ru.isl b/build/win32/i18n/messages.ru.isl similarity index 100% rename from lib/vscode/build/win32/i18n/messages.ru.isl rename to build/win32/i18n/messages.ru.isl diff --git a/lib/vscode/build/win32/i18n/messages.tr.isl b/build/win32/i18n/messages.tr.isl similarity index 100% rename from lib/vscode/build/win32/i18n/messages.tr.isl rename to build/win32/i18n/messages.tr.isl diff --git a/lib/vscode/build/win32/i18n/messages.zh-cn.isl b/build/win32/i18n/messages.zh-cn.isl similarity index 100% rename from lib/vscode/build/win32/i18n/messages.zh-cn.isl rename to build/win32/i18n/messages.zh-cn.isl diff --git a/lib/vscode/build/win32/i18n/messages.zh-tw.isl b/build/win32/i18n/messages.zh-tw.isl similarity index 100% rename from lib/vscode/build/win32/i18n/messages.zh-tw.isl rename to build/win32/i18n/messages.zh-tw.isl diff --git a/lib/vscode/build/win32/inno_updater.exe b/build/win32/inno_updater.exe similarity index 100% rename from lib/vscode/build/win32/inno_updater.exe rename to build/win32/inno_updater.exe diff --git a/lib/vscode/build/win32/vcruntime140.dll b/build/win32/vcruntime140.dll similarity index 100% rename from lib/vscode/build/win32/vcruntime140.dll rename to build/win32/vcruntime140.dll diff --git a/lib/vscode/build/yarn.lock b/build/yarn.lock similarity index 98% rename from lib/vscode/build/yarn.lock rename to build/yarn.lock index 38b1f00fd780..b0449db06eeb 100644 --- a/lib/vscode/build/yarn.lock +++ b/build/yarn.lock @@ -371,16 +371,16 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.51.tgz#b31d716fb8d58eeb95c068a039b9b6292817d5fb" integrity sha512-El3+WJk2D/ppWNd2X05aiP5l2k4EwF7KwheknQZls+I26eSICoWRhRIJ56jGgw2dqNGQ5LtNajmBU2ajS28EvQ== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== + "@types/node@^14.14.21": version "14.14.22" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.22.tgz#0d29f382472c4ccf3bd96ff0ce47daf5b7b84b18" integrity sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw== -"@types/node@^14.14.37": - version "14.14.37" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.37.tgz#a3dd8da4eb84a996c36e331df98d82abd76b516e" - integrity sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw== - "@types/p-limit@^2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@types/p-limit/-/p-limit-2.2.0.tgz#94a608e9b258a6c6156a13d1a14fd720dba70b97" @@ -992,10 +992,10 @@ entities@^1.1.1, entities@~1.1.1: resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== -esbuild@^0.8.30: - version "0.8.30" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.8.30.tgz#3d057ff9ffe6d5d30bccb0afe8cc92a2e69622d3" - integrity sha512-gCJQYUMO9QNrfpNOIiCnFoX41nWiPFCvURBQF+qWckyJ7gmw2xCShdKCXvS+RZcQ5krcxEOLIkzujqclePKhfw== +esbuild@^0.12.6: + version "0.12.6" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.12.6.tgz#85bc755c7cf3005d4f34b4f10f98049ce0ee67ce" + integrity sha512-RDvVLvAjsq/kIZJoneMiUOH7EE7t2QaW7T3Q7EdQij14+bZbDq5sndb0tTanmHIFSqZVMBMMyqzVHkS3dJobeA== eslint-scope@^5.0.0: version "5.0.0" @@ -1372,15 +1372,10 @@ lodash.unescape@4.0.1: resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= -lodash@^4.15.0, lodash@^4.17.10: - version "4.17.19" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" - integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== - -lodash@^4.17.15: - version "4.17.20" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" - integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== +lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.15: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== lowercase-keys@^2.0.0: version "2.0.0" @@ -1884,10 +1879,10 @@ typescript@^4.1.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== -typescript@^4.3.0-dev.20210426: - version "4.3.0-dev.20210426" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.0-dev.20210426.tgz#00198cb8828f6a04b4e0ae32554a486bf7137a53" - integrity sha512-8YTqlzf3w8O8XwnnRlwRV2rswu7V7WEPUnAnH1BPPMrr06thNByMjIadA5SDW3tUJc1MG8Uj3NgZYocU5fWTVg== +typescript@^4.4.0-dev.20210528: + version "4.4.0-dev.20210528" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.0-dev.20210528.tgz#42453bc42e9d9df8ad0741c207c24d56407c0347" + integrity sha512-ACV+mYKC+PhWUXIDUL6qmFClIdrKc20KRxDePt8bniCgkKQD4XRYKl7m02paxJM3nTMRdlfjs0ncaslA5BA1GA== uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.5" diff --git a/lib/vscode/cglicenses.json b/cglicenses.json similarity index 78% rename from lib/vscode/cglicenses.json rename to cglicenses.json index 621c771c4c2a..7c42f531d52a 100644 --- a/lib/vscode/cglicenses.json +++ b/cglicenses.json @@ -54,35 +54,6 @@ "Copyright (c) Microsoft Corporation. All rights reserved." ] }, - { - // Reason: The npm package lacks a repoURL field - // So the license at https://github.com/floatdrop/pinkie/blob/master/license - // cannot be found by the OSS tool automatically. - "name": "pinkie", - "fullLicenseText": [ - "The MIT License (MIT)", - "", - "Copyright (c) Vsevolod Strukchinsky (github.com/floatdrop)", - "", - "Permission is hereby granted, free of charge, to any person obtaining a copy", - "of this software and associated documentation files (the \"Software\"), to deal", - "in the Software without restriction, including without limitation the rights", - "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell", - "copies of the Software, and to permit persons to whom the Software is", - "furnished to do so, subject to the following conditions:", - "", - "The above copyright notice and this permission notice shall be included in", - "all copies or substantial portions of the Software.", - "", - "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR", - "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", - "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE", - "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", - "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,", - "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN", - "THE SOFTWARE." - ] - }, { "name": "big-integer", "prependLicenseText": [ @@ -134,6 +105,7 @@ { // Reason: Repository lacks license text. // https://github.com/LinusU/load-yaml-file/blob/master/package.json declares MIT. + // https://github.com/LinusU/load-yaml-file/issues/2 "name": "load-yaml-file", "fullLicenseText": [ "MIT License", @@ -149,6 +121,7 @@ { // Reason: Repository lacks license text. // https://github.com/othiym23/emitter-listener/blob/master/package.json declares BSD-2-Clause. + // https://github.com/othiym23/emitter-listener/issues/3 "name": "emitter-listener", "fullLicenseText": [ "BSD 2-Clause \"Simplified\" License", @@ -174,19 +147,5 @@ "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS", "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ] - }, - { - // Reason: Repository has been deleted (package.json declares MIT). - "name": "vscode-js-debug-cdp-proxy-api", - "fullLicenseText": [ - "MIT License", - "Copyright (c) Manuel Alabor", - "", - "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:", - "", - "The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.", - "", - "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." - ] } ] diff --git a/lib/vscode/cgmanifest.json b/cgmanifest.json similarity index 99% rename from lib/vscode/cgmanifest.json rename to cgmanifest.json index aa54e3243ab4..22cbc50562c5 100644 --- a/lib/vscode/cgmanifest.json +++ b/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "chromium", "repositoryUrl": "https://chromium.googlesource.com/chromium/src", - "commitHash": "5342041f85833c038dcbc5632d62fc10f7592323" + "commitHash": "cd7a46bf02a768a1aabf9443f6ee469bc6e28e7c" } }, "licenseDetail": [ @@ -40,7 +40,7 @@ "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ], "isOnlyProductionDependency": true, - "version": "89.0.4389.114" + "version": "89.0.4389.128" }, { "component": { @@ -60,12 +60,12 @@ "git": { "name": "electron", "repositoryUrl": "https://github.com/electron/electron", - "commitHash": "9ce7c512475aa6aa91417a3b08e19f85a8587a30" + "commitHash": "30f82dd1cb8140ccb5c6a4960eef8e3b8c15eeba" } }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "12.0.4" + "version": "12.0.9" }, { "component": { diff --git a/ci/README.md b/ci/README.md deleted file mode 100644 index 40f7f4b7b4bf..000000000000 --- a/ci/README.md +++ /dev/null @@ -1,141 +0,0 @@ -# ci - -This directory contains scripts used for code-server's continuous integration infrastructure. - -Some of these scripts contain more detailed documentation and options -in header comments. - -Any file or directory in this subdirectory should be documented here. - -- [./ci/lib.sh](./lib.sh) - - Contains code duplicated across these scripts. - -## Publishing a release - -1. Run `yarn release:prep` and type in the new version i.e. 3.8.1 -2. GitHub actions will generate the `npm-package`, `release-packages` and `release-images` artifacts. - 1. You do not have to wait for these. -3. Run `yarn release:github-draft` to create a GitHub draft release from the template with - the updated version. - 1. Summarize the major changes in the release notes and link to the relevant issues. - 2. Change the @ to target the version branch. Example: `v3.9.0 @ Target: v3.9.0` -4. Wait for the artifacts in step 2 to build. -5. Run `yarn release:github-assets` to download the `release-packages` artifact. - - It will upload them to the draft release. -6. Run some basic sanity tests on one of the released packages. - - Especially make sure the terminal works fine. -7. Make sure the github release tag is the commit with the artifacts. -8. Publish the release and merge the PR. - 1. CI will automatically grab the artifacts and then: - 1. Publish the NPM package from `npm-package`. - 2. Publish the Docker Hub image from `release-images`. -9. Update the AUR package. - - Instructions on updating the AUR package are at [cdr/code-server-aur](https://github.com/cdr/code-server-aur). -10. Wait for the npm package to be published. -11. Update the [homebrew package](https://github.com/Homebrew/homebrew-core/blob/master/Formula/code-server.rb). - 1. Install [homebrew](https://brew.sh/) - 2. Run `brew bump-formula-pr --version=3.8.1 code-server` and update the version accordingly. This will bump the version and open a PR. Note: this will only work once the version is published on npm. - -## dev - -This directory contains scripts used for the development of code-server. - -- [./ci/dev/image](./dev/image) - - See [./docs/CONTRIBUTING.md](../docs/CONTRIBUTING.md) for docs on the development container. -- [./ci/dev/fmt.sh](./dev/fmt.sh) (`yarn fmt`) - - Runs formatters. -- [./ci/dev/lint.sh](./dev/lint.sh) (`yarn lint`) - - Runs linters. -- [./ci/dev/test-unit.sh](./dev/test-unit.sh) (`yarn test:unit`) - - Runs unit tests. -- [./ci/dev/test-e2e.sh](./dev/test-e2e.sh) (`yarn test:e2e`) - - Runs end-to-end tests. -- [./ci/dev/ci.sh](./dev/ci.sh) (`yarn ci`) - - Runs `yarn fmt`, `yarn lint` and `yarn test`. -- [./ci/dev/watch.ts](./dev/watch.ts) (`yarn watch`) - - Starts a process to build and launch code-server and restart on any code changes. - - Example usage in [./docs/CONTRIBUTING.md](../docs/CONTRIBUTING.md). -- [./ci/dev/gen_icons.sh](./ci/dev/gen_icons.sh) (`yarn icons`) - - Generates the various icons from a single `.svg` favicon in - `src/browser/media/favicon.svg`. - - Requires [imagemagick](https://imagemagick.org/index.php) - -## build - -This directory contains the scripts used to build and release code-server. -You can disable minification by setting `MINIFY=`. - -- [./ci/build/build-code-server.sh](./build/build-code-server.sh) (`yarn build`) - - Builds code-server into `./out` and bundles the frontend into `./dist`. -- [./ci/build/build-vscode.sh](./build/build-vscode.sh) (`yarn build:vscode`) - - Builds vscode into `./lib/vscode/out-vscode`. -- [./ci/build/build-release.sh](./build/build-release.sh) (`yarn release`) - - Bundles the output of the above two scripts into a single node module at `./release`. -- [./ci/build/build-standalone-release.sh](./build/build-standalone-release.sh) (`yarn release:standalone`) - - Requires a node module already built into `./release` with the above script. - - Will build a standalone release with node and node_modules bundled into `./release-standalone`. -- [./ci/build/clean.sh](./build/clean.sh) (`yarn clean`) - - Removes all build artifacts. - - Useful to do a clean build. -- [./ci/build/code-server.sh](./build/code-server.sh) - - Copied into standalone releases to run code-server with the bundled node binary. -- [./ci/build/test-standalone-release.sh](./build/test-standalone-release.sh) (`yarn test:standalone-release`) - - Ensures code-server in the `./release-standalone` directory works by installing an extension. -- [./ci/build/build-packages.sh](./build/build-packages.sh) (`yarn package`) - - Packages `./release-standalone` into a `.tar.gz` archive in `./release-packages`. - - If on linux, [nfpm](https://github.com/goreleaser/nfpm) is used to generate `.deb` and `.rpm`. -- [./ci/build/nfpm.yaml](./build/nfpm.yaml) - - Used to configure [nfpm](https://github.com/goreleaser/nfpm) to generate `.deb` and `.rpm`. -- [./ci/build/code-server-nfpm.sh](./build/code-server-nfpm.sh) - - Entrypoint script for code-server for `.deb` and `.rpm`. -- [./ci/build/code-server.service](./build/code-server.service) - - systemd user service packaged into the `.deb` and `.rpm`. -- [./ci/build/release-github-draft.sh](./build/release-github-draft.sh) (`yarn release:github-draft`) - - Uses [gh](https://github.com/cli/cli) to create a draft release with a template description. -- [./ci/build/release-github-assets.sh](./build/release-github-assets.sh) (`yarn release:github-assets`) - - Downloads the release-package artifacts for the current commit from CI. - - Uses [gh](https://github.com/cli/cli) to upload the artifacts to the release - specified in `package.json`. -- [./ci/build/npm-postinstall.sh](./build/npm-postinstall.sh) - - Post install script for the npm package. - - Bundled by`yarn release`. - -## release-image - -This directory contains the release docker container image. - -- [./release-image/build.sh](./release-image/build.sh) - - Builds the release container with the tag `codercom/code-server-$ARCH:$VERSION`. - - Assumes debian releases are ready in `./release-packages`. - -## images - -This directory contains the images for CI. - -## steps - -This directory contains the scripts used in CI. -Helps avoid clobbering the CI configuration. - -- [./steps/fmt.sh](./steps/fmt.sh) - - Runs `yarn fmt`. -- [./steps/lint.sh](./steps/lint.sh) - - Runs `yarn lint`. -- [./steps/test-unit.sh](./steps/test-unit.sh) - - Runs `yarn test:unit`. -- [./steps/test-e2e.sh](./steps/test-e2e.sh) - - Runs `yarn test:e2e`. -- [./steps/release.sh](./steps/release.sh) - - Runs the release process. - - Generates the npm package at `./release`. -- [./steps/release-packages.sh](./steps/release-packages.sh) - - Takes the output of the previous script and generates a standalone release and - release packages into `./release-packages`. -- [./steps/publish-npm.sh](./steps/publish-npm.sh) - - Grabs the `npm-package` release artifact for the current commit and publishes it on npm. -- [./steps/build-docker-image.sh](./steps/build-docker-image.sh) - - Builds the docker image and then saves it into `./release-images/code-server-$ARCH-$VERSION.tar`. -- [./steps/push-docker-manifest.sh](./steps/push-docker-manifest.sh) - - Loads all images in `./release-images` and then builds and pushes a multi architecture - docker manifest for the amd64 and arm64 images to `codercom/code-server:$VERSION` and - `codercom/code-server:latest`. diff --git a/ci/build/build-code-server.sh b/ci/build/build-code-server.sh deleted file mode 100755 index c465f7e4a0c4..000000000000 --- a/ci/build/build-code-server.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Builds code-server into out and the frontend into dist. - -# MINIFY controls whether parcel minifies dist. -MINIFY=${MINIFY-true} - -main() { - cd "$(dirname "${0}")/../.." - - tsc - - # If out/node/entry.js does not already have the shebang, - # we make sure to add it and make it executable. - if ! grep -q -m1 "^#!/usr/bin/env node" out/node/entry.js; then - sed -i.bak "1s;^;#!/usr/bin/env node\n;" out/node/entry.js && rm out/node/entry.js.bak - chmod +x out/node/entry.js - fi - - if ! [ -f ./lib/coder-cloud-agent ]; then - echo "Downloading the cloud agent..." - - # for arch; we do not use OS from lib.sh and get our own. - # lib.sh normalizes macos to darwin - but cloud-agent's binaries do not - source ./ci/lib.sh - OS="$(uname | tr '[:upper:]' '[:lower:]')" - - set +e - curl -fsSL "https://github.com/cdr/cloud-agent/releases/latest/download/cloud-agent-$OS-$ARCH" -o ./lib/coder-cloud-agent - chmod +x ./lib/coder-cloud-agent - set -e - fi - - parcel build \ - --public-url "." \ - --out-dir dist \ - $([[ $MINIFY ]] || echo --no-minify) \ - src/browser/register.ts \ - src/browser/serviceWorker.ts \ - src/browser/pages/login.ts \ - src/browser/pages/vscode.ts -} - -main "$@" diff --git a/ci/build/build-packages.sh b/ci/build/build-packages.sh deleted file mode 100755 index b83ed286f90d..000000000000 --- a/ci/build/build-packages.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Packages code-server for the current OS and architecture into ./release-packages. -# This script assumes that a standalone release is built already into ./release-standalone - -main() { - cd "$(dirname "${0}")/../.." - source ./ci/lib.sh - - # Allow us to override architecture - # we use this for our Linux ARM64 cross compile builds - if [ "$#" -eq 1 ] && [ "$1" ]; then - ARCH=$1 - fi - - mkdir -p release-packages - - release_archive - - if [[ $OS == "linux" ]]; then - release_nfpm - fi -} - -release_archive() { - local release_name="code-server-$VERSION-$OS-$ARCH" - if [[ $OS == "linux" ]]; then - tar -czf "release-packages/$release_name.tar.gz" --transform "s/^\.\/release-standalone/$release_name/" ./release-standalone - else - tar -czf "release-packages/$release_name.tar.gz" -s "/^release-standalone/$release_name/" release-standalone - fi - - echo "done (release-packages/$release_name)" - - release_gcp -} - -release_gcp() { - mkdir -p "release-gcp/$VERSION" - cp "release-packages/$release_name.tar.gz" "./release-gcp/$VERSION/$OS-$ARCH.tar.gz" - mkdir -p "release-gcp/latest" - cp "./release-packages/$release_name.tar.gz" "./release-gcp/latest/$OS-$ARCH.tar.gz" -} - -# Generates deb and rpm packages. -release_nfpm() { - local nfpm_config - nfpm_config="$(envsubst <./ci/build/nfpm.yaml)" - - # The underscores are convention for .deb. - nfpm pkg -f <(echo "$nfpm_config") --target "release-packages/code-server_${VERSION}_$ARCH.deb" - nfpm pkg -f <(echo "$nfpm_config") --target "release-packages/code-server-$VERSION-$ARCH.rpm" -} - -main "$@" diff --git a/ci/build/build-release.sh b/ci/build/build-release.sh deleted file mode 100755 index ffad55380418..000000000000 --- a/ci/build/build-release.sh +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# This script requires vscode to be built with matching MINIFY. - -# MINIFY controls whether minified vscode is bundled. -MINIFY="${MINIFY-true}" - -# KEEP_MODULES controls whether the script cleans all node_modules requiring a yarn install -# to run first. -KEEP_MODULES="${KEEP_MODULES-0}" - -main() { - cd "$(dirname "${0}")/../.." - source ./ci/lib.sh - - VSCODE_SRC_PATH="lib/vscode" - VSCODE_OUT_PATH="$RELEASE_PATH/lib/vscode" - - mkdir -p "$RELEASE_PATH" - - bundle_code_server - bundle_vscode - - rsync README.md "$RELEASE_PATH" - rsync LICENSE.txt "$RELEASE_PATH" - rsync ./lib/vscode/ThirdPartyNotices.txt "$RELEASE_PATH" -} - -bundle_code_server() { - rsync out dist "$RELEASE_PATH" - - # For source maps and images. - mkdir -p "$RELEASE_PATH/src/browser" - rsync src/browser/media/ "$RELEASE_PATH/src/browser/media" - mkdir -p "$RELEASE_PATH/src/browser/pages" - rsync src/browser/pages/*.html "$RELEASE_PATH/src/browser/pages" - rsync src/browser/robots.txt "$RELEASE_PATH/src/browser" - - # Add typings for plugins - mkdir -p "$RELEASE_PATH/typings" - rsync typings/pluginapi.d.ts "$RELEASE_PATH/typings" - - # Adds the commit to package.json - jq --slurp '.[0] * .[1]' package.json <( - cat <"$RELEASE_PATH/package.json" - rsync yarn.lock "$RELEASE_PATH" - rsync ci/build/npm-postinstall.sh "$RELEASE_PATH/postinstall.sh" - - if [ "$KEEP_MODULES" = 1 ]; then - rsync node_modules/ "$RELEASE_PATH/node_modules" - mkdir -p "$RELEASE_PATH/lib" - rsync ./lib/coder-cloud-agent "$RELEASE_PATH/lib" - fi -} - -bundle_vscode() { - mkdir -p "$VSCODE_OUT_PATH" - rsync "$VSCODE_SRC_PATH/yarn.lock" "$VSCODE_OUT_PATH" - rsync "$VSCODE_SRC_PATH/out-vscode${MINIFY:+-min}/" "$VSCODE_OUT_PATH/out" - - rsync "$VSCODE_SRC_PATH/.build/extensions/" "$VSCODE_OUT_PATH/extensions" - if [ "$KEEP_MODULES" = 0 ]; then - rm -Rf "$VSCODE_OUT_PATH/extensions/node_modules" - else - rsync "$VSCODE_SRC_PATH/node_modules/" "$VSCODE_OUT_PATH/node_modules" - fi - rsync "$VSCODE_SRC_PATH/extensions/package.json" "$VSCODE_OUT_PATH/extensions" - rsync "$VSCODE_SRC_PATH/extensions/yarn.lock" "$VSCODE_OUT_PATH/extensions" - rsync "$VSCODE_SRC_PATH/extensions/postinstall.js" "$VSCODE_OUT_PATH/extensions" - - mkdir -p "$VSCODE_OUT_PATH/resources/"{linux,web} - rsync "$VSCODE_SRC_PATH/resources/linux/code.png" "$VSCODE_OUT_PATH/resources/linux/code.png" - rsync "$VSCODE_SRC_PATH/resources/web/callback.html" "$VSCODE_OUT_PATH/resources/web/callback.html" - - # Adds the commit and date to product.json - jq --slurp '.[0] * .[1]' "$VSCODE_SRC_PATH/product.json" <( - cat <"$VSCODE_OUT_PATH/product.json" - - # We remove the scripts field so that later on we can run - # yarn to fetch node_modules if necessary without build scripts running. - # We cannot use --no-scripts because we still want dependent package scripts to run. - jq 'del(.scripts)' <"$VSCODE_SRC_PATH/package.json" >"$VSCODE_OUT_PATH/package.json" - - pushd "$VSCODE_OUT_PATH" - symlink_asar - popd -} - -main "$@" diff --git a/ci/build/build-standalone-release.sh b/ci/build/build-standalone-release.sh deleted file mode 100755 index e85678a29310..000000000000 --- a/ci/build/build-standalone-release.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -main() { - cd "$(dirname "${0}")/../.." - source ./ci/lib.sh - - rsync "$RELEASE_PATH/" "$RELEASE_PATH-standalone" - RELEASE_PATH+=-standalone - - # We cannot find the path to node from $PATH because yarn shims a script to ensure - # we use the same version it's using so we instead run a script with yarn that - # will print the path to node. - local node_path - node_path="$(yarn -s node <<<'console.info(process.execPath)')" - - mkdir -p "$RELEASE_PATH/bin" - rsync ./ci/build/code-server.sh "$RELEASE_PATH/bin/code-server" - rsync "$node_path" "$RELEASE_PATH/lib/node" - - ln -s "./bin/code-server" "$RELEASE_PATH/code-server" - ln -s "./lib/node" "$RELEASE_PATH/node" - - cd "$RELEASE_PATH" - yarn --production --frozen-lockfile -} - -main "$@" diff --git a/ci/build/build-vscode.sh b/ci/build/build-vscode.sh deleted file mode 100755 index faddf46e6c41..000000000000 --- a/ci/build/build-vscode.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Builds vscode into lib/vscode/out-vscode. - -# MINIFY controls whether a minified version of vscode is built. -MINIFY=${MINIFY-true} - -main() { - cd "$(dirname "${0}")/../.." - cd lib/vscode - - yarn gulp compile-build compile-extensions-build - yarn gulp optimize --gulpfile ./coder.js - if [[ $MINIFY ]]; then - yarn gulp minify --gulpfile ./coder.js - fi -} - -main "$@" diff --git a/ci/build/clean.sh b/ci/build/clean.sh deleted file mode 100755 index a31802155226..000000000000 --- a/ci/build/clean.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -main() { - cd "$(dirname "${0}")/../.." - source ./ci/lib.sh - - git clean -Xffd - - pushd lib/vscode - git clean -xffd - popd -} - -main "$@" diff --git a/ci/build/code-server-nfpm.sh b/ci/build/code-server-nfpm.sh deleted file mode 100755 index e12f493ba92c..000000000000 --- a/ci/build/code-server-nfpm.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env sh - -exec /usr/lib/code-server/bin/code-server "$@" diff --git a/ci/build/code-server-user.service b/ci/build/code-server-user.service deleted file mode 100644 index a2f48e938e55..000000000000 --- a/ci/build/code-server-user.service +++ /dev/null @@ -1,11 +0,0 @@ -[Unit] -Description=code-server -After=network.target - -[Service] -Type=exec -ExecStart=/usr/bin/code-server -Restart=always - -[Install] -WantedBy=default.target diff --git a/ci/build/code-server.sh b/ci/build/code-server.sh deleted file mode 100755 index cb71c182775a..000000000000 --- a/ci/build/code-server.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh -set -eu - -# This script is intended to be bundled into the standalone releases. -# Runs code-server with the bundled node binary. - -_realpath() { - # See https://github.com/cdr/code-server/issues/1537 on why no realpath or readlink -f. - - script="$1" - cd "$(dirname "$script")" - - while [ -L "$(basename "$script")" ]; do - if [ -L "./node" ] && [ -L "./code-server" ] \ - && [ -f "package.json" ] \ - && cat package.json | grep -q '^ "name": "code-server",$'; then - echo "***** Please use the script in bin/code-server instead!" >&2 - echo "***** This script will soon be removed!" >&2 - echo "***** See the release notes at https://github.com/cdr/code-server/releases/tag/v3.4.0" >&2 - fi - - script="$(readlink "$(basename "$script")")" - cd "$(dirname "$script")" - done - - echo "$PWD/$(basename "$script")" -} - -root() { - script="$(_realpath "$0")" - bin_dir="$(dirname "$script")" - dirname "$bin_dir" -} - -ROOT="$(root)" -exec "$ROOT/lib/node" "$ROOT" "$@" diff --git a/ci/build/code-server@.service b/ci/build/code-server@.service deleted file mode 100644 index bfb62d78dea0..000000000000 --- a/ci/build/code-server@.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=code-server -After=network.target - -[Service] -Type=exec -ExecStart=/usr/bin/code-server -Restart=always -User=%i - -[Install] -WantedBy=default.target diff --git a/ci/build/nfpm.yaml b/ci/build/nfpm.yaml deleted file mode 100644 index 7aa51f9ef87a..000000000000 --- a/ci/build/nfpm.yaml +++ /dev/null @@ -1,25 +0,0 @@ -name: "code-server" -arch: "${ARCH}" -platform: "linux" -version: "v${VERSION}" -section: "devel" -priority: "optional" -maintainer: "Anmol Sethi " -description: | - Run VS Code in the browser. -vendor: "Coder" -homepage: "https://github.com/cdr/code-server" -license: "MIT" - -contents: - - src: ./ci/build/code-server-nfpm.sh - dst: /usr/bin/code-server - - - src: ./ci/build/code-server@.service - dst: /usr/lib/systemd/system/code-server@.service - - - src: ./ci/build/code-server-user.service - dst: /usr/lib/systemd/user/code-server.service - - - src: ./release-standalone/* - dst: /usr/lib/code-server/ diff --git a/ci/build/npm-postinstall.sh b/ci/build/npm-postinstall.sh deleted file mode 100755 index bbe23322c0a2..000000000000 --- a/ci/build/npm-postinstall.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env sh -set -eu - -main() { - # Grabs the major version of node from $npm_config_user_agent which looks like - # yarn/1.21.1 npm/? node/v14.2.0 darwin x64 - major_node_version=$(echo "$npm_config_user_agent" | sed -n 's/.*node\/v\([^.]*\).*/\1/p') - if [ "$major_node_version" -lt 12 ]; then - echo "code-server currently requires at least node v12" - echo "We have detected that you are on node v$major_node_version" - echo "See https://github.com/cdr/code-server/issues/1633" - exit 1 - fi - - case "${npm_config_user_agent-}" in npm*) - # We are running under npm. - if [ "${npm_config_unsafe_perm-}" != "true" ]; then - echo "Please pass --unsafe-perm to npm to install code-server" - echo "Otherwise the postinstall script does not have permissions to run" - echo "See https://docs.npmjs.com/misc/config#unsafe-perm" - echo "See https://stackoverflow.com/questions/49084929/npm-sudo-global-installation-unsafe-perm" - exit 1 - fi - ;; - esac - - OS="$(uname | tr '[:upper:]' '[:lower:]')" - if curl -fsSL "https://storage.googleapis.com/coder-cloud-releases/agent/latest/$OS/cloud-agent" -o ./lib/coder-cloud-agent; then - chmod +x ./lib/coder-cloud-agent - else - echo "Failed to download cloud agent; --link will not work" - fi - - if ! vscode_yarn; then - echo "You may not have the required dependencies to build the native modules." - echo "Please see https://github.com/cdr/code-server/blob/master/docs/npm.md" - exit 1 - fi -} - -vscode_yarn() { - cd lib/vscode - yarn --production --frozen-lockfile - - # This is a copy of symlink_asar in ../lib.sh. Look there for details. - if [ ! -e node_modules.asar ]; then - if [ "${WINDIR-}" ]; then - mklink /J node_modules.asar node_modules - else - ln -s node_modules node_modules.asar - fi - fi - - cd extensions - yarn --production --frozen-lockfile - for ext in */; do - ext="${ext%/}" - echo "extensions/$ext: installing dependencies" - cd "$ext" - yarn --production --frozen-lockfile - cd "$OLDPWD" - done -} - -main "$@" diff --git a/ci/build/release-github-assets.sh b/ci/build/release-github-assets.sh deleted file mode 100755 index a025ee596d68..000000000000 --- a/ci/build/release-github-assets.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Downloads the release artifacts from CI for the current -# commit and then uploads them to the release with the version -# in package.json. -# You will need $GITHUB_TOKEN set. - -main() { - cd "$(dirname "$0")/../.." - source ./ci/lib.sh - - download_artifact release-packages ./release-packages - local assets=(./release-packages/code-server*"$VERSION"*{.tar.gz,.deb,.rpm}) - for i in "${!assets[@]}"; do - assets[$i]="--attach=${assets[$i]}" - done - EDITOR=true gh release upload "v$VERSION" "${assets[@]}" -} - -main "$@" diff --git a/ci/build/release-github-draft.sh b/ci/build/release-github-draft.sh deleted file mode 100755 index 4cd65d59121a..000000000000 --- a/ci/build/release-github-draft.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Creates a draft release with the template for the version in package.json - -main() { - cd "$(dirname "$0")/../.." - source ./ci/lib.sh - - gh release create "v$VERSION" \ - --notes-file - \ - --target "$(git rev-parse HEAD)" \ - --draft </dev/null; then - echo "gh could not be found." - echo "We use this with the release-github-draft.sh and release-github-assets.sh scripts." - echo -e "See docs here: https://github.com/cli/cli#installation" - exit - fi - - # Check that they have jq installed - if ! command -v jq &>/dev/null; then - echo "jq could not be found." - echo "We use this to parse the package.json and grab the current version of code-server." - echo -e "See docs here: https://stedolan.github.io/jq/download/" - exit - fi - - # Check that they have rg installed - if ! command -v rg &>/dev/null; then - echo "rg could not be found." - echo "We use this when updating files across the codebase." - echo -e "See docs here: https://github.com/BurntSushi/ripgrep#installation" - exit - fi - - # Check that they have node installed - if ! command -v node &>/dev/null; then - echo "node could not be found." - echo "That's surprising..." - echo "We use it in this script for getting the package.json version" - echo -e "See docs here: https://nodejs.org/en/download/" - exit - fi - - # Check that gh is authenticated - if ! gh auth status -h github.com &>/dev/null; then - echo "gh isn't authenticated to github.com." - echo "This is needed for our scripts that use gh." - echo -e "See docs regarding authentication: https://cli.github.com/manual/gh_auth_login" - exit - fi - - # Note: we need to set upstream as well or the gh pr create step will fail - # See: https://github.com/cli/cli/issues/575 - CURRENT_BRANCH=$(git branch | grep '\*' | cut -d' ' -f2-) - if [[ -z $(git config "branch.${CURRENT_BRANCH}.remote") ]]; then - echo "Doesn't look like you've pushed this branch to remote" - # Note: we need to set upstream as well or the gh pr create step will fail - # See: https://github.com/cli/cli/issues/575 - echo "Please set the upstream and then run the script" - exit 1 - fi - - # credit to jakwuh for this solution - # https://gist.github.com/DarrenN/8c6a5b969481725a4413#gistcomment-1971123 - CODE_SERVER_CURRENT_VERSION=$(node -pe "require('./package.json').version") - # Ask which version we should update to - # In the future, we'll automate this and determine the latest version automatically - echo "Current version: ${CODE_SERVER_CURRENT_VERSION}" - # The $'\n' adds a line break. See: https://stackoverflow.com/a/39581815/3015595 - read -r -p "What version of code-server do you want to update to?"$'\n' CODE_SERVER_VERSION_TO_UPDATE - - echo -e "Great! We'll prep a PR for updating to $CODE_SERVER_VERSION_TO_UPDATE\n" - $CMD rg -g '!yarn.lock' -g '!*.svg' --files-with-matches --fixed-strings "${CODE_SERVER_CURRENT_VERSION}" | $CMD xargs sd "$CODE_SERVER_CURRENT_VERSION" "$CODE_SERVER_VERSION_TO_UPDATE" - - # Ensure the tests are passing and code coverage is up-to-date - echo -e "Running unit tests and updating code coverage...\n" - $CMD yarn test:unit - - $CMD git commit -am "chore(release): bump version to $CODE_SERVER_VERSION_TO_UPDATE" - - # This runs from the root so that's why we use this path vs. ../../ - RELEASE_TEMPLATE_STRING=$(cat ./.github/PULL_REQUEST_TEMPLATE/release_template.md) - - echo -e "\nOpening a draft PR on GitHub" - # To read about these flags, visit the docs: https://cli.github.com/manual/gh_pr_create - $CMD gh pr create --base main --title "release: $CODE_SERVER_VERSION_TO_UPDATE" --body "$RELEASE_TEMPLATE_STRING" --reviewer @cdr/code-server-reviewers --repo cdr/code-server --draft - - # Open PR in browser - $CMD gh pr view --web -} - -main "$@" diff --git a/ci/build/test-standalone-release.sh b/ci/build/test-standalone-release.sh deleted file mode 100755 index 818aac8b99cf..000000000000 --- a/ci/build/test-standalone-release.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Makes sure the release works. -# This is to make sure we don't have Node version errors or any other -# compilation-related errors. -main() { - cd "$(dirname "${0}")/../.." - - local EXTENSIONS_DIR - EXTENSIONS_DIR="$(mktemp -d)" - - echo "Testing standalone release." - - # Note: using a basic theme extension because it doesn't update often and is more reliable for testing - ./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --install-extension wesbos.theme-cobalt2 - local installed_extensions - installed_extensions="$(./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --list-extensions 2>&1)" - # We use grep as wesbos.theme-cobalt2 may have dependency extensions that change. - if ! echo "$installed_extensions" | grep -q "wesbos.theme-cobalt2"; then - echo "Unexpected output from listing extensions:" - echo "$installed_extensions" - exit 1 - fi - - echo "Standalone release works correctly." -} - -main "$@" diff --git a/ci/dev/audit.sh b/ci/dev/audit.sh deleted file mode 100755 index 0142eac2a906..000000000000 --- a/ci/dev/audit.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -main() { - cd "$(dirname "$0")/../.." - - # Prevents integration with moderate or higher vulnerabilities - # Docs: https://github.com/IBM/audit-ci#options - yarn audit-ci --moderate -} - -main "$@" diff --git a/ci/dev/ci.sh b/ci/dev/ci.sh deleted file mode 100755 index daf4ecc69414..000000000000 --- a/ci/dev/ci.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -main() { - cd "$(dirname "$0")/../.." - - yarn fmt - yarn lint - yarn _audit - yarn test:unit -} - -main "$@" diff --git a/ci/dev/fmt.sh b/ci/dev/fmt.sh deleted file mode 100755 index 849440feee99..000000000000 --- a/ci/dev/fmt.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -main() { - cd "$(dirname "$0")/../.." - - local prettierExts - prettierExts=( - "*.js" - "*.ts" - "*.tsx" - "*.html" - "*.json" - "*.css" - "*.md" - "*.toml" - "*.yaml" - "*.yml" - "*.sh" - ) - prettier --write --loglevel=warn $( - git ls-files "${prettierExts[@]}" | grep -v "lib/vscode" | grep -v 'helm-chart' - ) - - doctoc --title '# FAQ' docs/FAQ.md >/dev/null - doctoc --title '# Setup Guide' docs/guide.md >/dev/null - doctoc --title '# Install' docs/install.md >/dev/null - doctoc --title '# npm Install Requirements' docs/npm.md >/dev/null - doctoc --title '# Contributing' docs/CONTRIBUTING.md >/dev/null - doctoc --title '# Maintaining' docs/MAINTAINING.md >/dev/null - doctoc --title '# Contributor Covenant Code of Conduct' docs/CODE_OF_CONDUCT.md >/dev/null - doctoc --title '# iPad' docs/ipad.md >/dev/null - doctoc --title '# Termux' docs/termux.md >/dev/null - - if [[ ${CI-} && $(git ls-files --other --modified --exclude-standard) ]]; then - echo "Files need generation or are formatted incorrectly:" - git -c color.ui=always status | grep --color=no '\[31m' - echo "Please run the following locally:" - echo " yarn fmt" - exit 1 - fi -} - -main "$@" diff --git a/ci/dev/gen_icons.sh b/ci/dev/gen_icons.sh deleted file mode 100755 index 7617d5e6dc13..000000000000 --- a/ci/dev/gen_icons.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh -set -eu - -main() { - cd src/browser/media - - # We need .ico for backwards compatibility. - # The other two are the only icon sizes required by Chrome and - # we use them for stuff like apple-touch-icon as well. - # https://web.dev/add-manifest/ - # - # This should be enough and we can always add more if there are problems. - - # -background defaults to white but we want it transparent. - # https://imagemagick.org/script/command-line-options.php#background - convert -quiet -background transparent -resize 256x256 favicon.svg favicon.ico - # We do not generate the pwa-icon from the favicon as they are slightly different - # designs and sizes. - # See favicon.afdesign and #2401 for details on the differences. - convert -quiet -background transparent -resize 192x192 pwa-icon.png pwa-icon-192.png - convert -quiet -background transparent -resize 512x512 pwa-icon.png pwa-icon-512.png - - # We use -quiet above to avoid https://github.com/ImageMagick/ImageMagick/issues/884 - - # The following adds dark mode support for the favicon as favicon-dark-support.svg - # There is no similar capability for pwas or .ico so we can only add support to the svg. - favicon_dark_style="" - # See https://stackoverflow.com/a/22901380/4283659 - # This escapes all newlines so that sed will accept them. - favicon_dark_style="$(printf "%s\n" "$favicon_dark_style" | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\n/g')" - sed "$( - cat -n <favicon-dark-support.svg -} - -main "$@" diff --git a/ci/dev/lint.sh b/ci/dev/lint.sh deleted file mode 100755 index 1a0c7d208921..000000000000 --- a/ci/dev/lint.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -main() { - cd "$(dirname "$0")/../.." - - eslint --max-warnings=0 --fix $(git ls-files "*.ts" "*.tsx" "*.js" | grep -v "lib/vscode") - stylelint $(git ls-files "*.css" | grep -v "lib/vscode") - tsc --noEmit --skipLibCheck - shellcheck -e SC2046,SC2164,SC2154,SC1091,SC1090,SC2002 $(git ls-files "*.sh" | grep -v "lib/vscode") - if command -v helm && helm kubeval --help >/dev/null; then - helm kubeval ci/helm-chart - fi - - cd lib/vscode - # Run this periodically in vanilla VS code to make sure we don't add any more warnings. - yarn -s eslint --max-warnings=3 - cd "$OLDPWD" -} - -main "$@" diff --git a/ci/dev/postinstall.sh b/ci/dev/postinstall.sh deleted file mode 100755 index 0ffa772f3ebf..000000000000 --- a/ci/dev/postinstall.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -main() { - cd "$(dirname "$0")/../.." - source ./ci/lib.sh - - # This installs the dependencies needed for testing - cd test - yarn - cd .. - - cd lib/vscode - yarn ${CI+--frozen-lockfile} - - symlink_asar -} - -main "$@" diff --git a/ci/dev/test-e2e.sh b/ci/dev/test-e2e.sh deleted file mode 100755 index 171e60992b3f..000000000000 --- a/ci/dev/test-e2e.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -main() { - cd "$(dirname "$0")/../.." - cd test - # We set these environment variables because they're used in the e2e tests - # they don't have to be these values, but these are the defaults - PASSWORD=e45432jklfdsab CODE_SERVER_ADDRESS=http://localhost:8080 yarn folio --config=config.ts --reporter=list "$@" -} - -main "$@" diff --git a/ci/dev/test-unit.sh b/ci/dev/test-unit.sh deleted file mode 100755 index f2e76ee561ea..000000000000 --- a/ci/dev/test-unit.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -main() { - cd "$(dirname "$0")/../.." - cd test/unit/test-plugin - make -s out/index.js - # We must keep jest in a sub-directory. See ../../test/package.json for more - # information. We must also run it from the root otherwise coverage will not - # include our source files. - cd "$OLDPWD" - CS_DISABLE_PLUGINS=true ./test/node_modules/.bin/jest "$@" -} - -main "$@" diff --git a/ci/dev/update-vscode.sh b/ci/dev/update-vscode.sh deleted file mode 100755 index 1b60d57c2df5..000000000000 --- a/ci/dev/update-vscode.sh +++ /dev/null @@ -1,133 +0,0 @@ -#!/usr/bin/env bash -# Description: This is a script to make the process of updating vscode versions easier -# Run it with `yarn update:vscode` and it will do the following: -# 1. Check that you have a remote called `vscode` -# 2. Ask you which version you want to upgrade to -# 3. Grab the exact version from the package.json i.e. 1.53.2 -# 4. Fetch the vscode remote branches to run the subtree update -# 5. Run the subtree update and pull in the vscode update -# 6. Commit the changes (including merge conflicts) -# 7. Open a draft PR - -set -euo pipefail - -# This function expects two arguments -# 1. the vscode version we're updating to -# 2. the list of merge conflict files -make_pr_body() { - local BODY="This PR updates vscode to $1 - -## TODOS - -- [ ] test editor locally -- [ ] test terminal locally -- [ ] make notes about any significant changes in docs/CONTRIBUTING.md#notes-about-changes - -## Files with conflicts (fix these) -$2" - echo "$BODY" -} - -main() { - cd "$(dirname "$0")/../.." - - # Check if the remote exists - # if it doesn't, we add it - if ! git config remote.vscode.url >/dev/null; then - echo "Could not find 'vscode' as a remote" - echo "Adding with: git remote add vscode https://github.com/microsoft/vscode.git" - git remote add vscode https://github.com/microsoft/vscode.git - fi - - # Ask which version we should update to - # In the future, we'll automate this and grab the latest version automatically - read -r -p "What version of VSCode would you like to update to? (i.e. 1.52) " VSCODE_VERSION_TO_UPDATE - - # Check that this version exists - if [[ -z $(git ls-remote --heads vscode release/"$VSCODE_VERSION_TO_UPDATE") ]]; then - echo "Oops, that doesn't look like a valid version." - echo "You entered: $VSCODE_VERSION_TO_UPDATE" - echo "Verify that this branches exists here: https://github.com/microsoft/vscode/branches/all?query=release%2F$VSCODE_VERSION_TO_UPDATE" - exit 1 - fi - - # Check that they have jq installed - if ! command -v jq &>/dev/null; then - echo "jq could not be found." - echo "We use this when looking up the exact version to update to in the package.json in VS Code." - echo -e "See docs here: https://stedolan.github.io/jq/download/" - exit 1 - fi - - # Note: `git subtree` returns 129 when installed, and prints help; - # but when uninstalled, returns 1. - set +e - git subtree &>/dev/null - if [ $? -ne 129 ]; then - echo "git-subtree could not be found." - echo "We use this to fetch and update the lib/vscode subtree." - echo -e "Please install git subtree." - exit 1 - fi - set -e - - # Grab the exact version from package.json - VSCODE_EXACT_VERSION=$(curl -s "https://raw.githubusercontent.com/microsoft/vscode/release/$VSCODE_VERSION_TO_UPDATE/package.json" | jq -r ".version") - - echo -e "Great! We'll prep a PR for updating to $VSCODE_EXACT_VERSION\n" - - # For some reason the subtree update doesn't work - # unless we fetch all the branches - echo -e "Fetching vscode branches..." - echo -e "Note: this might take a while" - git fetch vscode - - # Check if GitHub CLI is installed - if ! command -v gh &>/dev/null; then - echo "GitHub CLI could not be found." - echo "If you install it before you run this script next time, we'll open a draft PR for you!" - echo -e "See docs here: https://github.com/cli/cli#installation\n" - exit - fi - - # Push branch to remote if not already pushed - # If we don't do this, the opening a draft PR step won't work - # because it will stop and ask where you want to push the branch - CURRENT_BRANCH=$(git branch | grep '\*' | cut -d' ' -f2-) - if [[ -z $(git config "branch.${CURRENT_BRANCH}.remote") ]]; then - echo "Doesn't look like you've pushed this branch to remote" - echo -e "Pushing now using: git push origin $CURRENT_BRANCH\n" - # Note: we need to set upstream as well or the gh pr create step will fail - # See: https://github.com/cli/cli/issues/575 - echo "Please set the upstream and re-run the script" - exit 1 - fi - - echo "Going to try to update vscode for you..." - echo -e "Running: git subtree pull --prefix lib/vscode vscode release/${VSCODE_VERSION_TO_UPDATE} --squash\n" - # Try to run subtree update command - # Note: we add `|| true` because we want the script to keep running even if the squash fails - # We know the squash fails everytime because there will always be merge conflicts - git subtree pull --prefix lib/vscode vscode release/"${VSCODE_VERSION_TO_UPDATE}" --squash || true - - # Get the files with conflicts before we commit them - # so we can list them in the PR body as todo items - CONFLICTS=$(git diff --name-only --diff-filter=U | while read -r line; do echo "- [ ] $line"; done) - PR_BODY=$(make_pr_body "$VSCODE_EXACT_VERSION" "$CONFLICTS") - - echo -e "\nForcing a commit with conflicts" - echo "Note: this is intentional" - echo "If we don't do this, code review is impossible." - echo -e "For more info, see docs: docs/CONTRIBUTING.md#updating-vs-code\n" - # We need --no-verify to skip the husky pre-commit hook - # which fails because of the merge conflicts - git add . && git commit -am "chore(vscode): update to $VSCODE_EXACT_VERSION" --no-verify - - # Note: we can't open a draft PR unless their are changes. - # Hence why we do this after the subtree update. - echo "Opening a draft PR on GitHub" - # To read about these flags, visit the docs: https://cli.github.com/manual/gh_pr_create - gh pr create --base main --title "feat(vscode): update to version $VSCODE_EXACT_VERSION" --body "$PR_BODY" --reviewer @cdr/code-server-reviewers --repo cdr/code-server --draft -} - -main "$@" diff --git a/ci/dev/watch.ts b/ci/dev/watch.ts deleted file mode 100644 index 646da328b3f8..000000000000 --- a/ci/dev/watch.ts +++ /dev/null @@ -1,194 +0,0 @@ -import * as cp from "child_process" -import Bundler from "parcel-bundler" -import * as path from "path" - -async function main(): Promise { - try { - const watcher = new Watcher() - await watcher.watch() - } catch (error) { - console.error(error.message) - process.exit(1) - } -} - -class Watcher { - private readonly rootPath = path.resolve(__dirname, "../..") - private readonly vscodeSourcePath = path.join(this.rootPath, "lib/vscode") - - private static log(message: string, skipNewline = false): void { - process.stdout.write(message) - if (!skipNewline) { - process.stdout.write("\n") - } - } - - public async watch(): Promise { - let server: cp.ChildProcess | undefined - const restartServer = (): void => { - if (server) { - server.kill() - } - const s = cp.fork(path.join(this.rootPath, "out/node/entry.js"), process.argv.slice(2)) - console.log(`[server] spawned process ${s.pid}`) - s.on("exit", () => console.log(`[server] process ${s.pid} exited`)) - server = s - } - - const vscode = cp.spawn("yarn", ["watch"], { cwd: this.vscodeSourcePath }) - const tsc = cp.spawn("tsc", ["--watch", "--pretty", "--preserveWatchOutput"], { cwd: this.rootPath }) - const plugin = process.env.PLUGIN_DIR - ? cp.spawn("yarn", ["build", "--watch"], { cwd: process.env.PLUGIN_DIR }) - : undefined - const bundler = this.createBundler() - - const cleanup = (code?: number | null): void => { - Watcher.log("killing vs code watcher") - vscode.removeAllListeners() - vscode.kill() - - Watcher.log("killing tsc") - tsc.removeAllListeners() - tsc.kill() - - if (plugin) { - Watcher.log("killing plugin") - plugin.removeAllListeners() - plugin.kill() - } - - if (server) { - Watcher.log("killing server") - server.removeAllListeners() - server.kill() - } - - Watcher.log("killing bundler") - process.exit(code || 0) - } - - process.on("SIGINT", () => cleanup()) - process.on("SIGTERM", () => cleanup()) - - vscode.on("exit", (code) => { - Watcher.log("vs code watcher terminated unexpectedly") - cleanup(code) - }) - tsc.on("exit", (code) => { - Watcher.log("tsc terminated unexpectedly") - cleanup(code) - }) - if (plugin) { - plugin.on("exit", (code) => { - Watcher.log("plugin terminated unexpectedly") - cleanup(code) - }) - } - const bundle = bundler.bundle().catch(() => { - Watcher.log("parcel watcher terminated unexpectedly") - cleanup(1) - }) - bundler.on("buildEnd", () => { - console.log("[parcel] bundled") - }) - bundler.on("buildError", (error) => { - console.error("[parcel]", error) - }) - - vscode.stderr.on("data", (d) => process.stderr.write(d)) - tsc.stderr.on("data", (d) => process.stderr.write(d)) - if (plugin) { - plugin.stderr.on("data", (d) => process.stderr.write(d)) - } - - // From https://github.com/chalk/ansi-regex - const pattern = [ - "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", - "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))", - ].join("|") - const re = new RegExp(pattern, "g") - - /** - * Split stdout on newlines and strip ANSI codes. - */ - const onLine = (proc: cp.ChildProcess, callback: (strippedLine: string, originalLine: string) => void): void => { - let buffer = "" - if (!proc.stdout) { - throw new Error("no stdout") - } - proc.stdout.setEncoding("utf8") - proc.stdout.on("data", (d) => { - const data = buffer + d - const split = data.split("\n") - const last = split.length - 1 - - for (let i = 0; i < last; ++i) { - callback(split[i].replace(re, ""), split[i]) - } - - // The last item will either be an empty string (the data ended with a - // newline) or a partial line (did not end with a newline) and we must - // wait to parse it until we get a full line. - buffer = split[last] - }) - } - - let startingVscode = false - let startedVscode = false - onLine(vscode, (line, original) => { - console.log("[vscode]", original) - // Wait for watch-client since "Finished compilation" will appear multiple - // times before the client starts building. - if (!startingVscode && line.includes("Starting watch-client")) { - startingVscode = true - } else if (startingVscode && line.includes("Finished compilation")) { - if (startedVscode) { - bundle.then(restartServer) - } - startedVscode = true - } - }) - - onLine(tsc, (line, original) => { - // tsc outputs blank lines; skip them. - if (line !== "") { - console.log("[tsc]", original) - } - if (line.includes("Watching for file changes")) { - bundle.then(restartServer) - } - }) - - if (plugin) { - onLine(plugin, (line, original) => { - // tsc outputs blank lines; skip them. - if (line !== "") { - console.log("[plugin]", original) - } - if (line.includes("Watching for file changes")) { - bundle.then(restartServer) - } - }) - } - } - - private createBundler(out = "dist"): Bundler { - return new Bundler( - [ - path.join(this.rootPath, "src/browser/register.ts"), - path.join(this.rootPath, "src/browser/serviceWorker.ts"), - path.join(this.rootPath, "src/browser/pages/login.ts"), - path.join(this.rootPath, "src/browser/pages/vscode.ts"), - ], - { - outDir: path.join(this.rootPath, out), - cacheDir: path.join(this.rootPath, ".cache"), - minify: !!process.env.MINIFY, - logLevel: 1, - publicUrl: ".", - }, - ) - } -} - -main() diff --git a/ci/helm-chart/.helmignore b/ci/helm-chart/.helmignore deleted file mode 100644 index 0e8a0eb36f4c..000000000000 --- a/ci/helm-chart/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/ci/helm-chart/Chart.yaml b/ci/helm-chart/Chart.yaml deleted file mode 100644 index d9fac9a1c98c..000000000000 --- a/ci/helm-chart/Chart.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: v2 -name: code-server -description: A Helm chart for cdr/code-server - -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. -type: application - -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -# Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 1.0.3 - -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. Versions are not expected to -# follow Semantic Versioning. They should reflect the version the application is using. -appVersion: 3.9.3 diff --git a/ci/helm-chart/README.md b/ci/helm-chart/README.md deleted file mode 100644 index 7d045d44634a..000000000000 --- a/ci/helm-chart/README.md +++ /dev/null @@ -1,117 +0,0 @@ -# code-server - -![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 3.9.3](https://img.shields.io/badge/AppVersion-3.9.3-informational?style=flat-square) - -[code-server](https://github.com/cdr/code-server) code-server is VS Code running -on a remote server, accessible through the browser. - -This chart is community maintained by [@Matthew-Beckett](https://github.com/Matthew-Beckett) and [@alexgorbatchev](https://github.com/alexgorbatchev) - -## TL;DR; - -```console -$ git clone https://github.com/cdr/code-server -$ cd code-server -$ helm upgrade --install code-server ci/helm-chart -``` - -## Introduction - -This chart bootstraps a code-server deployment on a -[Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) -package manager. - -## Prerequisites - - - Kubernetes 1.6+ - -## Installing the Chart - -To install the chart with the release name `code-server`: - -```console -$ git clone https://github.com/cdr/code-server -$ cd code-server -$ helm upgrade --install code-server ci/helm-chart -``` - -The command deploys code-server on the Kubernetes cluster in the default -configuration. The [configuration](#configuration) section lists the parameters -that can be configured during installation. - -> **Tip**: List all releases using `helm list` - -## Uninstalling the Chart - -To uninstall/delete the `code-server` deployment: - -```console -$ helm delete code-server -``` - -The command removes all the Kubernetes components associated with the chart and -deletes the release. - -## Configuration - -The following table lists the configurable parameters of the code-server chart -and their default values. - -## Values - -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| affinity | object | `{}` | | -| extraArgs | list | `[]` | | -| extraConfigmapMounts | list | `[]` | | -| extraContainers | string | `""` | | -| extraSecretMounts | list | `[]` | | -| extraVars | list | `[]` | | -| extraVolumeMounts | list | `[]` | | -| fullnameOverride | string | `""` | | -| hostnameOverride | string | `""` | | -| image.pullPolicy | string | `"Always"` | | -| image.repository | string | `"codercom/code-server"` | | -| image.tag | string | `"3.9.3"` | | -| imagePullSecrets | list | `[]` | | -| ingress.enabled | bool | `false` | | -| nameOverride | string | `""` | | -| nodeSelector | object | `{}` | | -| persistence.accessMode | string | `"ReadWriteOnce"` | | -| persistence.annotations | object | `{}` | | -| persistence.enabled | bool | `true` | | -| persistence.size | string | `"1Gi"` | | -| podAnnotations | object | `{}` | | -| podSecurityContext | object | `{}` | | -| replicaCount | int | `1` | | -| resources | object | `{}` | | -| securityContext.enabled | bool | `true` | | -| securityContext.fsGroup | int | `1000` | | -| securityContext.runAsUser | int | `1000` | | -| service.port | int | `8443` | | -| service.type | string | `"ClusterIP"` | | -| serviceAccount.create | bool | `true` | | -| serviceAccount.name | string | `nil` | | -| tolerations | list | `[]` | | -| volumePermissions.enabled | bool | `true` | | -| volumePermissions.securityContext.runAsUser | int | `0` | | - -Specify each parameter using the `--set key=value[,key=value]` argument to `helm -install`. For example, - -```console -$ helm upgrade --install code-server \ - ci/helm-chart \ - --set persistence.enabled=false -``` - -The above command sets the the persistence storage to false. - -Alternatively, a YAML file that specifies the values for the above parameters -can be provided while installing the chart. For example, - -```console -$ helm upgrade --install code-server ci/helm-chart -f values.yaml -``` - -> **Tip**: You can use the default [values.yaml](values.yaml) diff --git a/ci/helm-chart/templates/NOTES.txt b/ci/helm-chart/templates/NOTES.txt deleted file mode 100644 index 17c25f646dc2..000000000000 --- a/ci/helm-chart/templates/NOTES.txt +++ /dev/null @@ -1,25 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "code-server.fullname" . }}) - export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") - echo http://$NODE_IP:$NODE_PORT -{{- else if contains "LoadBalancer" .Values.service.type }} - NOTE: It may take a few minutes for the LoadBalancer IP to be available. - You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "code-server.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "code-server.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "code-server.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") - echo "Visit http://127.0.0.1:8080 to use your application" - kubectl port-forward $POD_NAME 8080:80 -{{- end }} - -Administrator credentials: - - Password: echo $(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "code-server.fullname" . }} -o jsonpath="{.data.password}" | base64 --decode) diff --git a/ci/helm-chart/templates/_helpers.tpl b/ci/helm-chart/templates/_helpers.tpl deleted file mode 100644 index bb36e8c21972..000000000000 --- a/ci/helm-chart/templates/_helpers.tpl +++ /dev/null @@ -1,63 +0,0 @@ -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "code-server.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "code-server.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "code-server.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Common labels -*/}} -{{- define "code-server.labels" -}} -helm.sh/chart: {{ include "code-server.chart" . }} -{{ include "code-server.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "code-server.selectorLabels" -}} -app.kubernetes.io/name: {{ include "code-server.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "code-server.serviceAccountName" -}} -{{- if .Values.serviceAccount.create -}} - {{ default (include "code-server.fullname" .) .Values.serviceAccount.name }} -{{- else -}} - {{ default "default" .Values.serviceAccount.name }} -{{- end -}} -{{- end -}} diff --git a/ci/helm-chart/templates/deployment.yaml b/ci/helm-chart/templates/deployment.yaml deleted file mode 100644 index 9364a4706aa3..000000000000 --- a/ci/helm-chart/templates/deployment.yaml +++ /dev/null @@ -1,152 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "code-server.fullname" . }} - labels: - app.kubernetes.io/name: {{ include "code-server.name" . }} - helm.sh/chart: {{ include "code-server.chart" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/managed-by: {{ .Release.Service }} -spec: - replicas: 1 - strategy: - type: Recreate - selector: - matchLabels: - app.kubernetes.io/name: {{ include "code-server.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - template: - metadata: - labels: - app.kubernetes.io/name: {{ include "code-server.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - spec: - {{- if .Values.hostnameOverride }} - hostname: {{ .Values.hostnameOverride }} - {{- end }} - {{- if .Values.securityContext.enabled }} - securityContext: - fsGroup: {{ .Values.securityContext.fsGroup }} - {{- end }} - {{- if and .Values.volumePermissions.enabled .Values.persistence.enabled }} - initContainers: - - name: init-chmod-data - image: busybox:latest - imagePullPolicy: IfNotPresent - command: - - sh - - -c - - | - chown -R {{ .Values.securityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} /home/coder - securityContext: - runAsUser: {{ .Values.volumePermissions.securityContext.runAsUser }} - volumeMounts: - - name: data - mountPath: /home/coder - {{- end }} - containers: -{{- if .Values.extraContainers }} -{{ toYaml .Values.extraContainers | indent 8}} -{{- end }} - - name: {{ .Chart.Name }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - {{- if .Values.securityContext.enabled }} - securityContext: - runAsUser: {{ .Values.securityContext.runAsUser }} - {{- end }} - env: - {{- if .Values.extraVars }} -{{ toYaml .Values.extraVars | indent 10 }} - {{- end }} - - name: PASSWORD - valueFrom: - secretKeyRef: - {{- if .Values.existingSecret }} - name: {{ .Values.existingSecret }} - {{- else }} - name: {{ template "code-server.fullname" . }} - {{- end }} - key: password - {{- if .Values.extraArgs }} - args: -{{ toYaml .Values.extraArgs | indent 10 }} - {{- end }} - volumeMounts: - - name: data - mountPath: /home/coder - {{- range .Values.extraConfigmapMounts }} - - name: {{ .name }} - mountPath: {{ .mountPath }} - subPath: {{ .subPath | default "" }} - readOnly: {{ .readOnly }} - {{- end }} - {{- range .Values.extraSecretMounts }} - - name: {{ .name }} - mountPath: {{ .mountPath }} - readOnly: {{ .readOnly }} - {{- end }} - {{- range .Values.extraVolumeMounts }} - - name: {{ .name }} - mountPath: {{ .mountPath }} - subPath: {{ .subPath | default "" }} - readOnly: {{ .readOnly }} - {{- end }} - ports: - - name: http - containerPort: 8080 - protocol: TCP - livenessProbe: - httpGet: - path: / - port: http - readinessProbe: - httpGet: - path: / - port: http - resources: - {{- toYaml .Values.resources | nindent 12 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ template "code-server.serviceAccountName" . }} - volumes: - - name: data - {{- if .Values.persistence.enabled }} - {{- if not .Values.persistence.hostPath }} - persistentVolumeClaim: - claimName: {{ .Values.persistence.existingClaim | default (include "code-server.fullname" .) }} - {{- else }} - hostPath: - path: {{ .Values.persistence.hostPath }} - type: Directory - {{- end -}} - {{- else }} - emptyDir: {} - {{- end -}} - {{- range .Values.extraSecretMounts }} - - name: {{ .name }} - secret: - secretName: {{ .secretName }} - defaultMode: {{ .defaultMode }} - {{- end }} - {{- range .Values.extraVolumeMounts }} - - name: {{ .name }} - {{- if .existingClaim }} - persistentVolumeClaim: - claimName: {{ .existingClaim }} - {{- else }} - hostPath: - path: {{ .hostPath }} - type: Directory - {{- end }} - {{- end }} diff --git a/ci/helm-chart/templates/ingress.yaml b/ci/helm-chart/templates/ingress.yaml deleted file mode 100644 index 07a3abd0b693..000000000000 --- a/ci/helm-chart/templates/ingress.yaml +++ /dev/null @@ -1,41 +0,0 @@ -{{- if .Values.ingress.enabled -}} -{{- $fullName := include "code-server.fullname" . -}} -{{- $svcPort := .Values.service.port -}} -{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} -apiVersion: networking.k8s.io/v1beta1 -{{- else -}} -apiVersion: extensions/v1beta1 -{{- end }} -kind: Ingress -metadata: - name: {{ $fullName }} - labels: - {{- include "code-server.labels" . | nindent 4 }} - {{- with .Values.ingress.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - {{- if .Values.ingress.tls }} - tls: - {{- range .Values.ingress.tls }} - - hosts: - {{- range .hosts }} - - {{ . | quote }} - {{- end }} - secretName: {{ .secretName }} - {{- end }} - {{- end }} - rules: - {{- range .Values.ingress.hosts }} - - host: {{ .host | quote }} - http: - paths: - {{- range .paths }} - - path: {{ . }} - backend: - serviceName: {{ $fullName }} - servicePort: {{ $svcPort }} - {{- end }} - {{- end }} - {{- end }} diff --git a/ci/helm-chart/templates/pvc.yaml b/ci/helm-chart/templates/pvc.yaml deleted file mode 100644 index 2f1c87405886..000000000000 --- a/ci/helm-chart/templates/pvc.yaml +++ /dev/null @@ -1,29 +0,0 @@ -{{- if and (and .Values.persistence.enabled (not .Values.persistence.existingClaim)) (not .Values.persistence.hostPath) }} -kind: PersistentVolumeClaim -apiVersion: v1 -metadata: - name: {{ include "code-server.fullname" . }} - namespace: {{ .Release.Namespace }} -{{- with .Values.persistence.annotations }} - annotations: -{{ toYaml . | indent 4 }} -{{- end }} - labels: - app.kubernetes.io/name: {{ include "code-server.name" . }} - helm.sh/chart: {{ include "code-server.chart" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/managed-by: {{ .Release.Service }} -spec: - accessModes: - - {{ .Values.persistence.accessMode | quote }} - resources: - requests: - storage: {{ .Values.persistence.size | quote }} -{{- if .Values.persistence.storageClass }} -{{- if (eq "-" .Values.persistence.storageClass) }} - storageClassName: "" -{{- else }} - storageClassName: "{{ .Values.persistence.storageClass }}" -{{- end }} -{{- end }} -{{- end }} diff --git a/ci/helm-chart/templates/secrets.yaml b/ci/helm-chart/templates/secrets.yaml deleted file mode 100644 index 6c600417a516..000000000000 --- a/ci/helm-chart/templates/secrets.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "code-server.fullname" . }} - annotations: - "helm.sh/hook": "pre-install" - labels: - app.kubernetes.io/name: {{ include "code-server.name" . }} - helm.sh/chart: {{ include "code-server.chart" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/managed-by: {{ .Release.Service }} -type: Opaque -data: - {{ if .Values.password }} - password: "{{ .Values.password | b64enc }}" - {{ else }} - password: "{{ randAlphaNum 24 | b64enc }}" - {{ end }} diff --git a/ci/helm-chart/templates/service.yaml b/ci/helm-chart/templates/service.yaml deleted file mode 100644 index 038b6cd0d23f..000000000000 --- a/ci/helm-chart/templates/service.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ include "code-server.fullname" . }} - labels: - app.kubernetes.io/name: {{ include "code-server.name" . }} - helm.sh/chart: {{ include "code-server.chart" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/managed-by: {{ .Release.Service }} -spec: - type: {{ .Values.service.type }} - ports: - - port: {{ .Values.service.port }} - targetPort: http - protocol: TCP - name: http - selector: - app.kubernetes.io/name: {{ include "code-server.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/ci/helm-chart/templates/serviceaccount.yaml b/ci/helm-chart/templates/serviceaccount.yaml deleted file mode 100644 index df9e1e37562b..000000000000 --- a/ci/helm-chart/templates/serviceaccount.yaml +++ /dev/null @@ -1,11 +0,0 @@ -{{- if or .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app.kubernetes.io/name: {{ include "code-server.name" . }} - helm.sh/chart: {{ include "code-server.chart" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - name: {{ template "code-server.serviceAccountName" . }} -{{- end -}} diff --git a/ci/helm-chart/templates/tests/test-connection.yaml b/ci/helm-chart/templates/tests/test-connection.yaml deleted file mode 100644 index 2e67f56ec64c..000000000000 --- a/ci/helm-chart/templates/tests/test-connection.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: "{{ include "code-server.fullname" . }}-test-connection" - labels: - app.kubernetes.io/name: {{ include "code-server.name" . }} - helm.sh/chart: {{ include "code-server.chart" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - annotations: - "helm.sh/hook": test-success -spec: - containers: - - name: wget - image: busybox - command: ['wget'] - args: ['{{ include "code-server.fullname" . }}:{{ .Values.service.port }}'] - restartPolicy: Never diff --git a/ci/helm-chart/values.yaml b/ci/helm-chart/values.yaml deleted file mode 100644 index 108fb0568990..000000000000 --- a/ci/helm-chart/values.yaml +++ /dev/null @@ -1,163 +0,0 @@ -# Default values for code-server. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -replicaCount: 1 - -image: - repository: codercom/code-server - tag: '3.9.3' - pullPolicy: Always - -imagePullSecrets: [] -nameOverride: "" -fullnameOverride: "" -hostnameOverride: "" - -serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - -podAnnotations: {} - -podSecurityContext: {} - # fsGroup: 2000 - -securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 - -service: - type: ClusterIP - port: 8080 - -ingress: - enabled: false - #annotations: - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: "true" - #hosts: - # - host: code-server.example.loc - # paths: - # - / - - #tls: - # - secretName: code-server - # hosts: - # - code-server.example.loc - -# Optional additional arguments -extraArgs: [] -# - --allow-http -# - --no-auth - -# Optional additional environment variables -extraVars: [] -# - name: DISABLE_TELEMETRY -# value: true - -## -## Init containers parameters: -## volumePermissions: Change the owner of the persist volume mountpoint to RunAsUser:fsGroup -## -volumePermissions: - enabled: true - securityContext: - runAsUser: 0 - -## Pod Security Context -## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ -## -securityContext: - enabled: true - fsGroup: 1000 - runAsUser: 1000 - -resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 1000Mi - -nodeSelector: {} - -tolerations: [] - -affinity: {} - -## Persist data to a persistent volume -persistence: - enabled: true - ## code-server data Persistent Volume Storage Class - ## If defined, storageClassName: - ## If set to "-", storageClassName: "", which disables dynamic provisioning - ## If undefined (the default) or set to null, no storageClassName spec is - ## set, choosing the default provisioner. (gp2 on AWS, standard on - ## GKE, AWS & OpenStack) - ## - # storageClass: "-" - accessMode: ReadWriteOnce - size: 10Gi - annotations: {} - # existingClaim: "" - # hostPath: /data - -serviceAccount: - create: true - name: - -## Enable an Specify container in extraContainers. -## This is meant to allow adding code-server dependencies, like docker-dind. -extraContainers: | -#- name: docker-dind -# image: docker:19.03-dind -# imagePullPolicy: IfNotPresent -# resources: -# requests: -# cpu: 250m -# memory: 256M -# securityContext: -# privileged: true -# procMount: Default -# env: -# - name: DOCKER_TLS_CERTDIR -# value: "" -# - name: DOCKER_DRIVER -# value: "overlay2" - -## Additional code-server secret mounts -extraSecretMounts: [] - # - name: secret-files - # mountPath: /etc/secrets - # secretName: code-server-secret-files - # readOnly: true - -## Additional code-server volume mounts -extraVolumeMounts: [] - # - name: extra-volume - # mountPath: /mnt/volume - # readOnly: true - # existingClaim: volume-claim - # hostPath: "" - -extraConfigmapMounts: [] - # - name: certs-configmap - # mountPath: /etc/code-server/ssl/ - # subPath: certificates.crt # (optional) - # configMap: certs-configmap - # readOnly: true diff --git a/ci/lib.sh b/ci/lib.sh deleted file mode 100755 index dbde849be20c..000000000000 --- a/ci/lib.sh +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -pushd() { - builtin pushd "$@" >/dev/null -} - -popd() { - builtin popd >/dev/null -} - -pkg_json_version() { - jq -r .version package.json -} - -vscode_version() { - jq -r .version lib/vscode/package.json -} - -os() { - local os - os=$(uname | tr '[:upper:]' '[:lower:]') - if [[ $os == "linux" ]]; then - # Alpine's ldd doesn't have a version flag but if you use an invalid flag - # (like --version) it outputs the version to stderr and exits with 1. - local ldd_output - ldd_output=$(ldd --version 2>&1 || true) - if echo "$ldd_output" | grep -iq musl; then - os="alpine" - fi - elif [[ $os == "darwin" ]]; then - os="macos" - fi - echo "$os" -} - -arch() { - case "$(uname -m)" in - aarch64) - echo arm64 - ;; - x86_64 | amd64) - echo amd64 - ;; - *) - echo "unknown architecture $(uname -a)" - exit 1 - ;; - esac -} - -# Grabs the most recent ci.yaml github workflow run that was successful and triggered from the same commit being pushd. -# This will contain the artifacts we want. -# https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs -get_artifacts_url() { - local artifacts_url - local workflow_runs_url="repos/:owner/:repo/actions/workflows/ci.yaml/runs?status=success&event=pull_request" - # For releases, we look for run based on the branch name v$code_server_version - # example: v3.9.3 - local version_branch="v$VERSION" - artifacts_url=$(gh api "$workflow_runs_url" | jq -r ".workflow_runs[] | select(.head_branch == \"$version_branch\") | .artifacts_url" | head -n 1) - if [[ -z "$artifacts_url" ]]; then - echo >&2 "ERROR: artifacts_url came back empty" - echo >&2 "We looked for a successful run triggered by a pull_request with for code-server version: $code_server_version and a branch named $version_branch" - echo >&2 "URL used for gh API call: $workflow_runs_url" - exit 1 - fi - - echo "$artifacts_url" -} - -# Grabs the artifact's download url. -# https://developer.github.com/v3/actions/artifacts/#list-workflow-run-artifacts -get_artifact_url() { - local artifact_name="$1" - gh api "$(get_artifacts_url)" | jq -r ".artifacts[] | select(.name == \"$artifact_name\") | .archive_download_url" | head -n 1 -} - -# Uses the above two functions to download a artifact into a directory. -download_artifact() { - local artifact_name="$1" - local dst="$2" - - local tmp_file - tmp_file="$(mktemp)" - - gh api "$(get_artifact_url "$artifact_name")" >"$tmp_file" - unzip -q -o "$tmp_file" -d "$dst" - rm "$tmp_file" -} - -rsync() { - command rsync -a --del "$@" -} - -VERSION="$(pkg_json_version)" -export VERSION -ARCH="$(arch)" -export ARCH -OS=$(os) -export OS - -# RELEASE_PATH is the destination directory for the release from the root. -# Defaults to release -RELEASE_PATH="${RELEASE_PATH-release}" - -# VS Code bundles some modules into an asar which is an archive format that -# works like tar. It then seems to get unpacked into node_modules.asar. -# -# I don't know why they do this but all the dependencies they bundle already -# exist in node_modules so just symlink it. We have to do this since not only VS -# Code itself but also extensions will look specifically in this directory for -# files (like the ripgrep binary or the oniguruma wasm). -symlink_asar() { - if [ ! -L node_modules.asar ]; then - if [ "${WINDIR-}" ]; then - # mklink takes the link name first. - mklink /J node_modules.asar node_modules - else - # ln takes the link name second. - ln -s node_modules node_modules.asar - fi - fi -} diff --git a/ci/release-image/Dockerfile b/ci/release-image/Dockerfile deleted file mode 100644 index 4b63701494a2..000000000000 --- a/ci/release-image/Dockerfile +++ /dev/null @@ -1,46 +0,0 @@ -FROM debian:10 - -RUN apt-get update \ - && apt-get install -y \ - curl \ - dumb-init \ - zsh \ - htop \ - locales \ - man \ - nano \ - git \ - procps \ - openssh-client \ - sudo \ - vim.tiny \ - lsb-release \ - && rm -rf /var/lib/apt/lists/* - -# https://wiki.debian.org/Locale#Manually -RUN sed -i "s/# en_US.UTF-8/en_US.UTF-8/" /etc/locale.gen \ - && locale-gen -ENV LANG=en_US.UTF-8 - -RUN adduser --gecos '' --disabled-password coder && \ - echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd - -RUN ARCH="$(dpkg --print-architecture)" && \ - curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v0.5/fixuid-0.5-linux-$ARCH.tar.gz" | tar -C /usr/local/bin -xzf - && \ - chown root:root /usr/local/bin/fixuid && \ - chmod 4755 /usr/local/bin/fixuid && \ - mkdir -p /etc/fixuid && \ - printf "user: coder\ngroup: coder\n" > /etc/fixuid/config.yml - -COPY release-packages/code-server*.deb /tmp/ -COPY ci/release-image/entrypoint.sh /usr/bin/entrypoint.sh -RUN dpkg -i /tmp/code-server*$(dpkg --print-architecture).deb && rm /tmp/code-server*.deb - -EXPOSE 8080 -# This way, if someone sets $DOCKER_USER, docker-exec will still work as -# the uid will remain the same. note: only relevant if -u isn't passed to -# docker-run. -USER 1000 -ENV USER=coder -WORKDIR /home/coder -ENTRYPOINT ["/usr/bin/entrypoint.sh", "--bind-addr", "0.0.0.0:8080", "."] diff --git a/ci/release-image/build.sh b/ci/release-image/build.sh deleted file mode 100755 index 5969e15ae9a6..000000000000 --- a/ci/release-image/build.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -main() { - cd "$(dirname "$0")/../.." - source ./ci/lib.sh - - docker build -t "codercom/code-server-$ARCH:$VERSION" -f ./ci/release-image/Dockerfile . -} - -main "$@" diff --git a/ci/release-image/entrypoint.sh b/ci/release-image/entrypoint.sh deleted file mode 100755 index 1c8c8bfffb7a..000000000000 --- a/ci/release-image/entrypoint.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -set -eu - -# We do this first to ensure sudo works below when renaming the user. -# Otherwise the current container UID may not exist in the passwd database. -eval "$(fixuid -q)" - -if [ "${DOCKER_USER-}" ] && [ "$DOCKER_USER" != "$USER" ]; then - echo "$DOCKER_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers.d/nopasswd >/dev/null - # Unfortunately we cannot change $HOME as we cannot move any bind mounts - # nor can we bind mount $HOME into a new home as that requires a privileged container. - sudo usermod --login "$DOCKER_USER" coder - sudo groupmod -n "$DOCKER_USER" coder - - USER="$DOCKER_USER" - - sudo sed -i "/coder/d" /etc/sudoers.d/nopasswd -fi - -dumb-init /usr/bin/code-server "$@" diff --git a/ci/steps/brew-bump.sh b/ci/steps/brew-bump.sh deleted file mode 100755 index 0d669f294442..000000000000 --- a/ci/steps/brew-bump.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -main() { - cd "$(dirname "$0")/../.." - # Only sourcing this so we get access to $VERSION - source ./ci/lib.sh - # Find the docs for bump-formula-pr here - # https://github.com/Homebrew/brew/blob/master/Library/Homebrew/dev-cmd/bump-formula-pr.rb#L18 - brew bump-formula-pr --force --version="${VERSION}" code-server --no-browse --no-audit -} - -main "$@" diff --git a/ci/steps/build-docker-image.sh b/ci/steps/build-docker-image.sh deleted file mode 100755 index 8ae5855bdfc7..000000000000 --- a/ci/steps/build-docker-image.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -main() { - cd "$(dirname "$0")/../.." - source ./ci/lib.sh - - ./ci/release-image/build.sh - - mkdir -p release-images - docker save "codercom/code-server-$ARCH:$VERSION" >"release-images/code-server-$ARCH-$VERSION.tar" -} - -main "$@" diff --git a/ci/steps/publish-npm.sh b/ci/steps/publish-npm.sh deleted file mode 100755 index 934a5decd643..000000000000 --- a/ci/steps/publish-npm.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -main() { - cd "$(dirname "$0")/../.." - source ./ci/lib.sh - - if [[ ${CI-} ]]; then - echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" >~/.npmrc - fi - - download_artifact npm-package ./release-npm-package - # https://github.com/actions/upload-artifact/issues/38 - tar -xzf release-npm-package/package.tar.gz - yarn publish --non-interactive release -} - -main "$@" diff --git a/ci/steps/push-docker-manifest.sh b/ci/steps/push-docker-manifest.sh deleted file mode 100755 index 08d0fdacf2d1..000000000000 --- a/ci/steps/push-docker-manifest.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -main() { - cd "$(dirname "$0")/../.." - source ./ci/lib.sh - - download_artifact release-images ./release-images - if [[ ${CI-} ]]; then - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin - fi - - for img in ./release-images/*; do - docker load -i "$img" - done - - # We have to ensure the amd64 and arm64 images exist on the remote registry - # in order to build the manifest. - # We don't put the arch in the tag to avoid polluting the main repository. - # These other repositories are private so they don't pollute our organization namespace. - docker push "codercom/code-server-amd64:$VERSION" - docker push "codercom/code-server-arm64:$VERSION" - - export DOCKER_CLI_EXPERIMENTAL=enabled - - docker manifest create "codercom/code-server:$VERSION" \ - "codercom/code-server-amd64:$VERSION" \ - "codercom/code-server-arm64:$VERSION" - docker manifest push --purge "codercom/code-server:$VERSION" - - docker manifest create "codercom/code-server:latest" \ - "codercom/code-server-amd64:$VERSION" \ - "codercom/code-server-arm64:$VERSION" - docker manifest push --purge "codercom/code-server:latest" -} - -main "$@" diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md deleted file mode 100644 index fe14b3a64000..000000000000 --- a/docs/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,79 +0,0 @@ - - - -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -- Using welcoming and inclusive language -- Being respectful of differing viewpoints and experiences -- Gracefully accepting constructive criticism -- Focusing on what is best for the community -- Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -- The use of sexualized language or imagery and unwelcome sexual attention or - advances -- Trolling, insulting/derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or electronic - address, without explicit permission -- Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at opensource@coder.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md deleted file mode 100644 index 22f4feb861f4..000000000000 --- a/docs/CONTRIBUTING.md +++ /dev/null @@ -1,158 +0,0 @@ - - -# Contributing - -- [Pull Requests](#pull-requests) -- [Requirements](#requirements) -- [Development Workflow](#development-workflow) - - [Updating VS Code](#updating-vs-code) - - [Notes about Changes](#notes-about-changes) -- [Build](#build) -- [Structure](#structure) - - [Modifications to VS Code](#modifications-to-vs-code) - - [Currently Known Issues](#currently-known-issues) - - - -- [Detailed CI and build process docs](../ci) - -## Pull Requests - -Please create a [GitHub Issue](https://github.com/cdr/code-server/issues) for each issue -you'd like to address unless the proposed fix is minor. - -In your Pull Requests (PR), link to the issue that the PR solves. - -Please ensure that the base of your PR is the **master** branch. (Note: The default -GitHub branch is the latest release branch, though you should point all of your changes to be merged into -master). - -## Requirements - -The prerequisites for contributing to code-server are almost the same as those for -[VS Code](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites). -There are several differences, however. Here is what is needed: - -- `node` v12.x or greater -- `git` v2.x or greater -- [`yarn`](https://classic.yarnpkg.com/en/) - - used to install JS packages and run scripts -- [`nfpm`](https://classic.yarnpkg.com/en/) - - used to build `.deb` and `.rpm` packages -- [`jq`](https://stedolan.github.io/jq/) - - used to build code-server releases -- [`gnupg`](https://gnupg.org/index.html) - - all commits must be signed an verified - - see GitHub's ["Managing commit signature verification"](https://docs.github.com/en/github/authenticating-to-github/managing-commit-signature-verification) or follow [this tutorial](https://joeprevite.com/verify-commits-on-github) -- `build-essential` (Linux) - - `apt-get install -y build-essential` - used by VS Code -- `rsync` and `unzip` - - used for code-server releases - -## Development Workflow - -```shell -yarn -yarn watch -# Visit http://localhost:8080 once the build is completed. -``` - -`yarn watch` will live reload changes to the source. - -### Updating VS Code - -Updating VS Code requires `git subtree`. On some rpm-based Linux distros, `git subtree` is not included by default, and needs to be installed separately. -To install, run `dnf install git-subtree` or `yum install git-subtree` as necessary. - -To update VS Code, follow these steps: - -1. Run `yarn update:vscode`. -2. Enter a version. Ex. 1.53 -3. This will open a draft PR for you. -4. There will be merge conflicts. First commit them. - 1. We do this because if we don't, it will be impossible to review your PR. -5. Once they're all fixed, test code-server locally and make sure it all works. - -#### Notes about Changes - -- watch out for updates to `lib/vscode/src/vs/code/browser/workbench/workbench.html`. You may need to make changes to `src/browser/pages/vscode.html` - -## Build - -You can build using: - -```shell -yarn build -yarn build:vscode -yarn release -``` - -Run your build with: - -```shell -cd release -yarn --production -# Runs the built JavaScript with Node. -node . -``` - -Build the release packages (make sure that you run `yarn release` first): - -```shell -yarn release:standalone -yarn test:standalone-release -yarn package -``` - -NOTE: On Linux, the currently running distro will become the minimum supported version. -In our GitHub Actions CI, we use CentOS 7 for maximum compatibility. -If you need your builds to support older distros, run the build commands -inside a Docker container with all the build requirements installed. - -## Structure - -The `code-server` script serves an HTTP API for login and starting a remote VS Code process. - -The CLI code is in [src/node](../src/node) and the HTTP routes are implemented in -[src/node/routes](../src/node/routes). - -Most of the meaty parts are in the VS Code portion of the codebase under [lib/vscode](../lib/vscode), which we described next. - -### Modifications to VS Code - -In v1 of code-server, we had a patch of VS Code that split the codebase into a front-end -and a server. The front-end consisted of all UI code, while the server ran the extensions -and exposed an API to the front-end for file access and all UI needs. - -Over time, Microsoft added support to VS Code to run it on the web. They have made -the front-end open source, but not the server. As such, code-server v2 (and later) uses -the VS Code front-end and implements the server. We do this by using a git subtree to fork and modify VS Code. This code lives under [lib/vscode](../lib/vscode). - -Some noteworthy changes in our version of VS Code: - -- Adding our build file, which includes our code and VS Code's web code -- Allowing multiple extension directories (both user and built-in) -- Modifying the loader, websocket, webview, service worker, and asset requests to - use the URL of the page as a base (and TLS, if necessary for the websocket) -- Sending client-side telemetry through the server -- Allowing modification of the display language -- Making it possible for us to load code on the client -- Making it possible to install extensions of any kind -- Fixing issue with getting disconnected when your machine sleeps or hibernates -- Adding connection type to web socket query parameters - -As the web portion of VS Code matures, we'll be able to shrink and possibly -eliminate our modifications. In the meantime, upgrading the VS Code version requires -us to ensure that our changes are still applied and work as intended. In the future, -we'd like to run VS Code unit tests against our builds to ensure that features -work as expected. - -**Note**: We have [extension docs](../ci/README.md) on the CI and build system. - -If the functionality you're working on does NOT depend on code from VS Code, please -move it out and into code-server. - -### Currently Known Issues - -- Creating custom VS Code extensions and debugging them doesn't work -- Extension profiling and tips are currently disabled diff --git a/docs/FAQ.md b/docs/FAQ.md deleted file mode 100644 index b071cdb05881..000000000000 --- a/docs/FAQ.md +++ /dev/null @@ -1,463 +0,0 @@ - - -# FAQ - -- [Questions?](#questions) -- [iPad Status?](#ipad-status) -- [Community Projects (awesome-code-server)](#community-projects-awesome-code-server) -- [How can I reuse my VS Code configuration?](#how-can-i-reuse-my-vs-code-configuration) -- [Differences compared to VS Code?](#differences-compared-to-vs-code) - - [Installing an extension](#installing-an-extension) -- [How can I request a missing extension?](#how-can-i-request-a-missing-extension) -- [Installing an extension manually](#installing-an-extension-manually) -- [How do I configure the marketplace URL?](#how-do-i-configure-the-marketplace-url) -- [Where are extensions stored?](#where-are-extensions-stored) -- [How is this different from VS Code Codespaces?](#how-is-this-different-from-vs-code-codespaces) -- [How should I expose code-server to the internet?](#how-should-i-expose-code-server-to-the-internet) -- [Can I store my password hashed?](#can-i-store-my-password-hashed) -- [How do I securely access web services?](#how-do-i-securely-access-web-services) - - [Sub-paths](#sub-paths) - - [Sub-domains](#sub-domains) -- [Why does the code-server proxy strip `/proxy/` from the request path?](#why-does-the-code-server-proxy-strip-proxyport-from-the-request-path) - - [Proxying to Create React App](#proxying-to-create-react-app) -- [Multi-tenancy](#multi-tenancy) -- [Docker in code-server container?](#docker-in-code-server-container) -- [How can I disable telemetry?](#how-can-i-disable-telemetry) -- [How does code-server decide what workspace or folder to open?](#how-does-code-server-decide-what-workspace-or-folder-to-open) -- [How do I debug issues with code-server?](#how-do-i-debug-issues-with-code-server) -- [Heartbeat File](#heartbeat-file) -- [Healthz endpoint](#healthz-endpoint) -- [How does the config file work?](#how-does-the-config-file-work) -- [Isn't an install script piped into sh insecure?](#isnt-an-install-script-piped-into-sh-insecure) -- [How do I make my keyboard shortcuts work?](#how-do-i-make-my-keyboard-shortcuts-work) -- [How do I access my Documents/Downloads/Desktop folders in code-server on OSX?](#how-do-i-access-my-documentsdownloadsdesktop-folders-in-code-server-on-osx) -- [Differences compared to Theia?](#differences-compared-to-theia) -- [`$HTTP_PROXY`, `$HTTPS_PROXY`, `$NO_PROXY`](#http_proxy-https_proxy-no_proxy) -- [Enterprise](#enterprise) - - - -## Questions? - -Please file all questions and support requests at . - -## iPad Status? - -Please see [./ipad.md](./ipad.md). - -## Community Projects (awesome-code-server) - -Visit the [awesome-code-server](https://github.com/cdr/awesome-code-server) repository to view community projects and guides with code-server! Feel free to add your own! - -## How can I reuse my VS Code configuration? - -The very popular [Settings Sync](https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync) extension works. - -You can also pass `--user-data-dir ~/.vscode` to reuse your existing VS Code extensions and configuration. - -Or copy `~/.vscode` into `~/.local/share/code-server`. - -## Differences compared to VS Code? - -`code-server` takes the open source core of VS Code and allows you to run it in the browser. -However, it is not entirely equivalent to Microsoft's VS Code. - -While the core of VS Code is open source, the marketplace and many published Microsoft extensions are not. - -Furthermore, Microsoft prohibits the use of any non-Microsoft VS Code from accessing their marketplace. - -See the [TOS](https://cdn.vsassets.io/v/M146_20190123.39/_content/Microsoft-Visual-Studio-Marketplace-Terms-of-Use.pdf). - -> Marketplace Offerings are intended for use only with Visual Studio Products and Services -> and you may only install and use Marketplace Offerings with Visual Studio Products and Services. - -As a result, we cannot offer any extensions on the Microsoft marketplace. Instead, -we have created our own marketplace for open source extensions. -It works by scraping GitHub for VS Code extensions and building them. It's not perfect but getting -better by the day with more and more extensions. - -These are the closed source extensions presently unavailable: - -1. [Live Share](https://visualstudio.microsoft.com/services/live-share) - - We may implement something similar, see [#33](https://github.com/cdr/code-server/issues/33) -1. [Remote Extensions (SSH, Containers, WSL)](https://github.com/microsoft/vscode-remote-release) - - We may reimplement these at some point, see [#1315](https://github.com/cdr/code-server/issues/1315) - -For more about the closed source parts of VS Code, see [vscodium/vscodium](https://github.com/VSCodium/vscodium#why-does-this-exist). - -### Installing an extension - -Extensions can be installed from the marketplace using the extensions sidebar in -code-server or from the command line: - -```shell -code-server --install-extension -# example: code-server --install-extension wesbos.theme-cobalt2 -``` - -## How can I request a missing extension? - -We are currently in the process of transitioning to [Open VSX](https://open-vsx.org/). -Once -is implemented, we can fully make this transition. Therefore, we are no longer -accepting new requests for extension requests. - -Instead, we suggest one of the following: - -- [Switch to Open VSX](#how-do-i-configure-the-marketplace-url) now -- Download and [install the extension manually](#installing-an-extension-manually) - -## Installing an extension manually - -If an extension is not available from the marketplace or does not work, you can -grab its VSIX from its GitHub releases or build it yourself. - -Once you have downloaded the VSIX to the remote machine you can either: - -- Run the `Extensions: Install from VSIX` command in the Command Palette. -- Use `code-server --install-extension ` - -You can also download extensions from the command line. For instance, downloading off OpenVSX can be done like this: - -```shell -SERVICE_URL=https://open-vsx.org/vscode/gallery ITEM_URL=https://open-vsx.org/vscode/item code-server --install-extension -``` - -## How do I configure the marketplace URL? - -If you have your own marketplace that implements the VS Code Extension Gallery API, it is possible to -point code-server to it by setting `$SERVICE_URL` and `$ITEM_URL`. These correspond directly -to `serviceUrl` and `itemUrl` in VS Code's `product.json`. - -e.g. to use [open-vsx.org](https://open-vsx.org): - -```bash -export SERVICE_URL=https://open-vsx.org/vscode/gallery -export ITEM_URL=https://open-vsx.org/vscode/item -``` - -While you can technically use Microsoft's marketplace with these, please do not do so as it -is against their terms of use. See [above](#differences-compared-to-vs-code) and this -discussion regarding the use of the Microsoft URLs in forks: - - - -See also [VSCodium's docs](https://github.com/VSCodium/vscodium/blob/master/DOCS.md#extensions--marketplace). - -These variables are most valuable to our enterprise customers for whom we have a self hosted marketplace product. - -## Where are extensions stored? - -Defaults to `~/.local/share/code-server/extensions`. - -If the `XDG_DATA_HOME` environment variable is set the data directory will be -`$XDG_DATA_HOME/code-server/extensions`. In general we try to follow the XDG directory spec. - -You can install an extension on the CLI with: - -```bash -# From the Coder extension marketplace -code-server --install-extension ms-python.python - -# From a downloaded VSIX on the file system -code-server --install-extension downloaded-ms-python.python.vsix -``` - -## How is this different from VS Code Codespaces? - -VS Code Codespaces is a closed source and paid service by Microsoft. It also allows you to access -VS Code via the browser. - -However, code-server is free, open source and can be run on any machine without any limitations. - -While you can self host environments with VS Code Codespaces, you still need an Azure billing -account and you have to access VS Code via the Codespaces web dashboard instead of directly -connecting to your instance. - -## How should I expose code-server to the internet? - -Please follow [./guide.md](./guide.md) for our recommendations on setting up and using code-server. - -code-server only supports password authentication natively. - -**note**: code-server will rate limit password authentication attempts at 2 a minute and 12 an hour. - -If you want to use external authentication (i.e sign in with Google) you should handle this -with a reverse proxy using something like [oauth2_proxy](https://github.com/pusher/oauth2_proxy) -or [Cloudflare Access](https://teams.cloudflare.com/access). - -For HTTPS, you can use a self signed certificate by passing in just `--cert` or -pass in an existing certificate by providing the path to `--cert` and the path to -the key with `--cert-key`. - -The self signed certificate will be generated into -`~/.local/share/code-server/self-signed.crt`. - -If `code-server` has been passed a certificate it will also respond to HTTPS -requests and will redirect all HTTP requests to HTTPS. - -You can use [Let's Encrypt](https://letsencrypt.org/) to get a TLS certificate -for free. - -Again, please follow [./guide.md](./guide.md) for our recommendations on setting up and using code-server. - -## Can I store my password hashed? - -Yes you can! Set the value of `hashed-password` instead of `password`. Generate the hash with: - -``` -printf "thisismypassword" | sha256sum | cut -d' ' -f1 -``` - -Of course replace `thisismypassword` with your actual password. - -Example: - -```yaml -auth: password -hashed-password: 1da9133ab9dbd11d2937ec8d312e1e2569857059e73cc72df92e670928983ab5 # You got this from the command above -``` - -## How do I securely access web services? - -code-server is capable of proxying to any port using either a subdomain or a -subpath which means you can securely access these services using code-server's -built-in authentication. - -### Sub-paths - -Just browse to `/proxy//`. - -### Sub-domains - -You will need a DNS entry that points to your server for each port you want to -access. You can either set up a wildcard DNS entry for `*.` if your domain -name registrar supports it or you can create one for every port you want to -access (`3000.`, `8080.`, etc). - -You should also set up TLS certificates for these subdomains, either using a -wildcard certificate for `*.` or individual certificates for each port. - -Start code-server with the `--proxy-domain` flag set to your domain. - -``` -code-server --proxy-domain -``` - -Now you can browse to `.`. Note that this uses the host header so -ensure your reverse proxy forwards that information if you are using one. - -## Why does the code-server proxy strip `/proxy/` from the request path? - -HTTP servers should strive to use relative URLs to avoid needed to be coupled to the -absolute path at which they are served. This means you must use trailing slashes on all -paths with subpaths. See - -This is really the "correct" way things work and why the striping of the base path is the -default. If your application uses relative URLs and does not assume the absolute path at -which it is being served, it will just work no matter what port you decide to serve it off -or if you put it in behind code-server or any other proxy! - -However many people prefer the cleaner aesthetic of no trailing slashes. This couples you -to the base path as you cannot use relative redirects correctly anymore. See the above -link. - -For users who are ok with this tradeoff, use `/absproxy` instead and the path will be -passed as is. e.g. `/absproxy/3000/my-app-path` - -### Proxying to Create React App - -You must use `/absproxy/` with create-react-app. -See [#2565](https://github.com/cdr/code-server/issues/2565) and -[#2222](https://github.com/cdr/code-server/issues/2222). You will need to inform -create-react-app of the path at which you are serving via `$PUBLIC_URL` and webpack -via `$WDS_SOCKET_PATH`. - -e.g. - -```sh -PUBLIC_URL=/absproxy/3000 \ - WDS_SOCKET_PATH=$PUBLIC_URL/sockjs-node \ - BROWSER=none yarn start -``` - -Then visit `https://my-code-server-address.io/absproxy/3000` to see your app exposed through -code-server! - -Highly recommend using the subdomain approach instead to avoid this class of issue. - -## Multi-tenancy - -If you want to run multiple code-servers on shared infrastructure, we recommend using virtual -machines with a VM per user. This will easily allow users to run a docker daemon. If you want -to use kubernetes, you'll definitely want to use [kubevirt](https://kubevirt.io) or [sysbox](https://github.com/nestybox/sysbox) to give each -user a VM-like experience instead of just a container. - -## Docker in code-server container? - -If you'd like to access docker inside of code-server, mount the docker socket in from `/var/run/docker.sock`. -Install the docker CLI in the code-server container and you should be able to access the daemon! - -You can even make volume mounts work. Lets say you want to run a container and mount in -`/home/coder/myproject` into it from inside the `code-server` container. You need to make sure -the docker daemon's `/home/coder/myproject` is the same as the one mounted inside the `code-server` -container and the mount will just work. - -## How can I disable telemetry? - -Use the `--disable-telemetry` flag to completely disable telemetry. We use the -data collected only to improve code-server. - -## How does code-server decide what workspace or folder to open? - -code-server tries the following in order: - -1. The `workspace` query parameter. -2. The `folder` query parameter. -3. The workspace or directory passed on the command line. -4. The last opened workspace or directory. - -## How do I debug issues with code-server? - -First run code-server with at least `debug` logging (or `trace` to be really -thorough) by setting the `--log` flag or the `LOG_LEVEL` environment variable. -`-vvv` and `--verbose` are aliases for `--log trace`. - -``` -code-server --log debug -``` - -Once this is done, replicate the issue you're having then collect logging -information from the following places: - -1. The most recent files from `~/.local/share/code-server/coder-logs`. -2. The browser console. -3. The browser network tab. - -Additionally, collecting core dumps (you may need to enable them first) if -code-server crashes can be helpful. - -## Heartbeat File - -`code-server` touches `~/.local/share/code-server/heartbeat` once a minute as long -as there is an active browser connection. - -If you want to shutdown `code-server` if there hasn't been an active connection in X minutes -you can do so by continuously checking the last modified time on the heartbeat file and if it is -older than X minutes, kill `code-server`. - -[#1636](https://github.com/cdr/code-server/issues/1636) will make the experience here better. - -## Healthz endpoint - -`code-server` exposes an endpoint at `/healthz` which can be used to check -whether `code-server` is up without triggering a heartbeat. The response will -include a status (`alive` or `expired`) and a timestamp for the last heartbeat -(defaults to `0`). This endpoint does not require authentication. - -```json -{ - "status": "alive", - "lastHeartbeat": 1599166210566 -} -``` - -## How does the config file work? - -When `code-server` starts up, it creates a default config file in `~/.config/code-server/config.yaml` that looks -like this: - -```yaml -bind-addr: 127.0.0.1:8080 -auth: password -password: mewkmdasosafuio3422 # This is randomly generated for each config.yaml -cert: false -``` - -Each key in the file maps directly to a `code-server` flag. Run `code-server --help` to see -a listing of all the flags. - -The default config here says to listen on the loopback IP port 8080, enable password authorization -and no TLS. Any flags passed to `code-server` will take priority over the config file. - -The `--config` flag or `$CODE_SERVER_CONFIG` can be used to change the config file's location. - -The default location also respects `$XDG_CONFIG_HOME`. - -## Isn't an install script piped into sh insecure? - -Please give -[this wonderful blogpost](https://sandstorm.io/news/2015-09-24-is-curl-bash-insecure-pgp-verified-install) by -[sandstorm.io](https://sandstorm.io) a read. - -## How do I make my keyboard shortcuts work? - -Many shortcuts will not work by default as they'll be caught by the browser. - -If you use Chrome you can get around this by installing the PWA. - -Once you've entered the editor, click the "plus" icon present in the URL toolbar area. -This will install a Chrome PWA and now all keybindings will work! - -For other browsers you'll have to remap keybindings unfortunately. - -## How do I access my Documents/Downloads/Desktop folders in code-server on OSX? - -Newer versions of macOS require permission through a non-UNIX mechanism for access to the Desktop, Documents, Pictures, Downloads, and other folders. - -You may have to give Node "full disk access" since it doesn't implement any of the macOS permission request stuff natively. - -1. Find where Node is installed on your machine - - ```console - ➜ ~ which node - /usr/local/bin/node - ``` - -1. Grant Node Full Disk Access: - -Open System Preferences > Security & Privacy > Privacy (horizontal) tab > Full Disk Access (vertical) tab > Click the 🔒 to unlock > Click + and select the Node binary you located. - -See [#2794](https://github.com/cdr/code-server/issues/2794) for context on this. - -## Differences compared to Theia? - -[Theia](https://github.com/eclipse-theia/theia) is a browser IDE loosely based on VS Code. It uses the same -text editor library named [Monaco](https://github.com/Microsoft/monaco-editor) and the same -extension API but everything else is very different. It also uses [open-vsx.org](https://open-vsx.org) -for extensions which has an order of magnitude less extensions than our marketplace. -See [#1473](https://github.com/cdr/code-server/issues/1473). - -You can't just use your VS Code config in Theia like you can with code-server. - -To summarize, code-server is a patched fork of VS Code to run in the browser whereas -Theia takes some parts of VS Code but is an entirely different editor. - -## `$HTTP_PROXY`, `$HTTPS_PROXY`, `$NO_PROXY` - -code-server supports the standard environment variables to allow directing -server side requests through a proxy. - -```sh -export HTTP_PROXY=https://134.8.5.4 -export HTTPS_PROXY=https://134.8.5.4 -# Now all of code-server's server side requests will go through -# https://134.8.5.4 first. -code-server -``` - -- See [proxy-from-env](https://www.npmjs.com/package/proxy-from-env#environment-variables) - for a detailed reference on the various environment variables and their syntax. - - code-server only uses the `http` and `https` protocols. -- See [proxy-agent](https://www.npmjs.com/package/proxy-agent) for the various supported - proxy protocols. - -**note**: Only server side requests will be proxied! This includes fetching extensions, -requests made from extensions etc. To proxy requests from your browser you need to -configure your browser separately. Browser requests would cover exploring the extension -marketplace. - -## Enterprise - -Visit [our enterprise page](https://coder.com) for more information about our -enterprise offerings. diff --git a/docs/MAINTAINING.md b/docs/MAINTAINING.md deleted file mode 100644 index eb2be4af23c1..000000000000 --- a/docs/MAINTAINING.md +++ /dev/null @@ -1,65 +0,0 @@ - - -# Maintaining - -- [Maintaining](#maintaining) - - [Workflow](#workflow) - - [Milestones](#milestones) - - [Triage](#triage) - - [Project Boards](#project-boards) - - [Versioning](#versioning) - - - -# Maintaining - -Current maintainers: - -- @code-asher -- @oxy -- @jsjoeio - -This document is meant to serve current and future maintainers of code-server, but also share openly our workflow for maintaining the project. - -## Workflow - -The workflow used by code-server maintainers is one that aims to be easy to understood by the community and easy enough for new maintainers to jump in and start contributing on day one. - -### Milestones - -We operate mainly using [milestones](https://github.com/cdr/code-server/milestones). This was heavily inspired by our friends over at [vscode](https://github.com/microsoft/vscode). - -Here are the milestones we use and how we use them: - -- "Backlog" -> Work not yet planned for a specific release. -- "On Deck" -> Work under consideration for upcoming milestones. -- "Backlog Candidates" -> Work that is not yet accepted for the backlog. We wait for the community to weigh in. -- "<0.0.0>" -> Work to be done for that version. - -With this flow, any un-assigned issues are essentially in triage state and once triaged are either "Backlog" or "Backlog Candidates". They will eventually move to "On Deck" (or be closed). Lastly, they will end up on a version milestone where they will be worked on. - -### Triage - -We use the following process for triaging GitHub issues: - -1. a submitter creates an issue -1. add appropriate labels - 1. if we need to look into it further, add "needs-investigation" -1. add to milestone - 1. if it should be fixed soon, add to version milestone or "On Deck" - 1. if not urgent, add to "Backlog" - 1. otherwise, add to "Backlog Candidate" if it should be considered - -### Project Boards - -We use project boards for projects or goals that span multiple milestones. - -Think of this as a place to put miscellaneous things (like testing, clean up stuff, etc). As a maintainer, random todos may come up here and there. This gives you a place to add notes temporarily before opening a new issue. Given that our release milestones function off of issues, we believe tasks should have dedicated issues. - -It also gives us a way to separate the issue triage from bigger-picture, long-term work. - -## Versioning - -`` - -The code-server project follows traditional [semantic versioning](ttps://semver.org/), with the objective of minimizing major changes that break backward compatibility. We increment the patch level for all releases, except when the upstream Visual Studio Code project increments its minor version or we change the plugin API in a backward-compatible manner. In those cases, we increment the minor version rather than the patch level. diff --git a/docs/SECURITY.md b/docs/SECURITY.md deleted file mode 100644 index bb24654f3876..000000000000 --- a/docs/SECURITY.md +++ /dev/null @@ -1,13 +0,0 @@ -# Security Policy - -## Supported Versions - -Coder sponsors development and maintenance of the code-server project. We will fix security issues within 90 days of receiving a report, and publish the fix in a subsequent release. The code-server project does not provide backports or patch releases for security issues at this time. - -| Version | Supported | -| ------- | ------------------ | -| 3.9.3 | :white_check_mark: | - -## Reporting a Vulnerability - -To report a vulnerability, please send an email to security[@]coder.com and our security team will respond to you. diff --git a/docs/assets/screenshot.png b/docs/assets/screenshot.png deleted file mode 100644 index 77ab4611e9edc3f89be48a06e75ee700b96d2f2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 997586 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¬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⋙gqcTsIXdVP9jL;+jwsMI#3!W} zA`SrIP5TvteuR;Nl3A7PXAo1{P7iWww#q%J>rh6KhHS%J!}!Zo!FO0WB)M35fu@e) zk=Y;8-D6jJwOP3hD(39+;?Vnnxu!uRPHH#~pYm7kPO9HHK72eTw~Vju%m_58xz}AI zw*Dn=<`Riae~G-iAB5Md_P ziAqT>=E=N|y532%_`AN&rCO3wwYEX4b70-wk8Mg#?(03w&-KJw0~sE^Q8{MZtAvQp z!C<=oTqf&(BY%ETE?oX2xFn!rh*d=PyqNQkz6cZP#GDd-H>!~(yjxuN&Wg<n+nrhSDKuPQZOLxZX~iyJGbO*U9LU zcg}XPz2a}2C!-pt*>8|1j7)xM0V=<4MjL?f2t4ylY`xcYa&dQYVCCYS&?V9SXl?yU zR(`O%V_Sqxf>rG}>BnP(M0ii9$>ir#5+6dOPbWgUd{P>WW z|Bh%%x*RC3>t<&Iv}@?em%oKl3C&~8Wwi#SU(C&e{t*!RcWywYVe7CWB#b4t=`y&hZsHaje-$%COjyP<~)|AG-d#Jj|0JEz|YQE!E415WAO~Q{ex7I zI2@M<#i(!&OO+_?9~ z-BH@**F6z?c}UGmD}Zj8tKOrr4@PWAyu)lXWi6RN)YM-q%nZ%k6-#-<7O`TULXKG?%=8M;m-|ZklA# zlo9(i@k5x&o%1o_Rtk%24f0Orw|Sbrcgya^1DXJg9zyNI@_CD?=<&OGHQwz9W;~0? z0h&2=d7`tzA|4&z@$+2zTd2kUSVOiH*6nqS5pchKdozfqBIAh$_WmjFrGNM2cm;l= z zObw|89K%YM9OcqYmvhWhPk{CO&-7(aj&NmaDU>twy9b1|hn5#f6cavsU(_mbRVXUa6w91=M8a`|6qKDnc2RlEg|Mq}!riFTK;mv9$jAfDu zju3PNCAEah(;N1agh3jaTso|+HZ$I1QK^Xi-Xb5`ullVz-8Xg@_v&#oSDA%wm;Fv! zN!s(AH~J$=w%WK&t!#rBcD2y`e`3Zm0+&inaT=wrPZtmG{6BQJ8yeX7c(n4-3sHM{ zPrxix(N|q^eSxaGGo0Vr{RP@J!BF2WqdCB?3ER0VVBdMHpeha$>2QbncX_hN54B&v z*cRrZH0B%v}QXb7-fB{Dz!c9g)cR>n$8$a|6bCObN-Ho%&LEs zji#ZKnl}SuyDp#<(+SEq$~oC}TBfjca`3{ZdVEKT|6li%$JN#`4ol|l1f)<|No)Me zsElSB=^ns|x;(i{pIrRk^6NH1Mm-#RNwS=9>zp7fqf`VR~Mrv-B9JD#xn6 zGK%FA6BAiP&f-Fk`uw-l{NwNKMb>Bbj&;}eR}J71ENzre+eh9|P(B}I=yROloyu23 zDh@*vJiaT9hm)0o>PspS{SDa*wO?hykD9)oLTDQhHb`?z!X5q{XP~ETlrj|LN9;O7 zUBNJAIa0aEILRg(a+f-ySrQW67cjE)E4t78Fjvrrm&mzbcHHG&?Q@;#;sQS$-iq7; ziVBYgGU(SZnLe;A7RB&=z3~rcb+XSQKC&c+l-FNktB(rTDv8o>^c;as`oWiMvlH)? zFIGZ8^4jYP94*}B5sfZ~c?oME@_0McF`B&eLNsxvwnR%-u~b(L7t9kHqwHBcnaY={ z(qV|Zy59{r{DR)iV#V09};j()t}+Z^K$mxCFGsat%CJ>7gZ zYgqf*1niCm)_cs#Bx9!yxPsw?Mb>AwRco&zNR@S0Gt}C73hs)b%EZR`8egrt?d=Rq zM_5ziW&fV`o0)qr2v?GH%~6%nd3D4L_A~7|!uUR=ox*KwDZb@I6&w|4(VmmrIvG_F zl$Ca3Rbb~;kaXyK8m0T``f1m;K{}f{K1{UNx5;zj(d`fQ;!7^)*vDu~T2>y6Ul#GP z;ree`dN}3Hy5RR|clcYNA#|2}Ss5Qhsv7UA!z&E5t zR;sxYgB-e>>Ddxtd78X8fx3j6c zCAG`(7i$u04QnJTov5-zxxH;A-+GVc3X7hYvC@*Z;>Uy{hJ_VIDCIV>3}$0=jTaXs z$;sEKLnB@g@E2nZfxw^NV&Z9hdKGQH90Lp10On-J?D9;8nZm6|5HMs-2J7J;;}Z zdHZ;zmlie7j&lb6Vio!@(@^B2VdcDWPIdo^8#^tT6#{CRU1)xCToTb2a9mW#v;DK| zdtJ3_{@kmDuXo(FUDEnsNAY(wwIUtxz9#?|pkxVQEc4$?5b(yx@IY?WJpPGvM8?V# z&eZ3aRT*C$>b_)$e{$X@7@QW0kl>#k@LRbfBmnYf@vbh6ptmV2DGo)oYDvR_Mw(rb zo@?@3`dvi|Ufc$W+Rk+FuG<;ZCCzoiF?Jcg zvCi^nV*M9NXYF!gDl6&*zf|%@aLM6WGfrPwGB%e#*wsgzHvJsBeFR{eKj4KT`#LYy zB)Y$cJOaYh0kwxi|HjtSGMAoPwBuv*pPBT7e02*-aLKN)eU(^o1cq38e4+Goq@>myI&eL5U^6BB}tKri0=55QLx zdLS9M4+3{Ox-9smxwZbUb#wnk8s|8th!f-Z-1j77?vR#sieD5iugf0DWUe`)^+FOR zD(m^g6OtOK7y03n7n#bCWc-oOYc;NjarA}RS#&EqDB7X-dEoiqQmhPmAL<73pesmf z?JM}SQ%~A$yW@@HJ0)h`Mho}E?Mf}IgbbL>isRA37w+YxnCqC}GZEGk%XAF1tbw$? z9E|k$PJXWA>1&*aZOwNxIZRP#oURLS@$Z@z=p{;#sTREDo3yu<>L#sJYGvly zV_{&N8;`kqrxa&rh#1oG<$~?Ak@ULoz<@nETmUN+Iq7bb!uEnlClx4#Rm(v0> z&x}1S;)Jl;v6~C~(aOJT0~SVNwDV z<|Q)BX(vNNudEzV>J|Eja-QayL0;Xt{^2cAg>6YZRP;mcfS;VHl~q%l=-%LjSs35% zE$0#LTl>31Lf<41i|8Rf5C|MxS*4OKwPZe(+-KL>LF?;0bD}pR&1^bk#(V?2-#KA@eb!iLP2=iYM=wy;flZf(7;KYvKJWel;H z@!tRy`8NQtV@K@RfPV&bu$LG=BIUd^M4d=TabSiMA?LVQh6^Z_;-C=RN-X-vs{M8Q&5GXssuWl2TfSfC}uvC>N#6_h8mMc@EV;8|*sS^&JuMM4!>yAfCMjgg3 zd-e`&Sz45tqD!WS7JJ$1kIP%{6tE`L-YPz1kep^M*vb3ZJs*!(qV=I32y)lM%qzU9 zt&N&r0V2S*l$9x88ke$U>_2mf<%7#}UwieNuQ&Hx+Aq8>i{?)GURwjEj0!cBL8>-! z9Xwhb!IuU)=A1lLhBNENxqOd5#l#52MQAo2W{?UT)W8JJvBR81PZMubcAsFiy>6%d zb@UkSl5>9qIP017oo{hMXWV%Y-dX?jWHnwFO;ROA5e=|>e^D*j?{U$_H{D$Bk4c=3 zZ1C|3eC*MJJBM(pszQs7k0f`RQYLh{FQKQIUwd}*oPxKl)g&r&7Na1{LLU9^PInHx zyR5>+V#apCfcJ)T%9EG36P28y7NkBmL?!oCz2Dw3ho5E-6FmmsGW*n;K!cu=*B`&Q zq+grOZHx${xOF-Q1I1x}i}A(dw~pJ^&T;1Pg`)TDi0QELzEmX?wOL5*$3E={$?zIC ze1A7&T;UZU00VLQa)v4C(}(jDg=njtGqto3$djODh+Gk4s1I}Haj2ZKXhc7_Qf)<^ z+4s1n$y-N-uu4v!W$04A7oX?yZSvk#>T#`~sR^{2r=DgFWGd4SI#wVak;V>^Hu_Wd zYNNi4!TS!U*M+|PNY23{5_%)>E zO-{1(c&)NmV5i#1;IrQDtn)*WPnRv~7#8yc7&qIN&&a?E7IHoe;cAWx`@>wF7)sKS71F?9n5**?GvV9Jj^wjMPy-ls;5 zzC1C-r{=cRaJwGyXi-FMb-r64VK5fpDsHDv?$(!$t*8#Z_j5r;uB&Ry+5$nDnyPs) z(O0zF88eHb&RAGmVVJ*IpFI;>LD+vGY-cp@@J>x7Vmkp_W^R=?rj+xfG_yTMjxs-{@bye@3sr3weR%Y&EsgJyQ0pR&P6W`>m8!F-J=MusNL)=&5suaeL_ za%YY=Y)Y%|`XAc4!5;F7IvKRqjSo(6?Sd1Jv3lIKih8qMfHuV+`&qU?B?KnoLa5AzxS@KHS^to>1>`^I6;UHACB z9UIZmOZ}xWmBmF?&LAPM$ELn4%(lNszbnP)=&WX!ZDMT2JsYpfOt*QJrhRdt7q!iL z8f`*rQ1@~K?WMKN79|_XV#j!+6Q1}0pTWWW>&L?cN?shRTth*_T!<#B>VhVm&x*7> zYnb6DE`Z82{Eu?kngx>ySPM6qn1F-(4$F@-Z<{l6pEER%gpDYZLSbTZ6WUKpQ^tngt3+b+1_mo6mBBNdg3UJly*!dU{9r#>So zH3~PGixDt`JQTqAvN*8C{P?l?&$~e~m4bstOH{Ab(1w<Z)B>>+GQfuRKS3-T3CV?3)ozZAYoY zJ4uKV`lY~lm^3Xs`$OeirHN6X&r0(cwxgq^L#h9`cyg4;K2jM|McD@%WX3AGT~il{ z&=nSOI6r^uH|o7c$DXSM*4G!ZZZ>dW3VxP+lu6rInDsaOjJVB99!X~LSd3Eg+So&X zaR9hNKUWL&gC6@cDD+z9F$R5`kr*LIH?Cc&$4Ld!=Y>84^K}W`C2=AhNhFLe+fcv_ z(*O~=k@QsLknNg?Q_YOey0#gRI=)dpxAqK2Kdk9pHnDtuIOU7mTGR2wv(rl1!`_9e zt#vnI$k+Uk3|}`XEdj*`v-55bEPZE?Nhk!-iHNRr>RlA1j8}9Da!4Bzkhg&4nabBA zWxZ>X$38`#dW55F88w=w0oY-X3Q0ajh<8lzPf5`!xca;!g`Gtqs6~d?Y9@i;)8)`W z|83^hL|)k&MFlldcbFm4`hG2oQe0lRS)nZiZJqz7|K?8{@}^z5iYVFG>I?La->3PkO}8w) zVd;2x;%j&0VEsBDhLr2Eplki|m6qyz_#+{v7Od|&L>EWuQ0fiZ3e4Oa?^MeROi4bQ zN-=-1U%~vZVTAu|SRFiXIV(P7VcpeaUb z;zBY@u=EOiaUE)o$@I4u=N;Mh#p)F=y`4y~yp{hX8C=!W^2Wui{;=QU_xkKJFm+y` zr@}}I6n|1ISVmGU%E`q+(%FI)xsVAqrF+fqI*|2Ia)ybelIzB$GSJ$Cg+1&5!cVt) zdZEhCW0HEDw9WzcTLtCHA=lnj0AQL$!$6|+4}1o4JOKn7O6IJHE{urbMV$NHwwyfYX+udC^^Fj5#1eMz6qhlw9SS#0g7KpKH&JozG7Y2)b+g+OSa z9GA^fub$?g=Jy!v{sgtN46F|I?>8C_po-d>*Edz)y}O>x!IR3Sa42wTQshQtER4sC z`Y~x0BfWIZqXcltn;+-$Bv$PLyHXb#QYEZ{9%dF&G+lDSM-DV$+diy{&NgkZph?7U zh6CoBF~mzfc4y#WwDcG?`HDOk7Nq1ALs!c+2e z*SroCLTyG8S+r^PHvpfbG+2^v!=jK{^bZ_@vbijmL7U!^G}Uwr?dI}(!*nY#bWPWda6Ocq}=>zsXaOpn9?Rh`RC-}`~)MX zu>=soSI6S9>d6NV63!NxJ>FaOkiXf3n&lnZ-CRrb*HZvwuCAh_-o?nD_Ig`}k1X^f+haclfBC8L%y|?5+guA2MYndfE~%x)fwatZkUYM`h1e7rVwGSwciX< z8y2*h`xO+(?*?`!ZK9$DM53=8O7weLpi;*8_)*)nQyNb|w*;M~>0Imkyk z0Ywk6oNb-%pCL4;I-7|*M1}0+r2Fr$%w!t_JHOoe`mYS{7!M_-H7$tcZ!V`qIp}Po zwM!0_PmSTfoGYh}1}OVJt)G}lq7_Xyn%X)a6@%a8#;1n#{1JXwX`u{v7IM`l=*{SiS<)-Omm@%t*Z%`T+bfd|9&kp5s(nAY z(ipe*r{8TiZqqtF#xo&}fqT;+Jp_zq!Jof&rFy@p3FAKsO#rUE?qAX+f_EpI$gI3r zoD>4|3vbgY;9EdK6sW-&w7?}f_=`7_uVJ4*0Zn5CwwZWbd8lpJ%R^tq zLNEpyM-6-ja8XGptq1v;f@2^YMvIID?r+rNXj|GgArfC`?NGJi9mfG7)l)C!0xjf|5HK#D=ZzsBqqGu*g625 z=@3Wis<>^$QL&rTm*M5;i}%+A&rc>Dgd$0y%WjMn6s070VJ~9KC>TO&9`tQ#+jVS> zqkHUuaNdvQT^ltl2FtC)?Z_)JGNwMCbX_82+o2oa;{rP@Wj1bGkwLT*l4(k|&-uU; z65H;)O~ES}ot)Sn%m4dnF^=nR^X5sHo?nHYJu;Z4T(yVNKdna(11Nk6}#X z`A|px`!C|MW3C*}y8dFG4F1r^Q(-)^W4FH0tKNNY=kcJ3#BN;WPNio5JG++Thitnp zP2l~a`d)G1f0Nx!Tho!D)a+ldM~@b^rC!Q zgsE_NuPr+hmPFf%d_NrPf+EP9L6Q9KN4BD>#atLoPEAkQuYD2z*E_Cy%bj}LWuxT9 zWf!)eg?+ibE%Am_qQeGjyFwCEvB?M5hM`woBE3tRWy>eik}3fUs*x%!qrj^4*1alRAcqdg|A&5T;o1dF7*G6{RXLb`44tKwlHs^wO}U# zt!HZFuO*(hre^UFieb=E0aWcuipRJD`&iXOpRmwhEkb2V*XuWZaK{SYeUFxIb-|Tp zyoNgr08U`oBCA{f`Rx8T@F@zfq7rtrk%>a{f80Jjqw7HUT0mL-4m$dQ-o7KjEwX-AU+qW3R+OCF`b~=$n*>P*VvnRls-$PHQIe$*yUK=+ zLm$CNp!+Xgwwy2-@nM2*pcA%45=lJ3C;B4y>>SAFm9Y7qqrSeQ67Hi~-U;5sZ@dzX z_|G2mHBIPTbJr?WQJxBf(OI+o8uNib3qMpNfv4i8g8fjIg0Q_z32O#>i|pDt0Xhqe zB(_Su^a9o_`5fgqpwEV8fvB#wJ%2yrX#_&cGOzPE33!Gp@CwnQ3LWuI`#Zxz@)_nV zFx!iS6esDsIgmsJFrhNlVpLG?IDIAs+Y&SQ2@sikM!BQP=6_qi_<`U0bbhOvO>t-X zt|*q{A}Cn=uVB;QxucUuB@HO9jbzqnb;MnLx#R-i#p8mh@0>Jpgd4le-88;Br&nw|@ zzvGxB0j||Ss*Ia;1R~dT^`!qS*-9M=Ce}uOwuKoei=ayx0FBkE9fgU0SO$8A&?T8= zYYM>lsh{Nu-SQsllm3|+4nFwC;d;yI`*tqhRS*V16p-(0CDL{lwm>uI&qSgZ1tc)v z)Q+E1lDvJ(Bz>i!hA*GYR9kw@kM+)L?cd{kebK_F;B{;n0a^xO&|rz3a%y?gW*Dh- zaFqc+wydzNTyZ&G7h`Bm=^AgkgR^elf&ojD&zXMd;A3fUuup!q;^yM?fu=+!y<-qls(BUc zsSf%?#$FTRSJ`~x0#+qsOC8;KyDXP1Vobd#ah}FO4kD=F^qpYomyuMQ#y=)Jf|gKS zzq$L&i7xBIZv;&E>yV!kghj*FG+T_vC{uqcBN0>~sg9$Oc$ibf;%KCSogaF8+Nzgq*(zdHASxH|uj=j0ye_!FktBRR$hSC??SmH%== zYCW!!Veu+93c+^NVj}A#U z*>!A*tZ#{hMP7f33Amo5yBs2sF&@V!e9`$lc_w)(ahrK>Awf!%FMUQGID854H-(8w zm7S138z(WmH9kMyRT=lIT~ELxT#K|TU!ySXeLcyKe&5Y^ue4cDRC zBRXnwCB@`vqxr9UY=8s&h%4+G2b#T()|by`nOYqUsM$93W#2*hLF(uU+@uSRASlbr z@7hQiIXOtM{)&`%d1p6^ZTWPS{4HVAVO{?de?8KQbieLvyR&8@!7P#~sBHn=;{$L1 zlNs>QKP}4r`eGWcsqGuTzU%|3ob(X2{$DnwMTakQA6cXZlvG~t<*6W)#0lRj&YB7;cMC>wf6MXCg|OA>-3-}H5o^%ES%PqelG*Qbr9^m+zg`Y z)lw~RQkA~xMgR?$FFQ~9O&>65EVuRSHKManJ?w8et5p1rbLh;8#fyT{Z5 zcPfhzZ#g-M0kriS$oZfuNv zds#d@HcMJ{ixxsCdLJnPErgOXpm*MfY38A{LY2RoNO7RZ&I6=_O*)91>AK>{hARho zsjk3f*G^gV{tHg7S7*(XaB$sZ%-r}MZJRMBY^~^f?&N>}7u-5=5@2ab{aFf*mNEik zGd>4~|I8F`d4{&x#?AV*p9I4E?sQaGBu%J@ zu3}9j*!krT4y5BsQ&iDNkSH3vy^S=P-053sE%nX3$`sK)dO7y`9WOsQ!s!Wt&+z_^ z1N^hz-tV5tfG_jC67l)M(vb7=F?A!N%+0dOhx5+Jg-C$SA^drWSqQDIds`utjur2i zB$bBtsg%!Gg28sBI+2Z&0TDMvoKhvLHsW)2owUV(duM6*&z=OS-U^2r*FN4t0j7@g zZ)t~9HT0-dP|u%B3U;Kk{}Ipv|4)_kUq2bVRzBl1m6WUitIk`s1C0NnP?MKs7G`>W z-R~+^75EZS(BsBv;m%g^>hIL8hRxpPOp@h<%@HNBYS`rSe$!snUdHgi%x@P1HzuYO z6W%>wPxszkPKVCz+EgmH+T0huATqwwEdTbGy|nuZ=PAC26-GvZX+m%pnT3s3J*&35 z$#E|H+p&tGO19_PM*8O!&pN*_^!M#6n08H4B z#uqyJ-VJSPINmup?rBk>uB1rVpLj0D;vB@}O4)RAXczExrafBwSKOw5`R%{Xaq_5V=9A- ziw^tW7?$_;i6qwT7?-?_3DG`mk=xY~s+C=j%kG<44ezhu*j;7uuB!YLlS#QH1tY1f z&JGC(wa6ZIR(jfM!3ufokSo7kk%XbvEBz)<*IC~JggQIvf<6WE_^WC5d0|qOg0!Z^ z`x)J@qDyGbJ#)}q#{<0kb*&Zyqrk88m5_Q`!J?W=rsLLG;*R9V?HELVOSE=}hv2%c zFL-|^4nHx`{cyayQs}PNzH(;Oi~HjCque6)C$z*^BF~=$oL4<-_w^8rnE$?!|Hl`- z`O%Ax$jc6)0zOwaboDBx`plau;B&bsX($=h+uKVgt6MBfn(e=IHf*BJSN7(k=sx6@ z_9VUA!Pk#|1a8*C9Nv~l0q^#(guPDIyZlp0ZIx|eeiC6&Tb|B$LW{DHb_I}zt3{{+ zcwxfq@Dr}(G6s07!`**ryE&P0fbPOe{W?O+TcgmB`r7gEd{E;Qh6e7NW#qdgw}Y0#d-hZnsu z@~jK}aw@Y4XdY$}ru)Q7C#`&pf^ij3|AE$Y)dWs(ys@S#E!A{yVsrWG5?btqQ5DEe zvn^z@BP-JgkT0t9+zyt0@sa5*`u;y-wKIT8iNmHjGE*?MX^s2;jvoHk+tI=Ow$L!& z=r)$!Ve$^?Bx8}jI(MN_;POeiN${_w_6l4w>5*KH}y)OUhAklYxTgn zY`H(kFqFWVohiVN0BDzMhs|0t1XCV;1~8RS$0JthZm-0H(aEvIM?N+ zcEc3n?Euf=>fLcH&nc|uw8K|rjjK=N5b1eXcRtHdQI2$7l^b^#%&;$DTu$3Xhqi+h zC&HMPI;E!ZSL+AP&?o_Sb}!q5T05nD za`6bekvMsD;Vtv8@j^JU$So0yL+q=|0IvD{X|>A?TK{%Jy3eHl7xhrI=07I9*L?pB zhDLvqXX2#WFaN%n#_gw!cpWvP0Mcb=1usO}z@8ggL0}Ics@?^#lBzzDGefRcdz?;L zJlWstj(*~&N8+Hv9a+6K-|p`AuSQ$VJ~aXjb)J|Z50z%e2tdFDCbuQ?2)a6zd5QZl;b) zZ=*jO;kwf#9HQiRUi1CGeMifUxaPV||4_=iOf4=h%UDnoQ{8SV(N{ir>_5fSYK8cg zFqK&O%vNobFX|oLfaqATzim7$LP=YWHCDWNSQ-GgijAKu{i*Bjo>-h!ni7EUyFMPS zsWliBU~Itwfst-34aQ84Pwb+VE5mF|Hn!EqiJ$UcWZ#AJIbG^Zrl+N!o>7TJ<;k8A z+GVMOEtt$O6}cDJF(W5wtZsD|i|gWii`CYQ)1;2ih^raqR+;$Q6ORJYL!x zxylkG2CcR8y^jA0lL?58Ie#CB^%2DZBst!GK&x}%+Wi;*A9wE=)dae=4O^(vLFp|Z zGD?$SsDVU4#0ID+5ULc75;_t<+R#C|C`FozBS;TO?-H6o5P=YS6%axRy#?MoGiRK6 z&hwqK&Ue=P{rUdgX0cfDX5V{Xd+%#so5(h?8C*VEmN()lel!Mrz`w7q`~U^*Q4K(o z^K;p-L*l?`-LEmuOGBj(2J_2bjN=WNq%C~C5S1=k+h*s+Q6e?I&jBB_6A_$c*_Bdm zKM1s3KKFh2%6aa4GwmbdEZ}e!bM`fd(zap+m>IC=sQBjIuy}+a17cWS$Y8p9@ylx_ zgs#@^LDfaq_bhIM2yAjkGB>Uz4khR|`RRUU2zga>MtCUdaW}Rh5u-iK!l%3!R>Gz5 zWN*9sA+s#bxPMFyBf9lgS|d%NPOhwef?wxRq*82DNS-E_x+9+##HC$dwFG(>C0ejF zE%uSY7Am*?aZ^}|{;eF3UMgv!?_E}{vDuv$a!=n2cJLAxV$0{d`3bD(X=Q!w44*+v zj}V+RL~I>Y!4~Tlf^r>T?HZf~H=D{q3?Q=q=xRq?sUCKvo0a8L zrCkNsY&!H3=$d|Wdp6fkJwUC&k;={~GI&Zz^-K_V5O>B;R;teP*akIqcSQZGD)YX; zObw=r^IP}b5sAk5C(*VG-`KSoJ?UiA^M6YdfY2^SlG6rwTQ2g!Y~Mol?^P$KrkQ=u zp!I@=mN@$@4vq7s?|Ut*paZUOkU6ba2HG9%nLj(38^9Hwz!;wdLn_1c{6$#m?>`U3 z>E`Xu6O3k@u7t_gZ{9$^O;jOahce`LcLtYk_v_Bt<-zu=IBviKqME%&3YWh5q@IB* zP^FYW859yqai2j|ix=c~>a0eUE)O2OI#MXSm@1s1-SSsB`M2(o@C%iP)?|(6`htG^ zLkDAxx8SDLF1%5CE4%Z-(?kd|+^7^9;q%Ly zLgvHNiukMr9%{l%*ozDt4-{A(6LX~umoS@ipHI4}aZ#ya=HA~Ov(-x;tx zLd1TC7uU;`OuI8rvEgQi;!8X`AFSk{F~l7b+l?ruXHg2Lg}D{Z7K~qEN=S5Zrwi@V zjZ#QIUa6|!(l_iO9V6h(B`I^grUYY>=;2L1v|aEiVofK??9#&(Y)a11 zan-R+8uNM%eyV7z)wq*`pOd4wxLm>?h{uTAbbatbRBh1O#eoM0&@^fwPs%;7BGW5s za>(sKl%M`Ty*7@M0MoqZG}lw|!V`aXao&_;+$etenzJfsmnDmS+-yPNXuC5{YxGrzx1pO+56a1gbpSg-zMHJZgsMjM9PxMhJrk@K{zN4Y`bld8W6QO-plD zsq!iQ=RdMAZWNWr34Ek|+4+)(xX-!tt-J>t3@1|jF9|_VmO81>f}NbXw!lST1FIgQkr9DFph5X}^qMyh;KuC+KP<~>=hB$orJ zTA6p~f%+Oc$oeEmWuXtknWDUmGcsEYFJaYGB`f|!6?yKoGthLq*v1;JWu8zHmHl0e zJLEw@;c+{eOH9)cp=4mH4u0NSj?-b~1+{50ykTTd9bs3OD`8o6$b}2|sYnMF+&m%m zW!3zwQK($Upy#Bt^G2^>|1u*DwiLa{8Y9iQA-cRl-6{yD4bY}ToQb;1nnXnhlx5N$ zxS6>ZAk6Ru2z`8?_~ZOsy)UP3qu9MYcx3-0pC5nhc$lI70!PvNesK$(G===mB!$|W z8M2w3*%APLH(<5z7piR&Lrg!;Gnykjyvp$;=kw%!` z6m)wNXPnAlP_%8XVW~LwPUz^NQvP>lkAUBF&4RqCs>#YJD1MmL$CBxidhmv=Ru`v3 z8(5e}tGP8(OEHhdqdllhhGX~v3UM+Z4?IQ`KY6V7pA{qiDUUuUal%KhO{Hw?xtLdhNZ2!J-U)A(8}11iR2=a)>mr?B~n>%kLTgqT9@yhI^Kf)f*FW71oJ20tL((k&+5NeVhFOSf{c&5AOvmI z)1_X1U~!47IsISgV?G)RC~sx1NKvlEDhf$p2tgD4LHfZMm=T*ffO=e3r)0Y zGlBA8;($e{oW?^LpE>E>ZDB$##z7V;BD8ob<1&Ykzi0vu&#X*VcaO46Ui>-aI=BPTECH z=lzYSkyB7g)vPVBbZ_aK5-kb$Ob7#0kvAf=k$j0;S z8fLB6#K@`6h{*J8*)8_Prr+wWTb{8*DzXSE?3aLT@5o|!<us2m> zPN5bePqq}r&wUDYU@VJB#qA)AFN7NXb4+Dmzz62i+D=cqJKB;Q6lz}lq}#($0iZ-{l~eN z`uieewPDeiRjX|O3{ZycN>;KWr1fws%cqhsVbesj?A)lT9adE1OOh^Ob$dJSX6r8a3I5E zd58}f%)`xGy=x2R#Cb9{^CP+r_l5<>8lU1G30bjq;~Qpc=EGnvMtvc-nn%ExEH;D} zNS)gX&xe&N#fz#l2mw}i6uSoJPnZ9C3IFNET=ZlkpbFJGs@xVo|2~pCW@TySq&1Va z`s9MAEaA%}R(RgYLe*N7#LXRsS;U`H=hWvd7ST95F_G8Bgc3>pzlqsB)-J@LBoEWJaml&s<9q>GtIt`e3Ol z%l;vIT9Q4JKo-s!qL-E2cg?V0_*tlWz0y#hD~842=z*$Q*t+1orG9q>l!^?wd%+x` z^x!(8*yg`Rf@3pEvu}+iR|2(~+-5!T)8J84-Gb zEzTCVj8L^2%^k}9ARx#KhdnNwG?Y!Vs~1n8r%Ez znNhblxlcQbwlXzbcFg-g(u(b1gUg9HTcjVF+&*W=vauC8{;IFMUSZ$RP&_~5u+xso z1skb!Ib%Hu$X(h#%JfT*y{8`bU%VbxRsyOUjHvC^?}5=61j9lA>V!5{V2ln%1!aIS zLq(ELrPGVhM|fXej+9pxwXaL%bm=S+grPotXmp6mK_iLJU<=lBodT>bA7Vxi39E~8 zF>=m3#)oXasJo>d@vWLQu&JWq@$|ji++0V$sh)jmW)}I*m2G!qYUZ_+&S36<$vv3} zos6bSf-Xu6MH@VNI!IxQDK^h}q9m5#vAcpTrXp`QwTEqO$x#ZfWVJCk&OPT|mvBqV z%$D^=VOhEmBWaescVYIckbqEWYO*UdW&2H;TRW7z+QgEfzYSVeei>5#g|8L9c#VzV zwNhK%4qs31mMr}2?AFNR-+Mxa#(|!}j9K>v^Cubv{a85A^#0JOt7csU!HQtlj4xY# ze3N1UGU*Y#2#qW*y`>0RU7CL*&-HaLmu@6^vOD$$qwkXi2>!X3wI7NjqI--C$ntC1 zI)Xl(g|@BZ7;)J!a;UE8f$aoc0q*k2XS_&t96_K#F7e{~&3mp~GRJ0$Sr-|Ol~$zA zoFxtEB3B#q0={+r-bd9Xa$~e z=k()SbQy!h{EM@kiFco6c}!6Gv?!mHsy4-h(L;LyuTtj)yxagRby#)! zgJWcnl<#~IhwH3tD}OIrae^e`PD~u;%KgFO;g+fgdw(OK+<(nxRQVikK|#4mH|aW4 z2g#TxKS!k^{>@}aLy*>euru;QNxnn`m(147;LcMRdK~=;_h50;c7MxOaq&>ODiXM` zCdD^`UuP$@y`OSc`MU31n3tTI{5UUH|4Jn#m6y0j_^!w7iz9a0GQyO9S=cMe9PTZV z&&lOjwB=$z@5kq+o!vm6+bj!J#%Yd)0l;qsdG%KGw7r{MdTkh2FD>g|V-+8vu>W(}=uzL}65f+1zI zCp26qglC_baf$Wxm9`Rk72oC-a^lM*8?`kf#@6Vh+!(=@l<^hO*2BJlyrBEY+ksjz z-v#ArG9eDFI3Vu28+2ihPg`mlU|dERrvfLLZNWpvB`Z^EPEeTI6GBb}im{YatPo22%)d+zF6z=TszGx5#BF>M z#BBt;2Dn#sg{7`pJ?9Q)YGiQ_5zu`$2mG%0>aDO)_fM7Zf>%|01X7cZy5am|0b<|u zO&RP{U|3Lw&D8p+QclkuHoGm5MzBDU+! zF^l0*1FpZ&ggV?Dy+o*ew3w;B@6e`L*fe#8Su?-`DcPr806!_rV%Uu#URJ`4FH zh%}W-YeAB?xPdL9h_ZUEKVZ%MA~re*st7(l;&732x(FW_x$rLm;eBt`N9n)==@u19 zSDa^mIT6?38kc&vAE(D?BT;d7zNJA+y_E*8RhyFrB)a-US_o+In6bVRMc>8v(6qxa zpH+@lk$Q{P7Li1wg`cob6*Bhl=Wu)TV3bt|*LS}sbkul$1`M!5HObWVRhChA5G7%Pa_jSf^=_PqwPeHb1Z9d%khnmj3@p~ z6KQzC#0$;dbk{eU)0ERjU{~qC#)B=?{=Zk`qjLe>(3A}weq-LrQmN^@x_kSgY=|i+ ztGftWzKIV7QrLsf&{JR9<-1K6UCZiZ`}<11hq71;O%KC1Zf(SOJa-SwaOE4u0}x}C z#>XdL6Cs};ECdnIdMSy!0bBO+_$v0DM`zB2dC)@y~4-o!9x z;????iUjUpT`5kzu@jf}? zPf%s(r$$XrQ_~vxx8x)sDDEzlTnmRK`Hxd&(+7tSt^CvK$m@til|}k4g>#%@1@JLTQcoD9Xp^NW zc1NHlCyh1q%gO)6ucO*`eGdqBy*RVcTK;tcM89W1xeYRI>Qw@bCxZe{yk}eQz$}M0 zOqTFH0tmg9fKIgicu6#DZ+@8`aU)T>S%}A);&-hZdZm9n7;X>BM>{b}T>O_Prv?^z z!++zH6{&=6)FFtPof1_DO5L4XL{yoB>O7S$gX!rCu>~i+FT>m(=Tb@Pwj#7?qu#c{ zL~Lgz=n(`6Nc+Hl}sfSMxJhekovMPQ`)7*A@|DTwoC161?f@t_?j17 z$GD%oTN-F#3)HJuQKrMNr+*30s(&Xzuh-v4zl}-oRQebZ?lao#KWenb8fJcq6!uO6 zm=U5j5RF?vexpY;DEhK%;CC!DaDTq4fQI`btQz?Hz6F*2_eCiuzq(4ZAI|!p>oyGp zkp>Bdfqre9esP=pyfiMnSU8<;#Em=bFwVD3UtgMXO<`OWI0c}{iu3ct)F?R%Xmx~= z%S`9TO$;Jy$y#mAxK^;bia6WTI<$q2iM|y`4R()sVxjSKWqKxh(8~Fxn|on~#9_a( ztSw7uu)?|17YhW8g*(MVexq=`WWI-~BVwPi$|yXks!rr8uP+r7EiH*f!HM{XS<&R& zq5WTX?zc5+vo!mrlKAG#vcq-FtiyYC{agubR+VsPNvxcTn^Blsn|c-v)RUl^845B5 zZav_AReSVS{_?)86ralq?;m;mg>w1=pB$0-VN7&Ce9|BO=e{I>#*XQ+{h+_jS+^^s3CvPN;6vA-WEry$vUgGn$a9E zqnu6W36C{2Wu~;cEZuLpMt<)m(YEZo8lopjhFvvHP{Dr+Df|Zy>nw$bg$F#W#rVLY z_>=z6U_1GbkIK#|0MbF%C?2Z~3mBE#tjs96TRJD+V!pG4$%X+k+!X$~*p0B5NZAt* zn<&|dzjdh@Rl!G02imC&%)*q@MCdDtzX8R6QbLO4JJBV<;HiPfxHXE!-KB<8H@0XH zFkT_n#S79VqanND{<$Ka4E3pe6uQ*v<1A?nnSBHU6hl|TxyKhX%KyYAJDfF8j}L9v zlH3su=-yxsU;f>qOmc2%%nMCeX>#%?3}>V3<~GGhMw4qt)xAPs!6BzHZvqM2P!0YQ z7hA3hizL9XZ#7k?0>yMQjybr_ml#eKuLrRq{m`);8TftfQLGmP;1P zRPs|gwI0OQ8yXc2mL=lMw7Uat_2K-Az$ghqlv-)w-6_(K`OUoF{CCpR+IMy4DR0fJ zItzM!omD<-b^G-8)+^I!I@-piA4_}M(g(Jm%*+J=Kq(_4p>a* zbBbkFd8MWq24VQh#?R()arN3ntuTA$7n19hFX5JPqIxa7sXb=+xkzq3=^J0q_vLY^Jt#q!-C8>kLv2slJm5@!KP3r!4D>u-M(9ieKy)LPk<+q!J$=Q?<1 zZVHC)QM4-`yf{rqdrDTaI*LEiNhZJ{@9bG`I`qEmT?Q~QCoBxvT6Mv`)z^fyzOwh* zb4lQTAZ67x&|M&qc8F`!m4=ep-0im%qq$c`Eh7G4FcDZ?^4gPOlEjVI3P@C%+eVLe zcMuN`D26`ZKO2a#~#Dn=iaopUCnMwkY11B&yf zXn`LLq}B7Y_fe=J3tyHww51|#wUrw3({kjD5f>C=uL?vRe%<7E=lLm`Ra^g^Mb-zm zk#Mnr$(*5+4eA)S?qV8f$4Cy^iZS%?6@eJR0#Z+zbx<7OSxFwFlWo~-bz06~OX)zg zC!T&NvnFf^X&DX`fMaI9BL}j~b<#3G7j%{tl>Q=XL8`Eolx6)RG+iW6vIjzjql01+ z<&>0xa`-oS1dNU{*t$uNXa>L1@jamN!qQH;u$gisBCUG96-^}C*)S?hb-v`9DX0&5 z;x<%MRz|`;E|(^=*`CM#ls|@dc35c3cx>JC?dz=+4^Ff@amK}9!}&^9*6uRMI5@Ng z=Hv=X?`=Cl9{mDI4q<*wQV8Y7LcW;rA%o2E-x)UtZGI z3I=m#io&#qO30zAnm#k2WoN(77bt)cly6f{{ZKCrLuy*+NfxDN%HB%-|P`lwWA+23`6%ipgW3Bn+d(8dmn{~>_K0{6%P}-IdnLZ1G7RTyi zz90D|qa-C%5w%kym@ZOItDz~m|0ZZDp8!L6U}!1(hAtyNXT>=uZSNCj6b^`CFprxx&0sfl`@eFn7l@u2C=&!YShCjJF~lv zNSI$C4htiHIe?h zIuEpiSx+K^d7bo$jmyQ-rFq}^`};b?q5zKfdm4DjLv_=tCy(W|TPO)<3oi*!0RDVuGy;^&lgxo5)38xaB>k?m zzXJU~`{Nb{f41~kYImx1MpHHq$$7#T!+tSwYPd)oy#oV7BN9js04~ohAxOH>Q_Nyk zooXVQlZ^eD1G%0CXn6`xP;XN7B-NI{#<6-Mkc=5hY&?P4Dly281=m^(IQs2ju!i-n zv3kTXz_puVT@q%*QOB04ABp94ACuxHKqPlH8wLqE=#$ginxC}oySE&d`bS085fS`P z_FZQ~{RP(ItDO7$nos^t=8>n6c`)=B=kVq+W|7J};bQgqjk$E+|0MGeNTqH`QLm5& z8hBz=qS%duA}zpQ1Q*1;`tffUBuKfILs1+xEi2`;s@e7O-&_zAB}oUpbI_8xGZ9u) zPW4lp(b{bT1A)oTfE5i@=)svaR&P4w6CbPyp=UC?h$FMR3dqUzWO!TkQ|LPaaJRuT zWWtwr%~XBgDD>WIIfg3N5)O%@wnJQJ^tf`Ewo(d84>v2DSerZ4Ts+;Xo#&ptuxFLI zsiw)ELc1T>$-Bw9aJd-Kk=vJIT6Gy=F2W|tC8Q}0X$*0O6qKjz#sXnr zZBYlWiS|qH&p)0W_an*!n~zaUC%kRxxk zvgo~!($(1UZ1lw&xZgF7hE4SQ{%-$|;s_{4eKP2g7c|CwcgVyB#jf$zT z4FuGY9e_-tBCT$?jc|o{YzhHE0F5cO!pH|mNWQL`D?z#GUQcxXW_$+^MAzjWN;{P0 zB#8ln<0bTCI3kRC57P(x!{yRV4g6~4zc+#H-WmdK3#<`c{O-uSf=w)7%%valoj!4e z2`*%Q~irsQu#xs_*`8FfI-x$)Nuyo110Pji4THVwy7 zjL$bQOprD+rqta5!oyrqCI9tu)G0ZH`caT;y*ed_P(Qfqn)T1_=8vDgF9Nyfmh17W&taFQ=YPE)-f{Rh=Ae&24u-x{=fkV-L3@2&Cf;nd0P`?lc z*juJ8vY}*Bd$Y5`0#H*$6)n0KzK;u@>B0Jk$tKXyA?+DwAFQ%XR|;sDW$Y5#C+&RD z#6E*UTfMN~n5)Uo#=QcoR5#M9=yn05c2yWq^2RO33o zdtKFLGlJr;FX|=K;++n zYON@r0DUm`ysEjE!M|Q)1_)E>*Yt!xBVRznCDEea=n>m$ zvmc|T+!ofEe`4{Q&@~$osyz&dYH`$UD1_}DbkXbCu_nEsT<&>z8Kc0zyxg*LJROUn zFT~h6kSn4#U4`-On*O<;G$s-oM4elu6KSAT0o_J+d)bS*)ZxHZrt=YIW=u=iw<&>? zHmlkM80m`?8+)|_aoZet4sRL_3l_3wR0sm(r6vC~M0Q{XKc|YqzCM>gV@wS1R-vs- zVLdZ4Xos!&SGKhNM{*1tt(T<22>kq@pu(=L>Wh|%5qN%^Ar)gT2)Dw0dHhrN;TAh9 zZiaywy+9aO#%S8vdgXY*Gj#7YJ#~Kz+iVlZ9riT?CLSGn@sYLo_<;D7ySXCj4I zthp0;k8*9rXF&>wJB6Ggi4K8~VOSK$fDBf87uBjOfL_b%addP=8FA^E%_$_-7#KrU zNPSjWT-#a9)tH^^%-Wn<{yE_>1W6RHokhdIr#uFl-1waLlNwVkLB}O8alEUiNApd& z|AY<+HJuR~O1Dqr{mQX0IFP1FB+gDYJ@i8ZMZcR{;^k(ue4v$g+3GaaPyWr(86NIl z?Bfgh8N4GIo}Hjym&%5ARgRCiZ#|jCwKw=OR=#8zj7oh{x(Xiqv8To~Kc4EzsD{fB z8#SwK0Y!$nj)H1W><&ep%dl?k<+t;Cp4Tf$Eqooffu5L^Po#LNlg6auX9y99znElg zAFX`}g?&r~GN);~5f%qlp50z!y+Xx^Im6n8d*2?&cp(zkLlkS?q`KmiQ(k6FG^&HY zO5?7iYy98*#NV98eJe;&DZN38iJ#RQxr$!UwL)F@c`%7g954~I;7UES^V9QmLMfnd z#3TkXMW2E)Ofq&;1+bSITk!Q3#%Jod#Ow7x7Y(eB%5AkQnaG5XaHH2ucfLfu;jH0C zFB+68LcMve*~|#f#5WbhM$Av&^aGW!p^n<9LQ69Xca&3T)U&22&iQY{lf%bXq1@1@ z!7gjz_Ul7KN(XdY17P0uJ#vp%lWFdfcneF6?vEi1&IKV`K!FV0!~sP+fYg zCjo?G+_fXW^-Ke;0>3%0?>8)r>sEthBDu>ywCDldz;AIe-Zosm4aaGpU@+`o)wq3&C;MC=VxKCfuy3&02oO_k-Ff8D3n*UM*M zyAIafh)(ZD)c;`xM$W8B7c6b7rVaURLcG`=+AjPO>p+^)Vl75XvW&1*{N!Xb5&61F z*;1=WG!OgfJfL80#U>g3PQhyalY(XT4+>Vgl9dslU=e30rXe`FGo|?cD`wtdr4ye$ z&e;LYiOU&fb#hQH94RCG#b+^0@!_6BNCL6p64E zqlc`>*BV_9Dh>4*AdB;vG0SBmE*)!rH7oOihpVA1sSl3G+bd|`@zP_4i(yB*-P>Ci z7W2!^-GQ)5|I+4w#kf7#Bw3a4lsvXwH!uo3<)TCFCVp8q#}zw`iNqw`Jwn%$4@^iSoFb1@B1IP%^b0|^Cj7X&L<`xvz_ z&cLOC&$ynp^!cRW^_jCgL9trLpwVR9Uv8lh~4j2tRUNoHKfgRfE%gsD^G)OJodZWzDTpWHCL^d&>iI^qKv zYdj)e4yR;|f7-jVe5uXYYpJvvJVl>yCCY->QF`&zThr$2ugt1K)rgjx9i{H|`$fwM zCJsDFM}1ka-+q6PKH5S)H@8bN$axDCMUm~;P}O$}_4}hMPbHX{a3$?W<>iuJ{x z1L7(wOCNiyC?0L}N&TIlgYxKM4HbU@^*_JOA0DxYk?!Wpi}ItS4yPCIbdUSbz6>r; z_y~+FF^G2g)WPZPp^5lQK$9pdNNI~sC4i;JVL8kVt0&2_dDd>Q`=tj^&rQdQZnRzz zT42rXs%pM#-PYO~NU%tc_7ok9bF~)Ldt*4<3N}aUN=jJqg8}d2a%qJfrKw-_8j)oD zdzh`5lL+P(^qqn~M2OET#OfG}qof4Y+2hC{Zz!CkvjqrhIRpN285g2Pg#6;3ar#)qYAH@@!e^VD~%PSWdfe{(%O@1C z(7^;Pm&*b5sC_vprtbZ@kqcW5w6LOCmd_M%?9u%C!@bdgx~J-;cTS5k=g0X@%i zb)?^l8IWSA&uM-(ewEs;Bd2r$0F(;szf?+mpmo2B-atRUK5y>Y;SB2|hqi#&QXS8o zhH(d?yE*Wm3t{N9td{gj(xtT}_e63g%zW3+;Zjg`sf^Ybuz} zgrT=mk3$mn2um?c^|1B4h!`NVlP>@4!|bHy>S87{dY|QU^TWR}90$~J;qP>2FEO?| zkwcr`cUuaxDD%5{{Egw5ry52}SuZd(Su_haSAmU%r3VvXJxD+6)bU*cpMKxoB*)(< zj@bAcezHy$H|5LHy4G(ESIwl|a%eLSG)yveZay=k^^n`Ynh&yw<1*0RxQn`0rojO5 z&G9pr?IOC{cWZXkXT@ur_tcx^RM)yk#^TD)_}-qo(KZ#)rVVo;8&mfE=9i<)p7aDi zsK2vKvFA~_bkfH1aTbqDn@7N(Ex=a&SvL0G5IF7(&cWOV@=ZrH8h3?u8cI>B7QfbQ z=6h|rm}ubdI-N-=^!_F>3M{9MD=l^iXb(qKiNkl>YlllbsK125z3mDu{_=a&{%2ms zmJW(8k4tq)FeZKr$rC^m-gxZ~kDJ4vI-CT;hJHi))(tBxiDqa-`QAdV`vEf*DcmGi zxMn;4y=%`8D5l92d%fsOR2Z<4XhH-FhjIpja#{nNYq`D{Et$ z+Q-UT)E5-H#dg(z8`wyNn#+CHK6zB`$qom8VoXr=lXWSbTYi7ho!IFkh z-rghY#}~n3L&^OQta~>Q2>gSBR<3yEqxUuqw1&KX_31J5}}ipHx*DoA90x2jAPdxVn5TMyph{C`&gq z$|TWf?oyUaD);_+V)G1ppitV=u+p${acBHF&Wzd!l?${`4K>PsfQ~X3FXA;utE0Hl zUo&W!o$hf&{bZX;J!rjsY*{%-Hoq_lRdX!1Bhbj=Sa$Q|mBTHvG<@rDD4?KF?6xw8 ztMCRyu=;BYVZ8D~Fl$rbXmYp~(UE1pWB{MeQ(uWMEvv+-+uKf*U%9;~DCA-bvB?i{ z+5MJSa`_K4N5!a(nL3ImG2T2_JaVsHOnWJeO*8^!3O$)b87hm-oO~2dm_E6X5dY-K z=kr-lVvF~_HJoJ0E*Egx|8%%7^u_f?^eagSs#hnY4}>>e`3xBm7T8X#Z25K4gKv;f z{t>U2lVCfB-wPSyvPh!T2l4XDof$_9LxFqshnt1DW9-H60~VhbO}fRU*cD%^ZC})J zw!o#-K{-Tk#?99yokn+&|E!CHuBnvCfzvI3tHtIy5sFdu)G}?XXTb zH`koI2=)_9ki`V{YBSG?oJ+b^!HT`?@n68`7)^RO zDUXQZ=*YndV$!`_CO&Mma@;65EaOy>D|(KyFsP7e;VfPF2RB&lcW&^_dqo|Y7#U_S zC8%f10v7}Fw?Z;vQ$JA6%FiGOHiL1WeH+agsBJ>KLebd&jjby11C-y(g_ZU(N@@No z_9_tOM_UO?(!WrPvhGJNp-b!U%ko)8df5{`e7DQXO$hb2Ml6lvF@}6u4r;DTO?6#z z>3c0#2~#WrXe-@Qklfc7BYy4#A{*c2Wk!O6FIfe2Vs%c23RV@>t%Vp4de3WW8~W{A zUwbENZnC~Nuwtx_9`}hElX#SHIoj6i^$LjM-_C^k8LqP^O*F__oaXKBT=8gyY(})@ z7S>gH0r#4f>#m8veD-2DV3~WD`R-m_d%{-i@jz5bSn7Bl@0#czRrFb^6RZy_KCmlq z_Qgcrs1aZ8FHAR_hJjrWIv1j!)~wlSB>-cSKQod*3t_NQ3Oa8yY+t@qx7S~2kR~(| zO?^BfB~$n=$+(_YZC-t|yO9Cx-7`1cA8N{sR>?UK+!#w=>6Ggx*4C{8t^XxmrOBXW z&^=z>f$vlHnk_CK($&p8zfpB)_)>Fi3SDq$D7*|xgaV4UAT_?p13Y&)*6N8>KH^4$2Mp?r;rJF9i*RpzC%& z67V0w2LDJ;(NyoRC%szUc>uqC;U>-T!)VT`&u_INJjneD?z5|jADnbqD`@HHFxWR_9Io z9uJlI*@uo13SpQrCq47aEf;yMSvQ5Ixq8d{ad|gvKe~#^pZoHOUJpf^{1TkX=t5!xzyau=K})yg5)f z7j$)G?A)NBU@<9Ea5LL>$_-Vc;SqbYZ0z;OU{QW{P~LCNRtSf-rxdK`11cXm`IXeU z2N^3luA1}yw9yCB&AGe6YH6SlwYim*ada^E?PXW@e3XQ91fL${5~=EOkjYyZ*fC;| zW+(>-dCnqPH-rS+uGDj%4CXTUdZx1TZC)wf_~pCiIx&>moO1VfU6t?eDEL*vrOEI} zr*6b)Gk~k+b%M&lYSZE(y{8+PDdsy<4A2l-=xC=kcR41I1y=Dqiy$}9VR7hUmgz9F zH`wiqm!*}Huxb$e8NUv`RrHbFd8zL?V);_QM$@C+SV_-dS!rlvvfQ!nE+Drrz<&Hb z56^x`hX}kCF7=}wMt9dy%(qA)f@b5syv)QIaNk^_3}iTaO`gr5vz%{ z1dlJ1FIhvG2cP-yP1i-e^w1LY`*58xrq)O-fGx0lXz3;)i5?@4X-NX{^6RW}1k7N+ zTw$R%!uXVek~|hn%}fu~Zg#p#FL*Ko@pst6Vosp`9>bmz`SX@NP=BXNQ%!k2ZD=>* zXB2)7FB%g%X#}+2dzw7f_kCsv8OE_MS&6EB6A&TzX6mSK-qq??H`EqNRC1mBeva-x z>`fuV4KPuWPGa@mYa>cAJUQb{mPjcs1d2+tXROjKQvy?VKUU^3ky`60$rlFB)0A zCx%AVX$9_<3+)qHKQDUX2IK*@1`5c_<3~O-{mR~$u0{4ZvCWw?s?{rp?|Hq5m{vDR zo$W`w-Yxg@@+7mzom*P6EPec^>84(~Urcquyj|kjEC{pC<>S7hL1VtL=S&LWj%8cm z(FLp4`;idt-1?26yf{wDs8Z-(a-M~0F8$h+n!<9d+lR7WX}RSZ=iC=vIb z_`rDD#ZQLMwT4#M>}w_2Yr<{LVgsC|4T9F*pUM{K%9d=q+gmyhZrkhjL@ zd{B8O6?P?$wM~I=KhV505r`lPDw8aZHZ7_nq^q*$GYz`6%& zX63)Z;i5q;+u)0jvT5_*HtPt8E6qaLUqc+|;*P{;+#*ZVTc#pGZD~L}t?GZ6?2msm zm}>ulKQq2}TNl*bwwejaD>x7xm8*cDhM~@(?k65!W9N{lVYj36t&qy|Cau(EyTx>S zc!(4Cr=NYmw?+#&oT}2$TfCno==BtW*KB=1ipZWju+J-PYl^vF0$=~iAcWr9`yMml z=w)RcBk*{-t96-&XsPB+$nM!2Dc=ke5LFPIe#FQ;nzV3wvueNz}k*jo6vMliX+_1EOW&RTPG zty54e^(i?ScSQ~SWjdY9wziJ;Z(G2c`K9F-`nm$;BbVQ00)4*fkqwMRIY`yfBNMSql{ts-#?8=(HwCgC53a37_0 zrxcA;4z&gE3`v!bd|j%XGf{CMXc%i4$VaYc3K?Q1-{(ij)Kw&wHqyk%SiFU0j=@6W zj&2IM_0f7A{`AM6=b}4n67i@p$a^xEN&M-9NtVZSAAKy#anp1J`n5)A-YM!=7VDV4l9<&Qg-W>@#lR=iaq%dsfVstxbT&hz2 z%%pn_MSK3<%F(1}5u9krvRLT{;z0j!sqc36xElpdcNctRFWX6c02HX>3#v4v18qVs zS?v!E)ER6(Xw2qJniY~dA7N0U)$-OIki%I2l`crbn)W~P{{uZG=jQgqz-ddb%*(Et zcq!^PpeCiL^_E?g-9!3${4--R_7X1OMt}pO>FFnS-h=t(eK{o}Gwe4aF-zA4Yr`>r z9~{y2t&ffhHQnbbJ%#Dh>ddMu#h3^QRFjvQ(s@-kEK506cIgy0ZGVEVO3dna5AD$u z{E~82wL<5SbQ?3C`MQ*AU%2RdF|jCjR_nY`{Of{CZ#hJri22tT^-P)$n@yWd*H{;O zEJ&KgwDQ!PX{mVa^xEN(GKH#=o(?sM7=@)RJMt1S>xGPsfrMwtmA0pY9p+c||5oh0 z()Rr3FLb|{%Xk2}Y-SfX@5YuR!uhQ9y|`tQ@x6p$S&&%N5%(Hdq;q{8jd_8a+V}N+@@;WvkRzBTh zi?Sp^0C`C`RlQGRhkV!Sp8UwJ^|c@=hi_A5V0O;Te6b>ryOf-Dg9U=Biq#qYpGD2T z%ISGZ|0r+DMRnTHBbv6ZgwKY6x!K`FTFTIk!S6#i1Tb{7-5A=%?c!7PW;!$|SQkk0 zym=@w6s{>gpz506J+{|!TEF|f5G>Ls(sBQbW{;k9Oby=wahOmB^PFX093f;+BJv(f z9ng_xD_)@@Q96(OVvEjV)cFQD?NZnlzYrkY$6r&49SAm5&3awh+A(6AHj48Va+Z=k zm1e9uQbYag7E)pV^?FiaZBkC!8AxI}R^`TRFRwMRJ8aXEgvx&!x*>w08+`mJ2x_w! z$NPJE^DQ~AeX2PEnXeeN;t-Ulw&k&&ox*mGVeB|9(ZV6pxSR`@cz1ufdOT^En$d{; z`#jiC;Myv|QdqTcL4VJckNP0Y21B=vK9Q(W}~N;z@! zOb=Lk#Bqf@hOcvB6;UcYX8L^9>qUJvMx)Hp@zYaKZ8!8S9Lh?VeCanbFVBPU+3fc! zY@DU(ol~7tKH0krc9r!V9*p&E*;{mY>`aEbgE|)Nm2Y~%Mg4UrToAIn^4MSOjKTV~ zT2S=vJ?3)#ucqyfc=>y>a-aIrA8rZW8{65hc-`(}Pslf+SoA2k@tqT1zMeZ)Jkf3T z-~6E`Sg3VRp$&r0_%gn&_0zk#e=C&RZec?<#=LLJzx%Jy{plL7g;1tu+5}26}mF`CC%!DZaou zoI3OF>`+R7GST8@?W<1B^g4wMrM2)zU5h6{bwo4FBx*lh)p4xmsV1i%y->0z)$9q# zqRA^XbAw($8`Y*QqjpOzWK z@yqjQ;B9mB@dCa(ZCuYS4%aFLN_5T^KJCYEo(aO%Ofos~p-|NlSS zkWsdhjKeWfQIgDzkWq>xTXv~q?@c0`LqhhdtYbU&cI+Jvkv-#(d2D{q)BL`yzfoGlJ0Oc+AzhGJm}z+^|bc+`0g2>|kE-$(^?j(a0a7oK?q8bS#l5yn!3fvsHMM0{c~_sadj zDbKz;q(YfHeYe&8W}t8lRJ1vXYXffvshcs)Nh5C;Ri{ao&MK*_I*6F-u*+P{tjTPV zEyi3FIX;w|DwcTw_K(Y&1Nr`t+E+i4YM#6z*EYLCHIu^4>?fLu{Vm2ZIyP{K)K!Cvvo+*PM+;FK|g^zaE5a^_0E)D{*ZHPXR1j2PDQSuze-waDuHb3ILezn(fE zmPePN?mcjK&8f&uZ_Z|!{i>6t_{^lh7PpR+`4PvyTpn&?^&4`ctYozgQ1s1OfZt&k zRJl@jrW}{Qo2CZaa(rOsrhw!>`Bzfq&|?t#Z(Z z*ObH9&4k{;t8S111UbkZy7wF=nS%AEux3yN!x3P@F-@()el3Ul`97`uIjtBiV7Rzb}B1= zq9<^$!Bd8NJtAWcUYsXpJDiobz+kVS5lm`tm1Cdf%sgmLCi=!V8-c$vYTZ@5VYZra za{9M5xZtZAf8Z$Tl-hA|^D@S1UutBH*)Z-`HL0zm%~ev1Pq%@+@}=;z0w2sg_eN*` z0O{K4r)C3dwqCn%vBPbML*9} z8z^HOAshqN_DfkC@4mV_q~a7I(W>lh$>A@CYgY!Xw<9%&0;KKhO>= z-KJP0cQ%;I`@tjZH0R8;UCopE!6URH`zwzy@SQ-TW$N+jdJX#XLUz&J-JT8)t<@O% z=nZzQ_fHzQ+|7~@CcDE*D#u`~S3dx_gzsdYz}|T3o~K{TEw0{d5m#&RxGlxFk1llA zq>3q(%CauzT@8in+AFwr&T&dD?fB)LcXN)_IFz!lw9Gu}r)QP<$mpSW(a^MXCSoK) zv#R7(bBEfOkPjAe^|wYXWh+JexvHr-)zUJvd8C>(K>oaVRppDz>y@XYs@1z=3_MU5 z$DN8fksN2>U;1c^yonUFky|fjd#@QV106^ymo8`0#S*>Dqu5^Y=E-mo(C~0(Ao)Zy zo%dS;u+$s3k%nFbY_e}!(z`GBw*`gRb_&k*4Rn9r28|bU`#wdPQU>JOy%*Y7gI01< zOM+U*0;EqxbVM1&tLt2jGYD{;d(ih4qa84jJ#u8W#u8F@=tx)q-+!6+{si}iVb#p1c2 zR^$CUgBluvh)Ussbn+}PD64oz3^jIyMhX4X-lGZn*<{j{kRA)Hb!63lmwYM^oS1#7J)i#k>xYrMC;=r!=Yt;2$*`&- zE z&`j0m^iOeJH-ncvi(q7=e5fpX)I&>AeO=48zf~2{h%4Vm%11YsmqBgMi^!&;$R~X6 z_X0P_@e)WR!b_sxFQfiViGyJ^+VY|5kUk;Uqxz3N2{JQ=}g5~D$|UCRNg zsyqm}7%VvZZn=RAveR@dh2Gw*q$Oa0?Qp>TK((vG1RNom5k`xedSN{lu4$2K!AQ z-gX=qKCIQSgd*^8Bvp_@ZH%fufasI|vLtnz+L5)k~q_1>t)!!)ORTIGzl7Ns&Xd5?42OSDyrwhH< z#K90kWlyomaYz*OB7|K|^R3U%ab{!fAy%t;K-qsIPo|ixRG84+VMqXWK@N0}v{DdH z%$iTUj*0|mm;kQN*fIBNwpYEBJ}$}=pnvtqEM%zIo<+i)LRPb)jQr6!cxMA64pTwA z(`hNeh~j&3E^93#r_O5)Ch#q5-}qE=++IjSg8HNL*xu;K{!UJIF~0+c7w@|z@PW4D zW=E4y)iKO@XD}~1Z;ykxR+mo&G;LLWs|;V+1kQX_@nMM{YQrno^a_^C79%t(uV zl0p`WoAAMDewbxJfAFp4L1&U8(Sg@z&f9T0w#bzM5Sd%_!qOA+4v^NTD(1j1z7%~^ z7r#HvZa?tE{s|Y^sT0(9t{Rf-83PlNBK5zb)F#?87=7%u?3}=jx|EBGpJ4!j` zAc&>WdTW3=!bQbdkbuvN-Z(#%jLgpIVN4}bKAzuvR0NvXP7MuEg|~l)f8-v_H2E$N><^|pkD`|%8b*E~m}z8-K| z1}~oE&LxM7g!Gg)vWnZ9HzK?)?+Z_t)d}i-^9Q_UGSR8@VRW4t{f_B_$y~wnrG(s~ z+rno!>`bPi^QL5bZS}RO?>w`zUbydwV1^0G1qaV93R2k_u{Miu=+P=eCa+@qohK&n#^%M{(z&u}wq&N#xj6cMUxnj+5?v`4RSts5yx zG)F(!=)LuOG)5zhr@|_M?zv^kciGoo_Fd51|(QIufurzML#mVauT`Id?CO z)7Ruc69v&&Jp-U2EGjyWxCA)5>J#15(bD{~t27v^-|6*QEZ z;e~UsnzTu*=OOxfaOJ_U`t%fy!c{8=z?`l;kP&A2d*(DF3pEWG>YPo@Wh4|Nt$m0w zH8HuxDOB2+r@sybehMreS7H6o>xv1=2?qh`o%-&(YUdf9QHR^}{il(!nx7(9H#~i% zTwPI<_V_9bFd3P7mYvpfn6ZdB1pt_ zqD(ghpW_uH&eY?6IXiwQu}IIb+hB8#Ol)Or=;5?_jEl9eB|2Hq%-8F>K!HnRZ}mDEcGw+-Hz=M z*>phEwt5aGDAQ%Gq8AC_i38ZBKXhc`R`lodJ3V1B${C+?lmAWmX+Qd%@h7Xo}LgNWZ7oD`ho@j2K6sP zgsnU`Ze=Kb=V{*YkAt55O=W%gAFak)qVYGRm8w^TjmA)$(q})(^c4^4v`3-5fyoDuf^(93x1L9XnaDC#(##q}}?-C0P5gfl8BH+l= zaHRY-FGT+~+2lD@EyecGC>)6~>MtZlJsDj`s{F%=55w}O^Y`{=%4oNIsvT?IPqNc( zAiH93eC|e_@+iLwj^>EzKU4F-a^{|3zCP~#$0VW2+fCDP`u(^J>y28|3GtPvoU9I+ zIq@_&xdLaU+NP3DJaD;n(~t72-04)gFG5#_?CxNXh{r~V_y2nG9NFN|Ez~&XDbEsDe5jC|Rvf zuFQZ8=PQOB%1PT_S^x~er#ZNH5t{dT;fK>ynPv}mnGxIRZ5i`T-tv&i*frzAUV=FF z?zot6wH+C({WF#QPI2M7Q7z|uet0S7Ngr*SKOSyp+QCm5X?}iOC!sBRM zrf(NnJ)3HHt);KtGUbinZKai*0mh4Po>eD~RvJbb4eT?R${O@s3?-@;k{|ki> z4#JI*5TxscA4F?{PC~6Wc5I}}r};LMv9j{0V$@}q!Esbb%0tFlAGPmx2(%#i6P~Vd z6yHbzik2JYZ+0Tqa&bXN7dOa?lM2dKl@p|Nnmm6m=>g=^d= z8!n!Vv!}(mA#nVg8-nl;H-tWzb^k#2^fpbC|4%mr$>Y`oIk# zwJM)n=12WOp8pK8Zu3V%&zlZx8}GgKj<4QSxTkgNj`Uwez<+L}X9U2`su>iaLv;D$ zvo)7PiSf4Ztf)B1>;{rmCd2a(!m^o4UGyqg3*|xswz6JPp zwipyMy0F?=#db1~Ju+2nGQRYA%^e8}0uMYq zPvTIuX}!YDs>gfSy!M20z0(&Cg0s+xF8GWdGTg$kZbah@|Tx?PvwEJ%@m!y>^u1N?03qOpFmmWeKu8IDO zqk)Wk&=*RpZuORWvf@*2r%MNWI-Zj8pJKEmbVNgg9kk(u=H3F>Z9gOB=6Y#TGG`Sp z`e%Awg6+toL?JYD{CeAjk2YSCC0A6F3RnA$&r6^NNn{X_4%{(Dhw z{$8m6BGQEsngC4g$i3HWxTJkJVsu4jyt0PD1Md`pRAriob`VhRS8sW}kJshZFNA*E zRi~|~DASLU*U~)Mc~7qS%5Zd-R%0=5%LjZiZbBjM<(??Gnsty7e59afOw9lwW^P2D zt5w)fblavdVro1bOrMCt_>HV5lAS$6YBTzRwNWyu_a#}2H{VxA-%9Qi^^g}!5PE0# zSb_oq$B;;jLU1C5C%M4`Q?%{3d%}5rcYISIZbmldB>FoK^H>nu2tA0i3x)!w(YD*K z=mx|AgwPkyGgKSB8Gn6n2P}}WwmKnU0TW1+PRzf!@OzgK^Ww70&8C=olFPWKuLLm$ zzoz~FmY;)~r~UK^S0MiSl+f{#g|Y+rHrtAu2R!sryqm9(y-FVy5lWnqQyAB-K&DF-wDt#ropU~2lOtk%x-fH zMy@It-%^ag^ifBnVHG?Feh*kr|sTn|lBHH`E&meK_ za&<}FlpsDtWgCcQv=)17HAbN&tUCBrBwr{n7WbG`YSnvG`mTJZH4{7k4Xs(_2d!C7 zEhshHIz~>LBa0!<0haeEU|q?lU(KbjN4rlu*qZzsVw++yMah$ZPB0$ce~7;Fu}5O^ z&0lEEDmYp*6h~{O{7!2Q7sepI)0$O&(wbe{`Qz#LeNmSPAD#$c5L?a0vR3tLit!4F zt-l*y7#w6l%;vM7uWj^9(4J2{D}fei`(KJ&fnP$9j~t&)T;Pv9Zg+|72isT;SxWtr zZOlPd2Z<-bV}l{9_&(~e%fw7yH2=Xi<``D|!8TS|b6H8Elf3G{jX+<8ncHpOc+=c0 z-puZ!3_ah|6n}^q3`9m6)9KW~bX1KkyxIKgADo?^_{lcr2vYyeHuk;428)^U`3lj| ztQW+5^N|sIO|wVUq#g1k{l!r-n#T9xMr24oWs2_$<2M1hR&M&~EuOi>Ih9|gn$QW7 zuAQbjSd`z@Jt~K%69CWG^8_?*pVCFW04SO07pUGpGK@5KIN%IcL12zf8u!$wz-#o+ zIx6q3;*~%%yKk2@1e^zT2*|l*#*=IGLd{Rk-O(qv^9olhVVfndhfq>w@~+UORK9cK zo&~a2)Y`y4UWu+6`I$VhV+7Q=2cQg%WS&~<^j{$Kgw?zlrTfZ&Vyl=QlzP$G z1q~Q{dyD4I4)}|LDXzX!Uo=m~tS7VVHcuq+d0m-RF=}Av>#OljR5~dxgJ_7SC(_t1 zfpX+<;`yn+0r8$_yO89>uTF|LH7?3yQ#xwBaZ)|r+w~ni{}jr|@t)Cp1n~`}k>@YJ z4B1TmbD{QiOOMy|bCc@*#JeY|N}8mJ>-^ya!T!RuDhB>TZ9bX$u8aDftZdcz zVn|lQbI5^{BebZ&l(;9=JfTy87KRuFQAZRHR~bER*DJCSP+MT01ZbRMM5gyN8l)Cg zu0V(4i0F8Oo{CA!M$7*6N!ZdmhT*#i$>S5-|up z>QxmOjY8m^D+>Yvs7oqhzR4<3@2108qyDvb@R1#@fb_;GNhXyG3S^VQU|hEu*Ad+* zcNDhXDv=m10>nPCxe9Z?FC1L~To*+^Y#}b8k*NlwzV?Qs zCL7B0{a9`v$6Ts5e;Ob8_)-jD7mEf9j4Q3ES0mHm8bq$K_k{5`(hCHG$=L^`{(Ta$EsYU_(dlikFKGx ze9ixgthVzcqtCg}`=`3_LcOF!ne7{+F`;}q@@E8R)yWcgC;D{1)0xVX;k$#Mt?|9I z77U8T`1W_(4HW3BBHX>kXr;0o*BpEYWa#bohLzkc`**SIkV>8Lm525FZtf#fv9d#k zq$qOY0e2u3LXW=|Qm^PE1Jn#{@YmQNp+23ho(@b)ozhn!q{gDoHeN1!nr&pkG_F|w z#+|qvw#SN*w5U&+S#t!E6{V=cveFHiCYh^7&&E1u9n(yotjS*jbb(rBTU9Mfsn62S zaAIK3{vrnEjS~a&24Y}4-Z(KZZy*L1^Gr%Lj);dZL1h8Mm31nsTu@UrMB>9vT zR0iF7N}l0PAcXr$`OYAHQO_m$tJ9Q?#(o(m2>p+Z6S!bA-v+~IP=_q#$HhqK$1^U{ zKI{`Xli#%bcU&}9_ODH&I-1>^NY*Px`lMb$Z(=i&_MaPIzJ2MF@SUh#ZU>x?VxNQ0 z#>QQNV_J(E!&-BRe7q}~DFC}nCWr)usATE>TAMl;uH7b7=OK0&`jhNP!of$9M-+1} zC4F&E+ex#sziy}hT&n_aU~g3RfjIB~d9Ku&V{EC=5F>tZ(W(sr^(E^UeSE6+0@!IL z(oblM?oi)Q4O3GL>b4r?C1={E3_vJ=x!3CRp=h>-a+P{NtEpZk+iA=ns?IXV;gcV6 znjP|SjWH753<}L{U=+fjV$Vvbi0e_a0Z$1$v8+FB$Ru34leDj9od(6FK+vO?))l|+ zp+C@opQr1B6aXpNgi8fb@3cznN}9Z~epT~i!ka_zI%0bov}pJt3^8`w7yBfKK+aKY zl(cC7I_FiVq;M>?>+E?YWJ`K&Haz@rdfce1711~zCYh2=cB@QeL^Gu%Lrt|@Eq5qE zYl$_fm?ynhq}>v-hJU(+%J21a|KNv({duKZOpyDGw{Nq;$Rvn;OsoS}LrmTEDb~Bw z14a(Bv8hG3A8F>LPG7`K7jpMaeueXrCLF}o9!@sIN6$WNiw%_js0AX~u&oxvY_OEV7yy7~cbBc~ksDg5`yD}~#sJ80|EhOji+f02f6+d0n zc(L6rD!ykDn6JWp*9YibWMk$ych#20hSC(cV3!BS`^W*+IM8?t2n&~{%?bLxSlWHp zqA`eoi{3N2(K=YH_uMD(xr$ z0$T}zCpdMQiK)DQ(y{sMnt57s^$%hQYJ94;QPSN@C_aFGF{zxL?3TXHx?e3k_6EQP z_N!>T_&}a7z4C4~0hAO1(=TZLloW!vLSly?c8Y`z_cYTKE&1n^{rib(r#!*JZ)gh; zNI#edO)tMQ55iEFaKr;1gvFyT=aI{+wUSWCDAC?wiGIdr-jq+wtL*Mxp~3W~cx~TJ zz)-ZOUJ!JrGrqdE!ZL{Aip2lHJh(15OhxBh%5Pe+gL1%kRwHBNgB6NynTqH)`35x! z(0WSpe-t9OBOBU%9$e^lyG~wsvU{E$|5NB>H>TyqUJ45&Le1|U@Z@`=V7_;Y&e=;~ zcU?&0f6hFxl0;Wp{I69OiKT#>c>`rP;}OHGNCY7gKHqXzD$7luNwbzsoFD(%X(7Jt z%L`IjLLAJB0W=1~;lfTzU8CDs3J|+p7HlnmOYIy8@j9Fs(BamT_IQxfv1c&|!c4D=O9#&S zLq30O6UZvgnfCzOgz$g1O&FZAz6u-BJbz1{VGDh;lV%HH>Yi64KX$l-kc;D%C}8uG z@>_)4tGV3NCp0;zzs~ALzy&)uN$!-mPBZ)_UEu7ioH!2=G6`3RDBfN{>JQt5FTgfI z?O$vYgu=i~=s#=|Dmier31Q}7XzwJ6ZsjmoF2jL1vv;_8aBVLhfmFFaJu%S#ff_Hn zpaoz2{_Ibm`7if$pwu{#f`bHaJis=AlJtQi&^M8O#3T!~&;ZreRYi8{${>%2b)!Pl zi3QOLB%tbotffgIcF^6bS}6`6^JpP6Yk9nLD9 z$tH2$Ef@l6Q8POnNRtPJ#}BUDqB0&XHjxQvkk|QoOUt^M{ z{u`gQW5+y$3lD|_^jE&BvJ*g6>ZpWPHzIA=Ceq(!SU`-Ud?d@?4Gt*Ns|B%^riF_NNucV!a4>2MEZY- zUF0}2IC^p{TlkIdc=5LEy}BmP=bja81Fszb9#pES69Q!3Ih?232Raud=>@Hx4ebsh zda-#B$1Lq4Ugvg=ngic|Nr0|cL%BuZTrJj$}(~IpQ5NRP%)4$+WhHB z%;JOC-4WC!nEIzD|7RQhWy{nO-UN94=Aj~Ci@U7KwF=_7t4xT&5lQCKC3#JC>3?@i zh>XR#C1k#XadP175)??Rr$-)ALGc*@q!`#G+(YnY8O7V)lU>5uC6KkQ2DaZP+Y<;A z?30R38WWu~brX7SK>OiS2s57zIh}!wujH{N8lpR>Pd;ikzA`SksIOGVOcBC_+|w}Y zZzibjGfCGr{VYEwV|P=EQS7d!IwsT6Ky5m$!yqA9C5{%`bn%713qT}yCI7TbKmfZ0 zE?9qup286o!08WMdXF%h2`2);Lk>coZ5GfV#JiRCXDI|da3^ZgpcDGvo+x^pPwep9 z>kh1M!pAdf9_W#c-I=6v-r-z8Oc&W%QDEkU$>r51kPrWd_%Skb@5A_>bBuLEYi0-! zvRj)DeE~y@U0Op+3Zf!F%iP>>U@NS~53ib=x^Fh##pI@$j|D*ZUx-M`s$GC~QvkgG zn#L_Y*v4EQdny|z5v}N6!4O=ivln}L_R8#pQf`!tn2{y2dOak7tb9Ex6)sZd+B_q^ zUEkZN*rv7ynqIU|m+qQ1FNkxqfaAq;!aDlT(Xl23h30IxPh84Bv1xv#$~83K*CpbZ ztc=B-@!A@8kF8g-ff7w!5OH>IA9}|dXkGZSfh*Q`b$U&HPbv(ZaH1d>sLRkHO-9L9$)7~4CaOUBo>QcxX1_+^ht|~J|4_$ z<(e~MW_48&bN2`1Lg^Rv*^7dj_@s$xrb>EmTY3pZGam>&$eOyxSxTzf2RTOSALIZr z&Ru&4LR@3+*Brl&s_pKjG3*U8I*HiT<*z~H23qdKdxsbDb_6(f-qc~FAk$Y+4tu$i z>=D8Th~2(`^j(10wdDi*gPEJh7%YaTb=kk{5(3;}bQ;Bl{kMyuhKEm{PYfecAC>Q? zd^a9j!cP5!^o(eWbfYdyu(G?N^FGtTU|R1i5;;RfkvdW~4efj6tEf?#HT9)0RIIl# zx$Q#|-)iT)f1DQ9Ulcp9|H_O30De{#n|9ibO&dfs2%}|XKPE|PRCGY`EeSW!jSx!* z*Fi);@O%n&ncy*^(DWt6B4t()B0j-`M5=l9tl?^QX+~>BPZ|g;M+5TP4&lmAI|QR| z2Jt)(%M+TVFn$0mt@BN4`^ zc5Kvoyx(0Awtx!)2N_VJv*(*?ZfK0JvUrlK=y|RdPVV`f|KkW1;7!HPn~IrC&$D!D zcgni2As$o-q6CZ;Gk?1v*d~Tt5ACM0WTFdFBjCs0o-PU+DRA;dOLr8(eY&ruEw#7z zqQkmR`M%NTYZ`*?fgC{WcUP1r#NI81$X(+0sI07&k=}UO9_S(iY^(NcXmj$WZo>|$c zd~k5oM~%7| zaeRy?0d9k{RB{S?ZDF-s)PsFr`%jC+!D%}s0*&;R1~!Ki+=M4H#{`?%?Gnee-U!^e zMd)dL?7eBXJK-YF?KAjxgmQ;aU2_w~#hUGdkQK$@$^%Vj%PrZ5Xl85-3`$%*zVWTa^jHvur8Ddu%J2R%raA{NDC$RpsWDk3dVTz@ao ztl|10T-a;?tkJ{&yK5vWfwp5KmOo8TfsQzK>VlkTYnGJE;ChWcH2&NpB1b||FOf1) zeUQCaJXZ7TF&fd&aNJ-|P_s4ubY8DP;fabAaK2b0pL?s55+^#}{%ZLP0@W&(U(Hi6 zX-_&yft?)+t8@eax@5GP%KoexX^--de82J zFNY2o)Hn-4emD;u*R^TNwtJ&3Gj<5x5~$oG6+-n>;TPVP^FWP*c+vCdC-x)DKv5L@ zVmr{m1be}&M2J(QVd%m!M3+Ctm_?@-Rf;Ym3gqp9Qj;zJ7YoTQYPO#}z?wI>`tvSf z10&v_6!CBOVSV6jMyTp6lk>y7c?JOSzrSKQ^gl zi!pXrovmS4Z4xO(5uc4A1|S2QV|1H2H}hX;HVyF+JU2O^i?Hll37H4>zV3>d9m+c8 zZ>9|BIhafRAZY%G{=@mkN177h+zowg>^?MI&qNl>HNphu`i-u+#)5rMnd_fE&_qwD zz8U@+C|-B9w*k5e@^BYEuYItfY7ckC7&zyYo<$nxR2FGgZ1aqi&c$cG=yO`BC9sD( zpz6z&RXlhGZQb{$7#CaNbY|P8_CO}ib}r7|Z7YTGAk9b>x&wyM{{EcUx6wnaC+thSb5*G` z_>YNQHxiz@HJX=L4oC&kr3tHnMm9%SbFOcYjYNXYT$aQy9|xWQy7>qYSzTTB=g6iB zpZeIKNyqWNYcZ#~s(h`L0|>e7c9tZZ%sV>#b~FkIE@Cz~IpS|!gG zK9W-V<>p*df@^DByJ`6+P5S#=zJ~sGB0L27MDRuhJw$*F0bIr6Z=31Q)GllE-K)3} z5l-;Jb|I?1HGXI)59wz0nFVz>8@4pRqQ~S0?aUZ)8q9HiA!#HeR8eqmMcyd}2A=Lhb|eKB{=66-vAK}O6~D(m2@)L(EP@T*5tC&4b)=?(Z24DPC(n5&jXpeaEi&OcXI0+*3&4)*I=c~E_ALVk2 zOIXM2X=Jbbtt~5sTT4?S40XLg?XhfmHpYDU^W&is@V(@4BEo6LOo+$!XN${N;KKQNZ;u{v-l;6E zT&h`Cggf_irz@7c2aalZBrVtt=b7f5}=e zu5Yg6{8Q= z>dFZ538IH!0W7z@F5dc`@sYSKLP~fpvVLm6p)V6297oSM^{)PKdwNoUZga^T!K=1e zPTi{ub!4_=(hvM_yiS|W(~-snRbuY*aKK2^&T3FI;oL1`f4~rxetJF3Jr-?qO1SnB z@J9rOjfa>HUQ$NxA@$YII_}*4H2b^TlH&wE%j$tpVB=LtB_sSQYe|N5FYL?(V_x&7 zD|^>~+weQV(sJ^AzA=||iDyn7?>#2)KL942;bRv$R@xbw+^_6UAMn`&LZxX52@KeF zGxX-MQD$B8;`H8c;BxE1$?r&a4D06!6RDd!wrK)oQpaA!%8Nr5N@&256uk1j!Sby^ z&1~HnE)4L{I1nM@ciBAJB4ZUg-1};N=zZj0E+=~MwYTl6e(Km$U+SNCdLl0S!VgUQ z`&0QR$+$j8KF?xks(I|C*okkamI+xe30wk5w^djnRY2#xYt!rw7ZK>Zk1o{MA%CHa zi*}Pkv=%BrD(ExXW%fo@*4=Bo4!+{uewOe~7gV&durnq;=&+Gi={_=|6hY`VNw8TD z7dXj{ZIUPHGE~6C6SyX-StPE@vv5OB$Kkuk@)h1ax{V2ic14K-!Xlm#OT&iV9$gECcD| z#bryfBQ;wPNS_Rd`|ki*tR9iIP&nprC*jDEIBKq$1-?+V(_xMsD!h}dX=B?QHdufZI0WBV0dDb~bvq3H z@8vj&@$ z2dHqb5Yzn!Z*BBGDZ6Oj;*#m zu%}cgYXrMcSzCGAUt8GglCJFe&W|-MPK^UaX>8($f~doc zk@J+A2{2{TBs66o`fTr~p@vURhezw8Q@cW2_ElRV#&0f^islReS}zDCTkWjYUA%LM z!bjhjn}DeOS-{bJm}f>ty;Btr*q0XA&vR!T*IIxo3$+RmvzOTXB**nSOrBN+5p}z{ z9Dp5Q*>M#>2caI9@YHeTY;8{|cv*Le6z6i6ZhXqq0}OC38>gU1Evpub7Pgc#2SDeJ zqEj%H&klHxoB>2m`!F)EEJ;$q!j&x)A3gA;v}PUM}gw6To7V>y2gRN1_TgA`wz;kuED zEYzK+-DH>H@xp%u zJ4rX_Nv7@w5<1-xNf*uANpaYr@?@akK7HctODQ;mdr*d-yJ*+awC>SH%AiYdFmGL& z8XCns?~tn$u!EA7kKzx0{SJVUxRoxNvKeOOw_Z73*DJiuwBe6!suc=wxO9FMR(|M04R zy>|~TmJ=7C#!g?x4p%24u`7yqob=zy8$3Q&L2t8vBQBIcj|68WQ);ETtQ1eh64(4d zNLh~l0;W_)3%&6wXxGAk#;?~isMMwT6qmQ6<5b~1Lsg)xA&6I0^_QU3p+UTx7kXM$ zkvC@#d#?8Pr_p1QlohRm=#e`WI~B(rkIX!!fKgIpHoE1{a)PTa`Gh`EQ1 z89C?SPLwW>8O6{i)L8_T#pJ`t5N8*79*MC_H#~hHuTLS3g>wlylA|*+H8c!lRD+Y| zDy|vtdtF_$482)!43Air$(Kl-$U6#~l;y=qJBi1V9q#$I;jTKF*uF)~E{6C*z=^3Q z9jcNdat}jrNA10L?DsiyO+aj8p+ECF34_yp2Ot2{TLxb9i_|z;T$E&v=nZGuWOC#* zjB5#FKkv4KcVFA->x@J=m6tD-Ikag}8y1 zqVa_xD+%h(ncl|iinZ32^05QanU=if9M1cVpL|?&Hi0Sg)k0m=Rt9rEa`Bk;8W7-9 zm7CqnAXJ~}`fz}ydq`fr=9+#X+sOr#UY|DofFk0^>OvEl;o5V&!0)d#@!E-thW)P_ z@p0$=*GvApWB-nX{1Qbze#6yz29JOfKBue*tp(V@`SPOBDPaTDU0&9U(la&J7{8`u ztSAz1TIo1&PuIwsVOl$AbzErrQ(RE#dO<-1V(6hWjvrXK`0kXBw?0>x&yC!=6DM5l zq@t6-IPxX|c0*subxFZ(`Z1}C@=512wMn7VcK(muZ&F(c9&XUuYoj5xw=LFJ7F-c?ue_ zc?mQ)-~4{mJwBg2PL=-*KJdBx#|MA+@_z&X4;bDJ3A9X)!EKjue_#8$ua74i5)FVg zjUMTil(Ee=Q{bQjQOQGg@DxYO(H(4FqSPD1+)G-Z`qvq?og#FgeIYQ5Za;0s)y&99k=~r5 zeJ4=A?+iui-IWPNS1gZ$%UQVg!Hd9*X*h|88k;+8Jk=HTB2=gHa_a7fLoeC1mGIYz zyaDeky*P)wZr9&ckHy-62zuTtb&a}c2$p%>uz6fQG_N^|Dt{FCidb}ui*ZI?K@&h6 zZV!S4FaVkTUNV%*PYuXqh+SY7hxxto4L`eD4|*ijK-xm>swRrs`_p?0Xh2v7kU-$4 zCuSSttj6D1B4xpbB{Lu}sSF=b%+( z?5$VteNHiCA7@IV|0F&TB65Wj+4tzR6A+iWHtSd^q0a5mYzrKX*luWiOOO<3=}<-Z*F z5(;53j!r&qs$CUG9)c%ee5Zy(ERnf2)!}nXS1c_mzftDUzp2xc>s8$D3HnNXnik0} zRDlY~><(?Y)f=774@w8m@4XpLSLkXL54>Ja7W&}e5=5kGIwW|PiiKO>t(ih7yit`} z`th@58?O*4=d93t0lyc`A<(#s28zaYUaNYejxmnTTIQu)qGGq7Tn0@Y6*WKxI5X_W zes~F7%^cv|`si0P#!e{S zTn1kMNmT(W*t_Wt{xJlU#?~ujbAP?d2VBwS_tXQ)KicG*F>V4;QiWIM+jAhb^|G_4Wo3XaYQWR=dYyjAi(pK$)u z9E(>DK#g#_0A*XR50TnsY3vDTQL>r2o*x40vh zm{is&O_Sr=ZvMEtrg*f##s0V`;Q&km9-14b>0o}~WMQMKvCoo*$7oHzMZLe-Yg&AuJyV2FfUzYnqix35>ryS>_ceCDAOj<0mCUZ)pgGRQMldt@#*dUpPOT;C?6} zqFYnra8GJ|Yc*E(v49~}wz3OQMXyU!ObMWgS|3Eq%KGcI6G<=|CNc71-sggo&TR^1 zfEt3lzkg!6{F_;5CgM3jnr_VZgt8VHQiz%W`%+-vbAJ)58~Uw!lt`Vm5@?Q`ess|* z{qSIm12#vMP2XPa-I^n%O_n^2lL6YOdwwYBwwXU!oe>o&gjuJ@75f&0m>tTRMu zf;Bb4P5PaXZAJtn=;y0HONdK^C;a}g3i$cw+Pw)4y*S-2-?}bJE-_wM6X2m)S5Hq$ z^d`)+TU_Op4>RNJd`qpY=uV>Kiqy)C#vPaU2HD#J53JFS*IdYV(m#SMq1=jtt7^eh z&~^fqCc1w?f3>zV*2UM#&pBncHHeF^|5{U`j4unnWuKx;>_sy;Y|=B$Z9QW$g`VU7 zU8&=5S`~=YQ&dlC6cFu97p2J`o_MJSxwCWXSm_}BOXmC(t~u)Y{MF&ZFA0LKOzo>p zs&!hT897xA^ff*NB2|P{z6+V&3k4C^#(3-+uH;y8sJMp2&<}>Q$oJCH-MCDdKWiM% z=Z=y0LS(ZVynw4}J3bx%dhOE%32Nu=yXqb95sG@?Z3Y`6vIQ^5(U8yKFs?ZpOpk&2D_t46y9Sld{N%^YN$>B6z(8$yNJo)>4OAUAl;JQd<@3JHzDr(eiqB6a~FGoY%n881)h|?zO3}o3#gBmsF{O?&P4gx$i*x{ z+eKh5Wh~x0Y+ik+2gV*(^|yr%K?7a~A@Zw4U;_69CFSpJ@uO1w*X!X&`lxGnhl$0| zm3~W%Nz_7_iJiMHrp51Wd(T}snK0E3PrfvqD`gfzG1D7O<8bAvyNh4ANLNEFgvL+# ziF66qT2Svz)vk?3dd7Yu5-#b@87k$w-2pNwWi*c^E2-FZKEHnL^dWnJr&XR5?YqFk z+((fhBl3SZd(W^Y*R5;Rr6?d$LhliRR1p#B5TqkY5a|enDpC}wk`O?ebV8L5(t8y| zq&MjTQpG~=AP_-95zd{pwtM@1`+d*3uJhX^3!mqH<~_%lV~ok8cq0FyuI!sJIT>%~ zeO{rmx@1d@OIa#7R=es?*^>I{EV6K_mqc-Py;v==#Sf}u3fC0hhnuGg+I_h z=N9`44pHo5y}xei!#j&8)@2YU3kg_~2bhnUT{bcSC3xEW30DxJ=S$3iNT!KcTFtV;PXvq##V2W`t{#gPKppQq|JM?;fI?bBn*Ygc>A$R4037 zW`JsMD&6$6>DT6|os;@k=&1)%CfDI==@r|59R;wQN zY>SL4i?HpGIb$9x$8k4BtaNB`&skyIB219}TBECjujsT3h3sy{8C%LvVE5phXoxC3 z3N)RSPfrdQa;A7&m%%QPQjQ36*0(-*yyeNM+3(YEFAPuwH69+;|L>^b`q|eE0568E zm+Xd_1#A4h;v+S&E%>?x4Ns7$%Yle0k1U1;$AP-!u9R;hoL~aO&@IW}+ijyYcC_MM z=Wftl`}#WzVDwc&MD$^YnazM&Ij&X3RLSMjkchrUX}mw95-OL0KD!4mYsTSh1vuE(R@D7hIOUS45HK zlfQ0139-wvjHHS^iVDl$5Rh{yDreV0dQ@`fTXg59Iwd1x(9E3yMN7HOV3~>QD3L%E{l1WH|n6* zY&6&p3gqJPPtXwEN?Xurs=DVS8BLzH&`v3L3ACj5 zW=45$M=IOr2QD5tDs^){JBYjL8ddq$=qZ6w=+;?@CWc~osrOVwh2W=&6MdwHiCD>p zj|i3qvQuyoaC?=h3xmEwso`UC@wL+(tWVCnJ3@`F5v7>JWD6PQe<6i406!d~{y*R& zI0zzVuPBT+LCCyYDYl4wubxK+AQiIb%_+)>wM}Z*sE)s$sEZQ$>ryg=<{Pfi< zONdC1BTK`HltbtWwO-QSEag@Ur^@H-ue_u4w!sh*8;6x(PqtK|6<`rvD92YtFplvs zSY08KrIhpt?n1!#%Fy9zaDF`=m(>9NwLYvd&QiwO}>5t0WM=E#&a#)59q{M)4=cZ#Sy?Lib7%UFkT& zzU@i*eF~4#)?`Z$MwTwVPy+G#X|#ZLj$oenNflyucAgU}_!%c!Lrlqjzrfk=9vuf+ z*N;Ic(@PWgPn>z#0VSOBwr#hypM7ys{ip}2QvcqGOMCW>oF@b0j0c^j;Y#9yf$J3x z`;aRyNdRU2&;Ufy+OO#f0v;*ebZnu$Dv@$0tu8P@W0&EgwFa;A%9lv#w zqy6dH_olij0<3i(w*lc;cH@D~@6S8nst?8gR`P$NhZcv3TOm<3)5~Tp(!SMP)HJXL zYF85Xw<6(D6xER<)$h4|)VNFfytU$S*^L_s5hrMk1=h-J0!%SUp!p&0D{PZ2KXwXd{ zxH=e?^5mT@qolJHIp2D+eOZWpp~*#}*GlhVfK*+q0&GcoL1?#4%=OEN!Mge#B^gm$ z*JEW~9_V;4*yjnMH}#m!!GM*s^K?PP<5D*b7AwiW%(+EC>Ge(K5@-Uv!HT=iJ#xV| zj*Ag&(%k)`3`lwo(~)ywBdha?=y5EoxvyHwv0bnkw>;%?SBhjsrdQF9ruuIy> z8fhxsl_kph<5vRdeH3CqGX6UVTo0Szev*hNh&6?kuY>cV8v=u)WXsrOwi==@YQQF_ zmx%h7GfwX?!Z9ARuiGvP1OSpaGlup;VGPY{gzR4RHfTQSh0}i@0AAP(O;vBO$K&6p z<9|aAuW3N>U!Q-w1z=+e=RZ3gIC(m4tLD#1l3gQpIcQNfkEHMpU2;lZ3MZ+=&%vfK zT#-}w0x|bR9tzn#$XIJ6lyYZLQi|Pzz~{}}F;&`G(0{VqJILC&R!m{$A_QL(}CH!n`Y|PqYC3tVz^5yd9R*~4} zmZhoq?FC64xuRI!ml8?`$xLhmQjKaw@`%6sQWL+Z#Mv!ZqMj_RMHm^0;M8~;?UsHv z?1w}zTt|irEcD&&_9M9g;9TuxYxyQ7X?F+T*8bGpn+h*03?J8wwe<>=(@N;Bwo~Tk zYe!zTl;^G5#Slq6ehdgg%09tb2hL$9t-T$|e>l+EX$7w|#o;0)CLT66v6e4NNIQ~>U zaUFPO;2mr7U98eXe=T)zOj0>7amsr4hv=qS#Anpt`gn>irfqDS>!_Zf*zDA-cwVYD zuxymLOv}hQg?8$DWy6AgW~KH9vb7?GndtIP=MSemKSY%Ua zyb=&sjGY|wNab#&%)H>jez0W4FBWLl=V>UV*XTq%hUVq6Lj6<#=#& zY@xM`73V9W*q~x((XQzR*gpG>(Si9fVyV5nNg3>#K)UhM#|GLNT6^G+b~<)0Pv%$40DK>dWje>Tgr!!+f#93XRh~0H<*48q7?fi z%5$MrKY(WmuZ_$RfTU;flOAbZ>okutO)Mx=nQh@k&QS%MQXfO2%L+1C*K|Fj(rcDz zBsju|VuS=Z?i|@a{sQh~MXth{rEzO_nyPn~)Ol|FO_%=N^W0Ks0rw&2|M+13IAkpw z;oy87a?M@84CjQjIu66`Q;S7&rws zFrTKW>OpYdvQrZ727jbfZ)x&m5^RBBvx$^A9*Z4ErO9OMcH9{Bj3M_4S$jEA#OF1j zmNgzggzHP8rwZ)~QbjNEBYtqQ4HM$mm00Xey|nJI=zA^FGx2Q&8jLBHe+ggE`XwP~ zdfAlGqC!hC3tdv#r|HST&+l^i2Dkxe6{0#fznsK!(VvkxbO zJF%vd%^0S51{QlI*=3hwTzd5d=$>Emnzkky6W?r{kw~A_LjPirZgQ+7#?m4(os)J{ zrCO`=dXZLVcRp*jCgVZZ5EuT(EhUTB3tHD)CvnCrRGrZYsU4SB&PU=Z^t=`Ux6O6o zES+10K>pgYHn)Jy%M16CNWHnszG9AVuA@7*z#Te*Rv*=seAG>*5~e7 zb`h6_c0ZWxtZRL_+(wzQ%b9=g&R(2AQH&6*fqtzogEbVg^&*u7KG_{R5uIVdw4;jv z-7!unK?iA7W{jlEmi;Iqs-r5)_o5*f&AXmb`bkwZxzH|;mMi395rj?!I}>y!5~Fmv zEkO!@BgmtJEG)y}>@6u3cA!(t9WiR0RTKz?Qv-t4VEn+cJd=~&6K3KaJ~?z7nr~aiI6ewx0J+4MW2)LxUFMkE!nv*3 zT!-YrfTgui?*Y8yL?Hw2H8nTI0sSd!-5bX_&SOP)&%@$BjfO9K2tb~)IBS=Y|9L3= zpK~{)OcF<8_{-ABgNsw3RUd>mGdG0`B}cgAmWpIWCJz+5 zsUm) zF7S3$a&z-sCB5lTG+2OM(2_%?6(F)C9H?DGv(wST1&3=u3A{3vF=u5tVC)tQY&i=( zzq+p==iXL5^_8H%0V6fsyka>VM{3x4Xa4^n=WelpDqc)}`P1(M*y0dy#wWbC|3+Ux z?n@*72CzI}c5ebn3H90?b_jT0Yxke0`!7fb&>9N?t$910Mn%p9xA^;N0)-O<+~V%z zBrX__V2GxQq=Cpp_Hha1fTj=jkU znWgU&4nWgrDkE-%1JP8}C4~*^tJd@CyrDkIaHPfl$xel?SWEA!n$qiV{+#zuCsY#q z^trekNYG>1g{)k=c==ljI*KXn36hdr9lSQC8ShGzBky0s&s5Kh3_jl?r^+|W92Gz*dZE!N<{8xI1zGJE z=R0QA|J(z&1ke8XAniEm{`s-ubdwj&U-s#!B|b#ppe(9+74&qP`0aMecCeR*o{+O2 z2OMdeor5ajVl0)TRW6MHz>Pr>~Xx))n`}!-*w~l zm9uE16K7~%R+tgYBAH55W?aX470((W39?93>y)G;c~KU%dCs6OCVdnJbpuZb-c zWlY>>l_HWmu-AA@1U-oNGDz@L%2#cq7P_Bk2bt*CIc!6^F;>psNyQ2G=Am@1Nb^_? z3@Y5nMs%ZBGK1Rmn{e?hd%-M^tD}3z*gmf##kB-3APpxk-V*ymoAN4%!%RVs(zEr; z6BD8ja;L`?AJqkPr+}9DE!f&3q%&3W_hhp_k_6D*JiA-dgn_+4zc8_5L=6&tf}ej1 z#%+P18OP+sn5tsg*WFW%8-5;+irm`{F zoqa-^u%1ZUHL&mLoyE#y4YuJ|1_=Wi;tr|#v73P*>oapuo0AR}!`Rh`y+zgTlJG)*Y^ zjrvKf5Af4eiKQ1h5>~7nwK)E!{{Ds?E1ZNYpYw9s!dGVYZdxv$N>eI}Q6h~>J@bR5fg3z}-r*~|R4|qt*k3I9wiLc0$Kh3l-a5Ia zIvG;EVG*KPhm!^IWObvpYDio@yV6x$-wPr4y%sgo)g;&`3_k-rSk;k-VLhgH^;v7wt6j6%*9|DY_#}H7&KR4ZcQj!J+Fk^_8 zjVDCmEe=5~Ao)HTp){xTlZk_%c5mm)PrU)VKe2F=qxeFkMdi;a`=Aj`xkiIpF=38k z(EtbW|Enc4b60q!)V&7XzlONPO8=JosjBN)I;oBDV2AB{N+oT1v3WQMGC*smSCwt) zAX#d`dVvE`Su&P#9IV`x{O+mAP_#d!HFCyZO(+8sLFveKFBWA=$tGMin{TuR=vhAT zozPa*#`m@#=fl{w1RJ9>55waXZox9IXT8uVFnnNQz``jeR3e%!7QNn`G%?Jb!%%=4 z+>KqPAw(d*INphEURub>vs-ilAWO?0x5G;eqs%%C|0vuGh2pyN-i5Celz+?Z^NJ^C z8+_|wZ7#(j@F5mY=(%zS&tw1S306V~4~_;Yx^El^S_a($gTL9VM=CR)r%&7&rCc95 z%^iieEr#%&bNc~x?2FhUE_{n22k{r$F|*O^hK2ix zJ&3OIRc}01&(_{kexNp>e>o`htW7o=Z?T z=0$8J5gx2xV|yRYlx>}W1y3(vH%gI$6pXvv?kJv%AT=a!sqFdlW+h;PPZYl4QJwLD zzve-TMfxRUh{x6bVd2x8@VOi_RV6FG&u#u@+6}HK85j0|W0Dj6{V*+eT)T;R+CHar z({6{+&YED+MK+g3i!u*PVd3Fij~N5~%FTSeYoj_o3-^TZkA%V(>o$rsW!Yy1>JKlo zPph|1CKrS>K$vaLshPfNAYIJ&WxcdZ^>X)ii&2wPGV}W~22z%~8ogh}(1G)$>UF{9 zWrrmPR%QXmId#Wb{0HaQ-PeYRB@1q|V}?o1#_QnMVzCw#^LH@m{>3DPn%6KD9Q}|n zvyPX`nc~ioSP-eXoT&JjycMK1-023K;lX_0zXvJ*R8xMUx5SmrqLt}M=if(=m6~V+O^cYQXyDOSv)tXJ8&__PC&9hYiJsr<+QBNd8p6Cd zu=LFoe+iH)mM)zQ)z*|1l{r|56(OQ?9vSS9Qh6);qhG{)vcg;>JK}{XdjC5cUi`XG zbCr3^vI?L~{9?TRs6c=JVu>bytG+tC+6lSMB!fgTB=+3~bJ-Z`WfFT3-HaER(`5A{ zHy+!BTK4x}n+d9lTvx>ZmefWo&{Lr?eE{o7S|CnOAFU(B@@LOgnU^ zYI|cMF!w!Qxi+K9q8=ls-P|dsWDFB9J?VP}kG#xM5EL9>_RaKr)FEyn++^G)S=_noBM+}hHD*jeQI9<@E69;Hr&n?m%Q73gG0dE)ZmXNFk}gN zWS2Z{>G^D4<+5r^KnW}P;NNZ7014p+%hb$(lh1--xgF^y8$$wo}7?L_%$!;es z9U0mm(?^mALA^Z`Grm6w2zLX_U%ssV9$0o$`{H&iw{FtIB8s-Jb74ZJhCjf1lV@K~ zG`fod`qlsIHq<6k4=C}4TxviS-mO4K3{v8z^A1xh?=qrWAXa)Y{AOZ0cl3Up{XI7{Vq7_rDBGV1V zup@2awLPj{K;aS55&A`md@(^Ndrc%kNK&~VMpK7wr(-6&kuL*huY))qEq4gbjYM0P z8FQK`>uRYAQ&oM859GG`OH<9U#p`DhJR;dm1edMZogBR)Rr_z5!F6fQq0yU<-M_rq zKfa;_p1#m**qR_H#Y22VO+du`LZG~%3ZLEPeB)&1=|Xq(EZ7NmHO0up5lmh}634oo zR)#WX!3^%n!pG9b=ZGmT{W{z$-hgC{0KpyG!zE7(-3US}xB(`dx_LP)qINnGbHOnF zO>QgQHjCVU{~G@ySzq%J@X<bHIw#O~rYxRo3@QN4LMJWh(bvJcbDsg+ahOuUEY& z=9GQ+1##7$NG`hAS=I%AovNAYIPP5I(#noLb>MSlU=QuuBWA z3~3fOi@F}!ajcz(9v33@pFZN^(t<@jH;dxnq_=%tq8pq#MKrL@t2c3GiRE(8F$a{7 z8xd=|S6S%&JqX+pZw_I^S%=0nY8ha*(Nivpy3*U3TxVDDFcQ%ilTc?77bJ>BXY9Mk zt@Y677s45564v91eU{q%(D;b?fD(_#=7}yJ9+G$|ywvOt&0wJa;|T5=5GvE&E)Q`OW;?Qk%F?_WFZV{5{tf;kf|-S7}Z@uKil=APhg=ZlB$FJ@_PZi}WJmY&{S< zwHdptmbOimIf7kl+w;)Vw|bJX`pDD6iT24#%dmakzQtCk!Z%%g6J4>~8dAgf3WL9I zmOrU9hfu<3$tU2i^f30foKa~r(ZQ}n2?469%uaWL%|EEIy1x~qx*M!KXk1xxFiXSY zP2$w+4?Qsk$<`O-#wT}d;;4cm8QI6fNrZRXlD&BK_KI=53?~~%R`xxpuCn*iO2{xw z?(m+M!`xhfIIg$}6YsC(9-*ZxNF+`z8i2*{J+F8f`M#RT0skmXJhRRrR8{km{i2PM z=97W>YAQ@md%+=Nyf$ox^y)xQ7!~%FzSnqYJX8#mW7Cm$Sf#3qYrV#jL4=-7v=_p) zYSsZg1oVXDT?4yt36Ii^af}q3K$$d&j;mZtKnLR%xv$6vize3?PZUF6$N zMtD89K$ta4Tf+}rZK&Yl$(E==v`6J`#sD3&m*@Zh`oM>>EU79rZbVZ{N{pg zfq&@Cm>O2dMa6yY$Q2#Wv9=j#juCe&?#wd_09@5mp6sXtH_63`DH5akFE6L7eAFlLd$`*2?H-k{Qyym$(E?3}F zv@RF7ISXHf#<5rkLjP)K?%A7?IIPML%VX}4H@)v=LBtFvf%o#I;p|EwKA4`68CCcO z=oJ@R5*X-Y+k!PDX}g$N>;qDJbB}wd)=a!8$0$28jEi~x7!c?2EOlQhBkYq>dRwHw z2MhwF+Ie?LjUTMiRIO!NHU8h_MrDSKQ1!jCm1St(^2?AMQ+seR4~O0HPp>0N!3_7P zn3@O%Q`#>kG&`$k_j1TK_0zQ*OU~UKdrs_c7Athp8^U&9Uy=d+v(sNlj<%1OtqnZH zBHwh=Zhw=y#B6OZ02H@dRVY9q&*3Rc4HEV9$?eYk$QaL`*MT3tN5Lt@tbI*o0KhHj zY%wf*j21;IrUtbUY>})#;8av@bT&YA=Pa=-N(bqc6*L()F=~7?vZ^yIxT#v>>>TI1 zpj>{qaBD~a>)Iwi!DFG{JQB z``{AY7kK>D5Ct5_L14MLbiAN@&`9Ow&jbgr8>ywH?4Ax`!nrmbP|}+){9hMs_$@Mk zJL&b$QG`=s=phLm3BHb?A(c&~4%U6DmlHO^6{=XyC?Qg^(-oP=J+9QjZ6wiTUy zb{EXK5R$!zGGgzp_~42hJE;@yl-Wee)iD-!p7gZyf=r@lI3kR3&$k)f8ObZ>;=KI| zrg8+71&g6YMjREQnSWh*MRNa|pXvF^Vm_7RAmbd31<@Ze!?{$r!ZMY)ArXEG7O62C zr6Jhb?Y)ozXlGvr;|7WF2FqDmSRK^{-d;!J_y_6<5AhLCki`#4sYM$dhgAB2Ypybr zg`F4+E~~NBy(bDUNey>?wEZ7kYS=C9k!tqO^(^9NCBb-c@sS4sWo|^C2`DB6FjK$C z__bj(d$?X+UR|SK2b2si?p&+OxpB2Ah#v4 zm(u$gEG`F8WTuz0aqn%1r7=v= z-NEv~JTJ5qu5z;2uZd*EmfP9(|H^()RIDXAsaTw~#4Ks|1N8%SZgPwf7RW@Ws>msD zJK@M&b@J^-=x|t}sN13<#a=5bw9#WU7SyItNH=p&;b8~lTuA64rUctrdO8360V>86e7z;drmd-KXpdNNSqka)0-RJ-A&hK2@V zaD55HE9lP{RR|St-#PLAb(lNo2rp+aF!K#Kf3zs-3G@#mKY-*g5FkTQLh~#_8wz?g zxC79vnS(BYjL;p7Ot8rAh<4W4j-GbOoj?dOm8V^7&jOxJKR#h9%+}ZuZJ%(DZvY(M zd8V_{(`4>|#;XABM&37kvSN!ZU`A(oDV|RaE(cu? za>)`u9)gAA+xWCD!Am%Vh53oy57eN#fmn-zgrl}+9K`O5|1fs>a&%Op@Ba|A_zWR@}byYgh8JMa&`AG`EtJ_QWpx5ahMP)c9UuhEWob1RRK-}m$SL&{pP*#2O$_&Ao8f@DbbxK7n{7CcHtbPxU{WM z*7(zV`}Rr5EVEceK@5-z37YV{Ajfq?aVTD_GWrDdn`N>|jmChxuD(jLlp}6$Yr6U4 zxak$74OPpo>cd5RtR`GCTDb2Jht~5p0ZoLYdCi!fKyBQ37t{xX??ax%{OsbBH#6Gu z>;s*3yQ9z1=U$n|y11#IITNL&M|M~wm`t>Tj>U-S?2gk+i*Nj!?*##7U8@FrP4I_% zs|Ha;Ja-eL)JApj^3P>=I%w?g0(V%;Y~UZ4^gq=K_{M;;Cwt{4Q28o%NYA?R?^p~8 z2hsRn4?4;cmBLV|ILJiZ?Z`Hd(@dq`d8!+SL=DTwa1uMdvfxP|F$6O+vocnEfy%df zFxzL`D>%m4bYyrZStgLPiLLSe%L){7$e{|nqNzoJwFRBTJfll2j{HV-pW^U{J>e5Q<1)7__aVeIOl!7^po9` ziz+|Mz2|NY7#71%esrkrfC1b40`-$gs$gAQ{sr$6UHtdIY^2V%WeZ>bf%I9{sUs8wG0Z$ntQtZQ9Yd*Wb|V=Mh!D zqZ3Rh;5GO-A!z9tFi4ipUk6TnJHS(P-XKbaixU}-b>*}Ym9i$820;}!TJB-JY2=aR>7 z=KB=kYKVpVvJqPG7{;E=WIQZ1lLFPvlLiQ3ri8T2J)hrJK3jxg#nes$I!>kDg0%B2`G#&ZdfT zo{2|VaV=^$Y%JIy$Sn-#VLqLf%dHHp2(P~)O@+f3GHvDzi!c1ZM3_kSlplU9^uBqe zXLB^)X7RF0;%rcNo;NL)9qFv5`YU8-VD|u}XwrNW_{!h}eyRV)Dlf)mX=2ONN(;S zf^6;6zhFlS@rzOu%8i&N1iaD4?l`jTz%W?qzWTZtZaVpI>80(hPM%r$`< z@Y~P-3A0c(CYZ`74RiIaj1J3Xq ztxzi(jV$rW_OWiN~OYq}dpCF11R`GyE)lluqY&$VRq6jVOfA#Zjg>w-w5lvjVHn%9W~UsI2|Z=TvvRcZ;wT^$wwy5m2$Uk)XLa zSkZk}F`{~h1^Mzr-O3dmsLztMZ@VHzXTqj!L}m0st3xoiZCQh%YgHjrx1wF7j7(Ke zM(Ucc2Lu~z`JvnYk>bZ1!_L%sHgp;=yj) z48eX>M{pmp)QyU)H;8Wred)dPkYdf`yRLTA$~UxXy(6hlu_T; zGNkuyGyqGkd^@*O0^YXusB6Lxa&#Uue|Em1nL@2AA#chgY@t-|$w`+VyhC<)CBe9g z)1^yi_eVSQbTtk4Yy|`k3@Kyu8wG}YPc{t|tLD{f2!^#y(v;jL z>5U3S#+#4sCG58>i}94npS8no)NeJJCz!a~YO1ARR`X@KDpdkXrhk2ZW)4)Wyx+th zjow0Z&lwGa=}Y0qUj*6uMxzKpRT;$c~?n{eDXSX}e#NtSo;9{%lPw*rVtxayI|G>7_5!>`QYq*BQ2m*sQLM>)DS^4tx z9c3M)s7^+W>p^;@fF3ITLFJnNmxY!x!qK0My1k<@b&#At0IetE2osMaG|CM%Oz`IQ zvidfx_ii?mDUT3npT->Fi}0_upa)NR0s8%{&gh-ey|+UOWSy|n33AZoAQdM*P*q*n zHz_oK!c^XLl*^>hJ>`A$c!Yi0bL$t#mq;iw4s%L*eE1?lY%O+|!Bm1Dvpd`+h`EQE zXX)!g-rGoXF!TQW_?gaOjqa!N>7P4N*e&jT7RQFdv5Blw)aGx!`Kx*kK>n82*NkQ# z&Q9Gd<4cXkfeR*gz1I{pZesDXy;(qIU8&K;=H}PXcAISwe&kSp|7iqEGwXLd)X`=w z!AhaMA6f5j-T-#YW6vO$MSMTOYmaMcr0$mILY2rI!_tX}^=5~0rlD@DlMNEikerv7za4>U^OTq9%?2<9+$u1tOC%IR|2hbOiQCj1OpwrAmHC9K<5w8yOz()uDM2b_KnY3oal|xAWV_JqFLM zuXokVWnlzjO}&|RPKezmZ>4DdjMatnVDttpqZpvn(YSC()q3*D(axj-2SN0+*9& zXR)}R+8g__BwFC({P`=_OLBEs70Rw>iptG_&j!S{gHapOedo6`wk6@LZ(g1)GSsU- zRO9K?rG*eQkKTf;yt@ZT{+K(p&I@cl{k3IYnEO(F;)USr{u|~XcA@;}j@jaKtCm82 zDg)-*Ti+T-#=Q2t3sbwA0FIs&@;SJ(MtUO_eXu0n%=GqMp{Tj$xeJ#b)$lBS091| zqlfg`+eQDF5{=1ENAsI7Om-7Lcpz7MaNw6p$hRF?7ujm~kvH*zW>7-Dw5B`)Frd6? zN@G(KM&P(NHg2QZC&)8KFw-+XmOv26T_vi{o1E~ko?DHx0O-cp*Q;8rH?kkM(&?w` z-hOsODC$LP8C!fa9|m0;%8XwVhpd6I!T0U>ibbifJ8lB|le+fsX9x2Q!17-FL>F-NB8ZuwTO202>OPdqEM$xDkvPw76EU zg6Ho?Z3m5Trp#sYuXYs53$eiVLRvp0N1HDCM>GU4Rb|?gB^wCL{Z4$Tp&YgrNi5J>xub@{m*Tnt6XI6T8^}%G>J39=f{W!#;lyrg&uta>eJt-Sh1yTYq z)%5sp1F1y0Us>kS<#4ZLOH$H^eHe!a#d-|%9TByTMi`~#bg$x{X-#_8+J%Wt;t zc#|kc5cxqDUaRn^I4v&7o$O#$Y^lHBxmu}Y0zH{N8Ob=g38*;15L&%OlHsWJMFNMz z?~+*$f}%c-B?o3%eAH8*&zK-+oDwCREC{}D{u^UOO-En1@-k}eYX$_oFHD2XfTFvl zYnP)4b}u(l+f;X*J+}$A=4&AAW6ouc5ZM2AH815M{)pl0rknj9P1ZSzzgaN1DC4f4 zWo_BnBd#rtfzbW%wY^a_O5eDxUwhrjuW>m-Cnn1aWoWKdeWaJ@iSOsxh&MJ0dWxr9IO9aRK!N<;&BBpJh7@%N9jIZS01e2;l&Kac<6*_DP6}@@ICuRBZXGb zp+O$->e>JQbKnt4Iq|o#)++_}rO*lAJ_w%AlvGiwtkP0E2^IPrtmWmrYQnfHvoOQK zE`2aszb4FiP+)+I&d_S?{l|ZY?s)GX8FWa3sur@?wjKq7QYAM!EEE+TvQz$ed7d0{ z`UWY zJxmdW*7>`uu9JW`be8(I6HkGK8XqwmuU@Z{s|AmV_U2~!b4$G5Zjvsj-7 zWFAFCYQHGj^@k8W7&rI?hFyCIlX}$|uyHVTj;5?q-%NCMZeIR{1o3(#zMWEP~~GMe2@CmhW^W4ql(&wYxh8?G^S5tSCh^a^_R`SMPOH2DS9dwUL>QbOGq zjUf{zJ|})r6XnR}i#O*fC!@pNMzvIPX$tt+)YZF9X8KNF7v~JG-o+~_Oo6#=kwR>w zTrWWrl~N90SQ9Ec?elpv82jTutx09#+?&9t^Bj*lf+3~eUJEs=A?w3y=E}%a_6gJ3 znv(sl2UMN->|*}aNF>8!4lDVKX9dbc(wIJeHLd-*k+hYc>ZeEV&ArSetcIfU1A7=m zXQyQmgKK5e6GewWG~{6bsN&+g=AdDB1MyccK-{NieB+K6qbFVT4N8EU{}v$Sy)b4N!3%3c#2bl#Kx03KEuS;myJK%z>+TLw2=<>;-HyV838!Kom%4@>MM-}3* zl2WTuUlOdO)I>wxKcCxMa7A$_8c|(7$Q25I&e!WroeW*V_`1|Hg&a$lRp#Kn0H3? zy!PHRw_*>CRe4*3QYUE#yOZAqI~O%Mga;p5BCfHIy;qTGl36J%|Kemc<7?8iBFY2( zQ9RGWPG&KL{E!rNo>@c_&CEe&HKkB(7p6(qYjXQ<6j-EQJ;a9DgUv=Kq)d-~zr<0D zY~E~t^VwT`QSNYMex!yCRSA0IYYw$0n=IJVqvmH_%^s)L-|5Q_6NOTreKTB5;2X*J zq18-~sC-{`9{HM(Xfcx<1*(U}S}(+zflFus_}ni}n0hMaPWzEvV=R|56x$AanP7^R zO#7+3YLK~59>(y%VR##eS90+e6JGF_Ng4s8DFGrHtOA|+oh}-|mlw73;SBI!w9anp zAKAl=1|L%X^M$Mc`a)D=ov+lr7+yD3JiMx9Jni1gmtS4K{A(ZRG2YHcy3Kp^ze?X?PhN_0IE0A;P-{t!L~n}G`jNC6K&Z9^!ctpwwnHMoR+GLKvKMWlG^JG#tEY}gX-rp znt?3G)SArLoRTk3_G2&=(GIDfPJFeBD+&MwrVl{$-3S0w7z0kc`Gpn|KNH>J0+HlH#IixV4WHgl>>~y`S=Vjtn*^Y$ z6x_)GJy?P{jlNf{sT7cNS}DX9P`Dp^1Pcug?@$#VIwcb!ah#z%&Cc2SKn|gcbTf$c z50VP+?M(F`N?W=Okuyu+O~>>KK3G(%RLP1cCh0t1#oWhoCBfom7iC6joQ@+5r}bTi z7Q-Bo{C^86DlXx zRMf@u+ffI;&+ov(n1dTwKKkQsYjRorbr;sA3wvPy%KZvQ@$%Fex!+j;HAZ!f0wjh& zDzAJj@Wtf*lr}ErrEfdo7)Om64 zNuAusNeeF@EAx3r<4=yD9rh2(ZZDLyMQP|6%(Cn-oIAQuW;Bd!pxFmHfDUBjHwJFa zvJ>mnGEJiF>64$&b`q*TGt_YSYor}IygkMhYv+QO&u7|Nr92>H2?B5j@MN#a=Hem8 zr;J<#i5Oaswl;$&7v@!qL1l%3F;f?^* zVYZg-vE}O^8MC_4x<2p}Oh_O==vdlo%It+Ky0l_po$d3iZmwoHBpD^}dxHI+Pvq~h zS^*ZcJ)+mqZ6m${ZM-0-^4qR8c|H*6?w}VGOW0leLwo}|jUCx76}ywdcJabIdQPFb z-s8PO83p{VRqa7qYzND31su_72JAaeDqer^`f=RBM~~c#h-94#bLMAoC-Uihq*H>q znfLto++U?37Z(ZHfGchG&{uYc~ zUE--r%Njh5(S}BSTZ)*W;^1gfA;9UPhZ z<<@QM<>G-_+3&fX5f6&p0fkn&*Xx}o3FzqQsmn33hxu_J8ps^Kj?AZ91!nRT57}M{ zTUn>M8uLNfXOzd(v*2A)f*?`b*{+H1Kn5|S?vEaxjQ7n&a%B}xUgVQyAbUnZKmFEE zsm*GU5mBPL&79as&2rLr1kkWVR18MRBABDkW6jmA8C#U%)BR(i`xRG-s3#E8n+BLI z-bU;H+s;s4uYV=7n)qvko03RjiA-m9xN_UC1T)B=a*C2NtS}iIryLimmtS&*iOrW=Kh>ki4wmN!f#M}efpC{7b=yU#>DLWk({T?1*T`qWKmmxZBjmE>SS~~1 z+b!qZZr5#Y+B`f^lnC@N(!_sz3T8$VB7^s2bNY(xx%hgUS&X$V@f8aK?bm~QRoMR; z?p+QDk2-H|H;r$p2dZCPrT^HX+pzLELghO>P~40^!exy&(r97Mw>C?=x}xvBnv4R4 z(y!a)%y`a^#bvH|EvRf$kv!Z(d^DeOeDdadTO$D>v=XXX4{^|=YX82Wsp6LAS7)Ez zJL&WamE%gccLa`#4IOB+NL?2nKBBH?#*T2|IY!Msz@}60cIHtzpeRdFRJb48oCR=u zXW++N@KSYwWJ{=Y>x}9`JE(w&^`VYt5fJks4ml8SWZ32AcH}ipmPp(T?UjNA%cVI^ z&T^$iw{_+gFH_iL`rYoi!&@ZU-IJC20XFGL$xE2$R_Fh^ z!<7X@j)JCxwU6G}ZEw6*rT0Fl2?FsO`uMT(Cjt&#P`R5YRW=9JOSFacTPI!~8q8_;C@0Uy~R=HlRN_z4HrwwvgCa(==6;%Z)_1V5h=jTK>dL}|AYFnDErmRfvzeDnVk+o zU~MmL1ftGPse5jj5z(_AersjzbFHIwC_(z3>f`+b`dCLQE-qUY8!0D#RsW-y5Qq2< zvAOl?2P8uTxY|Z_w$|$!x|k}{$I2h5{v6d((5s^-QbMHmo_g^gx#qiN`;0tXTs1Jx z_E^nL7*9o~&AWqveaAkzcWN>72aRq!5^ThO&k4=~pTeG#&QB~QhPqpgn&du7^O+Z6 zXKR&QFiFes?Yjm7l*0W?bea?(6!rgM?5)G1-rBbREf$Ex&>}T-3aG>&-60^-EhUoD z0umC^oze(M%+P`Y(m9lLh;&J)z`)S)u5pL^y`TGef4{#toUMoM@2u}y*E+BB{9H7P z$k%0yiBcb)!Mg(tVaou6>>fGV9+b7wX+<I_P zqQ%f9iE^bbd1aT$F=8_#fjc%b-PYB{#i%Ps={5B==JbB9trW|VfVaKwz~XB z8&zzy=WxiMsds25CARZv5%)0Z2QPxYL?uViD;-SU1ThjG_Un$=(%d-bA@bUzkMPlO z5%~eVU7Yk78LUtoT}ji`2$77KtBNqTa925%PI~;mugrI-PfJ$wO1y**H{>L>LDmq| z_rWG@sTV{qO@*)8^d!hVUTO6Hi2douxYuHP^~7vUh>}pnM#;z78^A>5IrKI}KPDzh z7&Yl4MB1sTr3<5S)!5|@5rhDGvU4l&{}{ISi(Po_jE0U7uZQWVw8S}Jje(YUN)mU| zsp6?jSBF(2IPg0;E(PTo??Kv%j0h1l!NX!xR>ElpkB{2?a-#$ z2KZRMG-RqWlU%@dv#M|at|>B-Q){i6SxAsF0bnDo{!qi#SAQG}?e;mhf#!p5`?oyA zgRN8L!xe587JW+|_PCdS+2o9GVBQpOwte3B{6kZ&uMH)5Ou1vAHRo{7ET3bm8esOY z83oSraF%HN;vuU`x9W#n{ZTf(nEz0q4%;~T`F=o@OGSPmFxqnhG4vI@2D%=adJUB5 zJp;85z)&}SPe2$NKH|5Lq38wLG98F2?!vT>CD-IV^=&I;-ko4@-KusXCBxUCMUbK5 zyM>X8XFK8|2eQ&krWn^3MnD_I-69fsGsYl@dfzhN67ayVV5mCTfNK`CBYG&o`w*#; z0e`6VHZZ{v=+W9bl0pj~XD2jauhc&Xt`}_VhGZqyl$I;j?PB^C{Vhy`@J z=2`0h+GaBkELP2N759>+_n*s=%VV?^4snV3IG@z~pat}1kM7D1=!r%YuN1hi-$KvJ z342kvc=)*V#80S+E}}dP@~I-i7z&&a%x!4#wgkqb_NNOAhoA`C(y1ca z-;Si#;^;yGb=iPLCTA`lM;Di~TwFM1qqyoVKm@@~fjlI?8_O_&kITv9D-=0jv!tRZ zq%yoHT>`Fw!Di8CYQtb$O#V8%6j^(mlvC%efJ06N2Mr(S^ zzLg3NQWmf~Z+cW}X|$zLQfaI|Zg6tF7Lj>h2#Pz5%NWM)mw;89|GpB;dXOEys7C*~cOHt-LYh9;zJ-v5?b8_Uon=%?e^ znR)CwM6HsZmRP2LPWi#L5%6BMjb1AW`#$;rE-lxP$n;K~trOo`tzBC6jC7UPcfQuO z)eRkt%W4;XUYpft(4qBMj`j1sH^l%Fao4#{{?l#G^8jOl$(N%7C(HkvigD4jbXohg zSA>VisfLsnSxGM27bg*+V`-9bYAC*%-JUQ!I#TC!?e$r2vYJOlh3u%aXczaEg3Y!X z_aQ}Q8DudcC4O4v!?*1VZZsTtwb!+RVU>w8n#UyMMS zkza{sMKYLc;5EJ)l}ES2O@E_#Rsx$bZ68xYSyQ@4Y5>p%_sJyAFkQNj&iK|YE9`G% zgL*H9CMtMMO*__FN*TY%XR*8dTpTblo}_sUkKpJYt?Q&myzVR2CaXNCFiTU-B2r^z z(VcN$QeFTqx;C!wVACoG*@isgY?stAAld&SX1Q?DU13%Uj*GbEtmc{f#yD*D#oXn` z6A=wB%ifeyN~cUv-hU=O`6K}SsB45U73UFVYJ@Okvo8-Ukb^eR8B1TaJ91b}DG2Hy z)90+EaUFF8W?H!PNsAj0fXVLU%4X1lV1Fs)T|JYC`1EpMx58O3TXBBr(>nf!H#xXS zJxh7@^OJ;c2h)G17Xgh4V^u$Ae!7Sc#s~%TJR8jJ2{Tmifpb2R>t0v%Y|H*WoR~-I zBtUN!aqAwl5wZ6RWn54e$rpH!v5FakITO?i01{Pvw_3mJ0+&T4T}Pl4aG^O!k9<87 z9a^=uvBjh$kBj17%zCh#`@XnfSEqki0&KmBA3n3+HtZ^x7CY)z#geWc4@A^>h-`sX z+e}O0k_cj$!o?tSlek_}xdnuXV&L2E?sg+ofnSkSPrOfW?kCkSQUZ4x8{rc&DTSo4 z4|Gjflo>TRY4Qe7^V;d5n=Z{9ZRS8yo`RU*0vMvhwlB!R{2t|+Hgxj3z9%#yo&8Od zfR-k?DRIH%PO#>TLQPmAhwdiMMUq3$L?2n>^~l=-rEye>+|*|W(;)D8rdXHxpBD^3 zLuqId@<5r-PET=*IwkhuJd|1O)(;<gF?ig7K;Z3@xwOWnD0%0q3U6>6R-S-d>1lcUaHtd z4!mr7Qp`UAip>Q4GvG>{rREet0vuu{PvlVcf9K*a|f)$hD* z^kinKK%HECc|gE}fIFX+wTHZFc*6OLw?eio%&@H1h>v%lLf@9|hTBzAQc^zuCs20N z>sKL69g~kk8aDaZCv#ei1_jv*=~%6ia~H=Y3p1tf2WDS>?n{TMA2xpbQe55GIO}}v z4Q#8pBSiVcBC=fTrp-q5?v?1$%mh-EN(o(DNv+xE3F=L?tptOBMbp?IYKK9^T}fVD zwJSQ@e~46!uaJ#yyxZKquByyrp}84YoZo0P*Wjz8E+sV$d{;z`NiMCVc`QiP9R(f1 zpVbrGr_Vc|lb4DK{;VNBLyH*Dx=SO0Csg&AL(qqO^>pWK%Xcordw;#VF0MNeN1(1C zE0fY781KPX$6-?QJJwKuZFt*6Hb2M%5*xmU1o&OAJ(zq$9$kfie`@Blty8k|SC<0( zZ_{#0j!FVshpTVcIH?KE#oJS>zU8*+7z2WCpD3~OJRW{>hLsOPggjSnUXsc-qkE(+ z&|qepC;RD@;CoQ{S!i+8dEU8~t*EFHxN!WAb73zBb1L+XGR~BnwB0Rx%=m@t z$=A80WiI*vb4ZP%|Ls~2mrJ-ll9oa09kpl|*hQEh5CH*k~z50Z!_L7&0A24ijN9-z&$ zOc!{bDfZ|NEC(?TolWE?+|ufX%Yr1)WN^ww$D}ajzNc>H&b|p7Na& zYW6LwSA+6yVx0Xx)fSv;cd!P<58rAAZY<=a^-hHK!o|Zyo9=VVuiI8yg8ZtJ@ zO!?tM9inHG8UXKw%=K9mGNP7toMc=hkrP4ZsG-LQDkcXJVjbO`skIw~y#d>+p}&AP z%;HFt89kQ_xS;z1V~jwNdU!Xc4GiYzd>hTth_|T%y>GHxHb19pF9p-}EtyPVW{&IVA4t zId<6NJ27fgprq6lyjJF?YqPZXZXX-i040+)h=e}0gT({{VjdjYT(}Xqm7Xq1mnr6{ z7pR7OtiXQK!HPdIf!gU1f7+V(uo%7Ya>!!x+S&o#81t0Wyd@3d zbKe9eut>qX!o`vIROnna?FEsx5>XsG42nzWp1}{!P3EObjv)xNpai0VMGxrGuHBl; z%J$hQegGnx^b*{Wdn!l$V`PTt<7B0@t;sS*+i}EY3VNzn%EIX%PGJGigz?8p0c%{2 zu+kmP^;iZu{$m^CiZPn-(&%^Nz%4ZmvM1lHlkIqnhe#_1|bW)e0Z)X82D|~C^Nxwlf>b>l;Dkp*4 zl?U~t;}N5|v>n~5B01Xlrz=Y5I#pUUvNgP678;zM=&leNHRb+LXf(~@GQzWXNwDcA zC}KEsrM)X?S7J-dH7bZKI{l^Z_ZCW8-+W;gSnDMt*&39sEs`20AsJ13g;AQX3g(p( zFC`h_)QK+YO@*laujnD6{{=mCy3QBweemhV^IGCcFXgUa>gzN*s*g-&;;?Ro6WAQ` zWOFIKWHi^5tbw<)Y`PXPLpR~)X-^YbN2r}=NVK^m$3e$y4X{6WyNc8?11?*yKZ`-s zcycG<@$1Y{dzfEjQwrGoH!&AJek{*A`@<3O>3FED93) zlIKSQR_BTxye5rb?H_!~cyaFW2H5v5|BQOTesak!eJkTd{)r92`!X3Fn-V^1mUqzS z4d@S_)^e2EPD2=uk2v(sIr;`3JkL9sXqqK(K2uYiWM>KM2rM}aELnY$H^oo+=Zbcr z!mQ{Q>HVWmSip1?KYg2$>bo2k8H9=JIu=YUYumnXP8f*G6EAusHB<2n8Iix@5HLK!krY*ht58}whlR1fiYqbD&0RO_{NXfZH zY=pq%F3@@kW2cayNyCp|*Ou)hUX%kE(xxtDim)jQtVLotYc4y6@B%W(Qf)7VboGI+YQ zL;IE};oLO%{Gq0U9WYJfQ=0J|5bjxH>M6(^M97&Ykc%`{h}GSVl}a)3^IyjHA(0t& z4r7m&^$OK=_DTICTXtw+AeSmaI1D{Phcb!%9IE14!K-~%le9PpJ?u8Nv1T|#a{p)( znqd$U*+_JsB?+;HT(7+m+qA)B+LbK$<(9?BG{QdvKtFsarysMJs}aKXC(UrnAcY6k zvspi0M|9lzdK-%1l}2grTPfOmn%7p6L|Sd%(fZ6=g+5sg%!~be&Glw zFL(*;$to?BAIz)r5Te4G^*q~rj$Vx9XbnQy>s)4ayWC`XvU=Pe2 zwMBH_&OvR{UHviP68$}Gv8OnB-HqNS{F})vkuiy{i`W19pZ)g_Ryn$W7^Z?ZG4Do- z=*V06hI0ReS>Y!KsfqUOsB^kW=YC&95_fgfu0&_;^(awE-oX)#bEo;HHn;4@(MEi7 zmpnOW`Vb)(xfW{11?GD>TeBPG+D1(7Fhn1#8x-%ZK5i+J$Ij1A)j$beqm@?XiFPf9 zShJ}n*ue(xGG-r_rXv);$l;g-QGK&1iiMqp3g^9@K%1;2+57w*i!wVb1!hl zYq#Y5IIy7g6wJbO+$>gCg$td0H~9$ynK+*3gcV`x%YrRo#AS?LNI}zfST`vweX3*K z5Ls?w`3cn9clvxUPQ>a!XH&QjeSPA-eeKGs$YinLx?Xcle5%6KFHl0SS`(eKQzCOoL6B z(n+R)k@@?Xx^Gem4mJQrxhCQ>8w;>WJ3kdIm0cd4(P1V{chLAT3*bFVb*`Ia$*QX! zfyJ01m{~PKcXn(_6li{p&~}Ky){_L-;tk9UJlTR-Fzaj@^xHOl9kU%LGA&8{ZJSA* zG0D`*zS6aZj9Y_PJz&dbuVY6?-23bRL|vyZpTn`uyh^6MU#z>XIr?K3uMxIxwa?7r zMEUqG?dkmW^OyVIiQlfj-sG)ie$U6W)h_6{NL~nva>Lzy$~qM9R?leXee1yD&TNau zU**$ZRn)H^2x2wlPWd*Kt1Yyl6L90_MP*X>E6|S{y}|C% zM@T=hoXla53O1JAyK4S-rSj-tp=f`?T;^wC)i-(t?2}*>C^PATV2Uqv)Hpg~c+S`l zmn{>N(GBc-Ime@FMz+O}u`byX9pt;lqOyiXIgt>ZHS@M)uMNN0`r&(WA>{v^A9iaC zhbF_u)#7cLO`IfVIlBlAoor3i4&|0{KImqvt~S3FUs;JQ9GaU|^+Iwy1{yE}hDoH` zt`GQTeix&t5zy_5$4s&&guw<3IYuZ(b zW7~(N?|ccz)>rP3ueH06x$QL*t_fm~jwx>mrWLiQ)M$C7*?s6P-UENHpbAb=wE-{? zWd32~JN2|~|L9xR7I3VtSJicI()(X3z?Luyy;`YG<7j!fy^z^{{_y*3@lksy@!2{; z$$S;bV7}l5!Xy@**~P0?Y^RS2E@&V20!t`FMO<<7>v5{h4^TR3ca7N^kfyvK(vv!w zPbdH}W{b>aeh~azzWA~(j7c~ztm|1_1dV%?4S;^f1_m!#xlP|X0xS;ehjqnCB(a7- zd}X`v?z?L74pq9noUFB$VSJx0?!)P?B@gy%(uRC4yCoZ$rusLfXpjpeCHgRYK4!El zg$By#YW~U=rAl;JwS(e32zABlCvDQCaTvU=0nucO{DrwZjD2H7OIusp4bL$@mksaF z)9T+F_!=E{9=5Lc>4&{GVnI#^<--;lTK0Q6ZJ$Gs*9c_V*=-MV!{yFiJ@TlBb<0sN zCS>usB3qDB>882}fg=b)aHG{#LJnW{$^*%p^bKB%e4-9d3sXt~OXbV9Iu~00%;h-- z_jYVmsk#@k&-^)hQi8>A0oFeWy%QL{7P&EezF5Sv3qJ`$eEOgV}z5j53X2r=J4D#I0&+Z${8~ z$2L_~o|j#fSBgnS{kqOc7mX;Y%qgCrF13SsDyP>I)B|w*NeX0lE-wR$N(~tAsYWFE z1LSY-89;SRL&(0H?5%MqstmMFH(k74Kt~uT<$JN-^*O}@+pv-R9yoy2>1^L3=~qFO zOm5^p6nV?pkO-jwF+s3Vu$4vrwS!UP`qkB~Q`<;!)u(~W>Euer(>*ZNwe1Y-rS=Q> zJtNNSIJBphIC+Ff=vZ71K{Tv?4WKI7*!Vp6o=t#eC{YHPSyz;6j5VA|Mq7XkQi&?< z2nZY?jbu*z#VtMF^7UCfTo?mBh1AozhPX8hgfu-Nai7ccA{{U_?2q@xPfid?ft(Ht zLVWTLR^4?UVzyYItWOo*`Kn?rd;5||tP8y+d)+dR5*Lq`@6N-y8zAl+3yHLuyu_ODbG$XPh6EGPA8%X zNlOvz4gf-*(Zowi`XE3_qv zN}jTT6rvH@-e?3B>aBq7vUzFd>HWRD*;`EOK7(D}g#!C!_3$z(y#kva8rk$PX*VXb zhXbL}uGR^wRk~k>cqhWY6-YdbixfAf&lL2!$_)CqJDS4IF2e2QvfG+ow&Y(z^-`Cj z%QoIK(>%zvKD2uCKB>$Wj(`|1LR^IRy3QB%rlJAV179NfL++AVDNbhlP|6(L2%D}f z616t^XbP0Y@7`MB|GLg;jn48;C_Adp_K1eUYXggcGk*B&unVnS{xH)k83r*L-~z^y6H$Dg1Gxj!wDQ;GCq)ClP(m%PpZ4E^ee5VeJ{LcnA7%9FW1;Lx6iiQ zqOnrg8)+b*6D87PrhbuD399d;w0o8+L|x{=)E{G~S`bWKjosp+tT`}D$3z|pX7^g^tWwF(U8v|v$l%!%}&NQweZ-8?bx z{Vglk{_$#NbH4##UyH46f=UI|SdHW}@ynAKaHKE+6TTZ=m-!b{L;dr*XR3k4U@d#% z9i@=YH9hUF_t>o*?H?zN4W9*>wl19b5-6S_u8!TJli9vbpspFJDzFSvsfVT6YlV3P z7}e&VA9lAco!zwl1>>FU5(9>r?q*WIE_y7I-Lf+Vl^br-(#$nn!r1&BO5|PlzDXdX z=cBpNw=7u1rb)*gxht2HREtT=X6xC9c(w1WhIJ*U!nreVx|#T?I9qo}Dx>A_(f-l< zt#2}WOOHpFAdQs>g2kPFk_f!e)R5b69r<6iUmZ?+suHr*5rYl-6C zam1e_9%UgHodiQtt$9qtcL#67$_~tFm0gBv6t$J za4a*bB&3R-%@7f3IkU$&Cu(Xr0^z_dS4Dhty7s+3NZZzdgv4Nf`j^wq>#6U91wSzH zgzbL)>&~40gB~O7{@|au_F(DuZjMd#F`)GpUfk9&3ny%+3$wt{E|I`44C1U^j{6yO z+a9S5f-H0wzPTS2zq4ezn+oz3N!LE%eYtP@0+55BrcjnJ41lR6nYXn8MC0Dmh|Td5 z{in9?mJ|D)s54`4Pi5ZUj`7756xD41i& zvAHTdI#X!lb?x!fcI{J!G3|kf$+7F_*ft$-W}A+oWKYz{d~XQ#?Z&BqtfcT8iTWFS zSW;Jq@?Dqbhw|^karoFoV5Yv5=DTYlL&E!(yK9h0ET!8W#tppe+~gbR*2}QcYNhNHZ$Yz?Gpzpg8SW6#TIZ2BM=UL^fY~lb?pE(5z3CWu5Ged?!}zy+Ojd z|HYE_1xOV<^&BL>LRxAXWr1m%gW-(Q#q25C;mulmeh;pOW9xoPcaHk{BmhtGc$i+< zC3d#6lVR|^<$!~p{_KRxc;ZvcHR)%O^BChEpO3(u`ZD*PG(=%YI%1k0*SVBrRqifJ zw^=I<&9y~(Y-zqP)GA4A?UKShH(YFELOBU6p_nUacCYEW==`Y zI`-1ggon1n__#}}xw8=Jtk+Mkmb-0!Lv{N;pa$_C?7g*)m7;TUkbIWpaF>k5{GG*+47n>NsOgMj8#6&y!6ygCp)ANo z(-^+V35n@oyZa=SDH5i}%3&l_N}zA@nzV`&tl6`ZxzmSvKajxrlI77#MC~+;ccnfb z3C3jozHbo3qX#g&tM>81li-mBQJ`$by~*dCd_KNzXzaBk^E32CwJ0>)n-oG- zTek<~M5pW2E{}d{rbV_OKwqdzKvD~{JT5?1xmR3zOo+y^KXnCTkkc9a4x5N`>Sywu zuu!mpWR-sUDTMh=7S$w;AD~x1=2HOqedy!V-;3j4=TZWF481uTt>yDa=jDPxh$zl9 zu}=)>avJ4kUHcPT>HZ5_$@~!vgn3W_=#kQ;Vd%c2e5ytA9HV#IqJR&&qTyX~i?2)d zyd9NymKcA03@z{x7pLj(4&WB*c-GERx}F>=A5CyRIzUPl7RYFQg^2Lx-9XsuD&28* zX%#yxTAGdx%4YY=%Q0fh3>}A7g9uUnvFNjHZKE+Q-(_))EE}x#cs_rzqiW_d=~|t8 z+IZuALq*!CyV?gPjP~C$K1OeT6I3fKYPB+yDR96* z<$eOkLjOZ!>19(fFFMiZv-N$GiU~4Dq{h<7R?K8ax4DzdMrsX>Gi+GY=3Xj;3}Z@? zP)R=QOwu7>Er}_;SZY8SQhKNFQ@+z`UrI_rQ6wc_4-mDjQ&xaR@4M<#Vt&n>bwbAs zuZz@P7X?Ome#;yjqXbh{@ppp7PNDI_{1!bVz#;Ihwq899wcS7U(ZvqEnbQENv_7lb zIhJ_3+z`jofA)esrk9rXY-%zNG5cQdEefKoJJ{oNaWJH5AtpcP||rBbmmUF)0#Gf>BdF>Q_J z(J$V>$?`%eTyM!?!$8?SEk!*jZ5a$g{sG+YrNAkPzPl?jM1Z*&X#7TTI#V=j0vKVr*Xzf1mn{;sOl`5PG#0x_dxv$}Mpxt>E~ z4v2(d=XiGg=OrKhT`>Q(TUASni#<;f_CO^!u0qfK#K4%5pV*A7f~=`0R;`Fw8spW7 zc1a(9%hp2S9yU>2oAuKwMi$T0MJfj^Q^_RbAot@q-}HDLr|tOwo-R3?)xF>{)0F|r zhJ9J@qn<8=5Jk_I%R8Ec@ zMFm^%qK=taWQ=-kf*8dq?O~2O%?fi8%XCbSW#4j75JuNM%^*0X@OQA|4QY zB}|_c8-R@7Pq1&8JbfeP_l4SPyG0W!V@~!g$LZw9Zm9j9*K(|!kcxqIu>%n)%VUdf zz=~SD)37&uS6ym?48`Y$>Sp=$V$S;`=Lcv9NC>Wh;wsBPpz$*;;1NE2X#=S|T%cRd zg&9zx>pWfLGb@YqzW6W(gadgbd}T9V;EydkqXXe15cF^5dmEulimj?`=$g3H z(<*$lX?(GPv7cMs8QMjEPHay9JUZzswj>Q?x{L>4N{5+d_bISwIRadPYG^5CxHZ~1 z(kKDAAtYO6f4`6aY)xU963O%B^BRV2g?ackUGYNfGifkY(sPx_7A3=S+XH5Iqa_$j zy)%aGNU;1xP(8gr3J9vK_{KCV?f69;8Mq=Ri!J0n5nhAP;#i$BpTQAak8(`a0#`L! z#mrcGd+bBG*Zyu7s09NgFmuX=#~le2Vw7PL(sE`!9fdHTLo>_K)gh_7VSe#t{L$2E z56|GDDrilmSLMt`^VuxX8wk}sue*d8f@-)J>=Csr3Ih5l7#_eR;a(2|HN#GwDCE;| zNB$`opwm&=X?#*UdqMYpx!|FjB$>mQ3b=_qC@zWn{c3SiVa_*WL4Lgz!}Iy;Vwj+N zMYyjngQ5TC=W9199`Sz32RCPX5L}TjP#BM4quX*YRZqfjuxlp}-Ly_PjPZ(r1W8}a zfCa{R21Xi=fYWi3b_1Dzl^^8P=*bVj{Dkot5Qu**dRLMJ2Eb=Gc9OZxqyjm;N&yh% zBd|x_>nBmsc)JRW32&@aIbg1#>b)qW&LL(lF23zls(9&}`&N(b_0!>PRu7$5`?}Ez zw<+ll#3x_X#4_O-26s+e*&3@yd>n>BcO=FSvo4OZrVj>_jeTx4&Zat{^p!GWI*bnW zx*t^BY0w^j-gxwsuEgRC<#2V!ua$=NO|Q}3)9^^>4!zQj=rSzz>yWg4Fb)l-inFk;ES)+N zsEv&fXE3*TWy=0vR@z;RmUSw-`u2PwxSakDZ*Usc+_j(Bo`Ot-h(RTwFOdWr@j7Vf zEJahts)%iO+>wyuOeZ~!nWPo*pa@lusuGPt+qY!ZZ|GOFcMxr+EUDg+wXX0*@$``2 z_Q*RJVU+crFEgrO=ov_-5(ZbYa|&Qyu7_)2+sZ!^$6@u)3(wY;_--8*y9y<@B6jQ- zjDDdI=mkf_3hqUOwFRl5Z$b7#z;(@ZNp1(la_s@VDajSqOW`yR&M7sCFWhOqcDJ0b z%T?@9QQHKnRTPKH4DLKBAltny47K4EV>S&ez7m%D5UexeHzgteT4&O~)>(*~{!EEe zMMqLSJhq<2ct^09$zY@@?TS9^eS%z-#>Y6AmTt!nPba^ zury-|oDMUfpq-*y&wWfpIw9=jO~zP8zi`YL0>cd7$-gZvh=h3*a9UjRuwV-0ES>T9 zdhD`Dw(Jk?{Pf@7tp&2Gs4lvs)^pU4vP^JQe*3`sEz7qNw1TUh^#ewmL$xqupwj4@ z^A&SGCo6GTheEKm>;NZ)+x5)pIT-gYyTvNf%C3H(Cg+}N&20S0CMErSOxEisa6YRW zQBLTwm=6ttDY=^%m*@2CaFANAY%S>7-7hJ9HbVvuN)9L@sVvRNV3uXnPF~O?sw_h> zMECSnYS~0iJh5gOk<;Q0j^cU23iiz{qw~){=9-$)L|%S)%nw|3OHqD2so#)uy9aZ= zzL~W{$JPgPYu6~Tc_g(i|B>?Lf0zkw`d!7A1|aMEiP6r-A6QKY3eWy-(^M zzOgLhT~orvP?H40aAardam3m(LXXnScZ+PpS_6N7FuSmpUd~R`Uex}NPn2ePJh_X{ z1o|)65byJ?s`n-|8;O8eIx+ zhlR>ed=YCr>`vx`X$Gj-h~fFHQ=q#3M&^D4?4Bb$-Lq`KW}!)>3-h3Y=RDC~m_XJi@a`Haf7l8-B@DLkG>-MW|G(%^Nx zUhos}ikwCYR9}FyPlZlXV)WJhiT9SO2f4Iog%YR{pfo{{bTTLYRM!-Wi5AY(wYABO zXhUKU#g&TgbS|2xSsxHV$Ff2cYS|D~9_qbnejMs>7t+8lH#G&+119saW7iRz&(-fY zi{D2jy=DLkk*>j~-U)uyiBdzukM=XIO$1&d0@B5rewZE`P!V)`r+2{p#ubxnFFgZ^ z8t1kkyx!^pJi^{29n;V%q2k)i*b!C)+t|;h)P~qzY~3;0QPi#f5H^Fvmmkzta0u9V z?U-mpqa?~GY=sZ4RDCE>igHG_Ax_f8=E zXX78Rf_P2E!XmdHoy#_B@aE3tp4}C8d2AvN?aQ5x2JzSxWlUFdpxTlAqpDyPOkMzr z>*crap`4h`W>~1LOzqV0uf+hYO8FC2aU;Yl`jLQ^HjT<0{!;g4U48>rr9u_ajg{BaAeqVJHr6A^FG4uiE@G4Cu{|tR4r{ zI?d-&I&M`WSWHKAQN39Z-(!m?Lw=XZ!d&;&H65G15xR|FstPerCpa0uv?n?+Djj8E z$b5zLzffJT2V5}hcQI$1(hWl4W&QGU=`QV|JTmDUEAxrTDSxv7B7w31_^z>X4IvaA z$n&x2tRNT|JSdiNn(Mx|p_;3G)z=ogo&8Atve=I{RVh5Lu{0;R@rG(S2d*C+-40wc z!3~=H|2zx7s8Gz;9#vaG`7GK7JnX+YyPH|FvJ8~pa)TkI$p%pZo zk(-}J8r?CXX3$XWGq+aA@z%#cj+fqQA)Gpv)_IYn7Ys^n>4M--GEOFljawPrUDRPz zlvcNXEHoZwX|Ak(znLnQo8b!MrBcC5Wv8#gShE&E$Hdv1u$Pkdh=b+!1WW63J$1~z%y0#OkF=4!nuCe4oqYvC|XN@!zl9vn7{2%hhO zoY9JS9oV{jSH3F#-t?L!{eHdlrdeDK3Z*W`{m*@fOHUA5Tq+w2sreX>p#ocNKHj1v zlQzAU-aHV8UPuMq#F-e@q>Nv=u4@ZmDm{1k6uYX!4MICe^<@g4^Q{JQ@(q?5i*;FX zj3t1rVic%6@KiRNI0TctF5!ua;6k8mY(*8urGD3dO{W_j5N7pkIgEccIWbONFD<5e z(li`~WZA))T^Dh3UBXnQS^_pRWQ}*G?m-dNMgm4I^1A7=z~=cW(Bu6q_N|uFVqiS( zwm&`Gxi#)J2CPOuwG3Uy41z&{`!&O5SfSSK7DoA!TqJX)@!FQC)wV0vy3n*?O$6sJ zo4D=&>}~~#<72T&YSC_8`-{7J{Da}YaaW1{gS+ZO`Tyjuwjm_{;jZfb$z8Sj#a%7< zVG>y(zxae-I{tq0ET_I|db_mQj%g8!4{SY5P+4D@^w37njtv zqYS=X*A0PGV%_9BF?&s_RjA9wVg9fFOmpk2<|?ZZvLL&0^JuT==0t1YqqeINEi00N zWn9nc0O!E$D2W19LDWsk`$)U0A=&N&p3n*iu{=AVZ_iDGIOSwWp{ce?*cT8>puY0D z^9JoHMig0?5;F|dw38$gIa_8Ca|8n=3-zC-SWtd74ZXmO3+)QtH&_}ovWQpacLd{$ zTrfDY_aB;1PC(1w(f6>8HZ`%pav<|32xPc`Rj2nJCGNg_jKoMqY93(O$hGZ7ncFW;F3#pIR#E~oeSMD(*tYVxu(MAMXNew1p6lmuuYhUyG39>+Gyd)2_A|Xg zFF8&=8~>ah8rW>*M}GNZU~sLVATJCXz*OB?{wq!OV1&n#`u~fjnp`6QFPlCzRsZ2~ z6O1%II)`FDr6Q7*_bH1d!Aqx#8${E{`iOuYO`l8Zo?1Fnp_=gG5!Mt3Rs)| zpd(KshAFu1txsbaet0AOE_3ZNl;C`gsRG=?pF2Shx3jee4#7YyO89_Yo%_HfDWblo zLDY1TLL3V_5n@B>@|B87NyD|^7P@|^~BjjTV!FJmD9 z(4}AEGdyAKp7-&dgNRA$^nI^GhXXJ?NwAw*^{_lky(*O*l!7XPR?onoO?Kf}*3Sf1 z-$9vzC(VhxK`jGZ7~CJh-w-@9AEsidxOD&yDo0hZv#K;f$DA~Q=SEZ0%Y1VTP8qif zo&w_5@p!|6%RS4_E@qt(jv&!sHwkMq1HI4zCU*?4V1e>|L^&Lei5s-W2he4UOIxv7 zm6YMC;2Zd!q3?a{D6%=F9!h#wZ7g7NIVJkQ5k$(^&rh@~BGMln0%Xz^l!J3wM_^xH zld6>;wilr3zZw>E!(k#kM2NZw2jk_<0+Z6r^+=c~d?1y!w5ZXmo*moM`kC<|1N`l5 zMX&b0;5FYrX{e8kTq=*O3Z>Ffxg5k1iD8svkHX%y)YSY*LTwIreineHLDw!$ukHAi zGiGb3`$SZ-y%2^sHs=UPi|Q!_XQppNR>b@MBB6Ex66*e6B-Eu}Bvg9aoqVb20W@Ld zVN0FQw(YO8Y32O@{G>$#PygfNf46q36u|hiuq|$7y&IQG@dB#`bL9xS>h(X`ztt#E z$)LKzDG#Of+V*=1y5QDsp2I*fyQMO=4(5B%jfp=?5zE>dGOVG2pa_>i3(B*odx9y* zJo5B%B{2aDjUOop8k8S_5Xt4DWnicyXfFrX=VE|S{`Pq+;kIqL-{l9HTc9WKR<%)V zdAVRf>_Rx5@bb>Ho&+`t?S>6I4&sTcPIvo27;zKqQm~Jp9eVZgb#spGSJ>?@Pk}4W z5z}5zd+@?O-2M+I+A=&A%bls>s$s>q+_Pfgcj}(G+pT>Asv=&&k17{2uDUP$Nz>q% zo5URsbOTUUi;p8J4_=q00Z%Hwm&k6N6BhKsXa|j@Mq#=Fu7Ryhx`ZkSHsG`NJbZ8! zi`O?={813ks8L?S!JLu92hrc!>pz>-Gd8eOkxdZo>plvmO>Koq%$GW}CJORIOtyD} zp@!#uLka|QdFR39?|3I68JQghFuqo8lhSktJ#+PX?W-AreDKIj*k3?U(r9HW%6hTc)fzC*;6!|EKEw?maNJ{7{xd|Oi=IjQslZ&{f4q2#Jl+CGyS#v+A{+osAY z9WhF3p=negBz4z&mr9$Mx_g5cw4j8f;Wx;RHHk9JXdi*+Q&?dJca#7y)I+%>kV4Vs}^K)TT8z~MA-MlAPrRyc5A<6wo zcCo1Bcq5X}pB7yk^~j$9R>77T%jXIK{oF4U5Oi0%fiOHW(%s8rP~Eup?0yTl!VlS~ zh^|f?ElrVkJ<%rfm;3?Bo5a2&N?Z61oD}y7pjm zQsA>{y6KMQ+#2$218aekiQKk!gltEToEdh=1zk2&&2N%hg@U|ITRAuQ$(2|1tR@rJ z60~=w=xhLu@{}UB3a{x6MF&_B>GfA%!BwBb+tTHBhF@w9-lK1SOl*u^Ea*;khZF&d zz#8l*tbQ`KhG4bl)@IRLs-7-A5!Rp`PgUf`BJBfcZ@>^G5RAvgXRQCVXykq^nxnDm zhW{Un=6)bJ(*1eHzKU(z&xd&Zpal(_NAr2vmeLe5&*DTII$3;>0R%$*MY)33vEkQe z!&HV^@7!kC!G;l{!B;gOE?-tRyddYjcL=|BG(YnwOH{{fWUauYq#lg?9@2xYu+Wy= zS~_mU5^)_lW8?Pd2{gqEjay9K*M2|ADowmL+&{?Z#`m*8Vq2=PC0(wOHziCNI=M)r zvrD)9Z9(Rd_xQ4w%2?>h{wkxaV?<0*Awo0+YE%L5FU-`KL&T-;Nu}F53j4G#1!UIs zK{hJKL-6$tUbISFrzQbY?E!$LB5f25voIf{aNw}~z4uVlfX`eHlPCF~{r>RZ=l;K6 ztw*oGGg|Cv6+QP;#k!?{C2_-V1dIHtedy}p-DvOmlyWT^(>M3nGpVo{8im_qag94T zf^BCt;sCD!dHwUv9m=9mJh3ql1}m;m7l_iPT^mg^T@r?uxjVH~n<#tBjvb89wG(#* zJV}mur|5|9yP5=~t7-78+{r4q5JVe7l4+pD@Wd~c&An!@qv;^|rfOKGlGdxvw= zO%E^|j(SB)`FkJ4X}h^XLXPTuLt(Q}*9? z-S7QnEd(1l5*QlcA6R~W_@58s?}zB82>E5Ye$#e(x$LUnVf*FaEB0YDhs=jh0+d>* zZadTL#Z{@et@AB%o01>R7q_Fg)$w+8tM>DsfB<)UxEiNhprCa1&~Bk9zv)gc`98O? z>`F%`rP{y_RZ|U13CID=mmQDB(-^O)PO#)ZB+&tteRJv4L@HwEJ(9QC{5g^AL28lg zvZCu04JON5QUUV=mm#73adNeTCgIL+rAXwAoQMLl$pw4b^w5b}6oIi6*cziPrRi|m zZ_))ILF3&8tAIpjPo$oHS8X`7GVPM9E=P1q`$}pFI`*m{u}Y`HLGK{CR`a({#V-mB zY^oI6-?aI3?;nltKTDl|>OodnpnExjWBuGuiT*L^DajRTpm`eE2r?UU4<5a3k0LN2 zjr~|2?i|4N`86&7dUyCErT@d)SB6!&b?q9cgwiG5pdg4yN=Pmc0Rc&YC8ZJ@=~$GM zbb}xgN=QmsbR!{xG$@L|q81_DamI3Q-R^zf_xsL|^K&h@F7cW3nRASL+_4@Caa3WXx;M+!70^zDP2c(QZsqQHQ@%*tWYdeCFJQ=I<`mzRWa}Qj>$E!JnqKT}1QK`|c^Oz@s zRcA3)ku)XDVf^0}M2nwsGX8Bj;A%7=aio!xQv1L?vZe zOy2I}NMvnVW@>6iIieL?N;o(;cwL|#=OYrsAA?Bt;pvlQ6DEx9mP{W^9Lbv3LQn9k!R=%WFH6PX^kX?f^V|x_66QnSE6X~^eZ*82Ag=2E+B_!cXBC^W1r1FXLbn58?r)hl!h^$w5{=>R6D zdG3JNjd&lB9qxZ+sCdip^TPAl2!ylj)2P)QdfI=F>Hhs#Z{yx1@;NQ@D5k}qCq=b6 zaL86=?Or&agPm@%?CINaL=Jo8+~W@vhO3o-6YqNZ8<2XiEsJ+%)U>gJWbVCz0ge4c zm!AA~H7es%8ZxOS?Hmm&TY~I1isDs8(w*8q#H?R*ALc zifm_3=*_7oqnKQhS_8hjsMJCEUeSwPnG&g;p4- z^;boJ-(T=V)Zq?qR8;ZCSNHpyFVpt>E`U&g-HW&s5=`}68qbh@0XISo6VsAz1=?~T z*1Z8v=a8tw6psB6NcX0&blvN zJhpzoL&kPCzo!*I$cmP*J^Fr(lej2^uo%GTmK6LB35kka)EAoE>e&{{A$iZ{^B;$t z3#0=`uWj?Xd!Jr;R{%gf1P;1)AA9}H!dxK+ssO{K=l@}n_v=dgs~XUy{!tR`>@)n& zqF6z3au4|p6T*@sv_KaJzAo`(eS)Yjqf9am{qEBm`_@R%lT=3u7{&?`9Vk|5@1vAG z>Fv3Q%C(S^O|0z*!ab7pxXw@&(Z>nFq;Y3iPP8c%Q2A2}N^2Hq>DJi2>7D3CtEE}K&u|pcwX6<4SYXn#K88UfbxG*WE}4BvYy(y=L#u97*9y+D;q7VU4PQ;ujZ+p2Kw-h3s5#Fj@E0eCRYCsWnBQC4>@ywGB)jT8Z09q<)v2@%-^&HA1ot> zyJ`D##n#ss%BEqQPkywPOjV@&Ln6QIg`r=~8aWHJCo--bzrOgrU;C$o<754wb@+>o zRU!i_Tov1EuEYblLeY;h8&6%LWbxihoH)J-?&Oo3c}!b%dd#Or$RTJtqYAB|x<00* z#N)L^9QZBcwY^eT5b<#rh4ua-`_{m(#nG|lAnf@Vi@F<^xhu`M`RwaZ?Ftyb-b*Pw z=T2>Ro^&`qj9-FNav)bdsrQaKqQ!tOHSOdxC81-{!LH*=6p29AZqixqfHZ(cntGk( z5<@diON$7p8bHTg=fm>GvW+|SYf2%I+#?wAarq?nmhzLYEhpUYC z-BvzO_?PND>7((1X9WXjJF9|{hr1xf=q{iXhU}ZDZVu7`~4c1@DR9>#>9XN{0JVec%X7sK?+R)$87sFtT}#uBiVpWcAuP%lv4LllimK zb5+lGb}1%2tO%nS(3wQ%6jor)Z$dg}fK$aAqu3_Vq$Y`MJUy_GCDK8zNRC3zXM;Pt z7vB$qzLlSr+?sob`G1fC8E&1D3y_OBejm%mSQgykFs@=5GO$!Y=C?fd;wUFXx z=NpctO!b8XBw-@yFeexn0{A5o4A*m8SUt>j7@H=ZoTH{C6(kXsnXo<*Opq!3Z0|C$ zpASPr%vYR($+_%j#`CD?;^6k)!m1b!UaEzaKSHGjkYQeZx(7>3bVx7LiFtaPd~WsXp)subKOaL!zZ2q4UW zfy0L;a6vFx`OFf^GmfX9LCOPE$yA)cYa0n{5gcclv(y$s)TXW>Z{fDhfvzdC^op=W zk4l?WOwB;?vrp{7>GDZYPEh|SXit}IV14)$9r=TK)Ia^gAX}vYn-#4~{PZ^{`Lp%^ zcf))8*;Op5YfktK=ZOeh)9Vj>!`LO;b-W^qr+mKqO0n)yj1ybqT1~;#`}8g$B7lT( zIBpQ8_3ObcIu4VWybVDqRbix{pXMY~Pa7XpRHL6-YcTK>80S8S#^m2sn8zIV_J3`n z75jR8M)~#r<*iF5Ef0$}zGY9Q%Ya*4c-;-@R~Gc5uCLC8Tgs?hQ;Qf%J2@;aW^y@l ze^?wPmr>WFunft~?V(a{UVX{;mGX*8y@|v*2Tn8cp4(0P#=We_B7BKbDic>?4B3+n zL?n@r3Dd3IyW0d*Cd=k*5oDzmJ3#1q@DX3*9Jni&h#2O=P;(KqdiO7%Q#Rviy$NI; zzHJhEjTC!YM zzXPQ6T_0Fx^EBzjS~G8isY#4eo-14MQlo z^_f~xU&p}C+$55dxT{mbMK?V}O(8FC@3@`HVO`Wc2tXObmzv^d4vkIcP)iM~xL&8t z=@5UGfP9w0Zt`X>@ODSR?_h4Rjq`93ipPMC)3Zasx9`T9Mw-{8!8f}gYe<^uwVRD? z#EwK=pod^PczNf;2KsqMtWy%sX13IR+dg0Uv*=Jt7!?lU5(|X#V{qGT&g=qau#1G5Gk$maN zc}0R5Q(J9mx~Z>f?KJ|w5>Mf}UFIaJnIX?mmq2Mg&Y|*H%JwS!c7u&goi*yg?I`As zbD1AXwVCZL$+nib9`&Xzg$iFK+?JKp2unLzjWN~SA0qOe)cOPT?Q-ko98o)36w=yI4R z(M7siW;gK#Y$X#4Ch#~7>@M}V)HHtXEsvBs7y`=fvT-WMVP-I*zU{DnJ;dN8S1_Ie zKeO^i!7>ys&SV@TQRe6Sx)0r^!)>t~oI*yqVj$pj8hUM0un(SnzL}8l4Y)j!oMr2( z9kXTUG@m~#x_fctw%?&WVPLQFQHMg;i|tyPiRc z@u?y6*^urD-%zTuRCM0jLkY91 znD&br+)~zCid{h}>*kwz-~0@PzT%+960P`F>eb4-l_D7ra4X6f_zM;QnUb-(W{Rh` z)=u#tIqvmLdg#vF67L80JZoU!EG{+f3WtWtS1ZNVu$z5ImH15W)b}=<+xWgBWXjsA zjSTbJ`JHY$r{_jG7+RF49P17KZL_`ckP<7kOP1!v*e)0l)nD!I0*!ot+kzPG9V~<2 zBrwitJeae>s9MP0pgIBYhLzwe+i1-ZFqZIDMtQs0S=ei4*`arVN;(2^nnf&wJ!TEg zpYmHEY4%fX$~S+c_Z)5ZV$CT)L`VP17YDG?@40TNuCwXWGK&r=^t>MM=`R}0ZDx76 z?FnWH?tlK9yZT>O8y9N=6zIynN8-w7i(rzjm+l5(q)|Ae1>a?(Tp<%DQryR!7#rG%`xLBn;Pi z?E#yw?ig$ zol~Q72Rqe%gkmBc-20~BpXyk<)9)30CEHZmq&+5HTfYsd;-X}N+WfLP0@WkUfW?X$ z1M^&Ftg0gzPU*$?>5D}}wiMPKOJZ-SF&HWC2C3FqfQR&Eva=J!jkQe0Yy;D81}xUD zC_C~n-PzytzP|u;DO&IGUP~JY(c)co14ho5M1E6W$?96rr}tw$*v$DIraM&%$(s@* zxCwNh!cU)bnx;(Ez?*$30geQa95_p$)*Rgz*55Y?dm1u7bX>URUKkg(-bCi@0?F!n zJ$@=bPkx_kSU8BC>v81ITjHO6=kK5XV)ZXl;x;PpKjm@CduKNu^6gP?Kb6G_Ck21V%l|)d_t3VN~6F_~l zzYnH1x`4t4sldjR8&43nIM2+TQUnXnP-%LMq0~;JKbUjCRCD%#JfEL_b8nTe3}|m3 zUX-?~c$SXmPl1%t;rjO^HZqMsgqgauLZqOS*g3S&$ ze#&Ral9M1QK#UXe6S5@!su(^}!`0AF{i4*%+GXS%M_8xD&=eF8=))0z4K9Y1EI#CFdoPHBGR<_))HsY zjy8{7NfT;nD>gJ*e?Cn-Y^7O&VRrv=usY*bzRrBmiU8*+A~BO!QVRV#yhZ0Jj?t3R z+&C7(G|MuhMO>L=lIhke|4Gh3pmV~IlsOG!$wnxVF<$&k(^COQB0cqH+R&DI)n0IY zL=g3fqu1)vTOw)|`kSOuTb%8Sy?4~D#Stwu#y5GaOu(yYD7Sg6}>3^)xF>x+Cd0q(63$rt` z_$w5g@(@_ibg><`4Zl>22S5%yG+&T%jCuyIlbXc(OI?qwH%C=a}gtAzx@g~}s{L`iyy6n5$ zN^fqflT&@C+5~F%hy=8JdKLyAe~dx3Gb`qViL1J!H%Jkand5vX`b7I>=D7#Q2~R(o zd~}Ojal&989`40T9D>-rNC`4;PN1k zPNmN3ozcSMJ4H`Np#XMWjA)q~EIQVqo;?mGnPlZk*_P3#>KS&Qks%a?25e2KgL`G^ z92Bg#8bgh57Nl`hHztq-hf({xnozShv6PlPmt+;&&U^H3XtXk*f+k+pT{ex|l6SD4 z_SJUTcG=N+%dqH%u#gPq==jXg{bE*@^U=4kdb4+w(>ECNivCoaF-i^mkeiLF`4P!+ zVM3!Q$TF6K9Y{kjmU?@%wfPlm8}|3mT&Zw8y*>OEQ~FMAsFa~4KH%pBbiXHa0QYi2 zlzc6V`Gty^^nEQk{ zVhE&p8>qTSJMS>iO zF>Lbgs>oY8)b9%B@Vlw{-=%W8`Sa|-ej^{u*C}F)>#cxn_k*}sau#GiLF1>`E`j2K zDaX$*ek=ce-Wq?^3_gUBS7Dahb)R|>*MMAvXZ&-WC<#BVL_-kY2x;@TMjHDg8TPjm zBG-)Kx40BM=(Za|nNK;}o9fsMY>hSMFif(l0zF!Mt7O2al^Y^xncGk3D7ec6N>p=V znzs92?r3;^r`)?4OY#I`<-GziKHu_bhTh`@vIH-XXC=nOQo9?-g}XW3)A%sc%%p8+ zX&^X6>^ymcz6ie|iMp;?c!QJE%DTO%YUU<#qwL|vQxA-~(~|rvZ9+#(f+!0uzc~8g z4f)X|0TVJI^wq$NoTnP-)OiP*f}RG1la)5uNn+K~eMWiGt?5>(w!Y{UP;ThNhq23n zBKliV?Prbm7iG{`VJ5bTr_apMJ%G%eAAbJ9mS8Gl3m3LlnGwJG4xWGE_UiN%)s}1T z0XUk4rhQp1h2!w{(^DzW<3xB9vBz_2m}8tDH9N#=%>;GD48N3e0NID*qud*t`N)N7 ztn`934SWPE^j=CjMRj6F5~QEO^m-h^$w?jEcDeC%i_3t&jdiGxJDX4=v;-txXJx)> z$Cx`{adPB)AIVB)?b4%&RPv2Sv#jRq3o%tk9gHbM<|~Z~9Qb^cOFmOAg-o zfThG=U;H`^{G!w(D@VuihyH6GLlO~&AycC}SbJ|kN3(E()}dJd(V`FD zGxZ8K_Du&fZ7=jeN7PRyX5XIR^qBZ2+mI3qvC_k*gR;kGw5Yx1%1bO5P9H=LF+O<^ z;&U}Hr$&gC-mZs)vw_?$FF`m)_FyYWQJ!HP^voGXxKd|)i6SvC(^L=C#Zl|o-GCYi z;hYTH%k@dy7|T}jT7RC5N!THqZ8+Zo~OjxJxc)bg&i zWZ~&Sii^-9c(W*7vZXh!_1YI04 z48OdK4JP57X6u?>|DuC z$OF!(;&~O2OaZ8bYIe4$oZqsKR`b8m-y2l>r*JGMGC~YpuOl`Yo`;qd7vlX>I+pNy zuBMxW^O?30f`82q2>o(i9l@GBR+I9l7!e}3V{dC77-YNk2br>}r&lS>;+$Td(d{Ka zGcz^$9`~rygO>_8RV&BOr+b7Xr0jL%O7mEGpo?7R4YpW@a{21IxgSQ0uU!|n>c5>@ zRKm@Vxw^@_z(L0_dXzsqvL_Z;q+YPD>rSQA>Jkw-YLsuY!wRBj`fuKxtKPkTR8_5RMOv z-Z8NmLOB0MevjVeIxe_5DW4mgNp|QY1TopUhXVz7JGL%k32}lucPPN7UXfbR(ky^2 zp{09TOUIC6NS-HQaglGc`kU|a?2w{ka~XupT><~{H2cl6iN5cRz66~k>~kU9g}6{j z%El9gmYNdG(dz_xmk3p$Vm3WsxbP4h4{jQOX;oT#GF}nM758AXpa{d#ub!KR&na1d z#O7W+c8264b3U`U(7yw#{`xV{I)TXuAL^_luKGm1MphY?aoEaTZlLuk2zWZ}8`%h> zh7(;lBzU2&awBIa&BD>kFkomnq~n2pxsmHFr-OF`?=SG!|+Ax%Vu?_y0~`|4~!J+fpA z?XVY|Rdey9SYFKiuTK^ON7|J~%F1L1Zb#re5qG;}_efIV_EVBloG!3np#V6qTrv5v z)b+=g*detN*+7My@h+Ow@2X$=%b*u1B!|Cu6$7_}82o`-xDM*P;9~B;&0rbWY@q*}F7C0kVp=i5oL zEyB-~bCH&ww$6W@_byJ@&u8KD9J?(oa^~;-{oRjk`12QjeR#=y z>@4%#s;j%{_z9g8_N1&;kCPLd=)m5oP9R!})e7Jb%T5|~$rr&s*&1st3A)3p1|73L z(YpQS{<|!rA}S8+*Y9^Mt9uSCncPH5s>kD0yI#%bQm zI``0^{cLvI^W7dAM#H=|eZkfvF6SFKpzQ;;~()F%+FI{Lko)%2VpG(V=FZY3;A> zq_~a;Yl-nC$=(Lb(=mk9jyekuC2J=%OGeDBFUqHqjDdH<`)F=?2YfN`f#>G(-i>K{ z0nA~14o`-z0DS%s7Q85DaSNqgMMz(Z#|ey=|8(k|6hC%CW}s&I;kV$rE7DBL^;AAZ zz7e6KRit}~vTsaMc0-85HGX;l+=Gv<@^mfa24j)?cu)N5gB#>S@duL7gg7u8vdsR;ycOx=-t2M>NBG!?B#QOCfoUs9qBOG}ewcKTqlM@Lua6|)b4_22+Fqwu6Q) zS*&Z8r~lvr%3@>j!kfaWn=Dx`5fXUqmQ(3pghYkh3^Em&vo} z0C4lH?&!$ZUNtFtFvEVw@!j!T`Qxbm)j{j}6I7>{1w3aWs)la)7hpp&jA7wtx5LRV zy}H&)BWiEUa!z;#ASGF3U^oxj7_vKgN{!@^XyWoL-64|8w#3L`E{}&Ty0qP2-2R2U6vNOa)T=X%q7B_gcn7Z zIzyFQ49U}zZ-+`mi8`@i6ZG!~(@0@CUh0@apw5{4=&sQR?^<&`cSxKAKFA5hxRghC z@bu;tPBFiDJRuEV_cIy=s!n|O_~)DQ^PH=zLp;6OD#rAcnFvk~^ z$12DuTK8A{-S|EFFQaf3j^Og+)fdv%OTeMXjOqZM(M%lgm?S+Mjt8^!u4m^93P| zp08f6lGTv%)+b{X#j@HVpe8bvXljY84G5_|cCeYR@$%&d z@ZF-V+5X_MI`NnnYeL$91>6e(+7AFcMz8~tg^hu`M+6>-Hz5j{z47BS*}Esn?^M73 zOpYK2eg!7LvR@h32Ai0N*$0|0zQCOh#Va)30&=`d)Aw3XGV^dI>U4?UUWZ`b&7Nf= zA6%`C(Lbugs^wdO(P8~9r_NyO{wf6ebZTAbVg#SVC9r%I47+6>uhm2HEd1be8<}HL zRDYUL;GU#}@PEF*!j9mY`Sajv?!F`VdIk(lCQi8EFyJSXuZ7`e;Hvac4Q`>S+?J%X zMV-hI7wqkp*>jx#9~5oW*%tp$w5|S7w1r|7ZI=EfUqI2Ov-X#wE#!xyjUijobqIk?>lQvGf@%v74kb?EmCQ< z+@G9~Xo*gRI(YER>xSK``JtMxK$Ed+A`xt1x0mCp>{)+g>rKq814ZqlYmPBd{i8;K zj~*1i{HuHWb!Y$is$WDfVN20c+gjIpPME2%Df# zBlIUh@{YF#6phErzPXpz?q?{9K7RM1Yj|JN!!*o03(|q1+$SyhM2;Ah5;ul^9r5yS zpNgMLW?)(@NXLUGWQvtr6jdCD`pHa7JO#lsB zHP+hGb*cVTzGFBgHo{rt+k@jh$7$qiRTnQe^G8bU4tHIfyRmt&`<)1k1dt^G59b62 zbXjfpjE5tn=Cw~gE0FSdXyHnBff^R{Xu(VcOhX`D{L3pF;!2H@)e+-BdTrTu%mo?k zVehxt)PSODwZPM7NdfVr#a6>1#}7T1Mj5=Y#v1Wz*|>W9%T75J>U_U;>%SJ6m;@Yi zkWG_`uEBCRweksyN<(GDvrPAc=X|A511shcse(-eQ-3AeJB=Yu|4)hbW&b77z8RZn zFBp?^YkA~62>~AXuySUu zKxzN1(j5&qtk|)P*gsL9AMN&2U%)IVxRO$_2BO9v1P2S2r6$4zK1rfZ%QQj3qZb?d zrO>8q?BRI{^z*~5$itkTl5h9dAv-5qVKl`A&=EpVHrzXN?nDFrW*^=#@FLD5Ez#Rd z{y!M7z`pD1SLtF-dT{IPxqPz9M}l7z8Aag8rD??`j(j4ipl)_wgjbq?jN`iE^TWNa z!veSOo0QCR{$#2-sG@`2(L=)8y-B{%3(nRb3Uwhq;Fg7?b7KwoC-p~B&o zMh0qJE%>`+_{V}z-TMKykOUo{IPpU_c>=4O=7r`38Jv3Y}J#|&o%S}z+FA`OcT+am$+ID1t+Vya*;&)5&$10Pw?5}rpYx?_E zkbKE8q3+KyL2HI}(<&VBU&cEyAdW861Dk9yYd2oUpz&5^RTJX1V+c3h{F)Uqzl)^D zeL}>B;x*S-lV`|jvva?Ta|(@6c7o=nrX4q?gHRf3ll{W4fhwl;Da9 zg*VT*@+hyladbT7}?mst@{`9p6K5P`i(IZPl7ct8U5Zk z3XF;K`=rV|(ax{)G~PACScVZ4JHzP}xlVh@WZ2T|{HSWQJd-j#Oj-mpsX|neE}w%0 z$Un54ZW&sGvdS22+Y9mL*q#+|Z1dbmgq<;CF304oI)Qs5q9tyPojG534pNG6Yqvk# z@4MF0g7W8)>>YLNRf$J=sd^S9hHb_U?9W{Ul{%t0b4_o96p;LWa8A z>P!pzeUYPGPU*z)Wf}B^`SFq4?;XYhRZuG|eHs#zGLd}8iUM|45Jl8eO;Kd^r=B>@ zbhoLMgw4cjZj)z=ceD3XJ?0)vXeL&(LEX7Yzn+;0_yR)+YM48N<^>o2|0)Ot9POWi z(D7FqX>O_>F&BzLBXpbdU1nQ9WQo}&O`&giIk-Acky< zLh6A&Mk?JGBk&@L(r-ao-Yfgt38t2>?nB8pcpnzzR};xHrkoH>bK0UsjZqQ}A@-@_d(T9m#1!}H6?xLzGUo0dH!QAQ>+inY_cjWETOD1QP+ z7*f4^pz#?4Yo*hNI|((cc+WKbc`${b=bB}v!w}MoUGDeU+Jv0t%uV97ZLte|S=ziF zZ)~W#O6i|wtECw!A=%8Tp%@*5za@8@?iQO;^iyHy)+E4JjvuB>_k7N*XJMXu&sTdI zlC;df?Z+!4NlWjn&qa;Co&L`i{{s?YES%w`P88|SH(mBEzfQ%Na8#~|bGX>5Q?bC6 z7i+&OFzx%K0e99nISg%HNHgB#n@3G4i0{8o)H_mU#zdgMWOv}Z7rhpcoB z-}Sfi_Uc`1u^>SQe67$rtvKf(y3w71w+*l~2G=PTYYz`>M?E+DXPB4g0YMVn0Va*e z2-NN{A0Z#zn-V5d;@s>%PG4S_vJIA*`I1k#TCjr>rn`2`5gKFiIn!oTD7l8?gouP-ivX*8rIgU$)GV=|fqi+`7Ulif$nP2%VT|q15 z8} zB_Ng$Bk1;7f>gfxwHRFT=S?<#YpSlAVlS02HHkTxpr<&SkAFuSY*p@p+tholFP+#J zj3m={!=gbM9qkM`IWA@_SLp1TjJ;z}Efl3z6qPzo8sNVf>4@W=x(e{4O_>$-6(M@t zx}$=2ZV@PlB}q8)WCbdTxKCx$1<8FONk@0#YD1stBxZB)QI_a~%B;ZGV9r$CEbd#j zVc6WKn<#6u$F+_lw41u(LYf=e?@H;@gS^2dzY%K@dM$4Wtbe(%m9iE;@sO(6Y$m?X z=@{0^N?-?1oftL%Sn-k`}6t!y?x)6I&W zXyEW(nJWMIK5|Q((`%-WssvZEqIlMbx;ulF&=|mM&t=d};B#m=yZbDf4b5 zp5ETmI?XORy`Zb_Fl-j*Io+38Nz@i8M|?1Vsdd7Z0E_#fq=^kI_IA-`q^zREoQ*Wu{mD1=x6i~Lz8=u$o(K0mL2XI3 z607clI1m9!&Vx^< z_Q@@+^pgaZNa#%kTSf$NbFIYCQL=f?M(;{eG9)9fESA-&nwA$I?*ne(qx__#g#EXD zovJQhC`?ZYN#;+lz-|nHU&=`LHG2bAX;~BJn2lt%(A3Jfc6;|5G}R=uDjK!erJuxp zWiu1}tbwd1{IFpv^$U6Yi6Z@|!*6%WJoS%aKVmQQ$T{2B0B2AxVPNZ0pdZVVR)rPm zNTf~VdweNHXGe6~#LCDx*%)W_3Ta@JvTr0?+O%7ruv=4Fo9E+DWm%iO{tSh+rqV}X z2VQ>BxKO;5-=sx>VLiLdfa*iPuO=&VqOYY!+bXpOv0%OUV2MIsmGw*KAjOBA*NZl2LMoFG1$IS zmO5QM4)&$!m9^mp|TZ0(uu*@ax5AMMRv&+I64d7uYoK zoV)0R>2th%4(Ej`P>E7xdffiemi+qQ;}ddKp>;?6YopJy@5^KSc%7%IG6@_NhxNr2 z_T+kQ6Gjv8;ycW*n4cj!fsC$B3>C-_pCKp9R*E}?oKiG;soa}2A(>M|w_^HY$Bl1% zqBYH+$#yIfZPow1)Ulrgc}mJYzsBPuR@`kuyneGIRHd4~h=e_d-wZz{R+kT#-_rNF zZho=H>Yc}A+)@gT6+zKwdZHhM_g)UHlk-v-zA2Tb!I!5-|HCWB)4H!czyNbAlW$v- zh=p?7ypgIBb(^hd4ZMu>E6mgg%-U~W-H;bnjF}k6njX@fiWg)eVj)f>1qKCBy>qTSG zJzpcLDkvKd!8R#`s~-|lyK;lwS3d|hZY@t(t!da=e|}rDe&IsCg5*mqv)sZ(Kv5~G zIj1G!n#YDETR1K#8;J<9jqYrOLDk7BJ_gUV?pLd%2wNG)Ptd{~Z#n;nq`%_x>lf;2 zr6pH}pj$@vl3kJd0zb325_z;Q+}qjdc)mx+zo4{6G;g_bbl>K!9M5`EWb>ET_P6pK z0C|(|IQZ@P{C2z4%|HB;)FEYO@~yZ|(C11zea=VYyK-iJfh;BzLJODUBez(>LUbfC z7rO@gnE6<#>_W_6d_^O8#0L5T=6oaQKpKF~$(%*}9QQsuaH zt;J6JeU$UON)GV>Y6nTNu}OLHU2Q%&h!<@wS#)6rAWpy5!sYGJ%K8LzDLtbGmB72H z#o%Z#fvrsGys>RVvykkLJ=PCjdG+ho-SvJQBCy=By!K%k4+}rtkIQYdkkLNFru{p} zfxv~vl66Z)4G&@NUkJvT=L~?u`9%mqBP#>?wQs$+C8c;JDhzT%7mnziX6eM{B-u=e zjoo+?OZ6HkntiI7_qk8uB%To(ddfkWYy-L^Ig@;TudE@+BikA{`Sd)BJVg;mn(12Au^&(sdA&0 zxxWXOPT=2ScARv2yh*{FKfnHfdUL&K&ML&@?w6wBGm(Qa;u0ier6}K2Q!qvPZK;2L z@EJaeC2#3frIjrE&K-M(r;10_KvVym&+MPlbl%CxJhrVRd6GYKd3k^2@2}?Wn+bzG`#C!E zGsKSaSHyTHX&6Bzyw&rBk$)$)_*OsU>P6{~Z(a3LocX}0=c?fjxKO_M@M&fO6Ycw; z6R!?0Uj3V0;Xnh|%KALTUEycP2}PcAv_WqX?<}4N2cYvilfmS41Kau&V=!MhpQk*C zP4&}-+Clk`@VI%dwRg1lGfhd{qB64mBT%ogd46?vp5@omBqfsFrXH8)sZE>vGtiWQ zy?i5-!XN+OV^s)KObZB!i25orP{d_U{jGPN5V4MHhR#8>9&^A@26S0tk&{qNlHm8; z64RD}`M736BRakzGCfc%%Z#{Ha5Tf_re&fQBn>hkt_WFyx1M+5j&`5$%SCP(?dnZw z0STd%vDyjv_ll#H-wJ_PHlUU8zZ?R<>{4hQ$1U9-hp|QKX#)~h9+s>8hnI}TGjAj0 z%zQsL1l-oFa&!}S;03+t!Inmvy7Nltbj&8pm729C{bkIByz^pH?acto);( z_F(4~r4dvCOAs-i>3091QFD^c%10dZyFQ%T?zaH#_`^TtH;B6z+qF&?Z9xVl{Zxvu z=k*-6iLyF?o61UgpEPw*`qWN1{0O^(H~LY2MT+-#_tAV0%9(-krlT5NK}h9rwpqCH1kIEiavJDlu3J2s^=Ccy`#Xg}xCuYFd-mBCwQ?7MvQ;wY-^1l$6v2 z5kt7vdPpcEK=897Ee2gBF~p^x;-MRf-+vpmd0Gh?n6&G1Z6KI_2!7F*PXkIqZ_$4D z{=&nQmU~{%h6n6^uSLFp1fv}NhaE@%+rGhG9)cWS8Is9GSi(e);$M2S#f5AVZAc=h zAvg$I(g~6+W(G>mLq4zw13`g@ndaA=Yj%B{49E}hu@$(i&MTL$nIT$|MdUm~kgO6; ziM<34>mP!Owh(zmsb@>_iS|eaLbOx{LNfUJBYM$4@@y*tMP5))#F}sxm+sNUi;3eucWkYN5z$J^z)Tx?TXVX1Hw)#s+KN zA;KT`%oi#NuvXlezqhvk-CN3&gUO}x5*Cp&Fv)iAIR81^^3yAeF-ViJc-zd-yimRQ z)fkvKTB1y6vEdYBp?qumO7Z26>i19ODaCTIn>_Iqf>_657@ytKJNsl<`o%aMr!sH3 z*|*lpbl5-p^LM2PpfW+myXR-VM46T1k#VeTy=1Jsg4L{O?F%|s8xNDDffYwuL)ziq zbe_Qro}G{=t${0^D>Mg_eBMgmX{XlBfID;=#%}JjB!NxRXls`QYqCLk%rWyyRqkmA5aj2=kJBe;9E+iz5rdA{GD8=~* za*b~BNc;RUo0~^kb-d6Y|5T&5SoDAzoiVtZT}r_ph>CkF=5gVFiP6)~Z(D{(E}ltQ z+is;}IULE_&x^#{3Wxs8XMe;;J=+KlWa3S}+->vwNQ`Ck-P| z=cs|Fajkio&VzsSvkBOqvCi-PdV%VaA3`T9;oUq;ANu8f2n4LXWlNV=?@CGu9P-KG ziaI|ek!yGslxIU`u_`^hGV_JKgrWo*El^8dDZMq&<$bVv(bX39Jj-4g8Vwr}2qHQ^ zSCdTV(82FBG3a2iNnKM)A1MiSrY-mlY4s#5_?{d-Q)-m2p0MR?)>hC=^`xi=4oLha+mPo53VzH1G)#mlONE0;}cZMaMVVtqold3d>AtGOP z{W-6BM-x_Gwq-r9IVBXCj@ICCvX09UR+~@1*IY8USa1nl!G@a0HqfS7UYm&~+*FT=!AwZgMNninN;`)W7RD`wTOQX)diqgAd$Qe_fU}Tf~1Zzqklf@_c zssKM%k%c9%am($i8+c3yqBz~47Bq~W^@7z z>jd*+scG)-v=bTD6npqlzy9J~x|mq}ZpEkw-?UI!2oAp!5tI(z1bn63!zyQRGk|Qf z5=FgSt?gT?&uo-05K1H%H+UeiVi5GFI@lj zx2FAP@rj?UT0g*JpJ!%k8(n(O>JyYv$xy~1r(zw$bfNadU|b&7L{>3pyU9)?>(X2n zoD%R;lm31;G8BjJQ#k6#_t0bLKB!!4}9h%M8^c-vFs**7%&3zSMUZHlk7@ymFu2D ze#BzV`xL zV4`7?wXRhPSiK>jto_hlSb3;7+Ut)OHyUT8?HSVt+!nYW$fsr*UE!sH_s-h@MP?CZ zNgQ;ZB>={}Gq(>+)A~1K^xBJQ?%$Jw9l}6!b$?BBhr;Vx&lG8Vj!=+8@C-0X1qXxK(<==6MMN#n#*%d)K@h`f=JrSN$_ zOI>)pobC1p@#PME!0>jyk^pHy`WecuhI)O3@ASqg?Y>H0bd~GWP$AZcGQYCft0|QI zn_%quJhf7`AspmtL5xZ9CAj%^e^l-{r|87n8Fc=^>)AC%wrCb}XZF1q@@lUE zBgu_96&2J~OIW`ION^X6Ur)4yVD_g-c=X zUMbYl_cog);bq(JF9b4`0S`L}QuZ6IKlk_V3w|e+2Fd^|Ia569Ni>>6bXH_dduGSt)(6OZSEuMPD|R%hd>U$WhXsH9ei zFQe^qjnP`#His%d-YrmvzU$KkCLAHd%#&)JqQfTrL-t>QpIb=f*IzH?->;0wkE=h# zCk{2{n>VNO9N9KBrv5AGb@U&SUcr_9iFP2oDN#eRRB4%Kp3*PayXj}rtI3~9uT)LV zf0MGyY4JKW%K-MMh6>s1mYmx{oGqweXNuljr};e|!5>MlU0EUbo}J+~pOA4=7BbB* zk{HzIKh>D*;r}!p*lWXjxA>o!>AFmqpYXq1z8Z`2IC{k`=rxE5exc92L>IO&qF`gG zUqA9J0}N~ohW1u`1wsQ0Je@r7T8M)v02PQ?EPi_VqofE1aCq^s_oY8;io7jwxd(%B zRPC@W8G#}V>&BVSAfuPUefvNnw(LZ1{o4Rmx+$=L%fBq;&sxl%jQuX4{(fYX^?G6e zTE{%f1STZ|w@4;Tf)ir2AX?Zm=HTJ3gj_QSo*wc~dlla3w7{r6oLGjY)Ck1)!EZRQ z>}slo*K4z8fq%{Sir73m{p{+s54;Cns^J6-OlObWw^4GY<={r&~(c2i;n9nTXU zbM{95|3jYsK|&KRPxmixWbj)JeS(FTXncZ@JUA=IvHOQQJu9cjD$5x6hdR9q`=>g6 zT+WkjE+R^%5A%rgZ-J{OAaM0q2-xVU=)I#DN&ECW`zyB2)ZJ*e*%>5l0G|6oE`dM4*>wCjs|`t|H%GmQqw<{x%H$2a9p-#x zBX3b9J5Vg$w=RRF`|MUvl7d(l1x-DezKPrDeZ1Uk=jwB6f@>vm;8M3Wk^{H)XRjAQ z&_y>eMae^`1l%4aGbD%Y-K_*ZH+eJ3hWPXr3ovNOapoUtss#B!K_DPiZ{O9qp-JL9 z*cHPu&+zct-ZZ(NL3}>==7lXkS31q&nVh=RpSv?7M+VlsGt&;fwmhq?7?UOI4=ivq zKa2Srm*nqbj&c&bpr_nJo3MrCmnfZ1kJ=1)d+5ZQWgQ9Nsn|LmMGlS;RwY~NR8 zgjFb6@LfbhVxvUI=~QQ)KrpG0OD7wabkvu!kpWihCKY#wa~RddRN~n@}l)^M$)hX4%4*|CWubhczAC_uIPK2 zkb|2(wH^a;Q&|Ulr8KP!ZMg?d$p}^*9rHjwRRVL49(BIP*5lcT41{5RkxPyyd9+_p{XB&*+?M zydjV_?sU25^Kwn(HV%{-1jy}`uxE2$2b^4%BWBk}JPSNzrUHqn8eMv1xhwiigGTO$ zO(Yn_g97E6UDaHIo<;NF!Dx>!4KPNietfQ&1Cx~0hw(0`0O1Ph4``IY8>`lM(#E8>s){pun7tA0BXJ(iyk#g^G(6sAX+7|RcuSqc)@0Kh>mPKJe6T+ zq;kWm(3`FJ3AQ=-GOY>y1eMfkvv;Oey18t=;2_GrO~Yw$ z<`q#ep$=hF3JzTA&n8T_cepbT3h@#kUk(I!tAv?IGO31~nm{E`h1Lq|djL0^)9XE6 zx4>wqMZ69|W4diT4HV@U%n=P_F%u-aZL-e5!xW0x?uGlaLekcm%Av(=6@I9gfMs)*#WU^HJ2PzNm+Ntv zPdQY`>Mpiu2|S4mwYjQKwi7O}ZtAuZXu8=h=%;$Llql&o`pF^-IrBWrs!&KPE{DY# z3-s@~f78E5Q4FY+#3{4JUQj5GIQJ?4>Pe`xRlf}Vj9itR*s1t4{$x5n6Om8Q>hM$| zU39KlZ44t016St3<Gs^I&{`ge7>jGKFL z+S?vbj4d6Pw)61nGohMLZmV977$&OgZH5#ns!8=<@VEjag>(8xe?G6Ya%d5N>AjkNCTlE7xvJFAA-J_lZdc+&|_A~43 zOjX}EtOL;f0>Cbx7^?MuXd;)B0T|}n_KXk#U!W<}UotY4ZwYv&ckx7ZcCp&aPn+g= zrEt`LIVTI5cOXq`j>`ZMnR?2i$OuLm4@W(o*25ZDVY{I3X2eG&k}AB*@H9|r=jODx zD$Bgs=rBJio9SPDWw$H32F5qq1=kyzr1og$fX5e^V9kc2j%>#;KG_U!nxA(tr4Wg4 z@znKIGdobH3eVeF>8RQ*Z^s159WQA&DU$Ht9yF~+%fxONBEUtN-;S99G$T@=)GF+C z&jz);bfDee2r+*zgTdMeE7C{@MuyRvPzpd^{XMVsD!hcPkN3UC=lht%2n4$wB&4`S zq7eIxnVIB-$OVzB#EetVuF=tJ3yC7p@!5QGarpjM;QH^%IncgxS(SqyQ3}ObX{A~k zg0$Z~iN;eY1Sz-$sjhrg#!F$8z0Z=LA>Yl=8v@b&RXFyC=$=>WBd^>G_V#R#(YBsc z26R~q{3IOH9V8f#c5s@p){?GGsRvzthjf0Qq1rjteCM_9@x$w}pL4Z)+7%+NHj&3@ z9$#jbt;0qm502eJ3Py~*mJvYgWRdJf3D`c>iVmx>%_uU8$nDuC@W#=+(M(BL{`O7o zOnmfN0rvY~Mv9rP|9)8C1YW7p&yISy^|$@VQvtVS{gYg`x+(&JUrYW>qmv+T*FqM% z?8Hb@he%8>#(}Q%{XC(v@9j~*EVJ>w*kJ|8KQ?1wtdl|-fqboIM|V%f6x{GgK8k@` zuRUSS0RDh%c%8S=P~=@-FyI|rEd1G}Ugd`3Yisl4GSia1!?Ur$>-{CF;tpUh19A61el;^Z5m;Y{iKN$^{RZ-Z1Hr7iB6DHK`oVN2(4CR`r}ZXN zyM@lcBES>SxBzIFWLw=SV(vwO@&o=Q{oy6m_M5FLY7b;5q6$ZpMthO8CXNbYrC;${ z&UkNbWN#-`!tw6FBSo6(F}$GDb9B3&5Z@B^SO2!qV1+@FM)1EkD7x;VX4kdGlS-Hp z9iKH_^)Em#H#=S$NGtTa?P<6&v+_OyyE`Bl|SS7w}Mmpt<=7wmMb<_Y#TIT{!e0COS% zWpR#LFDNaoc)rI_CuBy?ylT5~8jOxR;K%uLL%6X1?bEXwg)$jtbVt+?+AvIp!7|C2 z!YrQs`PwDl*1{Te6i^0|&TBZhy;ycQ?Rg(Swgobt9aI%~Kfr^`3f01*Afr6&hpdxvZ1ZJzy&R#U81 z4`9g($y+^KDRz`7pM5Q(a@&to+DDul=`)yYFn1QkGi2IY$fdz;;hnri4&ML_CKNBm z(9#e1TsMO9!c(U2esc-Pn>dGLQwF9sgn7Q9lx)28vvS+*-FLQIgt#X6yE|EgT2S>R z%a|Wx3Cr)R<@MRKa(n&`VVpGNfN)_yPW*C(@QUwVW>NDmBHAK;h|yh7C6OM3uReFWb4?RQv{mHHOU%XaI0Cc7Q8gItaZ*L906_fZAya))` zdV0hcaYxj#-W&AJz)3E(^A_9X9^(m>gv#QpgM&0ob|vlt~N z3PB0zhTc^3NB(I`0WvKuGDSi|Vq`cXDT|vBx{rNI);p^@j{hAF#3k{fu+5_fU#EQE$wapn}mMbvE#r+ zPrQl(QTZwV0Rl3pPdfO3-_-X%!)=ignjqX(B_>)ll-QhX7w&(d97yis1!H>Z2VWQnrPxSJl-p-WwwlO`Wy{{gjgZm{bHLQ=-LJQ4-3H@J z72s#6suu>RSe$%y9>e{Ez%Z45PvOEep@>`V41Da8eWg%L=EYW&h!uu8$=BcjC{Oa; ztXkc3lV$dUHh?p(y2Ycw&fO*!H>ToEJiq}4R&OnPhz-$@3=#}vIj0jK9?-8Nzo&8U z!cl8uLcjHaE7a6XWyn%oe0B98DDslK@7{vk&Ua4rIlrHTsm@Y7Y`UMAUN1TFIPZ&n zMjnwuFw^6`!`IYTK0glez$qkD0eI9{owjXdg@B0uzBAZpK>$0e=o~1sUmd}j`lxM# z-IQH_WottB67^J$ja&6h&a&{dfva0BPh45nxy_WT7K$F*y93zi}e>5iV0Rq>ev0% z@EDd%_E+Uc_4Hm?7sABAT|&%Fu|t@SNmeO0&@zN5H)G9;Dm=;5)EsDV__D08} zxkX8+rbv=Y_zR!{Ej{!oG^Y2y-a6v~=_pY`P?^0boX`F5Vw8&RUASQpu~}t z9K19;zR7M@7nzr_pi^kjk@)qe7r?l-%bae(a!L0rR@-;q@jH48pRs%PI4zpm`-U{} zoO$ZjSwRBfx&jCNJh=`&^96Y6aWBPbh>j z-U+Cj;_KE~_4t9Y=M^q)yRc}z@j{KRjWcLw?fz@BAw5vexRY_^;C}8yPQu{fiOcEO}eCymv^cQ>+ z?shmu0Pj`!Mh}$#hR@$h^I%i7hXWOt%CWEjvxnfo_jqrB0x$*kRJ-pBtTKau*->fP5J8{8=7{X*UV$5E z025BS#+jBP8Fz>bN5~|x(O2z8uD;Pb?PLu?=$F(mJWcu}U-a?ft1F|0%u5A)+WAtj zOOLqcy-L3_RvQQ=ZhxilA9-gBfFvTk0+VL5x1};muy__=9r~{e=_|%;^52p;MX~Wn zn8iUEE-{I>3b?G^ON<+OMuHmygoT3p9ahyqsiQZ)#kHib0HY1^Mtw-2)k9}i4V8V@lsQ8C}Q(Dm7QanKkcDoL#*Fc;Z>uixiU6iQ$R z^B-;@s}<7sdM}xuFR#`)IYTP z7TsLx1qfyaUS4~^T6T1UWV`<=lX7 zW8zUAC|>UPUj49M7p7P3d8I9Ygp3r=d^OSn@~)HJn?8uBBblErCty?zdLMVQO)vPf zxxqc}?1>4xOEJ>7pVlA$AY6hc>6O*;2-`(rD!<|Ka)FFX?X67V^?>Gk+OOaB76X%M zjub`t-ccj6jPZF_k@TuELDfSb952>D-;%++p9ELCQ35imRc@+fG6F9N9@`0@@T)ui z>X4m=emiR;^vE3}fctbB?w3fsiw_BT({pZoD}Y3R4s~F51yYaed2+uLkTq*szzTXy z4AVtcX}fXHx=i3TBKW!NTj=B353-{{xdq=%hC97yK@LF#d2~&3$d1Ps9!O{p2ZqVr zWN_he@{}u|Fdo)4>^ER1KLd{{e;QA zY3&@iqdc-o7*dD~kM>*v0AjOx85>7c_HBF%vlNow_d6wLwN?diW zRL4eQ(O0B;0f^0f^W*Cs?^}S}NF+vd?ED(n!ykpSc;JNQsDD_G0I-ob44yh`n9IDG z6JN*bh#!}cy6-I8yO&rmmu?wuuH#e#`J8d`t-ytB^u~d`PdZ=|dOY*oh4ZYx+2C|AEh*tOzXxK)uJ&7+1 zB7Ak?|2_D6{Acj>!D||^?SlK+umIWOFr=s#$1VV`CZ5_{W)XXWZGCLCu)k3Vp)LYU zOVPC4TS|+rSydqT+Wu$owfLDOwahn$RB^)(kc-xv)H=kqs|;b;@0at%0bgWbeQcOT zQ(x2BQn%*dg#ZXJKoxs6ruVcpzaAS2?i-#o_Qa|@;v=os5kMLW17pi$SUWv^{vnlb2LCQR?du6A&-8jIoWLyMOuCI!m zWqSF6e2|{Yon+^C0<9jGXs1c>Gff-x^mzRQ$XzH;e__ktHG7QAovr*JJiWIL{^7FD zf!HFQs07OU-CeQCWzh-Qh%a~D)4Zg$-X%xZyR*H)&*3yf`kH`V-rOCNX-&ClxD3Yf z+R`zu3q6no(2JRyHtJ+~oSdr%!zNod4x8YkvSu1%f}(UHxR9dQ^5ao}DXcKR+y`kS z%^^JY%N`_!l>Q!fAAz&N^Yu(41Nxn6;{z@tQ(4Y4xG_0kXOExyKE7Ra#aKG90N^7+ z1wdx=dS4qbn-l6q9`3ka=C^zOZ}-xe@{h7p7eH9!7a{ReF&|wZl2^3im{?j39o3UM z2nEi&JfYwPgZ^s|ltY_oS@!3lP6I9Qccr{?PK&vy95T0~%22`XUMEOC7`_mg$0%IH z2ZpQv3Je$c6&TK~azyxNVEA=-xG3dBW%x}K*8I{M9p@{mE=L<}>gqf8%CPpd1=ix< z?;%mYTNS46InGG}EkoR8km9nRBiI}9iUE7Eq%*ATF*?_cIc34R=u6IPQD`Cvcel3h z@vgrLeC(PleXEp)fPB<&=P5ZR19a;ok1F`mO}dD$jVtjs>Tn}UkAO1z9p#YIq`zA0 z*uA)@*=_^)_ENXOY2W-pYvwt30HJc>((IyCk-3b(bP{{oA2pFDaT+R@DJ(~(6UgU# z8(@p2SJr@ZnjAQyXk-bCzIP)w^c0+JNt4rXbI7lv=l$9GT%f=gkhQeogwPh`*MrYF z26NyUTO64jVnpo$nqmFttfO$*i^E4kS5}XpUuC9PYcDd zuszpg1ad^3rBjOQO*)P9BU;qD&AQt`HQ&6U*T2X{cj^Vv^%2)I?fD)PKO@*PN#$_7 z3yaT(p(?%6H8yf+qW6LNh{jG&lHWN#-dn6Js6U$$o2y~ z?{vsR?{!@lrYWYD7M5>U#EWb#0exeRPFCzC z?M%77yI&!6z&<~!i19hFrac925r+ezXsC)n%|<2@^mE+KMV)am$tc`nKOIsY)!>)DT!I zeZ?y_2BTGMYOAkNtWARJ=<1`sS9v|;J4fD1J(F3hQ`aofp>N#t11?_!g(rU3z3SnS z{Th)qCOL*OEntXg+Pk4_>Nab$Ye9{3C}}un0az6Io(|aE2H9JLiWeJou#DwNB(N@K zpSC8d0fL2wr-TcSZ04~(cp)d4g&MJ^4szHiIduwQ1}KK`6B5T3`Uh`g3J;^pvQ(;} zew&jF>xoCTjrMx@eroru2ssS1kz8VIoX+c#o2=MvMQbTwmZjAO`bjE01vl>r1rr9v zV*Z*}AY3|mvz|MeF#E>yTTi~aO?0n(dVEXzZ%pC8&%RY(sN=Dxz+9i%v+L)Ot%;if z(x=JKHWGM2xaoE{qqc$2ZeN8N0qFHi%{mb#CL4F&M$ov8(uKhRkx_0*?~J*!*I+!E z+;SF1U$m8QJ@{a|fgz;@AU|^|sLQCK_A7Gx54)0vX=xU7jaRij+jOB9SG1m8tk0}Z zZdPSWme;on<|@tKl+XlmprrFAxURO_;}-+?*ZoCl6@3NF2nHW$+Rxoit66_oguaY~ z2vfTb5(=St@4TZQj9Z55adID1a2qqDST^@wWDB?iekc&lY)Tkrk^{MTZZ$ zB-6P@buxprl_0vuP3pr7W`7(1vovZLNSW0Tc)Bv`A{QPiA{(aEjgf*_2_@Xyt!JJN z0m5Jw4zl@lBmgz(@ZJMHU$l``lxW||4q(^mx4JOO5j&lqK6c!n(;r~WF6-BlZssme zRD%J@us$n{TS7DaNU>|v7Y`GT*jKM-)13gS7(kYMI8ONE>=>Oqfk;>XDCxo_F+PA2 zlE)!gpn$d(8(xdw+*(d{Y&g(uzR7O(6kKTBi~vIi&sz#tSBf#nd0B7!KRrrc2;zGf z!JBKJ8IB&;FX!dIso&rC&LEj~P(2x1NRoAH3NS!V+8(QqAtj zK3OHT>1isjbyAB3cBFj>Ytv+5wAn|hJ_g!q%grf;>_F3jJsFG|6Rf{f!TZf1TCi`>wc!zQ~F3F@AE)@|)NDX$bDP(0$kH-yBze_-_8cVs>U*9b@AV> zc0%@ZxTE&&#+kZUQq1J~U&Uk`u$x+Rtov6vUlGWQB|oq<1u7)fIaV_NMa~8m$Wl14 zGBa}}?<*fdApAbF*#hK7i-W4}NO>>Q4V36iK1O1kYuw*2TvQxVz4Vw4DYcvfW3$@q zlXsjUgkk~XUqhPl6{syJ`xtBs(i4t8;kNsGUU4UckQ#HG{9a-iBy%=KU0Z$uPJ^4J zmFBA1?lbR?TRvLcNLw$+-G0~f}ag!>0otLSOeCL`yYFgkLW_j-6zpJ zmbU@S;rzJztJo4DWd0~=8upG;-$ zI{7bNRexdJc<=7!A{MI|PD;oTjVU{)#jN71r!|~KBqzX&F;UWM$Wb>*q%0w0=JkVt zAQqvSPV9c~6>T&4erU&n({r3K4^pbVFnQ!T6gw4=6o8aC8jKtAOq0pjMho|N$CCPm zEz=C=UGW)I%Ula2z;&e1P=sSbG`!|{w6@rpdN1qKN?XoHspwG-{^e)%V)>=My(%u} zr=QVwz+I)=C`q^dC9~GH)EZo~w%0OmFr*>z5Q8EC2}Pcj6mx9Bl9F^`O4*`YzACLV z>h8$+r!r6FJ@$ck_nI-4=DE{s5#LKsP~Rn9_Ou$*d?RGKCKmczv+h@r>PfX6zFN{m z-UxbkQ$t#AMt&zSGJM57bKi=P&#f_!TPC-w|FfD_t7TW*1OT*b?+=STQSk&|U?YFU zxRL8C3vD99Rjv{+rVIp5S#J&UYzj?3<~=j}d8;RZzMRdL%y-jg<<~R#_d)K@QVslh z3UQ8oEyZa-wmIR`B8#N0p&^)|qGhD4yz*fxW$G!Z0I`c*XVoW-aH-MP!=d$|rr4+D zvBOQ;qUZ;`QpvIW!&y{q0K0>O22(!9zn68P_OQVy*b%Oq_E|) zeuLTR+j~5Ir7$7U%#RFB`sY_|?z9OB!L=dhmsOu+gdb$NYF_piQDA zdQrhaU~$WE2c&I3L4-%H!d!s~U@-L^x^!ftf?v1f!kaOi1(r_P#+l%{z-k|`m(dOa z4cW8&ev`lgP*qam86^zT=l5&&W;9As-gyX#`TL-N39l`@>6#(o1F)<|Z~^4(+n-hSzrO5`sUbj8XBkp(JbN}#`4!LJ6(T8tKuGP7$D*}(lAH8 z)@+l%c?zL()16;pX#Iy3efG2TFSuB?hD|-yl-gdzW*ew(x91|lb<-DPmm@mkS2`?1 zxy5Bg@{nG)Zd~KkAy=tgjn|2~b1{hcta@gEjdD;gbdT*fC<`QX<26}bCmZu-;|zDo zZ_&sYl7y8?0o8gh-YaB3UWzmY4%zdbyM=eEIXU+RgMH;449R|*{G#PVM=54@a66AKsEHB z60j%wor20=y@c^ef$!Ld2(EVpS$Hp-x5x{a#DJ%s2%tCS?CU;9o0uJw{B7WePiz8e zL!G_te(ij_34T^`fw!LmVoC;8!e@@hJ~#R(5?lhH*jR4lL=D4q-{)hA`akhyC~oT^GB7M_ zgATqrUvp{hV{kgcBpLJQHOxo7_yDc@lur5BwebA+nGv;;4mk1a{$!6Q7rRq#LPuU_ z8z$c&Q=K4i36u~BtTaI(8Ji`B(AYpu|6t7>dOeiPGIuf6p!&rS%>XT@0bM}`J@aFV z2-4aE-Bi1R=lNu%CPWVD;{Y?`L_$djF+!brOl7Rec4ci`cpvEOsJFbmApY$h+5;`JJLozzazyyfsk3ey!bfD-T(SwQUAwQYnh)4{aEf#1kw@wl^PjuUHk@e zry4K130R6YN?H^`WEEiob~tW_bduVm&>okW5G@}_#8ehZ%32UaR%(UcOVk3MTX(I`b1d(|V z!E%SbUt`8aB|Q9~RASox>!bggJpSBq2TZ3q1NnB6sLI|->uKE$aLE*{>uk1Y;3|tj ze455w_D;RCr%;v!)n-mypvfSTTZ&JV2sEKYaO}(UWYx7nPj0Mrn3ym)&lWR_W^yOI zQwDZbLBuX|F;Ng{FnJJbLIb^n~4fLZQY+{CZcS%U?xopA|PO|<8Gvg@yh@gBBO4hEMmj&a^4HfcAk3a zOM{o6h`T$<6W#q3c{h>@%D{g4GBtNRo#pG)WR2HK{S$8#6yhkN7Y8_OK6s4){z-Uoz`3EO2`nI7 z30PV7|HEj6kc=31Z`_n6Sq2BO3pH`nDG5vIU}8RB6}*EvF%Av$Ph$>LlZ<2(QM z!5Bt5$$@;UQo4Rp1%}+;&J0$9^-ZS9F+ER*nuo}ENl!8!g&r>|kj`i|)uG2py%R?6 z-g)8jDYeCyb)b?!!^yp*>bPuVAUULE;bjZmE2w{=bvfJBUY5t5`-6jSPB52MjY#Pk zgk|S)kl7mlQU_vQ0i9Vd=gS zO}borQd^Oh^?dL?_Ia_UwzX7##gczzmivLzs{cG|H+)4YMVrhgQj#_bwZB$W-1Ckc z*4?~yOlpYNjd{-Tnj5-Jrg0}Y0~^-FV#FNp+;qtPg~E9p~p0 zOFG_JJSE;t{}AP~bYFWnr$~q26MHixdUnDLq<)J!K1f}!`*t;CBD77{nR{jxyY}#Y zCHaXjx%=$#H`hAZn*NH6M>UUP=P75!l*k`1duK$Hr9O?CZTi-fZ%vheWh+7CWFt)) zUY)z7S+p~K92s}w~0IXUaZ>VooL!z8?Z`cLQZuSHXsx}x|3Xkp@l@>l$&PivnmB9fu8LyV9Q zLb-z^*kg$8NeJ1jYwPNmQ=WceVaqVFei_woo~}_J;p99TR=opq>Yyy|YfB2b6Q6e{ zax0neZ9Edmr?vjTB0C<$I2ph^){@pEgWO|qCtq%3;w7ly7U&ghoRRr$iSPo8g&)mg z!$)$9Ha~*#u0m_$q)HY_Aun%t-}T~Y2ywgFz+LGK>F;!(qBGuhovvWU5cdbbz%_AuJHHMluktHPmD*SjCitSP`6CyX9A zS0HOsO}i2zxU?coCU16)&b%0nd4#$vL9zY`PL4#~st(jx&W3071jsP6h>rQdP#9Fs z*^ZFdb^C{hvD$WY#YG9)%&)i?G@{v&D6>xS>`7D-W_;O38b@OzL9~_2G(XE7LMIws zI6jJSdYNEy%@v_El&+VUrr9dBRyo@aX5*bXW%oN0oPmlc5$FpFClYZP;F#jFGb;Xe zOwZtt>AAcm`u}xIBhKP4vd0rZvJcYZ&paRyP%mzKS{a$HAwNs?n+uTHq0lYbg@(=dxicMte?dyki&YS_>75#}Q0 zJY{kv5eF;Xy-+keOUH!5_BMpCsdOmg)GCWS`4$_Cp>Ef_J4|R{*Ax4BcytX;j^01I z!RqY{Z_TcEKj8T`gZz47ZDemezHVe_Bt#lBk?7E2m0oJ|e*dn#*?I-}{)lCR3{GJF zQrUa^38Ob}-YmN=v;+4|{s4xfu4w$v z1E{5VSH9IqAM?>=^CPwYDgjEl4`M=zOl7Fz9Jrg63ni;K>wEs)UTNVRnRpPLCz0zn zHWb2_8S>?V=Xh8g>P}7*oHRt5;bpLCb8fc>K_^Tinc)KcrIV1hUs)aY*CRS}qPd#>Swg zRu*)ce7@AN<#&fiDzF9?2)#g4|82W)`{Vb}>6&N%b6GOsU|FPI!-!6ZYG^B=(J!W6 zJk)nV=l5z0h$S1fYH!^5^sO`-L9=#{Cz-|Vi#uR;yyFF&ecpS06RuxZ=a-ehvW{Rq zFxGO;g`yeKzLPBom#*BRp$?;Kim69VTcOZ3dF0k+f0MW*RsDJcGp`uqrSW+V4BSHG zck(uWGI{~@1f%~na@&^$>6f(7l&ZjlPM+Q&ui9I+akN=_OB>4L+&gVvOF0deO#T)zbquw+tUh12(+3~soRY)O1 zn;~>?&>w(xtf=4rR`7C2Nv>*S=q?B@dwfoYE-slu{+M zc9MQ?Gzf;yoxVHk0`n<_%%B&ik8F_3!9JBxEQ*?{5OxT zgBf?2EXC2cUT(4z1iRBNr#0AWXrndkVY&t{n=L0X5c0~a%+uq`N&1aQl3%BZiy3^x zbpq`^^S>&AyJQ4XU>-qQ`JQ=?k1`S4@v*{RI)Fus7|jE+ne#@`Qb$7{pHFMSoRnFP zAv5P;Hq!;sA=~?VOHbc)Gb{O-8}}Q*d?r2{Eqg5;k6`;ry7<0mv%IZBFJ{#zXEE%u zPMU^6zhT}G60(Tak$**a>kZ#{>FC{fTI?>7Fk`@^Kic$s7cM#ip)6OvuB)r6D7TQ8 z+k|?Lq=PMFL5@PDB{RlO3>;vhXh@h2#R~!&IVap;H%EQNp@gi5+@Zne&wG{7hqhI^ z5mU1i4`{y4#YexZS*8GyE~hvG3(o!~3;k;a!c@We3On)Gs{C1J{%t$`>}!6!_akIK zs>KSzQX64VctJx@=n&H z$*p;A{`&UjG4A*@+Vn!#-M6lM9ER%V8F0p!9AyXFqpP)4E8dkMTgMwo+0nBITqQ|a za(Z{Mb%#GuGXhw@2!*HCala!<-i_1HCTpCi>c(j?PL>3p)O@ZQZ=*6^quq)NGOn=a z*VWbCVR-IT~5kY(t_v1gC^aTIWwzkCjUmFOVum4z(KYysApra@=Gk2LrepK;q zVxK(M9foE-B1$%?Kt+~@$ zkxI<&lZxg(+nm88Bt?-9jc~*s*ZlVJ#At1*dB0J*NH02d{jf7DTej8p+@_&oqe&lz zzWr)Sf0BnBx;d|!e@WPvZop_^rh7^O{dGEZ*`_g#A?&&jOty-uyxwP1a?(StNqnS- zDNRXWW`cQdoc5BCDrv|Uio6lyOPV+A7X8T^-Vg>vjYLR`Qoaq{BsJV`Q;arX1+TaN z?>!^GHpX2`2oamDrQDbd->-%GrxgKzfte7$S^Sgh-Y{3Ps@ab^G4Q8i*~wX6l|0`n1Yv5oaJHfS8j5#B;UXnp6_6qa6H(PvqH9F(7QmW; z!wxMwUT*TEOA0Y97*o?OF7%=%3dSN=o2GK1cU^05@sYr;p<=IzVk%dFng~IC$k`3) zBn0{k`mOPclclXN;@ji|F!Vl5mBsZSC+@0B+7`1$e-px)<5n-mltcC9F>BsvAR}_i zvxj-d05y3$FgS<{W24CLd~nXQE-N|fWX)Q8_x{O!urx1>B*4;4m-Jx&S{h;e(g@29 z*YNz$rC|X}W9w3Api2&3XadglgQ+Tlp7>)LXBq27A0Cv5?2M=RPfUh=jyvfdUN~Z~>BBtl>HhXYwX;2e)@3*uzts@>V6u%sr+{apxpCu!gEnsQ+oHk|BN4v$EaJOpO zYLniDzEw#8&Vm%$T3R9-(2&U_yVRwCi1u~Qq7A_q^)Ov}`DOnb?kNNzE*+AVqsBHz2caC{0+OW zDzo+1{h2tA%6REgLPZvJtuCGK+mhYx4qj|n z$Bk-{s?e>pX~f#WfjCvgP~ErpL$ZsSYsMfsUzqlL`rx+LQ+>uQl|i?~_D+J5*tb+(I>YGrqQ$QCqg{~#Czj=w^UW?{QFP%^pWaq% zdhW8pI_c!)IhI)z$xy4dotrVo2xrJj$x_7RzRg0vG3!#HgswA{ugw9Yms4=nJjA6= zTEe`hvcI3fYqUI>f4;gVZq`X|t^0*ImhZsCfY{JmKh2@_bl}-&0Nnhx9r+g^!Nq{D z;0|WHX8$@$|F{|occqCg5E*h0Kk;DS(4uI)wV^VVKQ()|iIcoM?>L=_Ju#C)NW|X%r7WfIH${FkRnpRfN#nEpL|N=PH6{SyCBrsSZfb;|brP zD%xWNp=9kOo%AS4#&PL`P$g>#LfQm3Vg~4dBtc5$%+$0MC)X%Simc-$#5PK(39%9) zWRt2b2%;^0$z&x4sIoJvrOBhV$BgQqcR1u&)_HCVgDTKD)M>*h3H1r%u45%~fp zPqmemM8|aK7aF~@94)&K4#lj{x*zQsHd_D|3a$(n3xco=mC;J4{u-<8+hlmJpblV< zc?Wcvw_qom+Rp&~Y85i}9VhtRSrXVJbbPItG&`9QJaG=O$+&?7ksve9okDWP#(ccA zrcZP{w{^a255+AdkNsTKxG>OY#qC$k>;3c9{Z~P>v4^jMv_|ioT_@;^<=_g_*`t^_ z3VC=f_2T-VoxA16&DIe2MxP{o(?U7l8Asg`YU?pVx#LO^l2R5i*zua8-0r%|R~05F zf{d-XK8mKE35hL;+tP!XS%KX*Jr(JUlT#NCAx&@;Y`%6KzQ*UYQ6RtIxYRvJ)3~m5 zNY@ktBU9UJgPSmNRc8! zKva+x5v6yeN$((Cs8Wh-J~G_eldP)L)~~8+wxfntL9Y zvJQVd^PrR%v-CR!2fzJ>;*0Zkvuv|eel5UbXB;9AV)slANR(6 zG-`Pm&k~?N5iwvr7oiEaWGjF>k=|ov{bXIa=lrB$jCm8^5&XTy>uUuvt{e4rOQ>o4 zL~1{|NA9ND*pbdB!CQWXW{SHDwl--G`wYjbd8+J{pJiiix#`7g^2#Zmoz3Po3ohN} zT|0Tz#_>pSv0~%snqsuckY?Iv#%u`jBwWa{UHg7^@~nB6Tyf^2yLmBJZb`h{)|z}S zcC*;T7$gBJBcQ#Kbts2}Mz3NOsD*z`GbqRhrWA^A->heVAyUForTIoIs$PEBn1T@M znK8g`-E(bo$6Ri3+sMTk-ODr{G6VbYw@0gbZmKkJ3cPkd2%knwltEl+n-JIERv

(!RrB1S%|{qx<+|LKO|_|L>7p+AaHzByuYu`#x>HX-u6P&B z0YckkQ5@3|_%>5tvuOR`60Whq?ZGm*Q_t)9VbaW~!NOzlF&c7DQaThdbbJeb!bXd` zeR`c?+jQcq6bAT4{;nKQ$dr}24hxZ&kTT=tJYCl?A8@O0ZEU&4;Lr@}8In=D-fg$L zd*_jl{=?VvV%^+B$>CS81Q(A?M`g~abI)#80LwQShTEBVg%efSBk8;W^yt#vbA^B$-2|AS@AdWtK(BN38u!5? zeS^P2el^WV*FmLlkUJeYk6o2?# zGDj=Ac7=K4iu!1fMX4(+^V7!pR^2HZ40@m~tPv!>sxT9<_^m}KB!_oikdc2rJ0t-9 z&+5KnOa+v1wd<}A1`dMd!Rh^bZgR0=nE?zJi_tkZQ0S}O=DW&ouRrp!;(W&$_Tn~A z%c>z57}2FCQhS{VSLG>f$Q$OZvwEZk8QZu(-Acc1^^jGtt*G0kDn=H$?Y3Dl{iJ6D z9c`yrI?``%3F{|!+o&iyar+d)q$F2ZoJF3(3ydvawmfw6cskFuChfFqzckS-411#w zNx~vFYlI+^RELgn%}%eoPB2SmXfmi|_=wo7z89apUZw2>9aY@O34V@|aLCZ-ZlAjC zr?hsv0U=~0QO!%3<61-ZmWkp+j-u#90)s-1-Y#Z6YYnhKqHV6N$Zs!Cp6f3t83NAa zTBK^!N1wEzX9MXwe*4Q+jv!LLT>>WLS}uErFDzrp1CtTv!H>_*_u}+H1T1?9+(1ny zfkbCIQU-8viXLQ~3OIPNx|DfVo&{`9LF(_?sye=QAR^qm9O)*+Qfaqx^}0Zv@|yDS z>v`;;I*U5VT69w0!jLviMGeX#=E5X6AE&pkoG zb#FTWm|OK^iZ}||!I3_#Ixb*7~P|fvn1nh%6`MvtrZJ3SR zNsryk{h_K|ty5)_=cnJ`_jmE)`vkmVuBd_ZE?j+z;&w0zfUO8u(rD~`!*4*qBGj?s zH|jeVyP2A{*5~Vkw`)XT#(=S1?zmLC`3@MX*uLpx%K>sj43p(M;roU+06*pMX${k1 zlf6mHCX?N6li8PyhyU?3vV#q{`|K9QZ3@|pTlvP~N8L%Di^-@BORq%U8 zjg7(;!c^(SXr(1=7%>lKBr{Aj%WA~7Rv_Kmt`l;qu)s}DtL$NH+rHA1#Wjy4T&pm_ zW`}#4E&ko!Le+N5m4R>$=b9Mzs1l6G(#W{jggnl5t1)li9tO>=snYYbWgHW;Mym9Y zPFE>G##Gali<6*J^wvAn=9u%gDllpRR_teN=`zc_`>1MKytrbr@-kg8x=d111IpU# z4TsNM(*sO0Eja*qpI+pOyq974qd{}V;qcixipyU}K4oEmS?s+R^qpdRbiI8m@7aF4 zAIvZV$cS7Y);GY6vhR)mZutnfy1t#1#E~_S>J9xRu1H}+#oNFGHq+FtcptyN?R}j? zzL=#-BWr^qIw09Q8yg2FH}2~JUqYPTr}Ws6b#YK72H8l*XB8W|j9!^s0&+$2TFnQs zO`Q(p(sw=6F};7=l4($8r}z-3>x%Z*gzi>qDK9%POJSDmHF*1{QmxdYxeNbzUEtqT z#NV?ifQ`Ux2{b##mM(_{R#=;skxA*53BIv3ay4tC^_H=Dk9Ib`;G8y+&)Sw*WDLVI zeBIn~CHv(F7McuD2fsKx>1y#zgTw`nt8CO?{k>NNC-@JU2Okk|e6K1dT_Xt7U42FS z941B0@28I*9tz@q$iMa(E=Rc2(t%otC0V550g({5PbC|9<=?NDZ{%4w z;dff_QrjT%Jvnk#>~)I%hrOavU#@TL<)m82@gV#;arCVEw|V2uuN?*Vc7Nc|Ur~ER zoQ%_*Z3|jGDW9hsKyA7d;08?2gL2aYy-EA_(|UNfxgP!3G7jl?+z8 z$dQB(qj~LYnkF{xBjbD_F*ArkOkMQnhm2z}7#hiJxz;#p=_>l&M{@ziGR`iN&6`11 zW;9=?hx)uZFk22^QspAsjJIO66eW|C2ko|`N$O*UDudiybHp2puw$F*g)|PkqD|j7 zl(uPXd@eDn7%kN!u%NS{jO^cILr+vne5;QueM85MS=Zfg6esR9fDJT_ucOqtup9+xUiqoN2|wo=Inf{{F10;^h!d^@v)yRQLCKY zV@cAx6q$0e%s|`rx+;9xb2D6(QSMU_FB5-L|2Wp;iX1R97+43IC!)B$wY37X(}+!< zv?a`D@g&cZizP%%+=JZI6gB)*jfkE%!2huXN>+q}HSV~|J3IkuWz2x7V!3@f$6>tg zW#^K#yvIS!APNPQm%bIwWti*lDlf&uR4P4Zp~q%vf@u^uNJ7iT%%F6vDFTB+`=n42 zb0$I`?=}+AocK;~_N8peNy4M4Y^>8%ks!uB#7=D2edP&6YLLUaqi4(+4i+fy`@7of zRbz@;$A^2nt&8RH`d`M3OX^{D4mxrpYgQ9pcYVimAV?2wE=h z=RUI4^`U{9OfNXyH;C_>j2z!kY8Y94xHNHyMe}?l*wKVv`ND|y4M%3M60HAw$eI7F+Lb>v#HL4r5AXGx$W4AQKYyPi=#pfijETw zn`2(U_!1{anYGg@dpDn!?eG$IEA1FCwHSgAo+mk59OJl+Lgm)@P|{JP;Dp49)BW^$ z*hoVwql`$wLxv|HWN!Blay|EQ1LO>S6<6fKIr53ydOf464U%~ITo%V>t|@y6!M|-h zqf7lb@{|)m8WLl?&)g7ms_UrxlA2me_Dy?h`0M^t=<>omF~c-U;PSeE1I)*AZDrJE z@qQL?{A01L1D$LCpaT_rB>)=^{6*~&S#l`ONvreanAO6L$tpT=Q4rX4w%=FBe%QFf zlCw9VwfAWUw=cPid|7?e4RtRQ_E}*kYafn`c>iZ-)_4Wf&W*b^#GJp2Lw&Hr<}`Yz zl-*tzj~8ewi+Nd(t=tgH=RP&o^|7V$Oq;%YYEbW+p2W;~_b9Dc%=Se{T)0Z`_W?9y zGXcBv9>#7U#!%WgJ)$$7_^#OOmAtfMx(=5rn+O(0uryjq9euCz-B3k>%INzPnnBKA z{r)D5K$E-B$!$(R^W;Mh9Scpy-OAJyQlyoJsRB@nwcIX8r-p7iC` z9Lqf%<2@y{K^0dgtoyRqyJa!FHlasB3dRJj0rnpY z<$a(CD%;$>MFwKv)7h>L2Zc_A1!WUBp(SJYx0}GlpJRj!vg1Epz7A*824Q76C5|y& zF*_--y0RW=SOe?ZFlT(`Vacf2&OMhlNq91KD-bJ>9Q`^HPtD069O6AAlUN=GZ0q0m z?JA(UI0W1D2o0#Y1e_3TL?EpF6Q53sJoHdxSd2tHKcPgwk>9Z9c2*%Ha;! z$IXsh+_>NxomIKy_S&w{)89VckI;%G_pezbTN9^R9<)T}0NouSv&{poXm7+PRe5%lZ;-|8^}DrDs?&55 zI0YNWk=Xn03noUI4W79wOoeA#mE0H9#ofOmoPw+x1^q7ha4&6q$EqcH%8#Qq^Zeu% z)HGsW%d=RDI3vzgqn9_`3%QmGGKq_$F=e|N_RfzBK+iCgQUutf+PRhN8n4$&?>9gegvBMx@~! z3yOPV9K9=wAJ3>+;V1bzpt#+Q?twuK=~P^Da`Ieov&>=8PUnSKh{B@6OBbfU+3oh& zcS(=(8DM#zZh5i(+SFEOv+RyGBL8czrv+Wh1H}wn4@s#$%6~ z0#P%}xA}4VUi#L$UMXlSHXVUD%gM5ALfJM(wgetmttkK1RDhCFeR&Nh0_UZ-%gm_sByrqE#NNjG%WbbxNa&GG##%JpJR z?O~jBuA6DXc1N{Q!^-)YINL#T^SFPe!{&$B!E6CHV(-p~&VR~Yh%MMUgx4CHGAC39Bf=ZI+61!bm(-~9|x zhnq_`d##(YePxTfHWf){Ri-)vxy@*#$LOW9%b1Egh~Gi*&~y5cWlHtO#WotzGb*Pn zl0Zq=LR@XprQ|%`Zf^Ob@o(nqJRY{ z&}T7VPSh3-tfoHJl5z!sY0<)Z=@L4#WYKmX-Gvx$WX^HB-CYmc$X@Nv+>5u3!i;m_ zZ&I+D58JLZ2#l&iw(LRAXRV*%(RyhwpK0ctBnoQ$t9n&~; zX~Xdu)Icm!R>Bdj3bhRMeuzj=^cqzvQH3bV!mcl}iY4QC(J;DI7gX1yO|k+n{NpK6 z$n~<~xJ7kXwrR;%eVA)VY&6yug6jK!jM(%GIZ8vv7x*G%9SL{VAh&=9%M~z7B~Z)W z>~FjoFD0P`s_jxQjXbCNc9cEZgrt`2aF});fYpC*LrqCK`-jvjObMU@Px>Tgq8F_v zfi!M7W!fRVAI5L73$`a_a+7bm)7!u{Kp#eY4;ROi>SVqFp1@7H*-v5L=uAjer^eeh z0C&-uBIiZHbU)bN-L$)$f!k@s*{qlBd+cEG=YVZZb&|=egY2wMOX;w`C&m;UB%Ysx zkpB=6D}LhNZG%*$Z;uq(kG!f7o`t&F>nuOkL0)zgC>OcGQcW%5%lTrDMxw@eP1=OZ z7KScFCV3LQIO_A+rCpmB$4M)oYjSY8h=xg<@kT00A!2VqG6_@le(h`yWqGYSxzrLx zmxhytEz@KzZ0w^tk8(?O(K|lE*AFvNKSCY8pW(W;9NI@pcEUiTv~1IQyIh)81z$%+ zn0g>PTI;35hgnmalQV89LMKSl+doWfwN?jvBl4OZWNh58RitEea9j6loni%1%d={y z$&Alp#Ul;qdg5bbE}jCOSm3dIv8%2s1LVZHodVNfADocF_ChY_>Bkdkb-+_Yr(AhH zep1I{U8m_5f+tVa2doWUMn#&yR%WO`RL9Wafv^@jfgDQ@!qN%U{`P+1uFdGH-v-1& z(s(hX(Ty-~BrsEO?U;t|lgIU?@PJ%unDKQkrT&%3!8q#vcgm>hJA4%AVE>0t@N4e{ zhzmcFm)gkDN&AsESC4tQA1r;IGQq3-&>zN85|-~l(K1F z?dM5)5n{=-(@$!=vM`HUdStr_8a2u00uf{%L#5hGye7nPMKAtYJ!hmaL4}dr?4iML zDi#+IsC3v%+4rjGYW5({Wi3eMMQ-ce(-nKatzCeuh5~{JW||F&!6C}fF^iZrrRcV{ zBRL|@KBz7C#7r}B&D}$swM2L+I;uV*;ForZ17<W)i(Y1K@$mg^(=0C@Z@CM{!UxeZZ;PEMPdAO+wV*Y%Sw6$g!LAg9b$kMsssr3 zG68p;e(T*=%d3-3O-0jt$`mn3x+CW&!9-aMvbXFvprx{kd{wPq7PHW2ZqoC;Hxr(> zQ?S2b(gd8xW#g$WGQdDIbB>&58-D=rF-s_ee&Zo+ zq_CIHTv_}Ih83$o*aqKDk8TuZXP+Y{S5oG`Y6~ldB)J+iFsEXPrP#67Yv)wUp_(<9`IQztIpz6K^*P{Vxi{E0AV}_dBUWwd*fDM+FzQmE-!30TP`pKYFd?OI7zGb}fGF%3q z*K4dpF(^2_V)*N58Yxht#yu4A>%po1)mcVx0dW2NMC5s3ptfsgwmPwH ztI=8}JFOzVBL!HP)cW7yf1hzLJC_k-CL08Cy~oK#EnwM1Y4)-gvg>&#f%(QWy==29 zfy#Yu+XHwBJ9uv4xcIdzf7ZKMlFT3nSbm6%{i{Pf$k183%#;nE)JVVENbXg`*Wy(8 zV+0zEtT1!xNZJfwLd`E5P+7i^C)co`0h!|*Dd|P73h(#n@kFM`OYZc$Xj@Hd@|u&K zb@Ke@P4h4K%=jdB(a?t?_}a-+IPurI{LyGD{PsupSK`kwPQ z*wbLBS)I>HHK~fNvg|gOX=$FO-HlF7V1)NyG9yJ})s_Vb6DX@~^HOpbGeSsB`8liZ zPEDhZeAvz~VSH_5cfs7&ZhSoWL;B>6^IllhXuZC0Fza4T0keyr7@TL^Pcc(Vws!8; zV9yszjHr#0u@m!HruMk`q;RyZzWLfO=vssZrB`llgJ%9Mi?7}fERMgH-%CrSrr6J1 z(|UxSo8w$@T&}#OjASM(Yw-Qvk&0cHQ;p(8zmD3ucV6yd&31`fOg5dwRCSQD_B6k* zEo13O?T1B!mJY)51EJ7c-Z!-v^y5xR)Wwh=p{6dW4^8)ek=C(g8qP9uC@Nw_qsmd` zhaA{dB{^()=&s%S-aE~L5c;EIfD^8Gfzu}UV`12UeUiZs<5;u48hpX z(-Nv(9mCrKgdFZh{hAdmb z_}XRRiT(quZqmCf#KCG?18oGS-RZ1}R3 zSXFus|Ax!{bt*LipbxFVd~wzN^Iaa)Xuq!A&v&Rm0qyrtLD8Cu_E#oimKX1=nk}0G zvyrUPGM9P;qt}@_&v*gsG20tZ#Jc_61v?W|$ft>3=EQKHG^^l;_XoVWE!T>1T%feuInBnF#7l$nC!$}$=GJbBn7+I;t@tj%k34bp(?@La)mJLp z%6D>U<+!Jbv5Irqyye@;si~7}s(km}x6!Yn5KzSKP)jVKX{QMsjZ&UHIGQR`T;s2! zv7j7{1t!Dw?%y5_jB+$n`q=<3B*aa7eR#c6#PftO99#k#X%+eoyTvcgmu`spVOaCQ zXv3)Gme%gFZUZ8#@c|=xCb6xo8#;%08CF{`*Np<{XvUeCEvsU^lK!4!4L zx@dqMg5q}IOJL6RSn7<8yB4i((9C!L(v=0vQim;b zNpC>eh_F+1U@W3>n4*)#Shug4TFw>8Qx%u96^QJ{WVVr^UEtQ?ViuKyB0~K*kdXP6 zFm)z$bDPZ14LPXQuC7VS|5=|$T&4t{8ZD^Z-v^&S3SIGQPbJh-@T0HHVLiIaHcza# znvgcA9fVA8VH;wyMVvonhIgt2Ic*3&)RKjg7H_pYtIyRj6rXczDXs6MCUZB6It}d|ugXU3?&nqhkfGQMS{`*apvyI9mzH^oG64YF9#r8Ex zYKV%MiWofbYB0=ZJ{63+(Bh8F#OTM2{X>hkCXPc?QAPG<(M%q``i}nQolM!`gIv=C zQHEx%ygeg`q<9&p=IpY_pz?7IN9JiQeBBPzK_jV%LrI%x)4)?s=Q7PQwU#~ignU@( zJau;Yq4vP~Yd04%C=%wK`m4?v~XG=$xY58jM;QG4V znJ4M!McZ`u_9)&O%6Aj-MWwLj+`Dhnm-XAp_m-4E+hWDHjN1{1-b*g=Dw zAQmF&);u%_XzYXHEG50B517LICWpjh4xwd!fj2BQHs{>OMX0M@E6H^#e35Y9>?eEG zKJk|uULQ?NERNeu@^b^t_|mp)YFlSMF0XZTxc9x52U5sp18^|Mof zf6C+!CN1jq)pal5&61m_ek}12?F7XE1b|FzQj&n>)I16r zu9@dESl-szDuVNOf~D>_tSji`%V}0Fi4$CLkL|{Z1XWao#PjD@yWl?Dygzy)#s#;@ z69PS^o$Ter?$*QtrSAp~2@_{_y4K{@#^{kPf>S7G`!W}Y#6;*?jwRHf+1XX3ejGCx zqiolpw^o$JnzNB{3E-N3R^R6j&7A(l+|`hxEC<)>qw0S>rT_eZDxUoWz-G)YUml6! z3;8?}SfNu{U+Jr(!kdr3(LK#PJv@EAgv(Jz-TIQkD1<7pxC{H;$RZo1YC z5}z`W?B)O?4%?CpG(HZKg-*!fxrtlFyJ<-AEi$8{Te-xu9Cp~Yc^k7|vpu7j=pw6> zS`v~*+M%|xy8gOG4#bK3ovL6Dr@1e=hsnH47H14(pm(_4?2|-pz@43WIcM|oFp}Z; zo3$w7%mdzj@&xnv$oK_F9Cqnr9j0#>P|Rd|-5mV|!!z~stZD(G2t0~9^WlBp5a?2f z<^4a?%!N@fWQ2}F>|=j{_Wz<$MpA$TF*)Z?57T}UzNWz%zsz4V+WKMilS?Kb0(kqW zz)IK%)nGQeyTaxd<&}P+6Gob?kJ0nr1&_*^eXGa=XDvSGFGz|O5BKH35bEAzv(({i z5a%KpblLg@>6m37mILOtCb5KuJ6Z;KTOPgSr|z7Q&y0ce*K-7~IVe?W!N$J#DIEJA zI`(}qd3M@d5cbY6;5sQNHQ6$sI20tW!b>E}sl4EJW6kAli7E0|jIpB+DuhUv%C??S zQ!L`%X)bVvB3zhd*vqANv%~?2Cy(8eflK;>0FlCFCepjq{kj}%SV|YW&ob@#pRdWU zpnKsbL#i?||Nj&WFQs;S9vk}S-@D>6WfghZqr}zl&ztiXVbzBEClg-NFOf>;$ax1^ zE-`v%S>ZljSH-ED^Ob&@3__wdbIfKmitZg+ywZ6+de$C<4VlERYOwKT(`a)H-0$>D z2P?VNClp-&_Fk8sdWQRWyq{fmVyVC2gh70M54Y2~nf;qtiVjM+UYP~I(E0Bqig@f1 z;W1c6SBf;c;89Ya3`N)>6Bd_%- z2>J3zO(0g{&D`tv@C;6s@1nb*kvp|OO0g7zLx$bb-HqKj($ZqHM#ugt_oOvIxO zRooZcErDUV&Fb=!l^fnJ`)I<5!baCzQZmkz)EoD(w2PllaWcCUY1k|9ZC$Z~W9lWbap^}}O^_DnH@NUxlqMI$c zqer5CxK$`PsNI{Y{usn*qBv|5a|5ph&+FU0QP-doEngz9y-%+hzevl_JRg3FX1;NB zrv901llmpITa2FsYWy_u7^x;ddHnF}&@H1RCti$u{OmZOe8c!)99I4kst&x)V^ic) zZf2dmhO29mcupx5u_Y0#w@ZBj6LmHdv~NvG+pkUj8I9gapBHZc*@tzv`2Z`*eB=xZ zh3vDU-4gX{zV)AvWMt(Z%VFq$L5q6YsW3_u3iZ`w$&ud1wH0EZWY*#tYRk_!M6BdQ zu1jXzsrg;fM6IqmcO0XGG$xoBa7&%Hco~E2*buJcahM)HlZkJXCl%6>TPVTM_|AmDvVMde3}c;@947*f z5lvcoZ+V`xTyfDd25ogcO8kB5CN?!Lc6i~{vtW5WZB@-d(-|4qcd<*3^z_HR*LaGJ z-QS^crKyMz^z=8J3JGLb@n?FcV1D=mQ;Tv#+&!GLv!I_I4SH59SpF_j3Q{ZrJ3T)= z7T@FM+=~Fl=wN;BCJVuRIy)B-FuH2x9VXuyUg-MBjI^ec`=iI+a<3LJ+NXQc4Vt>T zPLwq$P!f#-Rjk9W+*3pOsm7zm^;gyMZ&CK(RyBM6>;)651OXJ^GxIP&iI)Y`h?v*p zb##40j)IvOB#KJrC`0Cp*hgDt15^-dAXlh0wjnts3Pmz6t*J%?v^X#-X0be+L1=3Y zmKIekzVN-2aT&m-(S?UAiF2M?ktj5& zy5c`?srN3Qx*u_0u*-pY&J7N8qn|I-?qqv+Bq)N|(Hf84UPGo72RPN7K=nwp8FjTf zL#zTuo#FGZ9O|Dj=5hOYD4=;un?DERL%S4(q-i}Iwli7oR7 zfBA!0^6#1G{u7EigtnFRCqY?(<@+OH74FJHYNl+{!S}3_*14KW2l91^6VYb!S`Gl+$oPV4>P zF`P;-WM9h0W}ogim5eqQlQPr$;%)fqDa6Y*LrBPs1~Z*~hlv%l%E!mwy6iAv)~O0W zgS)6H$8hck;*RMu!9Ca(l=Efnz=yDpJ<}*+!^%*#@x*QHvv=+zs!5=GpR!+;^d25u zbo!BUH}##kLB6O@+VO8HS84Rwiny?y*(uvUZ_lqH?Z4caEXALa8P+gv z78hyeI6zLeznaB=g=MKxmo>p3nRK^WZZx9~+m2OjMs01BE=M8I_%H<&;mUcHV7~}E zHmX!F_1^*Nj zS!k2V{9B|`5etWEL(T^g3ox5k^rUSKaCXd|%wi6+v0#L)w%4V~jZvSjN8rjbmd@k+ z6?Qj1GyW%Bo-+c9u_`)OS7;tcn~#1K7r+MYxnA$Kl}kd1RQSzirSLDVCaR2MtbL_e z`LWfyt8T0|R=yv?W(*ePOTx@wmCh(L`VG5xd7I#hFG5UA z#&2{h&OMGHSGy5-=LbE9RR!3K!tbc`7z>F@@y~zoX8Z%e?Qr=AAgwfgdwZ@4XnEct z0Kx?YmrLQEfext9dF$PlR&bQ1rY&T@f44u01 z;pMvn#x7A+n@jOzg)74F(p8FP}G$%{s$Njcq0BcU_6H2 z7aTxlDAGzgn+b52fSS+oe?jA|akoyi@@u;vx?RZRZeX*nQ2?|a^n0r%|n8ZK#_?SWOh|&mUMc9!jG7XH-Wq`c4 z+gNpyjvV%)8PgGHd?$8$aJnb2?k5eELSR^3uEwYilS*o5jQ$h5QcV5ZB?_e#$R1Q~ zwA}~et;sK)!|l(EU+s(KAph(smTN#|Js)5m{_XFwq3#Z4ahN(EI8jq!>S=x0xyJ58 z6@oj6!`n|F`(*@Ps@vL;<;(g%0ea|;|1SdcNqguZ&99Q*3VxHdKZma^or>wpZN13kKom2bser5r-6TkH=s>k*5 zpTGT=yz=W`n$>>No@D;_DG;jH|4&jNe0w*XGBcUdq>#r}iST`5yepWLJAW(Rn=cP0 za8mO;z3KX+$yge=PJ?xFAYAb~b*xEOx51)*but4OG9%7LgYqYik`ZJ8=Mf z`}Ydwpa!lGph$q}YvZUyjt0|k#?qor5JIvi;%zddt753|FHlnC{}FM*rKta@KsRya zm$EQ734AmLZpMpDO;CBk&pSX&w;Waj8pqOIPl>(J0QBArMl`zY!3 zM0**wl!vjMbfm(NI5R2;bn51JtfX=Mx|zu<5q@eyG7{B$Qy*inwqm8iciw9o#k*NG ztk`bkmiNa_6lF?SzaM|nxAFSKXK%qq{ z654=V-@sL+8Vb5Lqj2nH0QpB%?Nwj{J9ABMI@aBIJNep<)@KC@9J-t+Z}|>KevdmF zlJf=uL4Tnr=}!(VVcJ9;djQr#;1fBeI6|nFrY#G#@cyoSZQt zsuA~5a3ATd(-Je&ns!H6hgrh%qD{*b-&a5Jw>Y}>s1u-KdyW{_*LZ06b;b#p*i8@nvbRx3o>-9a3WqBM@Z1zK0XhNg#`-%51TL#JW6aRjsWYc ze+sARG9-=m*6p`)t;nL-%g? z3_0VqTY&|jBQTy(`0P?Xt+*rx-y4VTMJVz=1jy*4LG6~`KZhINzL%zZi|}=xunOE* zZaM#=p=S9|Vl*wf&(-R0WAs0i7THFMTt;3hJ@Y~ctQ;1jMcfD)WVOob=wk63I1GQG zzth*_=oh8(O2OySb_fCn$I{sODiCTK5$C!_<9(}nf^Jre4Z8Z}wL*I9jVFj0IRyex z2-^dg%9V(E-d2$_?Da!4ODN=`r*uX}#)`^{;h4%qMAIRkV%RC7L`}oWuy~wpv)fLW zeF2;kUYeIG$Lcui{S2n;p7NVk)|c79o7fR&n6q_@pjt3SN@AJ|sGq71a_rOWjAWq$ zg)x75ARf1~wyfD&v*eyt|B|8pSb<#Q%B?>75mm4_!2k!u%wzFwfCEq!gKhUk>D!EzUGrk!Qz!YRrA+UN(3vcIvEOlQA)X$>5C|Y1 z*lrZUDJmkaqjV;HD*GFD`}fLrCdIMpQKR0^YYWct0O0CkRAKDiT4Ff(bDuEC??w;C z>w*?VSe=i0^_YoR{Py)zn*35puEI$;n@gXm-&^=r{AONTSldimZmSraRLS%ZRYv(x zcNi7d+NX+VJ_a`3)iLT`V9t41@kagN+6z-8U({F4+x~<_{^g8-ixPzzyZ19!p6`Q)ww@1g!kw-)kJqVYVWJ| z2^JYCW=YaHEr(UV2-e(94h$ZtM=-2ot@tww8QpzIIUk?rv_85cdGbuKrz3OrWBaFO zcf)1JR&wX2vQ;mB^VCjz0x;^)kw%)aTdCoPOts1?DsS+t_eS^eOHV3(p5J?V=`Q`b zLAG_I+N@IkeP@FqZPE+QhB2K9XxwFuIQ{kMEbG?h66CAX{5w7C zR2*vcnhRiY&!g{{EvD7s&(r#(c~VjP#s_a*1E$#zWr1-eJLf0G&7CD6&`bU467ZYb zEq4*=;EUGv^94U^VL;5V3F{TM^8;1*sITR1=FnIToV8EAOP+s2ybH z9?MmITfqrh;MmwCToBKub^e~4!+w|PT~XLv18=uV@D!hM?ik_@B!<(luc2c%JEh#} zinc9(Hq7+U$q%%*2agnUj`iM5qh~6*DigZdJYN&ybyEwS_u4P!t}7`k8Gg=-r$b{- z>j~zp$;!kC;_@r6L&Ep7$3=`&-B@w+ML5nuIPrIx-t26I?%SqV!y{bm7`HeRE?T|C z@vjZEdTWN(>3LOWqHMe(eZo@D+=%8#(8BRva+-U?t6l)|xL;4Y^%L9GiN?|Qma(^7 zew@76Q&6^^USZCN9KGci;_Nu;;EYvRy*d{@!2WsoJMcoY$<;{pE3IO2%WAd)+tX+W%?pP{A4q3|Q0`)aSV*53BvM!1xcA z51xN8H_+%wnvvpGymAjiu6z=?_v4G2wr99EL-6r)>{Yzqj~)@Wnk-XD&=o;Qhekb3 zc_(|3L@X>!htk2es)J00wb)@#Yj4uMrcIqw%ex?tIvv{3pxhwhcUMJB0OG!tYo?v% z_PAx-Tz4+@F0|0k?Mij`$)u<@zc%WM%u3zI%_$1USoN;uD=@+ZKCg^K-3n zu+8+cg#fnvh0L+g7a?!!f_b1{F^ljKi5!pe1EASLPqycP4hN+-%p|NH0goTY*JcL58AAhAM0 z`&%Pf{&rN;muvVIXwGHZtG`jDcW>ZKOYt<3$U$iHtI3Ux|9;At9=fc}Rc@6l63lV0 zC5gkqs&9N;Ah?w9;%m+=cF0G4`v*_8`j*-8Z0OakNIhh-2fez(T;ofvT_=y1@d;MU zsk|h0pXXnNHap)u{Nsk{jw>6(sg}oA8RFT!4JRMluaEdHr}}PP)@I$9@K1VEuN|fc z>((){nG^RIR^9yI7I_Qpf8~n~gH0qmPbijK%t|%M?8$5z$%g@&#Xr-f)XvgvrWH)1 zPm<-g&Q{0?nR<5WSlxjZK*Pl*QMMjE%b4~8JA8Y7x?1MS3R@0`h^0(!n#2dXggq50PjvwOyUX3dFw`ReFIxY4u6 zBcVPa6Bdz*46N@c%2g%rcKliVE1O=xk2y6 zxOv6hriL$#R5+64kEl+GNIJDTnvzsDXXY&=jA6i71%#aJR$+SD&8Mcg`eU+JW8#sT z?8P}Pm@CkR{VFTax&vPaNgH5J}4gJ=s)t`D%*#vi4=Z z+w_$gfxl&?O04)>jfcf@uON7_T1t~j_f@-0WCXcfb3&=P{NF09r+%pmQBjZ(xP2B! zt`RfqreokeVIt@u+Xiu{zKaY3KidD2_%NT$o5d~ z&$AA{st5eho{X}*pm@n%DhljOPYG?29uQ5-uH!tr)~#d006cgyBGhnpsBx}FrpNOu z^^i=Cfj7bLt~PL9_~4;%+FCar_ewZg3r7BwwNl5GxCqeE?8E3yqoO$@G|<9kmOBVI z6|7jwH`q~M;F9{gZ*YkchH}mOLR>0^M_HAxx&NT3oO&4?PV|x8ptTf>eepX=|Ut@7cB(bDp_4Y0w18n@7 zX)I_1%flM})yKS(<|6Mnb2>b-aUmxylY~K5HkfITQ_a~0ln5rths#$x=PZC3_3@#v zPU@AEkWX5!W;%D~*j5|Csm%R=2%Nx zIXL8gv&066WbUPWW)J2dcbP~;nh>*fH12fLX^57ty1AM9>xfAd-B2i6V?Wl9(0}=8#l1&Z*c42 zb1|T|)~+R3XPjo?bs6!@TuWt(TN=m0X@O{t*6SAd!3lGCey014E$3ZE?|`%QUm1EH zq>MZk@FJq0Bd?YK&Yq4ZJ5_-Xoe_6*G`9~!4lDP`+7IT5$Ih*v@MhpY#s98efK`y| z>uP-D(+$`2X3Vw8iDtUcVyjfK>`1DZGJCTw$R2%B%?Kiq_oM#Ua8kJyTcB2HATmpE z;#QQx*6;9?fPwhf8ooJ`+;c>2&j*H$m#JRIqlbzN{paWo zSvepNy==gi7UnC3i;LWPd}c~1N$|Dy#Ttm~t1as%R{S;groGKI0&|(Xb8W`?JFzS0 zbe!%Q6h(UXcU5F^-qLhOH8_QaybX@$lzgZW^gv?YkVB;h%uhK$QVk_MM=-DcUUj|d zntpWB3zART_21F96hojYEsw3vGa}~6S&yV6m`2BuA5B~4NC+;1bzG&Xhv|P4U=5TPv2e0Jdj~sXk`qNnWr0F@x3mMzr zZ5(f8j6&@ZZF zE(ZJ>(XtY+IH7;cPGTmqDR#duTeFExFQ7%~!qFi|?}^}0-vtECY1eYwVDhY)Jze=0 zlWS?}Vr2X>un0eaI%9G2LzdY;ukZcjE0p4Y z!J6(v{!cVu00sI6Pa`pC5gX4jWHF4>z3e*ERhzM=-;L`({JNiY{X`M1yqqh2Ug1mg zlYUyeQ12}|@r|xKjCpq?QyLSuzsGVIMPf_cZgM%Ea`Hu}+;gkLzqVKD0fQv=XP}98 zF@UZD3pU?^VK?=Gs&9fT$LKkj_45wDV~%y3OI`-bK__+sZ$Ac2S1^x!U1xSMEzm)5 zcLBWLQ>PUG;e!_FtJw5eglQheM!Zp~*#Z)7)nLKM#n(AWagjMXwF@lUs{o5Nra0}_ zajVlFK4WoSSp19K|Ha)~M@8Ab?ZS$nq?Clz5CQ@MqBO%GjUod`BOxIwA&oR5okMp> zcZYP3lt`B%0uD$?$I#z3&)(1T@cZ7q*86>b?6vmVf8xSf%za;Rp2vB_=zo{)*2kV*%m0Y2uEvpq7{kIAdg&pTmc`_$k4w9rp! zf7l`@Y3u=|6}7H3uEWk4Hhrs1SctV|*PU?|M9920>0+NeF_NowNJ*jK>T25}DOhYb{-9mqrHhB3FFi#O@Msrb-%DsY-RTbyKbT_KTNz~+Cu`Dg zbn-qNjhH)=Vnx%o!G8KY}PM!ZeQ9f#w8DKhcMX#zw#cJ?>h|;~zT@nPXbg6~j z>eX$woOGm!xaS(b>BZeTL0+e|BuR7M>1~U*;{K1%Q9?W-Wm=mn6YUV2C#qF=$}G2{ zB;Cr739f?2GUZRBt$clSv6%?*LN&f(`Q%9rl(lChSR%A zp9E&G!4|73^LR6pR(T;@nMXqf$edYp4|^Pe*qMe{Ar5qli?Y#SHN)_>a?fh0$zuTU zRegD2G}q?sJzBXMU7(hiJ6b{co7bDobo`KW+WOzi(%YX2WMp=3^<|yxuTfzP4`h4? z{~$#-(>Gf$&hNXUw~XTt|KsV&eKf#EKl_8JlrX8Zq9$OF1dO5l33!|CrzKoSrdBu! zDr0~9WDR-SwEcMx8#}GVW+8}Oa8Ob__EOChcOQhnPZT>_NH5?B$;z+-uQNRvc(C~n z`L$_$9=rzQxy+9yAWuuY@bN2InK5R$ilZkC%>{Y0XpMB}`kwsQ4GCL46xG^PT@P!V zD4B7M7HnT5S$JH&yYzguGmS=X&q#yY0fhODL^GYY@v6f1)t|Riat*AK{isVC(qptJ zcULjzkQcS>LS<(^5z3?<|7xM4^(d2^Wp1j7jZe=7z*0+h`dEoo#g7&Dmju9|8;JKp=g3F(#K}DKC|F*I{3sQOw z-j^eLap*;}4Vj`YfCY?F-YW{SkeFz=C`YQpR*~UZp{zS?OU}S^>`$LAy`bhv`sFD3&DtsBkiD*JSVwL=*=eo7PR6e(E_WTg z@|BjdmgCj?o~P(I!E>y^?^Uk`ZIBdN+3pICpxH-bP1VL z;5y%%RQ}>AWDfcZ`*;2I^rwb;y?y=Q3?GO&*o=GNbfWcrYNe}HS{_IlwRScMcj|pr z_t^jjvZLNbvd!xfCs4sM@B;fi^WFJLqWsbwN1yfW3g%!F*Z#jd*!pupXsyizDpRX{8nzw;82Yx+vI zCx^WviM7yA{D}D(X_ij8{SJlWHp>y+a$(~4l?}-|8hCYPm5)7p)g3t$Th!=={C=_Df$X`38EYMwYDL zQ!bSMtdKU`F~2Lyf^`5Z?kFrOP3iy$SVEv^LXQ8@;-v!%lNvZ!k6=1P`tai8u~L?KkJ4ZBws-KYp$ zU*)2;-Rp)IyQ&b+5}hUbh{H-iQ96zc&ksK+ED%P%9!xrt>ox}Iu2|@*flpE-($Td+||LfZ-oW0qnTm- z9#sY|Q_f@an|3`~rLI-xZ2O2@DWxSQ)W+|a?dWxd9@GyagCRD$}kp>^3B zl_42b>{feti|xf>>xDSLd$SrQtQM^Hj?EHU*T2p8zisY34HuU#dMPS*1>4H+!7fX& z{VPAshk1Sz>2SOfn5%$q!FGIyOUlgTp0SkXsLA@xe>Pg%h#zRkiQJmSoYtvJThEX8 za3kN%y0F_w-7+-IR~DRl;bZgp_A6|d_OHEZqfY-=r8jS|^Wp@pb%v}ib?}cK%FF@J zZKAc}DtJ<8x8VioJxk5|VzmrJQozS$D8}<}wB(Q_#hFQIYVcP3{6}?7LjjWRakhuGpy<4iYFHIBv}X$LJbBXqks4FymkrMiv)mNK6E z5>XbLh7MHwna^f~NN;gzS!&Cjj!B+W^;%RTC?x`DW1*LNbc8Yk)dxdCO;_X2vPA9O z7Tf2~)r)KQ*Yph-Cwu#oEtH??XVS823Eia?N+pkWP;0pQUQ&L?(}j)?jf#iglq$wm zUhWz-%;q9Z%jCd2%+l@aWNN&xYFN_YtxlP7xqQokXlY{vW1Uw4tPrmyiKkC!5le^b^G1iqK4iT@I8^q5e3=y_tba~OgW}=qb zgjkJ?U$ad%FXu!g6_%u-he^$C+AG@S7`BrhpEM~OC_C8=?FK6HhXZ zeX)Z311L%Q*!>lq90XoDM}||!5IiHzq%E5E_@O9NdS1x=;2Dgdel*>xsAfXTg@`Lna&;Rif6t8@0|K}s_V+{~`3tD~4 zJ`9Q|Tou)+X{ivI-UmZEBCGGUM9R=@nK=(jMKbbA-I1b2ol7rZXb02cL!;J*oZBrV z8DX~Vz_vJ(paqW)Js0)ym-O!r9*){x-bT#@+4W3@l-MSS?J5&2&z3VFmumQoq)EbiBeF;Wh{qH1lP$s zOLTqQaKBelyVv`XEabGX;M_&YvML7H}E+`QG^R2pJBtC*Q!= z9E{_L#0usvK`(^xMukD345Vb*BJ-WKVS?Z80!Z^GF4!JQyGn@>rH;2|A7_$ z!VI2}OaWA>0|9az?t7h|?j=~v-r&hU-3kC+0YA(Jk|>7kr$O&=4aM7XcZg&f@N7Eq zxr!rZY3+_RSyuqwq5gI#v%{YfKNKfR^+!*3;|*LnB7eY+m$U9Q%Dp@Q;|*+h?;-*Hi~ackh(GuikolFo zbe^C=q9!Us@Z39rj}jH|>+$&za(I&bw&9J@PZAuvpBM%#pP$>TMOm{H=&`OH&(zy@ z0$*XsESN~zfP22Wj(mc1HlO~|k(d7-GXwN3_W6ZO){iWl%VV6{V@sfDJUI1^msnn^ z0QIz%EUF}*QdkJRquaG@rge}cK{q+3AwC{##1ThfKyXH(Oterx)SJO3Md&nLZlacA zr&CdsyUL;LXsocx`#|e0Z@e_DCNWXNgFo6XlPk#VZf(Dzw!rIlmF%GiX7hZ>F={a> zI;{J_q~3wr$0Q*)w*#r-gpaV_TNdl#@}c^2o6T7K4R9R`ltaye%`+ri;qFnqn;~I( zixy7P`2#sHRV7h@F-Wq48tNCh|DUXz@T9~BG(~qXaq_yVQiI*p=tZGI&uSNMCn#i* zwNtF@rrQMLx)vp|p6#PAMwj++mA`zue;(hB4pCY9f@>wGPpazy%}`BFiWtwgX-N2| zN_&C*0o>Oo@;1Y=R5`>(jH0Q4-9n_uL;j=8u+`@L=y&|~nBYK)$U{OJ{`^|Ljq{V% z3o-EzxsDc|u^hbVp2u&5fsv?mJ#lak8dzFVVMh6TMwrl-I0ow~kR2a$%ZJ1XxQ+3S zHL=QC{l|PT->(fUQz{H*BqJlb7^7x>MAP6c+{K~O1AuIcW=IoYf{jvL_1yA-@aL~9 z3H`Vw>aZN4U=ka60i3c1J28{ZV8^4AW5e^E_%_1&<-PG4P55sQzD-1k-(d~OU_x2c zqveGVibZ&l2K@XSjsAro1|_@mF_uq@Oop&#pk~U_KKMtfFC>MSMz1593qQQ!# zwrX!H5N8+z<#NDd4UjlnQLe!?eU)M>$6OcNUod$6>ITOC9`8A59y$y1(vn)HR2NSB zt{nXVLqMfg_Ay!Cq8RJOOAlHX3rp6wxZTza<6&JlSJb8?8DP!45bci6sfr3wa}pNI<*y*wCM1~n+NV)kDbl~%f~gJ=X^^EZVPz4 z2-ohBuvx&q3ZGegM*!bicz%J}v2us`-j?t@#TrQV-y^=%P*8h|lFo_G4+#BCftN09 zPsPF&N~#nhcR?fs9#?6dG2qs5bv(Cj*4PrnVG2>pc1Apr@I4IYZ9yA5gZ(jjq8Mlf zyi?prj=UDSf`aPqL=op1?=KItEbhpnzNU)hsp*9%_i(b=MMgxoIrE;NqLp(;>x6Fy zlQ%m{Gy-SFJaY4(JT`3h{m*Q@KOwDPwRx-c2mVsLjSxT3UIx7uwXn?#ZR_U!5e@^C zKJYu6FY`LHVD{ZkV;H%8I2feo&SzXTAgGx4?EoN0HHlCcyQF%(izmLtz&u$ZwJt|w z?fKE+oeuh{6af9yJj0y-d#vQ1?2^vn=u{uI3e40l&^slmfAa<|yV`9h~FI^R4J6*9`SyB_~zmk_l*q@*IFBG6ae&gq%Qm-;Nrb#rAU! z>&+lmd$cSxs&qd;pvC9AS48vXeupE=axeuR9^`}m88zn(JTY5Q!N=kb_Fb83(o*5( zOJ^(n22UBsnKh4gs`|p=UIRT(c(~3;ODYRm7XpVps3w`?+%@+{=%z^Q)T6~c>dHrb zzO8Fm$ea%4i2w9`6Yg6q{EEyoNU>Yu-FNOUD>KiRkd?XJR4_-$tbIYIqT!DYOqbTn zoxe&332d0&Lh>puimm0yVB`A{QPHtuH5?~@uf$7s=Z_P^!_FJx?%G-_+br(R9ghu) zNtzgAD7==lh*Qu`5{Qy{Php&oNyNH^sap1Km$t=w()`dXhyt^ zOYY@2Iq<#UpUI5yC8+9k=TpijgXuFEs9;Dnp)x;xThwoXpw8U-9@)TQKjp)YV0u~? zT-RCYGh}BwyXwu_rrhI@pPjH)K=Emm+2<#B8c+ydHD(t?bZau>-?epr`B7MkPASqj zHMcM;R@+WMPo3b(YZc2b`-1CS@pf5BGJKZ77RG9Z?#rv`htC)UeT9)0%GSQrNQ&-q z-Zau=o`EMV3P!843@A>S?bXiUbnP9~t5{`MepU%~Q%BQLJv<$E#!lW;Yscva?)9JF zQ9D*Bt_873ui3ui@1p~47=9?v-(w9h!uG}jtr^9~eBJrZ;F3?XqR8EOBw&6R9CXGN z5}0|9lcntCCz!+G?`3j{{rfyV<`Ab)`;20v8Q%Z|W?DUV-28WmUOU63wMl)IX$z#K zh&5CF>KX-vN0}uy9opoG@f^i?8xXsaqr(*$xkKyy2q!YQ+k*J^gFEk7n{}lo%!^7W zJugmvvfEJ^KC9asQB*Xipk-{tB&hciG7%VS@*JI*tdlgQ0R#=2{Zab!hZr0YMdk9j zX4iVPrWovuH=qzBjAdY%qV~N9XZG<${>Fhu+04}0nx|`SB&&6zJ(dDl!g13?fTXP@!I*QynsiP8B#M8do6+_ zafiV+Stgs^TM5p$jJ;~0@yS^^)cuPrk#SxA4<3W5m!rjd-EqHP=f36{Q%_q6*_~c{ zmS*m~`YFZ9m%CKFt1B{L$$!&TDGOZ&>50qG%aI@Y>A z*S^7A;91ayA>ZQb(wo?qUglU3fKnVg)P@U)Rd2Q3xP2PF)x(0wCbrn=CgRLZs-gKn z&W@krybwg>YPkSvX$C=%mb3Soa!+rEIK`hB!ho^#n$gcQ7-({&EdP(e&Bym`=O>$x zy4d^y3qtwvd?jqcZ6ELE+d^cl8a)&cs~157*~uqe}-wTp+09lPG>m z@Eh1@GP1QN&VRtf8+?inixplVbqJ)kQ61XmiW7(4GL}7%qIxCgSkA#-_*gwa+u_cp zj!8jmdIbUf?2NT3;KX^3)F zMtmTCjPQeNNRDDEUpk_8mGyD$ilg#n6lXX^GLId~$KlQkFnh&)ItF(ASr*4Y=J}qg zzWX{UXphVE@^k8CkDo!$7>!j8VaD4Q*ELuB!o!E;QCuZc0?|utdAfUyfb|ad!lrfG ziM4lhcTfme+Un^5FeJ}eW<5Z-ySL4Kt>>VCT4`j5_|w^>aid4Cves&p^K^S|zcbFl z5%Kf&(YG_?3~%SrJ7vO8u;+)L<^za-FfMZL*3o|U3;67wZ#7*rfXb69x|mU)m?Qy^ z43T7i#pUJ*0{8)|-TBXCK#)a;Q2;$9rvBbj+J=T(H)4v9ppVEbg1Z1!=2Zi^z*c1*RH(@imoB)kv+mw1;-1#d(p!~KQnqDaK4|2 zWMGwC;aN%{(ga5y!JyCOZiK5d*0fq!L^f=7ir$_FHB_laau~z5_QpG(sJSm!z5-&Z z;_;6FdFmF>GbBzHUizbS1^=qMx8HUJd3RzJVQt`cv1wYObx4oqG6J>z5YCoIPwr)k zE*Hu}_S}^r=H+&gd3py)NkG)nko*88-ix!2AU9W zrJTHz2ERaE#7P^jsJ^(HCX7_fV-p|enk?{sE%&FOJBOwiaEz+@J{LM0=d+|AR~l!v zn#FS?H0Uk$w753_4(RkJsbzW=Od*8f1z%Es3Z6QCt|fJruB92<9T;2j@<-gBmGvXtL2kv)Mjz3Ufr_%+Qbe$1W$)$jmgyS$k4x*MLGE5Nb;_} z4Ih(5dxd@OrKi`2LGeY@Y0NBswg5E(fE8-LzokXL$deAZS%d%Rvnw#w?*PE;ZS+tU z&l}DUqaZivHXImIgP2K3Ht~y{+k4*RdG2QbsQ9A4zp5l)-5f^$H?bFU39^!06{kt& z{juX*mmBk$&6KZbmKGQ%H?K5rc6>1;VhZUF^qB^vnUTk8M1S6$?N0`PqB>wfo^bVy zZ}Zn7=(b$@mk<`k2VEQtZnH&NWhxunUVwx%l7)M;a2@gC-a9*9gf?o|Z{ei$P|oDa z9YN3EZ$c;Ql03uz1%g7`GNl0MKM*J$@R^{Lz?V&!74SZ>(-jmeNr9igD%5tl>(Sh! z$(-Zi7+-2(uCe#YnGD4Z>hZdT1tOUR5sGwtD5kF0WxADB%&4|hRj+{}nqVVA_XUnO zY^Ptcr*&A7yDtWR4_VH%t^&sJYvmtJd8cn!^LZi-k=h}SJNC)fUkVGvL1-HcngH^w z@D`hy{0K$Lb-!2g6|3gaG8pL@AxMf&XLu{go3qK4i;t_=AreKdG6E~>6d>=woHfoJ zP=$AGyfqa&Ff-c0nY`e0Bjg z`!5ke?!}u&@8y60X;>@G80nP@3zAeLsT2--1Hiv0Ch&y&Op%qJ!)QM}GSQOmS?I?m z$;B|F0r98q`k@G5G&e+I1Fo{kW_*Um=v^P&p0;y zn1p}ocU6z_y@wTAEoLFPABglpF`|4=eB2Ov`?Lcqd9UnZnLbQ)x!@>2LuYHn04$v& zfWPW>Xn77u!YW?kyz$gP2Ul9PFk*IsXp3<-e;cAsy$du z|DM(O=)*H^yP@%P@e68gCW*&dV6yMr)~PJ9^zpiQf%HAWt6yNBx~+m$Z+aT{4q9y8 zl{!`np?1d=1?wKYBl<;dzyd5S6TMDA>er?$*a}Mr*lS)Ih!)N&`UxtDEzqrChZ7jQ z$%&OJvOd52G^N!XS?}~c{}uYrxdr=$%e!XM^PRm$zbP@q5B|NCX{N2^j*_ovt#+Qp z?9CF=n{?%N?zJAc7rT>q^P$ZrY+5zG#h;xmGw^g=1)6BC{`06m+L8c#-PWd9-S2P( z*qh3Wx&-rTGiJ$!;lE0C)SQmNVGEb6E=EJpdOu2EorgJmzar)<3wBc3@V+Z5vNG}kzJ@#hlz#sILD6b3%MdIg~IyI3T=xyl- zzG6*-VnaF@^kK#TaI#U?4vJKE%;H!aPIouXDPr>=)jS=08QX&(N`=bU+bORi^bbRc z^zEz2xXvSwEzC4elYE?go9)JqhesLWD8YO$UGV>Tj-?2Pn)R6DU z9qqs&m^2bPLm;Aud)CVx-VG;&*)cwUV}>N4vI~02iXg8PMLI^3SE9|tTh|%gI~T#w zm)Ko8Pv&~sttBU&ny!1&YtCQBt6HZ;tAo~xHoxMY7#C zYLq)7Cz~>3s!K<*KxiUtHA1a&gKpoT?ri$7BalVtX^T0YP6;ga);Fl5WJv?jkA#SE zl`gu=M3Dx}Waq6rO+SH1aCiI`w=-%)k(Y>Ad{5=^kv~a_vkdc3l}!M>Kc**if0)i| z_a#kSOk9rCE)GxUWk%)jC4glB>+0-J+mTU#|966Wb0+(t00mP>h7g#SI@pc-)4ok; zVT}0M1F%bKFq^25p+4RlRkqjSZl;l%0BF!!`LGW~G7gVLE>yv==l!V@;Nwwkq0A-nMoCwVWQQUTueyNknpYOX7SB?I<>Se4tH%Rsbfp`bG@ zgie?@@N~J*4^HP{FX3c~9)n0g6QKB@?*P6flo1|f-Ifz#-1SuUF&xmqeO+4q=(j?34Cq_%M%q= zrw30JjuAW%dIK-7+>X&>uTDXHi?SJ!qfg>%)8(q}T}IM)I!0eZhYm8L&Bv{lKl>K@ zGcP$`+LvQtm}c(RXo3N}u;DL&hS3W!T>hHpMD2`|Rbs^cTR@X5v^bdfkR3Bx@$PQ7 z3Fcwvbl)46uVIL->}5;#H9T9@Vl$0peCu=RUQHs#a_2Y%M~w%~>#e!=dBCc)sGLuV ziijm1cwBnzIw3BGHzTU^nEex3C!x>}2Q>zRA#la6MEW3L$FJ*9QHuEWPM1&P zL=69rhOFB+z7r=;#+0#+y=mHbv7=O=FvvMaTa)L`WI-OC=7EidX?NU7?@I&;yPd{c z`G8+o+XPH-fpW!e_&q@BDibeqSh%Ikqh;G-IO;*27r+kK=&$ z^kLxfmv7F=oTqTVdD9EBi8x zlP|9b2v&+g7l#~4tW1hd0>?Xyk`JgZY=Bn;4g=(_jykxTOcn|7zu3=t-^fiY7e7Kp z&u514NR_aTlT`l06d2Bu4|w=hI16*2WQB`zu2+x3=fS;B2ttRf@j1AIB3Pf@&ijQq zk>&w_#W^F->Nm+?JOQu;Lw1*l1VpmdKK{X*dH?Z7RwKodl|vnHO)RL{KeU~oj|z4dzH z#X_%o(L!11A+RW30<;$ohjrBQGdlZx37D-dKkfdwVMSp(XY0gkPF_IMr3s`)j$AR~ zrS(}c+ak^KfcZKc#UN7Y4hjc@Q@@R5>5>>1bQYcqYp8L};oVyqlLcL$NKzT2I8_WZTeRH5}@`N0zbb_=B=8_lV+%-?Tf7Z@Zw ziiYYvlJ6h<8SK0oKc4dCrIhA}?thv6S6PM@F!#-Id_*_V29N|8jpeIiRDK08zL52i z9K|}YU!(kpmC~e&jw4E$5N6Y$J{`Hi?`dijUi%;AsRTA7r4?W!W}x|82_A4@ z=YybYR@m(f4K(1|Ft8~lso!OJ2CqNN_WQ_;Lq@!*RnYyWEakZ2qtrQ1<9gJ{ulSFh zp|>BJ#}@iW)Ev&b-LT73N~R14#k4L+0RJj+aXJJhh}aQGHGPUx`Ph*Fky zZ_Rg-ufPvgCh@1sz}Yen7~h105{A1XkMy?>F7dEHrT;N7!qKMb)!(Ta3&i!{Ma_-( z!0(B2)kmbyC6*V4o3A1|)?bF0mn2OE^;@**^y2B*ChsIFZo4Si6|~C|et?G_EPs(N zwxbwiXxs=p57v0fpQGFNQg(~nuoU7c^N<9H+zT??o++<4K=vv#KfFveyd5;Glrj3A z>M_xHwlm{FFzNmE$eB{wZUeeJS~cPwM&1Gm5v(w3U+VD~CC8e{C(w#9nZPUt&w>1A zbCUj$V0t5D9!;MK0wFG?H2&-i6(|vi%oQzE;t}=y5shmwRkq|?T*tE`Pq`x;1!&qM zq8{jnE<31fs*C*1NWad2wl(yh#-Tg)=iSQwWg<2mSJxnd;R%w+i2m&!%jS*Fy)hAiPN5r;GwC@ z&>9j$(;8T5AR zQO1eh^0Qm4#N?F^REjSj`nQ?O0qhchAz>=jmis1RLQdxak^H9p@2^BBe?A$OH2UR_ z*IIqI+395u*#5P4)VQIQXi-{kHqT$=$7-q?)$L;MswMJ3Rlv6x4Dw30@;h)`y0T{7 z44vow=F=}uUtLX)d(^XV_yN?u4?N7S6a;&5jraXcso4TFY&I#a8kg`(YSgxTK#QXC72bw!c0i#Y2W_HN2=>P4UAMOynwi1Ul2oHh$|UcILIOaU1ynw)x|E-MlK7jGu5;p5kY;}mdw zc;Nn5j`Y6sb_Nc_;8E@ZEjl8ZhBG1)UH*EaSm){ot%_yoj3=f=peGEFIGrb^fVgPu zDZ9Z?x}HaiNY;l3-!gR{ zoMQ>{YVBOP3@Ph&zlzyw$({{K6B9+mMgZz*n%hR=to1o)s|t=4ueF~2vF-$d9;!5e zj_<+5tnUE;`gaQ;zu9SV>mRmfHMN)M&Jzql@tbC{x}IY(tzr88l(~~$_H^G2=>Wmy zpFIFPPqSP4k{IpDe$~euhm6kf!EG@o%Z}1-(C$m8)W>=jAnkPKpJUoyP>KpvT((i0 z``%XGb~6v#n8Il~GfBo}Di%boh;O4wr}z8`Td`^DZ8QU=F+xqCY!(Rq%3{mxPFt;&ckw5G%JTIhBs`2YO_Pwh9 zo=w4)eBC_IP`cs)6vg~QX7*tjxir3%`2P441}DwM`Oe()Vq7PghXoS#M>+1uXdehE zA3j#hdt`XJbIIys_tM{<<~A2!vS#$UKQkC<@VMELTI!)!{5-AhnARZHm?c2mR;<=d zP(yxnB=em2zV$gkvfg24r~JN0eVDx(_t~eDJ%UE72C2#)C#NU#W6up0kMZ@t`#tw+ zuw9-FdQN0?NFeXWv90P4__pro;kMXl?u+5((FYmIgExEkCT>)9pwJ1O>7n__*%M|v zY8m5RZ~OZBwS}09+9O0RGvFMV0eFgxTD_#1Vx|ek<3g>}XDWi;tIb@-EM_Nn*3JYi3fIX(pQT-y1eRC~d$1JfDE%;6< z4!*It{Tn0t>$P}ZH;j*eIAB6>^dpn*cBz!EsKy$o#GW7&pnwt6QD^&$)9>45ID#?& z!*0^~)+Fg)g>_r{zsTv+@cv(NdP+xC(Dyfm`w&~}i4XCv;|Cl5OIyI432FoKYR;RLsY+>>w z8@mBiToY{-R_@jFIoqTGJ=;Q|1T5X|340Bm)$|_vxYiQSwG^6LFn0=s!q#@pyD$D-P_Ku9 z?r*$29uaK;$e3L*T_@Y4a4~N2j`9{x%q1rb4mD8f(2oQdyDuX@O^3)rOt-ynL7v8v zM|Ln;O3oB2?hsp`w~8ykrTpdjr2FMMs0}wpe(sgTiO!Vg$)D)x)~o3@9e5h43e|v@ z;tvi&-pDKkPf*5#n8LlhC^oP+T+rYgOk5ZG>25z)c!%U2(K5)~D}3&o<2!(zp?P6)8X)>;x)&dd4H2 zOLXq?J4~2$NoHU$fu$jx1^t75WQMN4pXL0X-lG;{-x_I$xDQ`x}q zp#@m6MjUW)o$Z3w4Q1Ogbt2>OYhFPlD)A`Kq>-mcj!+5f%=SzXq5`8m@I@f`~jeH}}G_hN&^b^QM3e$$kDT!2Nq&Ml;3F3kJ&~dSm`7$e9tH zZ9H1@7t%uo-XB>Ck!f_K)myeeEaqa$G;p+N2NX&fKq_I`-#2q))oJ+3lJ>?VcbtF8 zREd6_-Lg=JdH=h+5#@m&QXB^fHUl2MO;<@$H@!`brxWiX+at@F^h@j|&S;?o} zGECHwjisrz0&+l%a_!t3h29G}1^x)*mI^xHMS4-3zqUhCbP}{}0z`fLyHZi!8G8Fy zXD6}5vn`!}$0K040C=)!3&Nu``4mQXu2kapAi#H{5)!fPJqS7s%A2CgA3u&_uO82# z{^sqwW;20RZX{o^yv;df2wWE&T&4Jc9YCEh_xqm^^pIs&AnD4rN-*)!cxb(SdKu(z z!&MKsk_W-q?!nukJI7!gqy(lr0$TT)CT9Q(b|h;VE%sms0AE~@Rlz1T0k}0_0p@bE z*BO9vF{4fpn=$ZtQ>!}|O^vu|w3w1<56fM@u3elTwiam^y{rXsfdZBd zE4jS~fXnOu^K?lFr!^+!z60QO1%RYu-O{Mo*6s%^cUWy203g!|t^xzWn@>f0366Ht zFX%RaHYloY=}FH*NX;C+NMXxlEh@K*4j}jW*y%CMK+A{A1>>Cegrc~b=ktFI|Zv$X5I2FS;=tF*i}^7NZx5c<1s!g6mRh`qIQoLx!sP6EwW zC5z3}lm-+pNJG{l{RjiqrTbh@vtaY7P97Fyt4Bv+8jZdhZq>wDvndR->7{BLtB-ZB zyfcB8M$~e9M<7$^qCJ)~0=irzhyZ@?lmK;ku!Q7{#nWk&k(!`+Q~R0ObUT3gyu|Kj z$S?kSBz|@B-{YazMi}|^3*IRVx8VR-uwnHEbGoBY$Kz3=AC6?vy75Uchz*bqKC@avU$c$((jxP)$f`!|(vA5?P z*DJY}#I`la_)$NR?#rcRh0wbB8((pdsVF9iz!r9sxl-skV9jng`LDOed}iK%nrqxm zZ+89o+ikUo4ZuW#`-svz_37tdifK@|4;M&|_z^o5dwdNNK0!*1>olpL}dlEilF!k-L&_8ro8Y)1_prlit4Y>eGwM6dd&Ks1m zrU&cO7>*1sNS1|++>nZ0F#R3#0h8CgduD30XSrcYVy zC>}fDRC>18BLjOe&+nrr{P-#@>J*SCAn8mmFIkljSG-zjq0Tm<+(j*i zsQ@K}v&(=HmprQ@=WYL+^hxJ&y+0EHojM8w9M=JB$tXp{;L@0O&-2AQo&_SQ6XT#g z!-{-r%j{t*I=(w7!D~NF5p{c08RKQ4>*#E#w_%;oBmsF~svyd$*;U+hU#1v*3Xh)0 z{B+G@7_FqNVi$O-~3IQ#WJ;?UiG=|i!V1favGw6KlxND~} z%dG=DOm1VseJeSd(j`D__J|2xKaM*%wO3?bY(!2DUOr=4Nij6TIcG%EHpo_^n8h{a z#ulS;r_+=%<#cAlg~?cd{NHXn0=qh7Gd3TkygfEXhzfC*VG!k_%A}3buTl*ON!Eb5 zIrzHogJF(MS5Mw~@bD=x05Hx>GI(LU5<59cAl+ma)a$s=o6~xK2$uBB5|+FX@U2jB zR%1K97w)c>U7vouyV&67$2*C>d00D@v)>h&v0o=f^D;b6rf0!FnVh2tOd3@U5;BQQx9xq5^bMLzif7vVSG$!=~-^QgW%AfE@K zxxY5an@Zi5Wx5)y0XHclO8ive)_8fiA4iETj7L!k2emVn3^zP!z>T`8 z-fIC_^d8O&_?+v}V!R@QQT~*0@a-aXBa2vJQ!MI`Z)M(pv1XUgVm(bohG5g<$Sd(#-{6@N*l) zCh%T=i$~QktFnY*w2X+I%fEY_UQ9r{AdlJ-w*t2U`Zbh#dMFkGZn8lOQlGnUaf;5u zX^rQOLF07Gdw%3u=UcCOSg%Wn?vsp@9m<_)Bx}2`>Zkb7Gaf#%^wvVFm znwul0=;l6e`p=Wq3LOqp|etSUc95`Bc2H$ z3y-ef!(VzMFH~&a7G+z!xSFF!vpA4rA$)*hq`6a;A!)&EZoXJkL4M8X@uPyg1?@$( zKkgb{-bl+pV{re72?)?yG&)Cu`QZNGTD}$oyZ(Mm5o~=Iic~Y?W5xu|iSbQV-;vT> zu6&ZvI6k<*HO&#;LT!qf;3X>3EUNk?wXl*^CWy1Y1XO9AmG9aOd7pKUrsP$rE<+~C|0gwqegPi1=6F)Go=lcVS>5Z*}?==wa=}()wD+$&uOtJl- zo}>X4qxTljKe0VT^i2cDvE2w=QN(ByI1VkQoBl1gDJ8&L;Xa>iBmdhj=09{Zmwsql zz`T{eEKijF|686YrO>SJRE(t4ov!O7YVe`EG9q~(P7eEH1_D6SwA#mWPkTIFZ~C#+ z;H#*#LzVC)rn2G)z4&|*rD4+GB~igYjw}s)M^~_zRXtg{Y@%JljUA$0yo^Z~GcZPz z78+jW1PbPgV`?b2brgzkY=JXegATSoNw~_}G^M5{GWKjBpDleu5zKAhzz$X=t$K9E zZZqKN=r7RdcHrrJ5owkGdEdHKEe(PBt2qABPgEDP05-UxlX?l}`7Sl5 zmuPJN@=;z?F#hF$a`UP(_ADNj4t@)+JB6j*^460;>B$v!7edbim*PMz)OLcDt;Sf0 zhRl8Ats*BFxuBWUnA)z2bbViY0Lmpv76#U?)mR=?&7G;aF%obusOq(7i7&q4SzUnz z_Ws%7i#9h>^VrkPWUC34rS+d6xh2=5M(%J*Ccx98LmI7)fb#g8$i{F%#BY_I8bd@@ zmAQMK;5zY`+e9MLU6b_Bv?JX$O5sZ*cp7_JbTzjCu-G;CtK+k*m#=68ubn!vzS~YY z%W9Fk@fOSEO`!g|hWKCs208qWP!5Y(p&Q(l-Bh{Vx58U0RFywJIVAO}HkG1098%A| zCmtTb0N9B)d0S8I5`?!0h5#wAy#4wbd*v-yHpXws_a1|XGpO;iQ(ShJ`~nzUg(p&g zI9>mm2oU}~-thnz`8?n}5Jq%h{F*G8&1_vM^X!?b%m(m*v00CP$Umdbp%e`HN2Hl1 z?O!zJ()PG~f>8?mrD17ZCEmmyiNaW%7)ft+rW*N0XL_iQGC-iW7UomSdBa0;)gfY@ zbsWoNu7x+9Rx9$TGF^c))8xIe(NmXV^T+^5d+zzd$lU+%H~A8E*!7t~EUKFe(zqch zu1*XQG)KYy?7DWv1=7R|Kk)JY`t%Lsdc*LHy#1ZSYh+Ffq(os~2Ofz=y?%XwLY)nh z{y0O#h}|11xy(3@H* z`=-i0=WSRqm7_*{*5@px`HGG^I0D(G+M@TaY-^F`XTdc8@Zbcwy#K_njn|p0-02ZG z_nBYX8jlal6F+}lyc1o(2nS?wLvzw}#wUPW9WOwnf80w0Cz#IU>5MXaWa z?5~sn#Sx00>xpWJB?Q2U)aQS=UjxLL2mjMzA?Uw-@WU8LP4teFKL|JU)#ze%sJp*D zAMmo+Th&gpr3E{xySo1b%okd~ z`KrsXY+bE zE+Xi|{}tXNe6NQ-I!H|b(&hGZN1@+yXy8~qv(b76RPK%1fSo6^$u^m$Vh^x~5SK19Xr__r$@B!^dIv`Pe+(S0 zl&8!Q1#!@`z1EHp-WKhC;Gx1T{7>~cRE&9&I;~KKum9bXOrrkF+@tpYv$;oCV((>d zkJU;}1nmDHZx09ZN@m;;HC<*V3s53%n-&{|c|M3U2*`Cc%~<`-1*#TAT`wE0e5U5) zhqdE1Yh37vim_B&#Ma+!=*J@r!+qB)44Uyzh4R0w5!-P2=`pL2xS2SNs)-VNft-qt ztd65$E|~b(mTa<33N62 z{mjc9Mb>?9rqx(Sg9_p%^YFK*?a|Y3J_s`=gR>QOv5G>&ne-GgRpX#vT-Q8_{vYn% zGpgyd`}>_y6cnV$2uLp?Dotdlfgqruqk_sHAWdqN&`aoKkS--C3L;H`p|?<_iL}sz z2!zl}=!6cT2A(U-J?i~`?sC>y=d4p+`g1LmtL$r+@7|y6iH~2<-Tr|UOv4$Dx>6aA zzi7p$Ag{haW!?^+c^=%*@ld^_V7v`(qWW6h(CU@n6IR)*dLy!S5~u$gPMY60YV+UC zC-pU?4P~U2ufN*{A}P40_mXDOjgm1Twd$4ZCYM$J9OnrfMVe41VoC*cr`ee;x}R%+ zKNskGyzF*<1E?)n!pZbr`GgpW1!z`=@SXC>^M`OpND>&Tl23kzwnVNzmPrx zBrE?K4e^oj5pkeiVrN2F-@s}o#5bFNjm5{oc4ew0xE|;*m^?C*tW1PheEU?8jb=LZ z@^V1yQ!B)QuzsN>CXDF)U2!T?gYGu@=5*`glw)(cv}92h%JQLxvtSopBVva(`=lt_ zi(l9u-Z&!_%x3O7-u>(d>yGQ%4& zkJGhFta`6d#+*@nz{_c%9Te!hI3I!J-SrNDZxFtl1T_@xuIRUn3lJ?E;-8}oEq{A; zeDgUNluj8Xl%4-6?Md19jN7kDlveqI{S(aY=nqeb zjI#pfTw0KN3Rm+vg{#R$;c9ws_x86mrX?6qLF8#|PeZC$tO~VQhuQJEH0DC{<7J6Z z&+=~S)w_!RiL)YmN5dBoh_zLS49rb(V=H25n~@alYIep8pV{;<-zs0p=~_v2t|=&p}kb;>Jnm~LR{$;uc&R5s(AEJ0ZJ%mNjb#vR?Wzj~2i zWjrqN>5Ez&32%cmYc09S@r}a=SU~I`0^%zaJ4@n=30P_C#yn`#UE4MvAF5#R;9#6- z#`9i%0N_*Ztx;{ag%UP0qR=6KiV=#w)2;|XfYU(;@|OSp>0j^0=WT&6>dhY72{d1s4v%qi(|MhB z6Az|L6NqPWHr1UhsFy*XggM7-$_Zei+Fm&aB+1A3&jFZcR<$hb!U%f<#~tz`g~22) z+pu!tw5cl;K@3*xZTS!ps$jO*RNj%@v}BD0Ip~=QD6UK9X<0un;VLy4B~Tg88D=m3 z+&1UJ1uq)Jp2Y98AR0T##$2;BJ{5d3Jy0b=YVcrVN<^;JJw(b_sS@G53lV^ngTabJ zCH@WduaoZ6&|E-*IhJzWsAg8*1E{KXE3zU#Kh^w>Z+_AYgQ6R@!P9q`aH4*@t z$JQ7(N`uH#<6~OwwK!aH%|17FvCftr(ddEoA3ooL7DJd0x>>6>{J|FyME8q&aLVPc z`Q1J8OAW6U?6ntv9(#`uhUxhwSlDVqBmz~D_pC{cLAHmbG46QAiLkA^pvj)FYbLwZ z8Qd|IGkNE95vzM-HX~uNJ_7XEZxk(P<)>jgISSw_}PJG`T;}wr!(-z7v~IzK~!7Kntv=dR8v~)adF00n#lY^rL$Cj~B`uVEA2=yNu7hIdlv`VNh$_gch+>EJzjvA6anIMZGYcFno zL50iXFe5m`#ff757zKaM0JcAS2j#K%xOOCML@Er}t(cd?mhdf8IkSW?v5T{~uBHec zU?V!KaF2%l0^Yv_UF`Cyjf0$~j6v7!Y~q=M`hq$tW`m(tAL1xY>;v4J_>feg+KcHt z&c~{=UG_Q~X3fN`80(Ws?G*)Zr$@VHaHsgpcb-xmlAn~4irN%l?-5F%g}n&i2)S$d z%zf+dZ8vz$!xgXiL9p?1MLx;)algI0GOUlr<-B|gk+s#*1ZkNo6pDymwTBCNf6S2U zGW=I5-WSSakINmWGMv=3WF)>HS^+;`B~Ww`nctW6-yB+IW?!HzE*u%#t{BU?e)qX# zJ*E5m{8CPM0;T)=AVAUJ7w3J9V_=X!6H| zoX7i{Pz3)?+^OX#k=|&6=;DXOHK8<)Vlb7 zp-T4;uvc5T{rIa|SW@1#L|JFkvBdY4ImY)A7=a3t-Cm1WyHqGvk~7EI+tVf(!M4U| zs-S-d0#TtKI==_WmkI+-yKArGPbo>tK`Os0F^~}SFv0<@q((|Xt86i|X7CjI?G62~ zYGa|A61hwD{klrh&OAoi5R+SC6CBB)x=rcW6~cKrTZ=f#3N*YM-4%p%-AQmWUF?kY z+9#4StkRvNA0>GYhY0f2Voae+eWW!g_63*=kUNSBx5#w@_f9&=SijKxwv;-C9pJGs z?5i8!@y8b-lmkK%ir@RM2jmvbul^!XJ-54t_UdCTpU?R=J&!o!?PBN%8c@&1j+GWL zdQHRO>s@*@n@kfSf3jBk%(po`gLQ%SQwQnM{;W)xY8gw#PQ%ykgEjM&&=b-w9wjQ8 zGbw>Zj08jco(q|j&U43W6GFYyKrbvSbCJG_zHZFmr)L}+#&x@NU!GGMPiv^+!*i`< zuKMttg<5%*BH{T<+^1R}Pre^alB}U4Mke)yXQzpAuK*~yT!ykHrNieBxiXRm(X_o* zQ)I{H4D{wLq!p7NgR(lYHX=W_-nvJj@@(OBPqm0q)mzbP7+{U1Fn^>Q{!I(xy*dZr zyYR0{69!jl{*7h%`%I}_e~*fEu|5+JbxhsATJX9u<`t?iYn}$i;>9}AKb{{MG^Q$> zvLL`x8$qugkih1R%S{tQ9ZWK3+uqydCvIo9<;^w)YH&})ufdDEsT1_RB*Z1??x>So zEfM=zWreza15Zb3R5{VGS1g)K32IucsvYzqJkaB$$a53b9I~`kLDlO@RoPU8Rq-la z^A!4J$_U2EofusC#QniULijLfkzCl)(PGu)OcmO@6Iq7}f4m`+mcWqIhPRrxoD`cZ zVBC!wg>XjCX@OgXg*VI(tPcJAbc^q+lSx^fhe{&`V*hP* zq@PoqhL7y@{kK5--*d@hF{#5LewEMfRc9%_VqO(>IL#w1D=~SgM}374mt49!PsC^i zNgj3o`8dNrFsqN^P+UOIO$ZX|#-s>f(9BKPSFoPl?D8Tr)r=7QsKH*PBsH{LKCwm6 zQWxD)fDHk2GuBE;6*qLM`4ClbSUEybEs&?D|L=}C|zjN%7)aLHnZtp@y^^wREr_IFq zz%w>I$M)?lziUech~q<@GG*WI*Wd5_|2R4?nJBS?e#-b%!Px6tC!c#BD-THs7_QFZ zT5Z)uuza2Gkqkp<&opsCrv%}=eU-6>aU#dpkPCtimReknHB68tv{-C5 z=|@4^1K$huJV>WUuz^lfiB&zHEHn3=5`Dp{c@n_}klXg)d4 zj0-CQOWM58N#4*dSztKXP=Z)sM2S(l+3t=+mH>8mp?S+IkFYQ)U{u1TCgxbbuML8- zHbhO?t^d9@M-P#)*?9TKfAA;gXv9w4q3|aizx21%GnAe1IbDwL>X@RFIl<#V?+mkq(?)v@qoTuELYtY`I%m3~6sD)B)kG2%U0ZkR_M}f%qWA8I`N}95} zK<^Uduihp7rgv+4vheKr_n>tN4qBIhfoDQ^;jW@2p;#KJ zTnjSx0g^GaLmqdLm8-_})mQ*oWF%61%d3!)5u>cq%ufBK``Wifc-up5K26%Q_5HgT{i2Er_JNR_ zGStKD+KV2a{ghYE->IVD6X){DlxsbvlYgVn`(-805eLa!9 zD99V%!pcePLDx8$2H|^1zi;_`O2`V_T)IJy=CnZ0o0cg_F%ofI7wLTfI&poX2nsmOsspw#|FmE$$@$ zn`Qm`O_Qbu{t!#jNrgPIZIQDvlmFl!YMi3*4+pXaLfr8kzLNE^Zu`N~^8(xFtS9UA z_~@Sz&{{zW3h<4=!69~BqgG#ehhY929Hkot54uq@>umx4@M*r4c#~YP>!bbP&92Pa zI<<%`v$C3!tY-z0A0+ku@hmB|CK8eW+uROS*h=x1m zr*Vr@b0GEFu`06llD_Y69eI9xV}?CrLp6^vGLh(FPv@D9AHtj9xM9Gor0Gnu|D zy;x2I*%FGDHIp0cGfK?P4qfO3#KTf?m}6t~daPHWJ$ZN2qUDv~Cfj*9IMVF!hHmli zCV)r@jGt+4|G_MNNwO4Qey4)G2YanAzW*io1VVnY#G28f>6()Z=zmT|#$+pn(D!-dlbWd(2b=mb3W1-rGu^@H z3su2oF9ZW8H~F*4OA6r7lo8>dp!-p9nz8=;S>{Tq6^@kZcODYc%}o-2^9@VnnAPbj zCD{ei10|s>4)N8rE+qhOXe#>g+6d?fIDmAe=PtKnEe^qT=#Sz`B3CCl^c0^&lRhim zpkcfHSn1v~ONY}0yEs{0DOXkbFa|$^b>gNVYhSa46R9h zqofsjoRiufW2jr{N$HuJ>KiZXlcoKyOh1A(2}$>S4t%e5Tvw zgm3{^66Td>9N!=1$6(n9iq!|t7B*K+4+*rA%M2=N`J;Rzr7Y$*9KW>aIJ+8@Z)7=c z%87HYSr+7yrlJBmh1~jRL}Ikd`NTIJV$Hw=P!I zKlLS*(oL$DrZfoF<4?)}sIX);(=}o@CA>-Kz9=J}anJL-&Ezuy&AMOQNrPWB&JaRg z-nz*Jd&$+Hz`V!b$zCQb=Vv*hd1F13Otx9_jz9Lb`0or_<>_)uPeso)NnwSvHcJqwj7^E*`%Zpn2Su z{+j0=xz#M<@S#j=xUoB24>7fq!VNF>&jAP!oTl>9?`d{uRd@THuZ5P4HmW0aQuAr2 z=>EmE|Ka3XA3NslpJQfqg@P4aT2b4l)hCK<%Mybr`rhCRB5O?LlDNsR;vL7w%@Um+ z+c^}fpj6gC0$O-C1C=1@dcFBiC}Pj7KEG1|+b|B_QQyve&?~0N&9J%~TyKl?oX^k8 z`$P^=UuKn6=($=mI-1}Ralz&qt0_(3LXC*DH~n$<=JAaBuP_Cv1YfTZbS+HHB_TCn!HTQ`3H zcu>^`JO?s1(liC&j@*c$tyu6Z-c2eazu))FJ9t#S6Stf-nL6l6Du*bQ5b?awRadl^i<%E^cK8@(n>B*G=rM3?3{=0F$IwUA4KuE#i7GD+%Ov z(EA~J`(2X%CG+Rz%m@t7Rv&#+FPJ%_L5q|-RpuWcMon!va!R`SxA<`7CXF+Q`SX8a z2|M}Erkokx&qB!0l(I+!JCJ@29PZDxF*Hp$q7o7rkbwrKD=AtG=;$GiJ$<0!B`tN< zMntOHtj(JFXhRMn6hoAWO7`s2>Av+J<(bc1vWh<;XXg4-r$OCYoKA;f)lZRaDmmgm z^-MUvirO$+&KI5CeSG%Kk%srSM#6`Kr)I?Ep&pfB6BAcUQ>MMa`h)nA5?72}o=dJx zp40s}cFJj53S-y_`mOn0c%j>>X=yVXC3VksJQ4BD@P1BJ=k?FI=h<+!@R69|Lm&5p z%NAV@hq!ZNHjhG;4%*koj=P?@@=-#C#XM*Da5kTMsyL{3Yv}hp=)wt$#rZvXNvgD_ z>P=VxIZyc0?=Uw{4kN^&-=Q{(g2^9@E~Dbe`*~zym)|}Fx~bWw(dl&uR=H-TDGp!K zmv0{B9_ZJv+_ho#De(EUvRp~+E4BUF4i+rrtId$5jBrZv|RP5uG$SC}HM{&aiXX}9wUzn)^1O{wbwv$@U zOf09{74mAstL&QG04yDGav%mgHfZfdXPBk5vnjFjyipiAJTpzBpe+S0PVXrTamUQF z(!&1CC--k^`AM205&qCM_xN(BVkJ6T8;-ABy6@Znd@yJ*JT4pMCwogDKuq~hT9y1I z7=BND##sr4msOHag!VIffRhN@IPeWD` za!K2Qyz8rEv`B7(#q89q7q2}L)G~Z?n?$PK$ zxYynlcAMBOS>--P80vYnjOwWL{b{izh7yKwuB8uil-Z9Ux}Htx#CRo#wxND7x_1#& zkMgIL!cbJcKYXR~RX^z)EBV3jhIHU{FoCbgze(X21`3L?&KSEEnC)AW%7tHTX{n8{ zRRHqgm3tXM#d5gyMZMfn+3hQ{IREbCPOtUgo5WlVq~i*~4EAV!wdKQuz96pQ#KhbO zh6%blmAVCkNd}7-K9osjmMOM7aIXcPdj(#;u3xx5Jk2&+C*G`jOQA6K82Ph_^-r@A z1P2cq_@^m~Wb*K$rj2iEsi~&*ERCEEU5PFkjTtYhk;EHU$!c|TTIm%56rrd4Ma+~} z{Nj-udB-5VW_b>d3)G5W!=q1cm{I>Df=#+6YLetBl ze{<_FxjTP*P_@->OMGD?cHLEEuVyJ(V~hGm-Z>dB$_-NJ=<4}=T+>6KEvo`-b6~7jUcA}=sQ%`aq3tbY<;D9V1gP7a2UuDJ)NYyAsG>q zxcjlt$L3(loLblC`{qSaQq31P2^~{Ecr{n2DKC$F^B#?!dY_0J|B41<^TU;!W7$v4 zKGX~I(Q_4^n~}yiaR{%zP&lZIVvDZE3qEJ^>l|3Ti+_6xEriCrT{zG4by_YIysu@_ z^WCA3PfN>6HS~|N5eAAj+nvPb-5E?DS3)fdS)>Jcw~V_*mP$ zCH2<)Pg|=RN#%_oeqa`#-7xmq5uM6wG+x}WVSpAANyekvkA_`T^_-SPEe`5bTN9La zgB-idMh18EO?!EhAI%J}prn^y@|)X~EIYL>S50o@&2=uo>}&{ju5hDAcEB9~-KK zi_OnWQm(4;p_lmaNo|Rs)K18!W_-R`sq2hv`jmi;YXmq-I*PAPP!!M?E`~h7Gw$2# zV`ZlJJ0$jZz{aVZV`;vA5OtJP4%Zm8r0Mck__y5G4os0*hEpe>Qp zf3iY}@tfT|wWFj4%z4OHOdM($g0J`3E_jf#>2ABg1i4|Y(9p%kSs~$a++-^`7d3rr zf%*cmL4ZCSYr)HPnZ6@7zEnwm!Xo5NhQDDAWM`warpQ4pI0d<9q+ps6(&>f3Zrsdy zhV&)|uYb@AwXpM=WNxd|K*DuOf~bAW(AhxzthISYZ`~f0cmG{_cc6F%!pRqUdXRhL zYvG{NXx};gqX4O2d>$(CkxvD;AD}7f$+I&j=F_jKq_b2$eTeWlL@A=S_prqi6``%2 zhg1HEgJp2hN@A5Gq3H?xZW<(d4>+|H+%z6Dq-0;s$qN6^>db{;MR|QgG ze#|4>_NQ#(tjYA1A2tzB#|XSWXNC`a=D9iNn{WUUnS55^tee=YsH_2?T(Uk9Lp99y z@zN}QEFB~pyZf0!9yhQJE=_jDd5|!6-fIQjJZJ`=3Ej!91-$O$**jbTx}DQnqXP|k zJY1FJ#rjxwk=+7)+5|7EI1gBc(u(l3R_DNO;P5l)S8fh*UkoC-a=2bUp3Y!azkBDm zfiE}1&cD zA)=)hN!H{=Vp5)ePQR46zsPkq>Qj7h&g+_O-`VAkh5EPeam^U_!+Qp{$> z%vbeh`8>CI}z!@&33nI>Ij9xTS`dt(V#Np^G$weYx= zY-~wKUEywGTKf~*W8ZGqXG>qOlPR8bXZUFAdb(U{D}4nDE5tqutlS?;c%ySYGgrt$y9Ccxam16;mJTG1mwJT z-Y+r#v1PQr=tySOBoZqXXFA(TYdr7j`7F9#iJkMa=*sR~Cf>nrlYwVrjM#nZqrmQ; zW0*w777j0S4VKgp{it1T6n3@0di&#k{;N{eXFNZ!A+syCGBdBJD1^ORjy^y`5pVzRQE83-bBt%TxN zyURLU>8-Jrw)#y6(-aUSY`18zCMyAeAZcs!!xIwmD-dSS!7^^@(8iPcNN+3JVtIEP zr_P433r4RE#52P09DiO?^_msvyc^hHjzTAsd|VtE*XDfRGixGm>ue7|-s`tjSE`UR^;j<4dQ-NtBwEnEoE^fGlH92|KZEpBWyvYxnQ zEuEU!i~YWdmI2^|$B|^E)tZwBxDOYHE#jJLtZ$7+ zM>Y-?(|ZvZD&89RYI2M`QgZm1S-32$WIVm(VXsFj>g?-0BpU(u)@Uj%Kk?yG&V{Sy z2i%%so;CYJ5k%*~n><%4e?R;CVLF3)_j(tvxlQ#bQkd3w`(+-v#n7EHQX-;n~0?ALWB#*e4H zFLIK`dMy&gCYoPLcH^2X6G~B=&G1bR;(TG8IuCr1SxH{y3=1cR^(52s-NZqtjpE{D za+&0ufDzj6us?BtdhwTmxA#APL_GDqn#2~3aE_C#N)rk!V3_lK0pmiX zAIMIu6}YQ0@MS;0nn+QqjjhMeD5P@&WYrXyWRjbjvlUGN+$oqWcmzdCEunai|Luq4 zMUL`1+-)EOQdMnr*ymMwl)ae{<)dvf)7SP*GA@4E%nm;MB3d1T=h+OYtLNu zTZ@$*`ch(4w2yP_O;6Op{-~c&zPw;9 z#`0!gWFr@qhvQ+aOBTvl+H(V3?3!Viv_}Cg$U>&@h76BmDzF z8E#P~2E_(TmdQIT-c77+(hDwAA{R5m$p;6MbWF@avfS6kTy;YUDoq;9>>fxAEgHFgIwGL2W$lO>zhsVRhg~yWdEF8lDEcALQMQfc^@b+4INZ#zMk6b4p`tZ z(3@T)r53IijXp^07)V|>-r6Cwt{HoEJ{*R6){aa`2zlkg^h<~pg_BX8iwO@%c}be_ z#!4v}`xBx0!dnLGqNtPso--;e;p9~Q-7Jf~m_eldqw?jz<(SKo)6q60q%FCJ0JnGX zmkPFo>xeF6cbLA#vsAtXKvc|o7n)dgXdA~Fbz-)GUnA;Vt{aV#8lL!fgn2V z?>xrU3&1RWVct{ztQ41@**{(}DChyRPDh`Ghf9}R6t zR#lj&J)5riQ!%=T(X_dDy1zg81FMSRJTu`g&{L}0g=p>$e8M+NjrNy3h_grni9snM z>fYC1cD5VrANAI@#Ab$$$|Ah*#lS)C7{7Zc32L`uNnSv3wSuhHxDI;zpYSskUN>{% zw+M*boIUhO`*zMlf{zSnkJ_E)eerD4#<&hlNGFjNM&S#Je7sCtd7ROrVdxBhV#XJlkP$NKu}hrN z;AxQDWb{ZbBC4Ko_6PaEmZs&Q`0F8R`o&qpTkFR!G@ia z8s18$IB&0Tm?_&Nwlt{`5H!@a`3WZH2iS>5$H1tBfXKc9^n(;7l%$-f$?Y#I{Yk?< zJr0Sbno_Q&+|Uzo?i)@lu6q!M^6dghlKZY~%3zQIOP#nThq|a)3n41NX~AeMP~<+F zXY5md5k_|SLma?=wt?y*6# zQ~fh@^y-y7WyG}7HAKNokvoQ!(F=Lmc5)xdq;MfY{%?gvHXTYP=hy9>U&h;W5yA}n z^DlN|Yh%LRf(hz9g|i=#qKxk%g*B0CdPSzQhsfe#!r@1vGd`}hxSaN6FCq6qnUVc` zuwC)v?R~8_9JNACTjf8>bMhIOjq<_hf39H$R#mqP^mtMS@I&g=U?73+Dk}e2R{6wt)5$9EaxX2RGs#qNAP=i?^)f1d`QmzR&U;z*(S z@io1(LGC&NxrL}{M_*?iSHc0dSwjp$W^%P5$waU%4;zQ-uJtcYQCNOCEwNA$;>LSv z7(BtL=Ye|1yN8E&mKY1KTp{o>zl=O_SM>4%7^tpUzB3)ia*tv#?Qup!B95$ z7r{KF=x&X@TL6A-)&{1IYPr=93L81}yl11YBo^Lr?~WVMU3cY~6gYSX&%4aC{W;SD z=)?WIxYO>%JsMeymWlCWfPTE*`Vg0As6TtCgWNobETR(h{ClARu^Chqlc=wOe4NE@ z)#5_Z4P1=2>*#%4?s;CE9h4dB5p_3KKDYgCjaDoaIas*l>)D#+X}bi~-kx>2JN1KK zbQDjPxI<&^p8LU8ABCPNo{k`;lLBWs{K}Dd=Efy3(1!D@^Q{Nl`q!fUFYk*u4v)v% zBbp-aqXIhJ=1WToIMjXgqhzhIQ#Bbvn1Ig80<$JH?&l+j zd`E4bZf9%(L_iMLsA0{4vI%Cp+OQhwJ3-^{>&;!4caNJAbRD_!vJ`*f{Dosx1YS_o z4m@Ry{cL_n$EWQti=(7#3>+%)tBG^rjAjN%x|xIX=<@hCUbjt1{0xrgOsl-{tIT&2 zeGuOBy*)ebsyI&if2hp`&3#{|=6EiZmsRZzFN*=PQ=7oaF)(YobuJy5V~uWPsmB?V z*&3FE;fJ)Tx#Ki?`ZgunJI(4E!c|;wRY!o>h>6nhAQafOc^vK?W_f1g0v-7*y|?Sr z-|&!U)j3XwD1N{BLX^i%XslcM+ovOy0UbrBUjN5gt-tq^vLB!ADDPv6pDmk8bciTl z+drxLH49%#;DgQjjC;A2ZYfF67rWco?A&O0Rz|_o{bKt1k==r4jv0 z-HZTR`s*s@R-Qd(La!33;^KY2oZ864Eh;gmpvp6p=|Tr27wYml^yW~x9S&($Kq%L_ zec*)^TaWi0Am0!(?acDeai zUkc(mXfGT_435vIg6RRLXs@xPiulVsHgxW~IRyswiq~v;YF-KALg=Dq8)s-oK~tWq z!-4G1WZ4@b=xWHY17M_2O@vZ=ESHTQOnp&JdW0BppTRc47*KN4+G!RH-$HL`W{T~- z%Y6fLwD5ns!ZgRufeW+-|1m4ZyK?I&s{3M1qbGdiQR?}=rGf>X2%_S+Hl)V^acB^j zWh@^{eov5zmIPQhLC+6uv1oc}Cm?)s3BIX5ka#@$XO6A+HBw;&>q7*~jx0til#^xk zmS^eVAF%f*FRqCU8>Cr*0FDBMliciUoUxu&Z8)aN8SXpr3&}T-m|voJvj!}IV|KmHKybZ7Tkq7NfFBOj%^kNvD+ zxHwDWeZjcg%=O~TXPBr*B7 z&(L)-B5AiLb_y^>OY?}|{J_tae^9)iTGeKnZ{Ln;eq(%K|621^{^_C!Pz3xbszpHR zcei8B_-(z3FZ`Hm!~gRw3cSB|@i3mKcbf>)0o1j{-ua&E@m-Rey0|AWJ`$`CW2+$1 z(*-j|SZ}x@Y;1B|3eebgj>0Ra373G%#s$nQiDuUHvME12pl${5ot1(v1wfB#y<@aC zk%xsr*HKg10MQZoj+RAa_LiRP?kT;rhG4l)9Emi}jd7G`!!ig`t&Rw_H|c%wI?|x6)_?!k_b_B+1nX&Q@=|oe{DG9BoTS z1maI5H*t{@iy`O2k#M)A<^QcY!d;Jy|KjbYz39(ZPIKcTPy+p5(jDO+EqEvTcPH~4 zrnj^HIq8av&o*;)g%C;S_Ooj|kmaNSIFGdd;X3lbT@JvdE9I*k;QfUb^*Du@_#)aQ zA)=7E_qvEONk;E>kt0>PP{b#_^ba zJKP036bm%HXMIiY+qa{afd>S@WRl|gkSy4dzxNCUk~JWsVR)F}>b-L+Nkk!yl2J4t zd-2&!xhe2dg_zvsZKjaB_WHUs(Djm%ommn8U7FQ~uc3xYn^Wb*MYBTDv9fW?*1bJI z&`vw-Wjgl^>3(gy@mQQZFfQrq59;-TSH+0r3ZK1hl;Ee`1V1m+pmXsY%t247P3*<~ zC_b|*ZsL9NY3*lvlNRG+Sj?jm4z?PGQ#>V#gEb{Ot|%%CzyJfSDaI!e&6@KVZ7o&? zx9zzm&Yt%|F2Ri#Kga8PDk3DN$AqHyOHU^8rz({M*9N^8AU$d7!xp_$N}Wa+bm5U!j5=~HM7s=7un>TPrL$qCD#YNRu_HB5Em`y)A_GCMp@_@vM1ak9 z^DinVOk*C_zgg47-PKM87#*Pj#$J0d z)Olida2IV>4@2&+m=Cx)H^?F;@Oo=ukC9TY2x}TCroA{g(slZ?kWQ0ic>|rW^m*J) zWY^EuJvH6UX*OK&LC*K+Q-7c_59;qEn+f$DXfIkX?G7Yx#yAjzCog*Fj_M-zQaJ9| zoYKbpt|gwtX<8MxnX_zrZz5hNseHph+8KWPb5@!Wk5h#v%S1Cr;dK+D1wVi-$xUW% zcIf6K8%DzfcL_T!by^zk>hAjlp3(5S!4kK&M;E>=&|6(fH3yxjllHw$55(SYhbW)R zlk9B2E4`_F(P|*))5SLeDnF%`wQVM~mtWFRZBaQgLue~KwILI4&_t2c-b@%h1orXD z0J_A-QBI)YcAnMZ?1~Am4_|{GuvZ9ECiuXpWTm_VXn&qZfy4OrjIw%0iUyY{I+m~$ z)+==*K7egvu11;f$%PNWe%FsZR}Q=-vQ`*xbK{W8(Q&CF?%>r}wv{!4I&gr=+(&N4EFd|;36nO1xMM>nGAwX+&nQRec z4vF0CNr(PfHGamzw^%7a2ko?&I_N?I0(hUY0+lEr3SeYLjmW* zMLtQ?s|liU84Qb!${arELy`{)!N7UvUBGG8`m`EuN4GZf-K7r`r`R3wgSmg&CPpfX z&e^If_@BP6*i&qmGYyHU&`7&z4E5R57jo>>Y5Er)+MZSHiw(&|QM5a!5>HjSOODJ2zK;odT^MY;^`$+h~EUqLFJ>3_X$FN$z zS&w?FNhj5!j?aCjNhICmc_bp6v(6_VVRSm-q{0P`fm9?f7IXFeOcs5i(|Id?vV&1O zsPk2sBOR$IFd(>9Q69_{bW&ba;oMw-RKnnlZK^Jo{|B0CI+mgWB5f15s%GBIbqD?bK-r1=)l9pxo~lN5c+{CkiGKDu2vss>yF`xlX?w|0LltAG(SU)>r) zxBXcgkvAsE5(k}ME4}Q`2FlQ121<=n4&N zKQ0%f*)Z(bCaUVi+;tUv-ml+%tu-QHX)cmT0NIR+GTn|OB_zJ7bugPU54;czB%tFn zfBDmS+J`KYIcHixo~rw0d!WE}^;Y$AZbP=B%O@>VbL$~Co(m*HtXpp*60NWmOlV0R- z=Ci{rgaqSK{cjs+yz#XnS+LhQ33X)`PB-9CR~!L_mYh0?%`qa}{v1Zksxphe20VH3e7u4-nJJ@%L;{)i&i4|x=_NX`iz48){<6e+Y@yqVBn zPBgBsko7Di6xD1=M!duE;<&eiXnq#By^wynLqx-5--ekwd)oF^(5gu!Jkf8^k9NE) z&^s%W89Vut7}`cbN{&$U$pzhSj2x_o=ysl8R27-%XUE60a&@WGhYm1iz12_PO2Xei z&hcF13>6pf>l`mU9S42j%o9-o#`_bjZ2&CW2FBywCxHs|HH#NIVw>SNU88}q7oyap zr!<&<1DcroDB=3=Sp?>vz_MKYtlAp<&Do+Pd}^e?5#7{Z&v5Gc_6~pu;?z;3I~^F= zC|MfcI|UrRPJfH2VFQmgEXj=LpJx9P;QHiM01-r}EG?wtCTsqTO$`VMXTT z7%#+?Ad3du`%MlD8|%_>N@IEAuKTk?g+5$JXU^*OQSxnzB@L7?92AL{_FG`;NpG8f z+yExZ1~7ej_TyZd(X&S(oF7oZWLsg-F3QPIR#_ugv=rcen#V5x=0oog&vf|pEa<`- z`g!5H7+PfhHohoxFi&xw!WJ516ecH$R(M-nstb3YPNrJ64r zJID-u_OTPX_nJ%^%=dJPj+kl#^60h-LImVj8=NOdSZ)$p?7yAg&r}q-{^KeQoZ!Q3FUXiyo-M+ zZLC2nH?7BzBsJdiq)bh_QW9~KXA|u-O;1za(`1XZ-rkIDik0;eJp`SISp!oo1U@4k z2mGR)Cb_q_w@hhumV7KIh<$ns3}3*$OuaX)LRV`~j%iHmG~s2C<8;y84NFgxj1*rD zR&YkJOav4|I7)O4a9-G1njKPEG(!ZNH%SJwlaMd?`-2$vhOgPVGk$y{2BwdP4R%uq zDbbQnwy#*1R11(` zv+kH;t=Ya=4zd@m@1zdw+#)@TXs?cR-*hKDlI zUdQb2%tTz?8r|<^B3z7eYEw)yB6;=4Rtx7=5#AL#&h<`V@~hWPqPkU@=WE#ozsL2d zl)bpkW1aV7Rn0+#62SjF`q%sWR|irR+ebkWXE|9>IU0@|v~EI}_h#uQA)8^ffsCPy zZU2k5w+xGNZQF*IiVC8X64EIR0@5WQp|nU0og&>x3?L2Cl2W6DbW4}?&{D%t(ji>~ zL%%2Meq8H*-tXJKf8Vd!wqYB7T-O=Lu^)Tn+zuHEvISD2G$$RFwr8v0ILwUhk^4k#?MT%@a6(&r4Q z_5nE<=kG+zd0W7`va{J@l_e=F29{hu?&Fyn7puDFDl zXZ3gtjAM)O-cIdlirMm({5s4K5kE1-$)dA$Je>~18TXl2?rjurHXKP&{1KjpL&`f%iM9K&8<6?{|JbFr=^FhiJ{U6%^ov z5$h7dUvBQc)ix#o`jPe@JY4B%Jg&wQV}f*u0|gwB_)9nA?y*^fr1>3J$E{wR;|^rL zYaI^{nGn~}>V3}6O8^rwBA17d#KEGeX(A@5u)vDp@ypHAyq3ph;=+UYCh z{EOOPg086onM}uh*R(^sX>AK zkJXc6@7PSA!H%YZd820prjICYs1{aUq4K2K>*n?;X{#H&sejbszrIZ+Pjy)&1@}Oc zeEWA~Q|f;GYF93x-2WQs08$s}^_8+6$_r$D@@{=n5WJMRRBC%ox3+k45?AOY@S}EK z94fO2wv!ai>TiicAF(-KZ11Z7gtWI=44HfLy6_3|B2i@{AYdSM;`0~@)bZUY%1E|4 z$K2|TCL>~ugJ|=JQB(Nk+Lpq)4X#saaD!3cQcSz#Gih0-$#tZNCqCylTxx29N@AKI z`6|Iqx9%$OvJm&R(GFXm_h)K4)OkfnHOGgpj*}#oWv3<)0A@5VZFY0`_DyiK{H?k$ z?08=xy!S+4%6~GtBKM#h2=EM!v95yHw!dtaw&Bc}-(MZvDMoyz0tXR@LDT%Z@!k#X z?3V^lTsQs2%D-Lh6KwD-Y$ju;mv>{qWpEP9VX>9Jyqw>BWd-=t+Vx69Fa`AWJ@ zPx9F|Qf2MVRt52<`qdIoW1+Uj6?y4EGZoShT^iXKC6d!;;3nt3+myZhF-p`6nS>B9 z+4kc$DbQoF*lHnkZ&(Y;1%|LD7*@U|wR2%@L)%K>%gto^^CUvIGF)@A8e|JnQ3W2WHik$9$5$+dk) zzaRaL9SmQ#+XkjKdPuFm!wptB)dZ`#0Jstg!VNx48fzT^ZwGH8F)JrN95No7BYFgh zljx$+!hzU59%kiZ$4iLPf=y8D2%=#GSf)p(ZzqV=uUp@ea)L}$}2 zDd7OaPv#)l;A6xYCo5OC$5I(dBn6iym1sDB^Q>&-Mc!=)R?9%foiOP6sFUki8Qqp` zvE9o41NB4x|LB28plsG`r*xxx`b%24Gd%7{{Ig````&-_Kx*Fv0}PJ`U0vyiu*PZ=J+FbV z-doLej_o%qswXOdX8fRjka$0#uvgsK{sNa0z4-FtmOKM31v*Gx=wijLDF={zaC<2S zJ$)EVw#FyWH<&H2B`CI+M+P?0)V!GlO|I?(u*9Mba{?WRPN*^97+KaHlpkn2oPT~VvKKAJw>x8&jH;G`|gCGb$B$d*8rbc_0?%{`IyP& z#uwdf$Ahbrs~()-bOBnLjd|nRrJYOpi31>GyQT<_Q#np7=R9a&u=)91@b5nBKe&Y9 zt?L{1uf8zQfn0-tao4yM^r!+h^Ott)l!!@ZxZ^@7qif>%_WS0k3(<>rw&a^K{;!Sy zpc?0(O}nPGxm+`qaLrnTeZSL(zBGQshao=w*!6OF+zFIFVs1?BQmu2-RGNxYi?M{6zIasGs8Mv(db`T?-vy6MSU8FHjl8jk)}TpbqLtZ({CA(6NQ2quUu1ZetT2 z4kLdCjlD7xe7Ma13%y{~n;-6kuK?ZDA(hIdTwb0jLKv6T7%L{Avu3UtcV7GwbOwO#!NppM=uG_CWSc>lr+`Vh(S?wr>?I!!& zUA}RSS4(X1wdc(L&G&9NHxP9_Yh8tDpNTfpxfj*UpEaJ`xjoi4d3T#bGxajO+?)NX z3<2jRpuskVoXOe!IYEhSQ0EtL7ovU7(@@2=n)wwdQKe=LdtF*IB*% zyj%F8;>XiYy&#%ZjS__JIkw}=iqP^hYR3Sqvndr&;b)LwydWWn8dZ~Z2{hzqNg{ak zKhJHh`g-@u9OsfrB6^Y?to88d=vi9md{=1&^YYVRBybJ;mp>zX!+>R;H$a$$(M%;CqZ}xjQJ0KzqY)FpM9E*S2kEfy62<{>7 z`;=FPlbHmcqs_!mtZVnkd?tRAos|J8KL?O?By((n^QwM&Z*kDsLmpm!r@f$_2xcHI z=w>xxTw)$avA&9*1F90I+5N5K_-yg>?_W_@b};QDvHcOVUzEz**2lURMdh32oN;3) zr$8Mxs3oAz+HK0o2)>Y{zX8a3!*G~l{O?w-0IXy3rc__PYd!VzYkxCJ|3AGm9=zV4*24HWjnX(wC+G=Ta`s09IaZ99}u)QHkokf6v5gPLs^B74Sd)e^G|Hi*`nDv<4~R{Qsg1 z^Stx_p$vmf{PpGHbHCUc+d-wKnz^|wJe#p>;Pu$A&(P2}?E=`Yzo623kQZCzYY6MD z!_pv>fUv*drn#mhBDGH062zHEfpiQtoa;zFz{kqL(Gk10Jg}|w5s(RCNx*7E=wL|9{^+Ou$b+SrVpUWT3)b*?RS8CpSc8m{t z(&`UPdYigZ$0w+<^jr|w9+wHxl?|WDimzH>M`GD>KMPMgi!Oj3iQ}?~%tx#EA}7m4;e!2g%M*Gq_s z&>z3(#cDJ+z517B1=#lNH={adYtumvqW@)^&f9tM_B3%HZ+^sNrB(0#a&K@rI=%#& z4ZS>oQ5jQVOJPF5h0w7B@%XdI&^Fh=@{s6qQ1oq(aZ-nt*Ak$G3jMW>De_2w899OP zislMAy5!;7%D~}5j{Y{GY|QQOt8NuJMU}-ysoZi9+d85q8nQL8X;-BZE<5@{*+6#6 zbJrXSJZc6I9g$jH6}%BVojjgXv-QR~c2`hD_5j}3iO%+nc2t)zn;0nXOzT?SpW*zIxae|ptzZduF=0v}36@7}xpi84LkFw9sF~(797s2X=X zC12I|y9iy(lUg^-{K4euo;)Fo*_PB$RdPC0mi2sG;}Fe4OP+kjG2DCwrBfQEs%Mnq z3wsjEdMlVN5UUr#>_x(+Kfg#g1Q&9d@OjCTbrrEMyOk73i zSw58m?r#ETR;#lTJpbuC(K5O@Oo5w`AHc`v7fb<~f+gIhnHEi*f)W_Ttxj=ozoI1d z(p$qT+@ltgLmpSV5o=ZU=n6je=-TMGXu_yF4ey&9UZf+8-WTy1C9<1NQ$<$Blf4h0 zJSnv*>i8j{deu>MA;q>6QIXviGafwiRVmaxc(zJD$T^;%oLWQz+7quo&(vO5+;Y^y^n&w>zLSIGR5sx2$o{zg@O@3E zf*()_ReWYK+@9{X5c=*EmsMVhKR?;Rzrko4znS+W zfGv_ugid$&`CSOhMG7h zKR(mw)A5$g=hPXI2J*VDf7@HXmFA&loh*wYROYDRE6f|rJq3SqTd2X?9Oiockir$! zo`iVNYpq&tz4c8!nL6!ZBGEW0Y~cm}t3q29AzMp3((YnGF3i2r z=ShpoUNOa`*~dS0YabE68M^Cbt2d^JBeP76C5(Ey#MJiY?O?i1ThN0FaOGyL-%AmuDQNwIYX5tE{Jl&{{b}a{3O|XX-H%S#I(@Va8>n>)xokoKNGlW7qq$ zM6O>uk{hGSOj09F$R&I*Sn!n{xEeZN-m@D2=99^Cntmeb5R5~yQ2B0%Hbum}oZUcw zw_dj?_Y(-JFV2pmU|UfX!d2~!>$ar)w&aV9N~!P8)4tFTf04Mg z@vE_ZZ+QowPUg`WDbvfQVYKz{i-byZc$BEeA*SqrW>^W9J{bf4W&h#&Snv9H300Xk zFg1VKI^FeW7cd2UcvyZ<;*(|!m?^@xA@c;GAqH#Cp>Y8b*fEg?;qwW*^VFAXklsW= z55&HaDZ6-w{9rD&_`-bK7x{xswe;_i`}m0iZQLt{Z^#AXb$H8oWZ^BhyY5gppbHp_ zMuaTHeutW+AJLOt5{&ih6?{8{(1r3b(nlLie*d5%BBndcqv?=L{5wRZmYR^JuFP-j zn|7VUn5Jz^%&>lly69m~zZ~Tl?noa{E8_V_kP?iUMCf_f5j%1-mO%Gn(@#Gdz1Us8 z+*_3V{#J>S1 z&R?%;r^^H3l#A^&RoGdkN70?C-l$+1RO=wD+@i#Q>{rp7iW{2YaB{OGvRFIOt@r}# z`HyA6fU#jg1w6+MQ1pV;>=#S~DgC2WZO)o}UOKLC}K2ABN`gf1c zVaEOCYXj6H62HM{r)nTg*nH*&?6%XVcGS25>=-VUO2c$q@NnqeJKwb}q z4>qH@s(C^KVRWVrqYH}sGmp;lRQ;p&u>%J4#L;uNz$kg@l_G~Fm>M@kRoP6*EGQ&9 zfoSa`&>OeHVLcUtVph>m>Kq3u^fQ~uXD(%5rGh*4!)QmYIZqX_NUWx4K~Oc3ha#I^ z-Kh7~+3XbfigmmYf1l{Meb$)T;icOH(IceE5x6a0Eoc5&K`OKusnP1RNo+KxWe@uW z=l#b0cIBywo84L!hdMZ`(T4u?E#zcQ9EYED(>8~#+6~${_V;?9YvYQK;lZRg3_n)A ziHa1%?^q|kzkoL;Gnjpf4C#o{ukktIX5r*Rgm@^eqO(OU9*C{q_5oVfLo|zzt(Wn= z(3{wg`B+K|APimYE275}*S+x4k69I)p$lrTP zxzQofPAf5%D)dIj*1PzWvJtN4%5PqgAJ^k_l-gUo4yVs@F z9D6%?yAH>4$45&CJ>FTG%>H8O)xmSey2D|4 zo_fh{jYoMQdRf=>6}f;Gy`Q6;kFDjY^^50XFuOFy2)DE&Oi z&;Cx!9Y=x#=uIO)^Sih64ttLYrZ0#l!=Pu#Y5=}((@s$?zlWt6?nU5LfTsS2CkTw@ z;lp&t3yB6fDP$WNOJkY_m1jH6;=O%1%2Gl1Lxn}n9`kWfJ4y8U{Uv>|16>tg2GaCK;_4FaGbal0BZqa-MzQG)m=5_lx@&vVbCoIvmurM=sU(iH zXv0_>QK1v&1pG!v7T7`@V@>-htyA_Xl&d{9CH=9wtSIx7q>S8P-Nwz&su6D=2|m2{ z>Ba4_kb9Z3yC6qOj23TRo&x&$faAm6Fqrkt=Rz_Z7*xjDBifDgQtSZ@OI@;}ffnDy zoHh@cg)2wuj2_$MrJWYm!uzv@j7V3PRJ@#N6`92alg6=#QDZ!Uq4897d^4O@0hPvD zYF9DO;rWA{y@ZM)8HN^F+*pwH0zeR~0yy5g$6VdVHs8Xf1Qo#k#i91N_n-3cKP4Xl z*wpbK%063El2*1Uslz(-@(?BZZ!@>2X88*BAl7dx*XP%E!hThfqEcj=@!xy*he*Gc z)NsHkxg(5wUzX@nuv5WjYjqypYQE4gK9^Wz+e=wxdFe)W1|L$@9H!C2 zvx`_C2$>+byC7yZMA+o3ZmnZ>BRIw#G^v|5J%36V$&Pa9Wn6*%wRu+@?aQv;An?%O z5zPh&)vFXep5{4~(DF;|zz^BXa2^m`C8;;30lZd&X)_iMzJpukD!mEpnZ&TOtBW0< zsCs=0FkWy4)*7a+e#XZ+AO~6~RxyB$8TkN28qS8789E&f$(p+goT5s6Y<3!t({<^F z)&T(6jTCg;1KOUCT^y7iYhU*$)%>*F@yda|p+rt36D!32@CpPVlfVuRL|$AjxTk`8 z{IkBAB+;u&v70iJ^Py=4V6;@dHi#dwna;5A=y(@|J(1R1)2z8akYHJeN}t2Pmw%le zP{`gmTYl8nC}~&#shAs-hk2h`K&z(7jtiRecJB`W3%kNaN*Hv%yRSJit% z{fmVE0*BL*;Kkuc#bqO=IMqM(J`|i^tW+$4E`kAtJbrf@@ZFy1?yApy3pu7;h_y!Y zn$v5D5F^@Y*FHOi?$Fxar*ogLV7e>Bfl>ZYu#6REou3^e6oOci%I!{-cY(K%e+@be zZ#U7LEu8OHF*we}Cu@~U`+gS{nl6~QVw9YxY%p9Pb^^~PU+2ud7xs~;>e0K>URkW{ z5mII6M@lIwbja)+NU{cw%nXK8fB;884Y)GMYaI$hUt-DMe2}uvlTYbBs;teJo5_Te zf|0h6o1_0Mzv+~Qh|B|(BQT-Gqe)?0i>EJ=M^(EdPcBP@z+L34mLi%>noFVeFgXCM z=b^WOn6rn!$4g)?Ta&!3SG)6VHXyncQn#-UTEYf=6!hQfq7>YH0fobjH|x?4qj@(y zp5NEzo3}|pZ=Q5Kk$c~z&1I4laW%sH_$m&#^Di5dx$k&8tbPk`>wLM<==08|>145n z^eouKW~{+a&q5fw@x)4OuAPME{7CPhb7f`N!|LDWud2*&jmqYfj6XlSu*?b>TBwSQ zVLO)V$Z&;QB97l}pwp&IBD)9m4dtIS#K%Y7t`9`jZ)WCR%?7y~fxeSlj4;CNTeR~3 zs_XCny{+`V2`J$j1v6nP7NR(JQ;fj%tL1Eym+s0h;a8Xf zi3Z-a)4gWFY>|U!o&2pk$oa>9BO&;7+$W#2+MlJ13P;e?1{59&$_DQ)ZrAS&oHx#C zHlM1C2oaD8YnJ&Fw#Imx!@OLlRoPhhF6GLYlqC@fzw98MLGgU01D=5anH?_< z9&t0O$gV?>UQ8}Xu0W$`b4Zpd;s9h_4+F4kF84SWQ#?{&Aw;g-?`fwMkzZ!mpJPeo z`ealmh+`8iR}nUq5b~pI<^1ut@S0YJt80MNC=!>LYoVLzuGLCi9E_LN$GEnX4mn>` z`Zg;a&1IClrxt}~y?eRO;KQO_AVxP$(!tF_)Oc$0A}aUWN_(^{vBSQ)D8fQltFv;Q zH9<9_sfKDfhTZB-8Jk)9?a+4#s)3^<+jaOW`-E6nWPbXncPzKDM7{B%@y34k&-bR1 z6Bx(w6e;T=!b7h6?}^9R=1N{DxEvcD3O`~vujzbu$ZK__HPKCG>^0RIo^f0(uS?BO zHUH_tcq=(Hkt79Nd1^8y@M{;7V)C<4SuF2E)fOt!EY6Y`yMkStMCUNeCa!}HVuSXr zkG%y-s_x)fJmM~X{|~ruL)Net57e)}?F**z6H!8|9ST1;eJ&6y=f}Q%LTTU0-RdgE zH&-7MnzG43KE*``+Rm>kgUrN|c)>`NwsSS*Y6IT;Wyu?%nB4fo#)%KDSM9D?1`@+B z>J_~&hXs^AlOubH)l2WB{X5#qvmSXZm3#WOfI` zam>cyv%E3u$7uCxcj66~?G3IV3V5f8eNvH5tsHY(eVrx3j?dx*;RUDmxn!V$vfSh97xBRsB}pk zz1R7+A5+)Lb9ONW)sK zv|X2b#%?v}5mCOVgZA^Wov0xyd)iR}BHtfR3*3qI!EF%J{d2tdmj4Zn&?HqzA%4@` zi^LQm6AKSC_uFluaFSC+s&Nx}ua!FC7vK+ISw*bj?>iX9iVF_wt}V+#lOKvZuZL-2 zQ0XCm#>!rNrNc2wN2qx1*_Xb2l&MRqPUVf$D%AKhrwL8nBU^%|TaO`GmX5Mpk1CFa ze~mWE^jpI8ekAR<`beEJ0!>h`()w(mmYMe>jt|GO;nHjCB$*i8u<6vbH^gL4W6D;{ zI23-c^U800eo^O+URtY1AxeoJ4EkA5$7pdJ32A-CjM^hP9m;unzPYPN3kw73L0J(& z`C1We0KYU|*<_VXO1$^}QukiUvv`z*@5A!)x#NFI%j>$uOy&m`Bs;it##d9jpwT-T zOP70FG39uV${KZ!HIIu)*2?8KQ?xuj@cmmOb`vUmv32m$dgRhU?@7>04jSy4j2KR2 z#`8%?wQ~aRec>0CzgD3IswK=%Qce(d#%VQ};sQ8js}Q5$56_PzkY!dayXH2_n=u*% z4rErS%8H_wC2g4xXa|wv=*kK1^NZWyuTgf zejH7|^MA%`3&;9Q(V{{m4R1xv=Njl7T;8syFVuh5vEp@jS4V7Fs$i-vu@Z@TWQBA$ zn9f)NyM>^)j@?tcq=mDiF1kbJSEV^L&Dy%7E=X^j)Mnbn=5+RIkm&wdm_kfQSFt{? zC4WdA=<{t0S{rNs2X6%*KaRqln|TfN5PQNv<%3CYP<1ge=&gY{+I+suxrg~yT6tPfmH0BD|VA0e|3Xy7qw z4UpSE8E?K+=a8+bw4D*6%!YGC7`D6gaoui~b(;Q_my@3STQw_RH$$V7M&ZYu)``B) zJX=7u6!z`T15zYtIS5xxx*{vD=WZ5qZwFLA(2B?N(}b-es_kao-ehh&HD4U{ZccW@ zc!GPwag%|;)ZskcwV~%3>64{l9K({PQ_HvSzdNt8g_uj@hhHA%h<9XiT^~ltXYBHW z(f4U~X{K3A7NOj3yC5F#gI4Z1u{W&~m$`W@;6nDf*;Is)*0=uqtaSVUX!R;cn^H32 zCMXcEq=F1?;@&L|&W#c)go)}t2ymE@wq;1?M2#%Kbi=t1< zaUbP(Z->3~`Wz-NWqUrBDRbCfo&fJmu6=4$EK<&83@jv2IW=#H`zHL<93-FK9?SZa z!-b}{^mETQiO6-I_{q%a^n%ZkOY=VPE_h`XVD=~`9fOan_RC_fr~0pHUa|5aV!_>c z+V@-bUlWxYUsLIkW~TcI#i}{%4@Q_5$vdq3PS?KRfL`HYLiS>Ji=^QT;z^*De%8c3 zl&ea2%J*w`Pw}I}VkgAC*=RN5ne0Qy7heZNa-P_Ux$``=`z4YP{{(c}&vF~1|6InP z)20TMsueb+Gn%4yMnV$;PSfs99Wfo9><~1kU8O@Mr!28Xm%%%NHlMs&m$n z(eVUDuenv5pqsYsdx7LH-?w7juCFMUB7hl{7&MD*Q^s@RP;^Z_AbCoiEI6P9<0qDe z`}MWszsLLL7^oL0(76Tritm6)yP6!P>r|p?;8nQ=ls^uPg&E`kQ|tfC!?^u6j&u8D z6&3|6$RVM$|8e7J1a|qXt{F5Zt{^{l89SmrwoLx$LRQN zzl6?xevA+WaGwz5;X10ms*yMOyphzr|HRa$`ywHG^)RG&+LO)F>+)pPT#4#8fU6{g z6t0LeYaa8wMY5JO7;`q&SaiLefI9!F9X?8dL$l*+MRx*TxyJ1+fFxDijW=~iAr!+c2vz)-@2!}A(}~oMk<3^FckGX zMD^jb4(-6@6u#b6trM<{5$SO2=tvCfq)tJMC;Q+&IF%suRP|bCx<;nfO)@oDmR`@& zdUeA*@XFwvWKGDiTXgQ(=8-D0ORN!VW3i_{zUhuqQ&P01o?;3i+F4g{K}THIpgI8@ z5kXDeVV7Jw<{&mtMvy5J!976CiEA-k<8V&&&@Pn$YGMK!5Wcs4N$9uQr#+-;(drO6 zPl|t=bfhXMv=9m67Ooza6<1~&b~$41v8AkIo5$N_42yjDman_wqInOBQfyAbzxrl5 zn@~SOy_#824H~&}kP^s`K3)pUc3rGOT>doBS}d)9!x9}y6lj8H-uS+xNT=*6FQhBe z+ob=L%6wCW_x#9D{DYZbfOL+@b_hKerXJn)xpr|a++{qLs!Yb{eMx2S+o{~MW=NJn z*bPRllw00!LKLbz=Cex4kR^-7klL1_<67$WM|dMaSFZe1rF>_YQQD}KsR7@$v6`;0 zkgo=cCsB$3Ffi&WqtdQ;ey3L!PWy$nG{AbyYPVOTK$Walws49W?`)D1>H;M)xI8(l zGF~BuG`>IC1~F>I4+6m5LPZ#A2El3iuSwU|JutQ+gx;uOk|e?+Sg_ z@h%N^IeAv~n;PXAD*#0BXeAJXZy-5JX~x})QQ}Q-z4XI|-q`5M>|>pTbhUB{e!bC1 z!-nmEvncPw%=>{q0a;=OuV#i8=HrHW=@!mKc$u&>6CC z!Wu%>c~%H-etdY3&QdP$-uDyiji3-kY^(m<6gihAg^jf*S;V;(gNLyz{*PaHJ%2>9 z-=%z+92=XQA3xCTn=4z?-IYxqt_%Llt1c!VD4Z^3ojW75$s>^irB3Or8)aQYQSNcL zW^@|$d@WP!u^7~iUXgI)O?V7@oagbj&FE5pk?Bx|G@tXD3h;0XeG@MxL{l(KbL{u$ zp?sh#O}p;8%f;s=Bc>oTM0&SA=Xfbp3E`O|*pl8ABr0(7xpUB1{pym+5XVTLR1^-V z?zOTWTgW?VMp=FAr!zrmqY7O!T{RkQ{q2|L$#p8Awr;WsX9=%=O$}&Ocw-lg+2`zX z6ekzy35_6%bahu&1Qtp(VsZ8&=953npH{NIim#w8Ez~cNppIUi&HL)nFXT&KB}UM( z&#SF#E#@;W_@5y%C~BUMNgL__AEYm?_a;BlVcXTr-}x~8Uz3`j16Y613Y0I z%sE^qhgT<{U(p{~i{UPu-^BpBz6HRDh|`WR;wdnHc(c}vZ2bxV)!#9J9Vjg3)x#0x zsK)raH1fiqV|Hs-(<{WUP6iBnQ5%{??!9&Iv8E9=Y(Cd%t+s-LECPru`$IxkpD)>(rQwY+9gbV?neo3A>Pgc-%g z@>G*Y`g!`gqo@8fo>t{%VLK3HfK@xnQ94gh-S@kYpo{EN{-reY+3P!T^!4+I_KX6 z%`Uf2u;!;d2J8}dJMG&;@H<0xx6&>_I+mBt0x%IPov1MHvip9YT;M6Cg@DB{eKwQh zG|(c3+dxlfGtwKRaW7#%8rLol!JuDG;KiUR&Z z2#=%9$6k(DkVIX_Pzr~3{GmIwSfA92*W45iX-(soy?ZAQ0M$>kK&QHR@AiBAbw|%% zpIly1vPHtH8EQp4|I;=bo?Z7$44zGsH~|2^NtK$Ik}fJH$!|5cq)2D`zJ58 z5U2h1Hf_C)`;_U9a8rAZpuorI)1}tCWUb_?4`i$@C_U&_Gkv4gIl}{+82pPx0=7H_ z3n)K}xI0eASb`}=fsk9pBI0Yi(*-HRKck!!C5}-$v z#VbM7(hJXR+)JrGAJZjP;jCh#wxAAv`C*&>G8VjYH@g1ne0`7K(tr@{k^RGE@5`+= zGBoMYZ+PC(cGn^gud;~a7m6xnDo@l5{!y#A_~6<9 zZ|p|^t?P6L9DuFMvz;iXrrqAvY&_rBwLm3bs8emLiUMDQ@zF~$NezGoZY4IKn>nAL z7o$u>PpqJzh>V~}bnI3uUyZy5DMZ+Bigw*<0#HAMLmX)3twFUKQ8%4RtG@iHdl+Lq zcn~!RhNt1bfvmR=nlQMEZa(R^ zDm4)tZ~iQEFj%!p6Mi4bF8LxLI_aK|`1A3smk)KCpzbS>=N{(+@0%XJ$GXK6S)q^( zu07Y)wD&UV?wd{VD@V2eX=#2OMO-&|M^GnBh>zpMJvy;+W;>M*f%S(`B`ZBI^#bsP-5)cQXPPLHXNc7@ zj>(pI%5>>^@hq@j#;g~Z%WSUS@&OYf_1MaVHF+>!Iy7sKd|)sml|)2D$YRa>6Z1ad zi!>~dQPH#8wFFmg;rqBM^Mk+`xG*lT`BX+dXI{v<7*Cr*Z_); zDLt}Or5LX68{NUvu<#LvEH~@j>?E@*eDoTzfvZOV8{FOF+3L|rk2pZElTDfM!yd0T z#E33;MInbvG&)hdt3JI)vzeZ$Fy|AgDr>h9rs{fv-2_d+V>zUEoJxNV5)?a>D4)hUP6gPLHpkqipO+-UygpwEjuNVBtgyH zh+YWebKTVPFKopRJY~B82XkMvW`+~K_^@8^TFguYn9KTf(CwDSXoBev8{90qG+%vj zkeo<7>@E!WfXHwY(LbeV4gr>SOJ$$r#5O}bS3a97ED1I>Jb++25*c8MU!oUzY8G@r zbLUv5GuDPHPW~RlB#jm7+6d;q*JfK^>99vAdO{Xa$HVfR9lCd^p!W36*#e=_fjbGm zILpj_e;&VI@14g9SHmL|Y{@cc_I91L$T3r5nvaXKDrrpkgecG~k-KM#^F&z`6}KmJ zCk2qXyO8V(gHa@DrGCx-V(R})V?o6`(Qq<`tx%m1w*Tc2aJTX@{?mTg)7vAA$ zF2_*wxJiGZ^&y(27jF#8@=IdGN<#}WdCSmCgoNEz)46YMvBU|#mXjV4=_y+HD?;fn zxTg2gPepE7<-+w~i&2X>c8bs;2634eOHVABnxT)?VYSe1yJkrC5jwFt{$=^C z;rX^~@8wLb^<4gyk0z0vv<4A-aLN0bvQclD-p@ZEnZ5t=C4`0Br1Sow4s{2XUBFbe zodKMI>Twu9&*(x@>l>tW82?y2YDK)LvDRIk+SCCTO5!jeXx_#DlmC}ntRi4^I8|#r z@zj^p2$MNNmJEJ$2OZ%PH&Nst*qMpzriU-o#ti8%+dW~O?N$AoJTR6$s1cL$cP_|)0-u=gd z!m?#knqu?mh!O*;on{d%$mpwX!xPIWazSnaw^C5UhUt|7v%*nmb_U0VqnkTHx!gcZ zz;!)a1i)no%3TAmUrBKJk$+a_Dsqz`zQ-(4kEl5$eSKK4r1@=svb6du_~h`J`gZwY z!|^ZADc*72Sej{Ob0H4hny1_3cWG2VZ6lxPZDZcpV-!DmSv)!ZrdsluR zOgAh1@bz(sQwd^x=hAoOIq8T!B8*5wHTTVyB!>l09<{+qi$5N&y%sJj#6Qm+Oj`fk z=HQDC1dPVRWL6xi=7I{kbqDF48fRr-TG3Kitbv z&e!%#N^%)8e@B8Rsmby8Y6rseQho%>mz^_UHXq)B)A+z;KVpsKYI<4c!%pW*8uE)S z;l8*VFk4 zP-Ia=1+>S^R9rJ-B==4pbr^Nw`;t?AzSR4x^>G)bQqofzsY746V}MF`9okHO56u!G zS}R?C1pt9fpg#+i0Ojd{#(d61BOxqQG+{qr02Fpe%>8bc z&VM}F>~mFPLgvj(6NXBd=5)xjwivty3fhx>tnz;H%bG}f$aib)`=;J;;Aqseo@|Lo ztN3^FGE99w5H3@ALSnFNK zHAaoI|7rap-OpW#T~(#uahg^U=tX%Y4Do#<%_wcwyG{dLd&YQ#-B~bMMLKTFL5`c2|Mozmq$+%;D7u6YdFSke#uix+WXg>z5Y1}U#)uP zmEEb%D@io><_>cK=wQ>P_^WYjQl^%EV_Q#dO2?mCHzxgg<0^#s?~q?2w-BD@R-<3^ zLnjTYpz#mLMEjex%YMuG5!}}J68o^61y5Ib>tERZ?;|dbz}Mz;w0e(@!+TlkZAU&+ zcyvwdGoQ?wrBCwrjWt*_bsYjJfTHW~R;Np^`?aUpprCJ7K1z3j#9j11ugW(+@bCJ+ z!4VUZ6U?*+{I%?9cID?{-o4=Dc;K-@V7)KRNapVHom#9g-r%z5u>x1{A(~tBzSA=1 zh!$|z@>6U=vogBM>DAV@!{&eO22#;cIb&MUj}_eU@SwqUHLgj@RP);BmMt}*3kK!Q z6Ape{D~ziK+Te!HFK@UQI-`PK;|=9Gte{yqz0oG-qy3q|rg1kJ4Q51KUvS+n@Dmu* zWWUjx?B?sAE|Om&HY8>J%F43%OuqV&3PooeIfJPCP=S~r-eC`2n*GncP~;dV-?I6O zD5eD7%Q~3sEgII#%7~dP7HvQlvxt&gnqvQyfeD$Za|xUEo+l$xm(Hi9!M0X=jd;L6 z{f_5tACo2=3@a{B#Rr8(7eahKdzwcVtW^D@3h&`U%U!rrkGr;QW+$5skX#WyuWy&X z-4gO#SdQAt(-e>C`RAtkfiH)btD0Gd+8IJjZjG`H*?J4PASB5Smf3Wgji%5PeOQnb zpSRod|JNIRLj+iY`D|H@N@g@a9HKW519q!1l~5nzI&f4#n^)z5y4N&^VHB3h1o~PX zND(0e=v<;*}r!l7O16~6un$)<|;yJ=$r0C$;6PdxH%Zcgg%Ce914K6 z)Mz}{SK3J>OiOWsze(WS-U?~KeR(ky8yq9B3?IuWYhgc))%0RbsCn~R)akstLymnL z26E{-WGH{PJ$slbwyRl!#9ua7!r^dkU%MnxH>mYv(ZQTf{rQ1F1*4nYPycpV0kceU zux?h0oYgmXKY1B=P915e)L^cF_1YU4zC=_m;}|1f<0DQV<5D_W8Ho=BrE6u2C91r8 z%By*4Q{p`N^EU(@FHbMojd40J2C@5K(xO-%+`jd zYPvfus@bgM%G30}>a`y@QO{##P}WhG6h%tx7pGd>avDYYRc?E>^$k3kr^|!L}1WH`Q_vlx6*Te!+rjjP%KyZ%yExeMY;n z|6e;0gv5Ttb5N?8EBqmg|2tGwC_*BBe)$V9?}7)G2ASWK2-VGFM|Gz?q)USTLZ9fN92GyFM1PHBuWlH~G}w3m$I2B!|1)Ytyg_@ z<+_nR=>(p4A~~;7f+B9$Ejw)Cc!1|WQy%pCzu(YDX|O{G!%EC&Juu0ge@a|4EVa&# zwu)ZHJ^==XEGa@R`4J>st@>Ulb)72f34~Q~NRN8iDy?nD*#8uk!cVWcyc2DMG^P)5 zRPAL!G?KV7M&j@P$G#xV!A_xh)yDjzf}*-!p#qlGH&mR;e--98Zz>`F29YS z5({5f6*$(%h0tqb5>p}UH$dYW%zs@;)U-|VYH;5+a02a8nXh` z5cA!peBZ|CIhE8b*N?9iy2svVzlexY`nQcMTlp^+Z8hGA`Yvz<1KK$vnoH$_uqWY5KZ-pUTFC z@p3K2mP%;^QbN`O*d)??3fBYJwqIoxN{10mNE7R&UdhPkv9r=_XyP{6?s$uc6|B1u zQ`va#OfsxL8PqadH8?g+m?8dCg8zsN|EufVb?ax3hx4RGm|@aWvtq?0p+O+`3P`{E z?*QXJrTP>nc(9Y+u%g+|e{RR?dPwKiwHE9?3V57wzepwIsG(g*D;17+<628<3zbM} z^BN+h5CeBMhXBjM(9<491)e>7^*96fA&E}}&3A-rU%>B;C_Gr{@r|;~YV0je4^fS> zH+=)>AG*QR>8)Wgwdg+PmdQ|#!e&B-`ebKLUIZy~Of#1i6oAmf0 z^in@JGHx8Qgo|fPBcDYD?b4yTo_u*t{gWoYBqb(N;CIMFqmKe(td{h_=X>}uA4S%s z+nHoUL!L(X;U=y-iT@ws-ZCo6c8&YKRTK~<6_Awf5@{He8V~{L1}PEgu7Odyhwf02 z?rxCohM{}tZibro;@Q)wQjR2l&jQUJn|Q~XRf$4V=;Sn@Kpg3s!W4_$B1CV2`YSI^&d z&j6%}T>#u!0+_{SfOd>F`_L~|p8^H2T&4NG%dbzAH@}dz?t|5JmF6U17INpK11x0C ze{^C~iuZ-4uq(uE)BoqT_&=0&;QJ0ao%;$fYSS@*pGC(;rbgn^sFq+iS$KN;Pz#Kw zm8`{2x_IiLm_dB?9>zgKExO*$6kBTTs+}L% zC`+ijk;VdO|GFa=UTBp6RcO6+aXPW`%GyoOSzYj-KAq6Bhn~jE*e5x+Qvdh!|8RdS z#XPMhvj0!{8z^$u|LZz$zZXS|z0e`xrzTkreFqmCwr}Y&khl~V)FE=A50KVqr&$?f z%)UEJ?F=3h3t5TANwUievkRvbJ;k5yhNbdcd|#6FJk5h)*INWB>sc_NFzW4m%t8oY z{tacz{(5Js%IBYZm!zKG}+kzgG>j=sPxWag6mGbU>12ClxM|vN@A)Q!8nxq-!hTi zeI(G1m8ii|0$GpssS50|8hQ7z+i-2yKzG{Ra8(r0G)xP9#qC$~GzOp$57asBk(fUt z4A&Uw&SvN{^-?Y}qBz2oIr;(mXKb5j9Atf}c`FYbrg zkM*9-;j^#XNQXz0`Cymf3%@{ef)%i(j(gC_y*Ru$x~NxZ$n87)&63OI?U%i~6?oR# zau#B=U5`{L`*X1vq|TOyaD#E2))C^-vU8+>MGsP%>tyxJ&4=HP089>i5pkYF4+_{O zDmcE0Hlk2gQT+bXhi%yvqs7djCrG|IdE<_bsy)0;Dj#uRbYk z{7*Rj2RrQV#O9$iFv`;#Szyzm`Xjl$+aJlq6(}IMb@aoO8Y%_fJTe(i=1GTW5j;|$ zo21k?G*PhU%0`zmRE@*i4~De89h~59E-5Mg_K2k^Q2#eU^oUC6{fbm)kY*24m2yZJ^WDm!mz0Gt-5_d;QMjuMDb8Umluc+ z_8DF1t&!iAP%l!Pq?*e)(TT?mv1V&(2& zg~{qi_1Cd^Ep`r80*BXXjZ$pdAp3Z>v?EP{FXt*r;yom zoGrF~U+@xDX}W8sn(cM&6`B>d8HM_`rIkD8$68dS3jIgAIZJXM9l%oqE>{0%o!?FT ztBvc42|O0ep(*0Wr7{v&H7vU}blA^mcx~-~o|UM*!)O~H6=h`SXK;l(q5U*ZtGdCU zuV^yi^b0^Iz##wJZJIb&;h7UWP03syI78vx=>zicWCcl~ExH!Y^4e z)&C(?z5y|dgFkDx#v^p>3i%X4MP?d7W;{bR_Ld;x01cgf<%BmTAB3wo`RLDbnNRYh zy7QjBAsj0DI~RJs9p^27t}o}!R@DM1j}nz5)gIT${LW4%qGukhS&z&H$lyPHhaBm9y;8)co7MlG#!kZbpO%@Xig&L((gbz*JA1v0_2PJ_|CpS}KH$|Q z*W|uRE{+pCw>Ut(-S#6DNGGp@k(wAZ6)m)fNiIT_7g!8=k-Av#+B!pM`-$j89PDPa@|a29BSPWgheBRlXlgW8$}#s4{>vVvb=I$1au^OPDn0^EfloIU z3Ib$$!DK`OT+~4^p(MxZkfKoH2?io#Iy4a?ftr9WdC*yrTZptEvzm~-nLqP(A57=i zNW}wEV*6_~9VA9EPsG*RrDMJ_Op}-I0x6+^Jtuja!|szEBv{5t`N|w1x2qK|Wa$#! zJKCe@<;q-7p56_Q<*BmljAjP&ST}9eB+n5`Yu@{@T69&G(^Lb)D}i>!G+msI(k~&S zEyY;haLF)zk;}Tq>m!%U;MGbZ3X|*o1)f2M|9AWjsGu-^xH+0@UW5s0)~6(r{9ae# zwYW?hNUoov|CnOVqJDJuWfmWJMfO}vNL5jk&nvfiurOT97aPacZ?bnKoPfXDt&R3= zP%eAAAA|El&s)C=5OGV4`8nqA<(F{7BTI{CTO&Bu?KxtKSck>|6}#6=%D?Y~Dn(#P zD?>rV)_wo1{r#=W9Q60ez66x4Oszt^oLl{`sJQ}(GjXm;+fodCqS77XJ9&8TK7SW& zAb{6;zJGa=(S^zxWI$n|BU1P+9JqT^iDxO#0sTi8!!4_mX6U#4tAXLxQh z=IKU-qLIJvg1W#LKS_H1pOXtHCBe-=5UjwbL~m%H@}%S#if=k*F{*>8oH;jaz1ym2_|h=Ro@AM^kNWbZF_QpT>1VZN z;m#k_S{m)}zWeYm^+qT*ep}EmV#q^TN{e#$gfh<8{cDZeW*YxlW4Ze^wgeF!^#1P} z=lyGq5kOHS57$<$25XgS9us= zEr<`cJkI5HT4TT#Im4T138N%BsPW#aDT4iDWwC1}g09 z?KGQjVL^wF>Lrd4%2w0IVJ}$Z9afpeY=0DVj!N}p5)T};F~}2~vH!yYprd=~NOP>X z{}$c#F|9oWjm&(l-JfOP*VTJ+$C^Jw zsyznO_oerCWaiM2juRFvD)YlVsDg{j1g4^O<^@po;o`R{`&#D|x)YWyw5y zvg6d70WUde(v<04&3VgUZ1P?Uk^&`6F3@@vS0Eu4qE49wwInV4gSmw9HVxFLUi zLZjQQd$6Y3U=_~8D+P4lrHh_7M-z7>>*!cK{_A_5f^}Y7vh2|)y6QMLb-NOQ{uzE& z0?!e((sG90aQVqg*HRiY%KjMc31xACXjrA&r)R5xT z$S8phIEG7rTliJi3!uR)I`g-hmjj{E3JBg!k>yi>+|m*dl&YqNbTp~}>(wO-h@t4t zfiJ(Rk5Tmt2^%MWBQ;4IWJCGvG- zLt%D&5~`Tq&a=&1B{(2BMZ!}Q=s+SxlAi`cBU?~+;TwO-q2#e zO|Eb;ld==J3!SIH;Ku1h!fzA{wHz}h6GOH9-F3g1#}1S|H&>6%%Ot5J)tXlm3DNC_ zv!=W>>JwW~JkolurBz73XED*hA+F%NsL;c)sDV4X0QcbGn;Y9bw2G_FOd{IPlp0Mv8mQHVmfyPbTs&A>;@D z`&-6OU98)S)6uQw@-M8g?nFQ$xa_SBx)CqNdGKnv>-FeH(UAg7|65(JxeNxx)vzX^ZLSn~hmEpSh-ddcVe zS=RmYfNywOu>a4if}Xt!al`SN;yo8)`@sBPbC_R*(m~vu0*cG3TL$Qsxh)G|Cp>2;3*UE%Sn9q;4{f+0O-N3B_vc4|cqpFpKHh?W2`V+` za*l?SYOvyYO$G6#N4{Qp*l36C^zRFcbyB{WJjtlCQ&tIS?R(So$+Gx^{G>;=h03Se zf_HLBr*o3FdStHIp0juGJ$Hr9x^P&hh@HdhM!8Vidn4vKScfQe@|RkMlXuQ)*VROy z#ezQ$(e73BoY6@WSlj<#j^efxbZVJjt*l@Uy>wKg316gbA9UN`)#lvgP%;T^O~2>d zgbIef;dRpn?HMIqjlQh1T1yWBrHmIWQiBe%JepGSR!_8quT+ze=WLQq3yBw^gEJH^ zz7rP1%q&hlHGGzxq|MLJawEy*n#S}tI)yc5B0Ku4JuOc_o^La9Uv2{m8xr%GYwcI$ z1l=0J{-UPbUQm#jrtQ#po@#j&`c1dio&bL&WsJ*NIuq~hSsE!?ZCKYF-h||yin^BY zsOeDiNvwOSkzCu(`{E5Q9I{wf-CWB5n)A!N9sO38!=u02$YgdhJpojPuDu~HMAF4DO!Q2$ z4u6>`C*4N0HFuQ1S1*onk?DF5m_%$YCuI4E#A0I@!PZz8Qu#BTAt`0-#Y+q zYHHyB8=A1)m+G{Gk~I(P^{WL3>V3$QzD(y_<5bYk<5UeY+_2LpA6Exk*uHK+M9uv8 zI|e?4*eQ+F>y?VDm%qDu|KS6`CK`GSU;o}`)Su&i zfmP2t0JHaeN3jh>G9);%kND0PJJlMxwCsPT(J#s6K)qd^-I@}@!n1qR$@!xltw*xn zy$3Fe+xt4HFi{k=yFJc@l^=;)_PXJW|D?E-0YgC_gcQ-{%3mV3a@yXu?c|O)%yO$; zJ>C+xY$eDx84q_6Bs)v0(c?T-i1-}Kwf-@y*{+g}_^6td4Xs3PL#)g^DN})HN1e68 z7M4Qngi4IaqcJGh5a7_-qZcyW8tdq-&9Ge2A7q!<{BSLQ%cEazTo-!X#^oBQcsw#i z-yo%B4GEQw3)?aeCI91gyR>F_;M@^nz`NY@-Z#Lw1Fvj`5>i=tb2V)?U4Xn-imgAA z52%})Wa?#Wp$YvVF_qKDSN2ViiUkW>|KA0H=tuYA2Rg3E|6zm;d-nu5n@oN(Isw1_ z6d)R~36wxEPp~xKEg=!n_7ZTtz@2`6_Vyw{EH+#_dN z7nP}|FLA@OgrT`?*g_6eOs;<9A?qGDKpp56SxM&?@c2DdUCf*^M~2Hw>%JoIjjRZ3ANGBCed?n;=h(B5rZjou|v znfH3pdA805q3fN3u613qstLpi>6S_^p0aKB5=u(g=1#7Os2(G{>qE{0v!S-K05Ral zP>KK51^_@ee96Z>TgPLEZsyi~jcC;eNKMaX_ed}$p0|~Q2|bV0lg?*&YzJ|iCboGu zWz2DJaP@Go#D?X3j*XW?QsU|VDj1_q;owARxm2e#yZ^q z0~NWTLxA%!KoXk*KFPb(RUJ4-mdOLjzeU?sA?n(;T+d%KShvai#9zcRxNWeHea-tF z@R@c>7WsB}`GA_xJbq=n8P zEL4EVO{PfRX^UrN2qnFo7Y^ep^iTU1FqH1dDXEj9>fPK``wRTXgl{ZVKC7312n!T&3;OhlFP&8N zSq6z}2*l3l)GGpt5$YvMBtdHxE8Odgt(}NPp3Z+98AXiN_(zcfo>zR+{yL=n-OqGv zr!|$^w+wC=>Raaq-V%Tp~@%a`wE zWH2=^#pzcsn|uwNv&{_R7-X_-R4Bm}GHL^)Mn_>Nrs zbxBF^r+r%plUnTsz*+o)+NpjF#>o3&+)sD#j&-LgBIGfqnb?%=w~5w38MH2{CIT62 zWSA+UyMC~1(RAY51Q&+<35WvU$X-U^UvxdD*9az8z^^$oxLC);KD}lE$zj{F883c> znOj|W{Vi3__3n*!bL^1gQ?!T5C`u0!Oye0#xvC0w0R~}DJ3`y1Uiynz3xV~4@9{}p zC-q(#YBvWj2Gs6`x!9GFRv zQPM3(CH$I@%p{Qd?``#a=(}!zC&jHx2TL80e6UIou#EB2c+lMEgzN>W9qA>-7;#3>#w{IQAO9<H;elBH#UrHQzzrUU+EwAi(}R5H>z?dV_5*)Vy<;{0-cy~e&~>IMySNgelZfVu zL`PD84xw8b2+~{Bh!EqX_zQ%v`D?kMl?#+8AUlT5V-T6dW6`Ybk|r|kx2S&TSytvg zrM7LUfC`fhHoN8ZC>*P{4l4GYz+#vVI?OCpQ5#4DxIj&&`f@1N1ETm#ou7TB)ugoY zAY~2y?TNR-2MzO{L>jkM^**}WrnAw_`e|!p%i;M215F#?`Sg+Lw21=!+ZYd?HF0fx z(8;i=vu2A>ck6uzdKjqglLKNxA`~8B?g!L}WHySQJAINQtS2$Fj#Hv>_wtV_o-5Y1 zpADWjfZn6z-8y>ToeAmnrO-#y!#Z1o>2dW3QZabp@NNxfM5P(N8ez!>>bZa}set2+ zdfpI`xNz-Of}-Pil%W?>kX!deU+SxguTl}*zh29zd18k#xfg0i)^Tn#KHBaQhc%iLhBb@d zBQmBE%w&?YMH5f?#|5F)-@nGl0{(d)^6XCG_*;MUwN0DLN;u@=y{#sRSZo*(q7B$P zQ01)^TVFD5eunU7371#4U4Qz~XXb%9!n=pj_?3x1n8Gl#d5*hVJlTObBlg>CdbFkV!R;)Wo_j*R&JV ztDbkeWp8;u*U--$tkcr19fEy(mZf_kqawS~6R&qaN-pZp&2Xg2>goDh-!j{eFA!Cq z_RLxP(-aTw-n>2DZ^Vk2k?zDc8MyXfSWme)T3z=1@~U2Q?|8MuTRFTIg=_@!%`m`> z`Wvh`cz2<@j9f@d3{JKV3!hjH(APSdmk&LReqbk=fMGFw%qUq*~AJ!ROX@-$IppY+q4aqcu>i=^I_sE{Nyu?R+LccOqE@ z0nO$Q-tYOcf2kh+gM#DqxBiC(N0@T@Hwvx=Z1955FQNgVj_sg>Vaxz%ctO)DvKjmw zT2VN^=pFlQISb?=Q+$P>iL=XT z{>jYBtTm(H8 zm&o()bH<%U3m&z+@Zq4PGgd8DV&Vwf1{anzCAQr(x1FKD@g9Ht`p}MKEb-{ zHNmy(=NoXNTrBClgY;HUw`#X`t_B%Q(m9PJ-c$$kQB10{ou0bR&11F_cA=>DaGIFO zmYwC_>!hZ%rc>Q)f;NYaa^7L6ggetx8?)hbwaB^Hg^&A6ML17c7U(5;CajWx7oneN z>0ds@2uf+gHeqX(H^HDBpua@3bhX)68sL%9Vx+ zJK1@hOND+FxFxSo2B)(}onWz&BTaxWO_pkY9YYhh@U_m`{&`Fc;Ab z*4amaFlE36qT6h?&9k^~+&fRT`w1?*tKtV#L(7&TK-Wi5;U2aA8?m+j5<-~KevtnN z=lT5SFQNS!FAgSv$cP^CPFe3WATDeOFSrz*DYY0(7C8U&2q(Jk^Oa!YTeHa9BN&v` zF|6=qi3qMhU5ZUH4~~$LOsu?1SL_gl0V%wo?8zRwMid2l*WyK~xEC>UiC(`$1<^g? zHgHX8bRvq%XTxla$%fn#MH$xlE_XL^q}BfxR@VN|t@R+)eDVbX2hkz8e2LTwoiW~i zZ%2CTzxt?Y%|2Zrqh!_TfIBS+$>VA$0_250-RFk~E@Si2RKw%<+d+IxgGikjvaR zRQO`1NiQTNFqc_bskgV5?)66^U$1af^CnLVVg0J zpvXwkmxVF@cvc~XuU-c0-EsjO2xWW2?u=l5WFE!NTXxn}t+SVXjEeemu;cDno;;1% zH$z?$Z~Jn@zCClE$FN5R`S?74U+nfa#>K=#C|&;EM@pA7xpz;{%p-3wlBm-)YQ(M7kl;2A2%bpAh*pol?3snQ0Kk|s*n7HSoxu{&bi5Z<}MP2 z2>Gk3<204e*atLDw`MKX>Tz-|v-F_)9*$7cqSa|YcYbTb`VMwL1mPE44JB>e*M{~! z58kO85Y#L_xx?GYq%xj(hWP0j=ka1y!p*Gl!WF)rBwD)0En1BU6`mF(KhZXy*~oE8 zUL0313Th|abBM z(Hu;7!PkU|knaMv&l^RxZh7maV_vBbl3QYdJg6bT*K3C@7rh}Mx;2ClyF%F3;OAGP zGg3xldSH#6TlS#%9??YrWukq7b7|IszLVtMh*&ox*Ymc-zEmu#>*fI;g<{0VNCeRt z(@EqHoXuU&O+FGRm8B|6NHqg$S_EO#7UW^H5}hF8J2|$QOKaxrcCAX9^X&UoU$bn_g1pD({yU%gDnyDLg3n>ZN zgYM0y1{cZhXi&|@NB(-s9U9I=^vb#rT zT3yf6CU?gZ8q^ZWuA|#03ys=89=2Vc9bVt@%BrwC$#1V+cJ_Jah3Jjt-14BHQJMqO zw{sghlgBxt3_tYmjG!og`;#^|cf2w31$(re1%j3xV9S1b zOamGWq!irU43v!DY0Yvskbs5p`?%_epLMjg&?`QxUThO=8fJOYD1oeCIGv&4 z>J6q?oTAhPMTmpi=pXms-7p3j4>IKmlN`~hC7q0+{bl)r{7$F0r8`qY^f@&pVS>O& zE<5jf9_6GGnIM`d(p=6GjS^{cRWdk7Bd9yWa@4?x`~L#q)v7-hA}`A;;}j!gjBX$X z#$#|*2l;)c`iw#R5cuO$6&@#GmKIq&ewkm(9tVv*kMs03(KwxMvl<-M_UePu-f3s{a_+iBVQIwf*Qs}W1>?monR4ALm+dm%@^XT50B5wk+kC8z^094I z-|X2EWGJdRK6w}O>*6&IQFweb_k{DV)|Qa7Nz@FvTfG`X_RM*gPeF}Q{K}tj8WyNV z^C+dzl;pO}xWQ)l%ZQ|^Ebo_rBo{SPQO!!wT)B%??YA zMhm5FpMrQqeCdeW{NORA{EfnJCtx*O!V`6;F*f=<2E+^WvAA4SZ6o6Tg#d;#@ zzzkJBb2w|Y+u3&VehdvltJ-RB)1`gH_OZ;|G~*<;=B|GRwrPL-G5~>4{q(K65mOV0 zO`l)K3)p}8bb#$#M2~CT+@hG~s z%9<_7TY`#~(J`twrRUGs@S)td+^WAU^WvV|9O$Xu9E_~xPn^%&fB7Q93@Xx2^kLo0 zSmmH_=9wjX5v%Vere-iC%cV`Sx>3nPUgqMdO6v3s`nl2*ImZ?wv+J-}q>^9DqMrNV zGR5IGPqN4TY2X+k{ql8&6iv0$QNr$@i*w3pHV-5GpMkE8RdXezF@ z<}IRA-+eqFl^>1|0E&qKJ}8)1YImwTXIE7wZ#I*nepWtinC^?Pl;#f_qMT+(kHk>$CEti0i||dtQ0|dR$4rUWN{JQ} zv@yrjl*4K4<(WEYwV9jqxxT8IFaAhA#Cz04L~_aMU`%dQ+QnzVZPk+MB0DP6b9~ ziu4Ugy=L$H>T9N=B8JoG{7(Y$k{^ulqU-=4U`gr0%6PZ4y;xJzHD|Ravbsp8WBX2{ z>%|v`XG!})8MZF~SeMnEV{-yS<-`SoSAx7O-kFSZ%6WWdpjoqKI25Ihqaq+9hx#~k zb91+JJy5<;zqSa8R@Pyc_r))Rc@Jk6e8C z_BnH-Q~(zMhOos|qs8@neJ2c18Zd2h0S~EF^X=1p#4$iLsR6buldt!?RfPf!nrt;` z&&y?WbgJz@hE!>q%g>7xJ_SIAD~PIn_nN+=rUVDX;BwSKG$#E4u&g;{r^E_MApx3% z0{{aLtV#{xV%h^x{ElhR)GOBr_a;Q-i&9Tu3I;a*81VBpUrWjSAvDygx*me07HU;K z9pbZJqydLHST{u6nlf+O;D9MTD!efWu`YxGSOp(Ivd|!3x7`Ci9ly7=@&FTtP&FxT zPWN);!}=vJtmBRkT!7Ww8FibRW|Y}S#!PRl+_8P8leB8( z$TLeGdEP~Hqu8}#>pkCJZFLBRw03cu_a!Eg3A`ntD` zo)q1DMt29FC+|Ygb@YN&)W57qp$1UD!sF&S+`3SylkmbrS9;;dEAj^(WT+0yd7UV4 z&(%aSh%L#W!*l`&aRK6;c%R5G=(*?FgZ{DngRSFSAdIyiP9@vXQaQhsn*ow^2-L^I z0+AvxZBPpPW=7uoruFcyEIkI{=BE?eR~h)I$aMmatlN#_!#Z&yO3iNDKr&s;j0sOn z&zr&e@n(u9SLF6X)H~*4S3Z>1O;q2BZl%%k+3g{LJCe0s2&{#O(W71pTkg?Xp1lI%^huJWxp zCKE7d&r#c*+U$`6qhwQqk-mbl4)MBB8xf81+IcjM7+i~z>yQ48DHc~C-%-s{`0u+% zgH5qGG@gKkh05-z?afI)#P%?D}VuT{o<9 zTUpkAPyBA-g&l!EPOFaj1kMwbFONX9|6JZd_WKI-HRWegdofzwJxTHa6u z*RTSU_n!YqY8@+3dTb<-9ZWoZiK+7E$}C>|Gqq@jMc#p`0Y{z!`C3OOiK2(ac#yBo z4Bwe!@ueaTHKE}2Azj+}A8Ea<1e*5p4Ht=G5i`n5Mk1a7us>%u$SaKJD9E)N^-!ZD zjP*1iIueMcqQ6&{{ZBOY4{gshsv2VyFvxITVGpI?Gq<-z1 zvOgWKoD-A!2xY{j%xhN@{Nk$fZn21LW|hLddPrkJ1C!8BsAwJCokovNrr3mFQD0`R z>C32fLnV27Bs;mB7;%8uj#%#^^qiZMD7hYU+$ZGL{EpCfG6aAzbbAfJ6yjMKEi}0P3RZf5aSA}tG990IA-HXp{=AE4 zW_)to3vj&21-Z%X`?;*rJf7}Lb3ra`E&#lhpNa#uAi(V=c%x8t(-+5qQ@f=>%VZ^{ z2H2O#5Xm3kz_z)HG)i0NZM(<=^UNoU_M?^MF?XsL-1`c+kzT?Qki&mjyd5+>9E%{G9*;y zOYTKMqFEMe$sA3#mSlZ&u1i_rVf?%r2Raq+N zlDXQZAFJi})N_{g#|`Ie(bF0}l{MbL@cFq(RCWjFfQ;0rescceOn;vH=|fUu ziB-THtJSQBO?=Jtc+AmO$hDY5xb;s+J<22m^^kejP@luQQHRsV_!HqQt{93G|$~pJd-XElFjVe0xDl>ccLhoOn2P7(8)e<-SJ%xc3qkrWD`xrjJ!-^$Yo0jrQU4)Mvitrwd%{A zivq?64~%Rh3R|7SMfbTm9A2n~Kl@2ShfhIW3e27@OrdcrS4)>|#(tP9SeN6>m=6URwujIhl^(iTOQZ+TDcxm0yDDm);_exaYp1r~+w8sj!m5j*LNTf#vgg z(;4yfqf^fG<_Mu^8ACC`I?E0kBA}OKJaIhqZ8ZqlM4AAd2QQ9|KPe|Eyl|EkQA_w; z$JT*wZTRn~*PiMVkhq0sfzYVy4BqGb7*+zryN9@M0>J<@FHUILXM9MO%>44^yPKMT5k0X!+F|M9HtJix}1s|j)Qc@FfNYG{q*+d`zJ0xL6y&t|EvJ^Y{oo)5<&{FJ`W7EGAD2 z|MpsH;4CF{Gy3re6Oq}%j`J^}mrddB>)6ecC{~dGBrJluKXH zNCj%K82Gpz|JC$wmdLQUMGq_=)(&z0B%u|(YKv|3)ISrw1nu%4q_w6xZ>~!Y!Spvp z1)_IT9!tZxO^_L|Rp(Cb;sKu>?QP;gv{OGt{cu zH+`JNf)}#dDXdk9=?>bc*L$;k8pWj_1AMh1m zyWy2ZJ47&iW4k+ki~<{Ri)ELob8Y^5ply9_Yk&5y zl{4oK;U=dPZ6WH=1Huqb=F1~GdgD?(U{=Gm)6}8|5x0U=fBu0Mg{SVZN4XuG@#5^~ zn9XcaSq7An=y5Xe|Gyd0uFePHWV$Sj>7(r9;|Qr_$&aVnH>&rW=3zgc^Ia1l)6Q5vGS-Zs}WD_g&3iL5&m=Ce)>6gpV=C>QWS1p@G;;5g=3IDzqOnatLHp?113UT{3B=^N72>FeuirZ6sgV_P5aEH~xzECV(!o9mVkPowC*`q16Q?ff|-x*B)$`- zahl=2oe$cgiMLV&s$=OVn%DMen7ZTAgnFw+`Znep&^^(qt^IA}>VrJqZTxN46UwQN z(5=Xd#K!=@@>A9ty&VbVG3)6?xkImek=TS*(V&$_q`cvWSefn_HQ|*>rT64zPG^hU zWb=Xjo+m?AM??zdq|5yMVH?>XTHj>;yR;^6Ee9PFgHjp%q`!;IpD}h-FrtA?Sk`|} z1$Zm=tUVdv#tdS;Yx9{*a-jLQmuJA6#%R%a#4b?JO%iZ-!3T|O_4BN81SoD|;CI7W_TVO6)4 z^&6WY;Qj5@85V*rj1U5hF!XNZ$J7iTp#U0>6?MQhg$ZWNvxfuK6fz8H{9DonwQd@i12EkX`UxnS^xgv8UWI-xJTrjjzwb+=CvEXjtIA>vQ0q0k+g~~RiypT) zyoT51sGln0B`x%7EX|84u1I6r&PIj4n2z@3%zqyM%qfJ8_>{!Rq6B+^dz zO#1i}y3Pk)#EV38%C<7^C9nhJQ_x-dZx4uBZV%+SZ$^AdRjkYEcOdV#9jm^cj@?N& z?|9Xg9oSTMnY6VD&zAazo|7(VQ6RfM!(;?4g^_+n`@C01^;yCfNj?tVG@_Hv&0j1o zZzD6Nnr}AVQ|ak{yIRy2x?90yYwJD`!u_pw*$CZ$z0zL}{6el?DPNVmR>Asc$C2jBz?H)^r9lK&7F&MFf@0a=X4uy54^d>tUQ*9 zo9a@OQy^uI=2z2{&6q{Fu~|(nfvrI%{l4KH2Z8nar%o=-KhiT$b^fz8x!hd8vqjkD z3@Vq(!8fJ8sHm#q%bHe9SaO6DtI-_N;)+GR-dA5ZjxgTX=C z`wFue_G%(7G94{h}lH}C;5pRbqQ5W}yST}45#!*RZ z!T?3e?YMB1t@fpAu;{s;7v3E=qD1_pcRiG3_^#RI*8B_<)Dp&VWE=Lu zb3m`#7l+qJAe|&+YDIWAG#STTOzkp?XwZ+3$rUXmT=h6!Tk>C}=lcpY<17X-70bm& z{^~yxBX~0;%A+lMLmbypCw7^{vKvMmdF=K zZHSiBO1Z>QcdyPUPw>L_>ZMia)M~c#OjJkSbOWJs@5)U z)ItgAl-knLB`L6_8>G8Y6cF5WBi$vXQYzggT~h81h)9QYcQ+gOo_)@F-*e78?l}~uhHp(y5%zQUVG|A`+-&Y&4a{!^hy5cdZ&*! zoYM-gD}Bm6CsOU~+JwM=exVxdpDw_MdndPz%3hrQG<)aanYQ-vs=tz-QdOC6DOt>2U%Cl^c~y=Smu|?IAvDYtIk8cl_Ta_Aazv+4_Pl?8u_gQJr8pHk z3CQ|#zOC^El&(S14=+D65kJRl0kqDk z*u0+c!>*u{ZJ_;N*;<_6l6g)Ja^IMe#S!Z(nX_5n@XZ#n*-jr7xo2v6B{=&;mo5A6 z_(SQgJQlDh+CJ9Vo`Mk2b~UpOS^lM?0z6so`MqI7q5KFgb0*GADHkUoHvOvV##0bu zd;(ngk9$K)Ph|^AMS0Cf#dc+NS+)7}SfjmPsrrz6Jt((m*EyNZJ(CXFH&7?{`|SUc z*LiVvK>5`WBd{Lo!oR5e(}5iR4+rulZWhj~F`g}BV&q=HVb=K%06jRa_b^RE_>K0D z3d&@+gUC1n&pTe61Dg*D?%3k5R%ckG=6lcSqjB_xk*h%Qi^;$#gJ5z0QT*jUOKns1 zgx8=fCH_7r)^BOrcym?Q>b^EAIT@L(VZTjEVpQ&Nd-QBR#=ocg!L_qS#&&Y8j?KU@ zA9P(tr^+l>3LY4(<2cjO96YU&!vP|*n_UPX0vjr{RRlR$5cGSzn$5nHrrEMjBPzuwVFNq z$IsATvU<%A-uvomP~;$5i^WJ#vqCk3~V+xc!g$_wO3XJGGll(*c; zD7ZqeOM=gkN56{*aI>)AOYRdCw(2yB1?56zBmIIo}BtvfSNEbKG4Pi9$hD9syqv?rUB!IMc4Qi5N9;rxKpNah_Nl96x-y$n z3bpS{xt-*9$Z|(%P%WLlm!TQIME3|@MMYfG*P4u28t%X;hKI)g`_36cJ4qI`$8rKd?xnXT@&$$c2y736YxvHs z19ux!xcBlgjnEu~Ft_Y;0HI{0ls&rn|INz&`+u$M%l~6#UrxFXcWJrr;e;-PKde)< zZes}<>lp6;sOwb`9&X8Jr)~|r?1g}r{Q}C%zFzI-LzA;ONr5g((Q?$%D_5=Bjb0`h zNrt~(7`)$;tj52*&rmb1l^COgW>UP@-}E_NjQYbud-kO@Zg@7%NlZG3QIQQn=vW9= z;I$|DeE0^>Iz^4@dluFYu>T?p+>|t3kpYNq_65>Cfa*&yl!BHrMdugAq@L?q7xP!c z(%Bi)nOcW9gBJ6W>#YzIUmuUQ6jOlY%4s7CcYF+6zQY!!`FT|2cT!upN;aV)W7+0> zH9l)UZk;5^BlH_ys*kZ`Wrp)nH0%U&RawlwXC|)ix zT(Y*CdiS8qB-xG`#}llBB}e&;={AynqRYNqCeYD@T-7(K_r54GOcXh}T+e1sMN(8q z<0Et_x%EmEoUbRBv#7MVn>Cr0M=I*=typ?3`*u-?e`zJl(5d~@z zW!-im${f#C%?P|fOjxlS)?n4iO}X=(+eb14$Jxm`oB=?kveW};1x5`nbBJ$(V(Io^ zodV2arcf672veBRveSzH`_A&WP6_WiESW>q@p5>wK@Q3`h&;hvN9}*2fKmRBjp4$T zyEv3&%Y;lSPJJQ=N-tjO>XaH!8M!Ydnu!6N5$-7dXImvnoK{fLC4P@;5eI~mn0kOD z^C=KwJs7GDOvfE0gYS2dkfXy|E~a+;*%|FRtFS!SJ27fN#4Dpduu?$urV83*OvhGtPc|sIZ_g)%0UQV1dC8L-!9cF^=Qy&(b-!k%ebktS!`I? zW1f6NI{MN-oJwN=6+^wrmJU9q>H|1?JS5GHB&+H{9dHu|D&|y7)iLaeCHv{2nZQEtwQ{AE0g=o*&5$Bn z*uY-HIf{31m|Qx&hR`)N4PWJYXtRLJZS*0GH6hAiCL!|FHA))6~g#rrE~K=rD_;rTf$)6qDH6rzb)MkNlJ zKb|KXJ?xRng5UF9Cw(MH#7N%{at79n6qbnwdMmVP9M&0k=hWGzGIk^E-%{>}cx916 zu|0<2Ip^h&tM0;y35XEhaOvX8kX6*Is!wqjs~X414=unRcA8*y|G+BauIu<}CsE)` zO_d*tebjoRMYmMsl$VrbsC`FV*m7?akC0JmS26w_st7Pd)eislqM+z+714l4)O}7^ zeZh)z2b0#4Sk|t`?9ctcpSz&QZ_zRc^PShftDQj-s8jDpcY0(&{+ zO_^MuzM!8<6HN5}JELp|fuEM_0wB(sMoKPm_7{UY&Q;za6Q?gF;w-d(p0#;jJ}c-c zM;cJ?dHQzz4$=>f+vcS}9<`q*mgq0^TIK^Z0LFtbey!TTng=54W>M_a_d71rl_fGg z89_LeL2(81h98rGO?@x7K>fLA24Qy+360J68{eUYyWS<+P@>B{&zf#1ocIdiiT)}m z%oq#C#7d<@28|GumB+7m(RgK5W4f3LTeDQjt!^s4WGQmhl+f0@5L2O6c??dw!j-6l zsZTR1MbPt@ol%bT^(0^3FWkyzI)Cr!m0GYY?EtS3SG^m+^S>bi2Qkpb2S{BDc!rt; zrLcLeE`XcMNJl0^%(b8f)Jts{7o;Jw7bgYuP{+fL)pwAKXWq8+^Dpfeb-d45?qzP0 zH?cI}8NPohd5TEBg>JJp_GgL!Jmr@me`h9BaMeEV7p9tJpO62qDFRI_r~i*B0wuEd zZ8l<;#2+aGzVWLs_Emo$V4v7%0oGh`s=1XOPH_{2O=82|2*O_B}`@MEjv%z z`u*{e9~vccW_UFCf|Q7DPG5Pd?BJawbUjL0IUSBb4o#=9FIbvvPA}(I+ul92>~yBF zr~(SzezO8V<-C%5E~X#{o#$k^xnB^K9tw!8ji!1M+_aG= zCRWtDglGfwOrhvtDa-<+391S~^Y~2uIREsU{PktdYXd>A{A5Y&VsP}h)xt6>n^SgQ zjNO*Ks)8Q0a)m5%9R(>KP&FiN3D)AxwhZmdes&dH=`RaJ9$v0@cEN%M@0l!-M7xWZ zG)JhX?|exRW{gzPiq8<60c0mVaM4L!5XQw=ZWfLLcycdq4JYgd5j38f%u|&4I z4o;H*W)h`At;?Q3$;D3d{d`PXsn?*Rg;DFBYOMWHYVCVA6u7x*Y~Jk*RoixReQ+SJ zA*Hd|`jQWzw&|@}`jL(A{Z{8| z-!%gS5sC$>kx$$2waN-*YZw>v&Bt&G;Uf_tMxI0ZLc2?!zsQo6Gl$IUT3AHIYSbk_ z$&jR8{md~AggulE+wylf4{`f}6{L$L&BFwLKn)^#TJ!EdOLIW9&OtR^AAA~J96JL+ zRSn0GQ?&TIlp08x$}(B5-KAkM0x>Glb_xiPEQ(tL{Bu!|D{!C7_XK1)e`AyLlbs#? zuP^bFRK?CL^_Jo)ndYRSUR#!R}zRiD5JR`ciFmlKB1u6AloI ztyB3zS+)7BzcVoN56B*0ezerUUYUwB8Gjv>Fj)isqPxyYjo~)%^B-=-&X#6o7YX*& zds*=+n2Tbzz|=H1;2UGtUnr2SN`}~!==o|UPj-}(d7(zGiWp`11jrH_B{W1~bNYjK zP1g8JjFPl#j`nKm?|P3GkvXy&giU!I8h8jg95w#65$R!Ar3LPY!&)U9g7N~ZdDFnY$X9<|n8$+ar2 zofnSAXWqAv7%^_S?10G6{BqsaUzfS|-g!)*^CH?#C-P7>cNEL>;XQS@>z?&WgFDTj zapMp>^|iu#xQSqWiQmq%D#f~eyS1ScLbmYuSUzvWk=@*i>i6gEsdSwU?)wA_`}V;N zVKLXVy|RHt*@QC=@fphaJp+{CWiP!a*{}HC$RM79ZIkS>bAyMHU~{YmmQG*BtUlx< zIaZ)@A-OsQz#2Cw@P|>9E$da?I%maZn8nqU;`71p-!Ia3Oe%fR>)*R+k;{@K9qlYU zo~>~(1Id1OHkoGaz-vY=ahImBG==~dtpt&Q3czb5W z$bB6ZdrYA$cygWjd)APQVDep4Jlp+F6QOd+_3j@*=@;{Dq&|^ezi5i$bW6!s$FbbY zSV?d{S z7l+s%mT?+-UmG@MkyYqp{*6_0-PxxrqrBNW`p=|OKdX0R8r0GFXfPv{UBY()Y5-l&P zG6Igl6d)c@S*rrO<)+=X!GidU7&1i|w3(|E@`eh-Vb8~qT(QHyYCrq>i)q4x@ zl?E#=A+S1=c#SX=m~zq(R3NynJqGi(+f=NTO*W8z)RnYcoo6Zjj^J!w1wjhQ+VddX z4qNv17sEP->;{m-NZ9ZOL0`mxWAOedz4ca1qa#UsZI&?GcXD`F(vS*B)=C%&_K6HU2J} z>0amcYjZC42LfZtm#XVkBo`z>u~i%L*Kdwopxjw03nun6=c7h!S{vKz^@fKpR-2Q~ zn$$r0cg2-ArA15C!Rbs)T9u@BgUeQ1A1@NpVA-{N63U`ow0a6nqDw-B^nJ~UTBYsA zM<9J4TYQf!4r-FS0y`q?W`L{ozeQSf;nvV{aL;s_?7p6j{uH8ds~oe*2@qmotHigh zg88n-@YfCl9=l)&o6i-^hICx5cD2i;I#{kR={i!Anqtp=B{u@NY{tezDR{P&`XF756e+{ z$aI=X<^ls|4=GP|Z}SDky?v&;PbBW2VBZXnGembm@)a;%?TJ*!2V5|Pm@fzkFIj08 zWiSSEI2n%RcOvms5tzOM7J)!)!5oTTp>WfQ_0``8-E(r#pe3%sZ3L|Tz6g%VvH%*? zd&p70N;~>VJmBqaTM*V1Si$Z95gC~E*`j%Efoi4(^-wbi zv!h_<`sxG&2B=BRn6ihx>7q|I{W!Exq8*{;(|N3u{T@!HvsD~zpvEan=e3IV1bLrr zO;v!bN#!zT_8BWN6^qVtju+73WpmlNmIEY&Bg+NoD{q4Ve=U%0H%RGjepJbGr|Nl0 z%dUey=uR!CJQ#nb&`1qq7jqkkAe4jNER`-^hBSMyEifl@n}rKgmJ9k`A>U+7sG2Q+ zwsda;o$^%aUgPOA^8273Kn5&4*Yk4+gv*J65qP!=Yt2Px`@1bw-zDoBr-6pg2Ka#m z9-gTLw%qa<(rGwNMh(2%xYf?-^pD}LCHi6u7CPC+zkl(`!vu+>5N)m}GmV4}t37|R z7=4SLld)=+;0r%0e~aWf=%qkX&$tj5jJQyyjct|{4j?Tgw6i}dd(~v(hk2iU#hq$Y zrFO6(RdS#hEj^?!Q}J`lv@;P@@izO!6x@{5(Xm(oxR`Zy?K{|6g)B#|&d$PATkAV8 z>s_N3q`}D&6jxy$9GcSVa#}MuEj_^V_;aCQZqUq07Y2SLj;Y0!^UG!&t93jXk*VC( z-723o+nQ-tddXAQJ)M?wt@j7so;ywXcBbOxL8y+kK)p20m%TAf8`jNBTED}X-6FR5 zO)bImEcykyR9zhe32H{h)FTxr%*IdNs{XcB%RPAUhAtpB>1Q`!^qpNeD2oZ;Ak}qYvZ!*z>^cbfoR4%;+5uc#wMCf`t)&3IscK zH_7lTv@b$$Ud^|*{gqE+oVe@ot5wZxQ9`$!*YA^5$r#Cn<}I@LxzEQAyunDA(a7Qg zHJKh15f_AfD`wVqr{yv8E7WRuAk;wg@8kB-23QRj7D3G#pnqRPAq`X*epF$x!#T*5{V18$eKfzC7!>+omqmK$G{n|EUB05GkLB{UXID9nx= zt;-(`i!!atd~Mia;DK^CC)F-V_v+|W+ARF?8Oz?5n&HUAa7T1%E*gbr``i{j6Cq?Tj z^JS|)fCgzLgoIk|0)ENXE7u@98Ri}T78TzuT)VkErhTDJkNFuw2YsPY5(HI1cE=yv{cupv1y|DA-=Yj}#M%@yAi)++z3zu?BM|?%j`2uO&_EbZ| zLiF#UDVqWMlf%K3CsEmG&-FU`vVdW$9HfP$cBRjLYaYYRtLURq{pl#gXxRM2A8c!- z0!dRfbiKu*k=n`)ud7)J69LDNi|E&qgHNi7!MS@)ObHLSbV0k{Ezz8?1e7GR>LloT z(skFF(ZbzZ;Qn;6GBN5HIrj2(^>HFieBo5Ccc51-3)i9;(4AdJRrxUd3I|EyfLQ0| z82=}2(2s9)XCt{*pqiJG;UE-Oiie)N7kcM!HY<;X^gZPOQ%W;m@fpGY$^^0knLzW%iOOT?`!0cTo}U@%_=iW0n^?MXDNhUT9((yqni2eF zR^VnB&6%g2AQN)FUC)ht&#FS9gKY<*KJub<(9D!0Llw%QLV6Y&K1rOQ(%?8M}#7^_$!BE;Oe;p&TFE>Kx1T4g; zqGxV)1H|l`_r+EXMnRSJu)~$;!7pYO#@(my=g~9Z5MPm~ysU4**c5l$ZUxeGf*4?2 z%c85xix3swip*S%L4d|l2x~lD?QVobODxJsErNhXa2OV2IX34>l1#m)_CD;FYRSfc zd`b7(?>a-boLop?)@bv2Z-ogNIbI)To#mkL-Bgw>0Hb6*p^6|)o(ULbe^G@?H+dXQ ze)G%EoL#L)i^Dd*2dDflA;4WWRp!^%!;f`@Qfv^#ei5AB{S<(sK-XJ73bHYtgvy~| z1oDWzDKT#H_=r{R^ke=}mr~bK6%l-QZWpC(6LwmSrDT7lowjVS=ugJsl5u%aA~#o5T^B);H2^`;$61gRqp35ByCsXW{r zzM4>W!2AgzPyyEQT*IJlyV3aVH&vo@VUz^XA1_`Yc8o4~w-2(CO6+?5G3+LrWP4Ki z`KRsQ+Q1ee0d~`&o>N7x_VShRh@7j{*6*Sm3iTvr1`U?=7t2dCXDWIjj294hjRr5N zbe1ZE+G=PE>n79Bd?BOeoTfvA8V7CRIpt%c?!*%^u)FtCI$@SmwAz83(wta))9%n%E z${c^jvBX-JbMI<`4>?{};=jWZ#76yOY{q6iv<2uVr@^gdU*&E1h4!4rL?7ZAZ}aPN zb2d)ipOwDosfL9rrOh0MC8Dh_!)Y+Y(BuWVqY>^X2U~WD|`mY(=mi? z->Vn@4{8hF#;xZaDi_sBOFpTa})?m8}g%OPJJ(0ADi zBkN>sK|a{Cn)y-Q6O2RQPTWUHWdk+@Qb&OJkja#5Z6=vDn*J+Jqq*n+Lp%t>5Y;p=zDGpg>P%rZKFBp0U78dP_9x2(g}MJ(|-tLqY6NTvxO{mx9Jb+3VcMx76x$lCfiSaIL5C3^${iShu)e;!eXC-k#}T*<}?z>DLFBk z8*|*EUU)VUGx&;^Q{L2Vf|06{yjdcLpa@KNbbHxrJIfS9mog`(-KLZ-b0*TNN5^wAh-7U5m2Zu$FCpD^8z zrh=CaF8h5CFdf({#278ZepLadMIfIcBuh>*^>TO6_yXZfqI-D!GopDWf z=F6(_5W07n5%osvnbM2sd1HX~3rNvPkVIbjT=^@ub>iA1Z)aCI?aH6_;ZUR!AP+M# zd}arswgapq4R-;TkMvAxOkFf;n#hZ+%P;*SkYo0%g@`Q1tGG9@)ZyA1hOS5CX4WR~ zY2i{iGYo}qJd&Yj_bR8`w@^tn*8|CSr-E%aQ|_ef!-abXWhk)-8O${%vYd*D`w$OB24zi>UO2eG)&%R>fEPuALHFC(h6{I z{9cj@)(2~vGb#QZz}M}+kz$vRs70F>W24W30x96xN1#9&keadnhXP3tr9gVVmp>u; z;J>mYlsaiM51mNr>$utu{J6;(e2M7hQ!F(e$Iz?$o{~ZHYy=+x5VdX3=KXF~NmrrJ zd;m^b!E*bAAoLBQ9G8!r>h(qKQz?9}_k`d{3~+FotdszR((hqqG1X2t0d;+H8dY-I z)>Tw&wvNx71wgS4cd$qAM2E__(OI{Ir(=oX(9!Y`ix5iDv(4kftP8nt}n0vnCyOJPKfw@5-2w4yV zJy7y%m&EC`nrJ7tFeA9h!Q=V-HlT|TFSh%@#X#;-njTJSsx}QN`@qkP!-W(JNjTjmwfy~csgY} zWU^avGN4&fn@_j+KTAPV*@u?>U*08s2hy5~6h0dldC9~0LLGp2{Brpi6-D)g|117= z*K3D+U>n!1D?5l-l^~hDKRRnd&-ICttQtK5YDxjuI%<1BiAXd@F!=l5~s&ui zVD|F9mJVdouQ)y-O~n^v-!-32dc#e6FQm?mY4ss%c@nPU;i4&h1^_)zX-^&4XvGG& zbs95*g*F69#X^yq8e)+X4GyfF%@g+=*W1F>yia*M<^$4%&hVB9PGpV}DNJk&(jEj* z(?m~psLAg6ke@y&2*dqyp0AZu>hQxHlLa$Y(?9NulN@;YKUjhhoB9(Rc0?a#&-6I|pqA1ia*fp8p7@HU46_Q!f<5=XPuX1JE| zl6KLtxSaz?w1;Bb*dj6kI2zP7YU0~#s@{gai5^&l>hTLp>IaHZ(p9&Gs3)S#g^I~P zOJrlH=Mwk#drAfMBT{TBZe3oSI3j;_n2d;AY&!lBMq%(@lh}+dWE-y!tke+l$6Y)RXn_AKOi#V_&mHG@L5GY${6YR zrqOi>Pu3k@F#Iuoo36Z|2mM64*@t|2g4fd`I%d5xm^AZzf3M)-YG&NwS}bo`YBIrs~dg)70CWms9&oJ)+DTi~^p=o9a@cd}i0Y7R`=+zzj@%OItk53+<*pFHhs-K)T279lHDt}_8oG!+zPS(N}s;wor ze%H8yW&M3_&gN6|)Apam3Z_4UpFWWNWSqQU6lLUD3mM^X1x;4|*iQ9}-jCaj2S2fx zf<$(|-R?|>CI_bd^qxp8RBtafdfdyNcA8`$a+PS<)?L(xItx{(-I06nt(lHh=AF&j zP1_UTq_Ns*f_O}831ge9OEIM3Zxs@sE%`MUj&Ih%sDfj&yl(~W-6`XuQzRJ!4|0`JqqAQE}%TrdGWOBaX*@_>iDez#muO0URMK@L&{9 zsz&L!|3$|;szBB5ro3I4^%sk1Ji?3E2-ZOzpD|4n&%fiu&R>=N87FoO*XKiE3q^>W z0RDSAq*#&!Z2C4I1+snOR@Yuf0|(Xog$&qE|9`ke-`4*=*HCUur~+u$#~TnkJSy8t z==aaiEjNZ!?hxBf;p2YcW8%GV!D!}=5XCAo={xQBQXJr(67Y1q;SL?K@L_Ta0{E*x zLbr&k5^q^2W?31@(uJ*d(-i&ON8Ea;;y z|2uT+lxJO?jqXc*I6S5iLAR3XsFG;pG7gY0W)TJCMzj>-7A4(tAuH66jQ{_qADQ!X z&LcOb*d!@)0&Ywye=0jHx>Ta#%g06Kt&**fX^ageXes7dzePw&o1ujAlDMka$dE)r z42UnRBHe#=U0&*dA3`Obd%l^hKlZCKDeWBnxRz0PWHoNgWN+0Ox8Sqa*snOc>Q_`N z?E)EjZ^R_Ce&x_zA6C0; zP0X=v13--9>mmcKjs(fx(2{-{o&z!4W_S^ zMqurmBeYQu7SJWY(CRZW$4UEMA{6<__g!T$y~6OqgSXl93h}X82`hA7Iz_tMAi(Ft zWUlgGmC1)3;Cvgodz7}M{~j=cZ-5VajPL#XYG)WYHXI~*QFR^v64`mLftIC}&Toa* z;a$evCt_ajagqb;yk@^}$-?hVf4q40o|l%^dX8?!jXru}QRDSyw<@K_I$c2k6_jJ1 zcV)FUv{T^f8MR3OFhS0z#@Y|%_1)gHy1qPdjP;<$^ANi_wGeRG6wDuxLGXuA4h&Y= z&rJ8<n25hBV$)sYV#uXc8$`k^YjsctHd z)z2jkOWizA(5+D(Lln@fLMc*J>mh_=2$jow8?aL;a+&P=@qu^h*XJGL)9?CVsbN%V z9D=5T1+s%sxz@e!NCl+vg+dB8#ex)9W=AN*g zDLcRZ%kAos5bCIN&^2KApI*{b5jxHWIvf-s7qo-o8zk_S4QNDUH|Syalq`}EJ27PP`tTu!+P=&oyV z_~Q@7ow?gL^3FGvo!>h$8+(*uddLLo zTF)0YoxZAIG?rrV`bv7})J)6iLO*@aaVhd>=o!wEMX~6k;5{?2bYmk0{HXp%XyZWk z^prt;q~dwc6t=+RtUU7!36?+J+n*q}G}h({d4>u&MO&ugvreE8a?ljJz+j@xhS~*4lWeQg;&V)T3=E<1-Q5-nFZE5kLX#s-_n`9!`0jA zdZoYJrP;@5RBBnQSDEt!xULMyy{_PvAPTU&SH~P5>%7}4YPj+VOYHBnrc{-Ip?_)v5~y#1IZt%6xZ+>U>06pu zRGHzyFR%L7^`~loJQAy5CP3HlzC_!(8;$VrZKd)Hxy6JgO4o)Cy&EUy7^UhJcMsz9 zQ9~9sL`zBvv8;rQKewQ#rn&d!QofY@ly;!7#OV}FcFhIiVr~LMR*<6dSBHaT+Qx^W z`!9=A_v2$mB4OTBtRCwxwpHD`;#D72GpMN}c`mE;Y>CVXS9t{58Ov=Je8}%W1Id5X zEmFkiAC{GO{!c0u;m+@rc#ulfX8Nh*Sp5E8xYlc#E%_sWU3d9}#$tkn?-Ek2!o?nBBTh!Ynuu%o857-lpuNb8dqH#Xs_;4g^FE!eNExExT}bw@zhqo z{v9k-9Ri_FkQocZ&~mB*5qYJPhikls0Kt_QEyz*UNJ|H&%TBt-dj8iEnLSwG;uZK7 zNgdWuNvGdm+BMle1Qy-K75TN*>{(DbxISz%3A`R2gjy?qeC*=6HO!8e6ABTqOQjI= zl1jBsS)sLLZhg;fF}c{KfmDkco@%{!qGa9u^W+@FG2Vt1dY;%}xZih}h*uS3s4;~u zL=MJpYdaAI)C$>8d#TFVY-4B`HL`P_0y0J)HZ{_Lz~Hk4nrgul)-~&D%dU63lq77r ztH3dwxZb3bz7$xBzTP;Pt2%over&aUVxCN7Djy$@yFT^gY;9%y z>u|~r0FR5pJ=a3(e{HHw(Jdtb{xJTGJMCZ3(YI<83vn_w0?-Nd+)7$zj#BB~O+D;A~j)c*hu)$Us54mYr0c=az8j>#XF|WyPN;pY; zmA@0;TX?(VQ|9Sn#s(Q-MJ?&JyhJhBSTGnB$i!T=c>@C^o{%`va#!@1Co|Vi9S&!x zJvX;;1ZUsQwpV&@*R2pzD9Gthvga@0F06b#nVy;g6_C(8ncaY-J}%Crtvm*=I?!1j zuOfWk>!C$hdS|$9oeU9*I8>2a(l+1TB3*Dy>isxky^aD zXByfngB`YB{+$Clg(dVMUZ?p~Ue&vk3qT;(r!X3QUM5`9FCraWO!w$ut6yK(1+w8v zyi(A6Xi4StOMF|Pr4B)uF;WW_EMKorMlXFFE^iN{sqZs2^m0J* zYb)fl+skLkcW4S9^#O$lohVJA^VkLu`%~2C1O<8j1!A4bqu%z6MT>If{{bPhP|pFA z_pZzDe>ST83%O$#&T-0kY8s%}MoHnwarjOtZF9h; z!=!^_zf~`6V=k9`zVhXkax2M3e;8?|?j|}c)H-uT-P^Wf9&TLgd&a}U$v+Z$Oxd>= zagxP%`jYdsQ0yoRu5-q_K^U(}^uDi5-p?pS%R%W!zeb>cJ^oalIa!rjCxVGrhLh~< z;@87dM{%k77hRc#t7V;azi7hgIEBK*e_>HBnH8URtKM&uyMKpe-Bd?qIL7gdMo~tv zH(aP3KjzcuN91J2@qBI=6=b-rggoXPNAL3jiEP}51d&@$gaO<$dlv^8WzgVKe9>cK z2h+$=V&(}2)L_s(UZK~TojEulXF;+H`5{W(0vstZ4}kdJKlG_!c$O4tG1y~rbx0`q zrv`eR&dJV&HkBbxL4J~VTe)YRg#^hWt(*+v9>nXtOQiX;b51~fbpUh_S6!d0vz6`2 zKAG;Xy_x8GfGdQZmd8Vw=Cv>HCrCVFvspRgb8)^vbb?vHl;Jht>aPD_Id<@2KJ4oP zU>wcITH=UDm6%8Fl?QoW9AnEe><3fGD!d?!_7gdoY;M&g0KRh~8Sj5|2Gi^-rwVdY z26f>F|L3fLvV+@uH0VKHP4TZr)GrN1NZ*?5o7tZJN5Sx$N2x99Xvpy^R%4yhTV~&d zYNA2W#Nk0)f5fnyD+@!j#`pXRCB&8pR_+?4VgVRGo|H!AC;>~f8NHEYy$8}{{+>`$ z?io>b_g@GZV`a-3<0%H-}0qnc@C)q6KB~uOUiJn_YQPjNy?O zXuySHA`~-Ic31L-j2JE6oFbLi2T76n)_JCs8?n)GSgj$tYhOpEcR!Oz81FA+ik`hv z&u~}rddFS@oRd0jb_U{76rGWee{_95UzPeuOP#`1w7D{yB^poKfFvvb96znvZpdAf zfBlKcQY*9aCpgT1eMsQC^@N8eVque`+0C^4UHMxmqh+U2^1Q4hoJmd#=;~3tBf1cQNk4ytrvLB6(F#0t+X` zB`VfeqotFJzJ#Oe!D>ncSE}(U%)bl+ddH;i)q#2{&ug4~Oov2-PRG@LGU?q6_RjTC z1R(emADwlib(r7aw;h{(h~op;(ik7utA9`ad8a-tqPApR7Iwt{tmr7Via)BTizD9u z^Ogb~oxvZqJ`cSV-80lBjQC{r6HOop-xy2i zL06BV&@UKGY#JiW=*&`sJ!(k&D1p(4L!Wuf2Cd+St>}vIJT4-IPgkYL>Ln&FJ#IT`(BKHb>LcO zd{5T_qv`1Ma9Tt}S|}?i=@Psg)67si0&c|}&W*yM^JVhD55r?3LS}f>C$uxz_(CJq zw&+74PPrjEXZje(RA-2$!zw)M*9&2L_Q)MIVf>DW>?Ay8#;X8`u6qq=w~9DJQBZTn zrEP|31cu&veGtuWd~b!j?id%54|q{rKF%Zl7$_fLJc~ierDRS^oHW5?a_8 zTPEf!i`osD_dPoF^tR|8!xkFca;tj*Zv*p!?Ql$%7h^$S0?d28;)T@T=?XS6ksUnh zkp4$$>pi%TDc2VqUSU?6>|3{~BqALua&SmJtYcHE9I#QnJj-DJcXU1KMDvB!{AEzv6;m_p(8;M7*BNyJmH=`fW8y z9mwXQPbo`6;xcIleg}!up=E}cw;|wq+{y#G!i(e}00~M|h@&D?U zpGN<2n?8Zty=6fb($b8 zM;EIvTQer>&!odKqaJhl*(j2Ax4eAw~1wJEmkX0T6~ev zmhm^PA5~OrRa2MlLn9)I5xWLwrw~d9IX6?3z%-sowd-Ve)%H$Un2O3Cw=Zasap~!A zkma*@pvw-7r5!cML3E%*+GKyf6ABHkfz#8Aw zKeiqF1*4}WfN)~aV44%D<9#lW3^~TRMfJ|zl7Ou zN1DBT@uOc`a-vOf^8d$AVvvZmSX>GXvl8W{Wavc)CM`e8RQtqAEO-W0|5O9D5+pwZ!D}f0(Jqobr}) zI>KHdqM$%exf=GIJuZsR(VE3L(>8K!k1pmow^nzhcgv!WQ>B3U#0(Mutg~?}lt{>-K8+WvnR8)jna2;UX-b=p>%oFl+uULx z6E0o?+K(^}M$3NgFpE7rVM)=WA&oORrPx>$+sW(dVkRbH>B0^~QXG$2xWfAr&;yyH zVVa~YPQ)yl=y$5S6Im;r{+h0+mM=CdYkq?kr`>C9AbT5V3KS!XwTnNZa5lmsFowaB z3&DVYnn?vkuRF|^k7wKtB#a*AVUo~ROUEr`-gfN_C*ICZzMDIRl_I#;L1+XZyEY$c zAGg>_0rGfRi$9+L1vC^j8*@{8=pUU5NqM1Ym5oD1sMB7_&Hs1-Jk9l-_<5*!Aun;G_5u3YRI7UEjcpj)8EkRs!XqOPUSrj?%VKciS|TGq@2D! zed)fBK@o>V8pNJ%Xmwp-WQQ=`eDh);gp;q`kimPgqD#aPUb*0idoW1n{__KLhd@ka z|44lyPIcLFc}L1+Ik1#Yb?1jF4pbg0IuyJ4bxMb=p}a5du^XB#r*D%O{n?8XsFP}%u4ug#a}s@e}EcpaD1>=IS&_#|3S)YL(){?DreFqfQzqq z-LV*Mbx(ihbi5-qw)D$crN%LyA}8(G45yy)($`@5vQD_U^#hjQ@r2#ypm>)Q)TOfss|O@om-lm>y}wJ_9#&D|At&c{hlY z4RU>&zvP&4F?oJenB08$o1a@uDjR*DfFM4Df!-QebS(5hF8d+HP~KJFo9J+`wG{r!F(kMHk~ z-ygr<@6X;m?#JzVU9abLUC--zT`$VUE}C*N%c^UZKkU4CXK17v7Z*5GusBpL=@^n< z=#y`si<)~~?HAr;?_OLmRS(7m=@xhu4r?7-aciG~nd*uojpnM|7Ns&9uKnxN_T`7} z%Z%RKC+kx2-~>|P$3Oq|v$yy|_hVjEX}&(x_$K(zSfv}a1IWJylD6&rgdNypw?!ont zC(W5|BfvWbuGLqkg@X%&9N&S&KV{q?LBqbEyuv4Iz`KB*e)HF{r4Eg0vueFOH5yWq zxH#vEPQP5B;#nB;0yKxKWLEP`ap(Al3QIPH5A;p6t%3^!2yjU)ynC1Hzt2T=+j3n` zwQZehC#8q^>!=K`1IMTQ+q3>9N4nvfy|wiCYD^T0C8W0G+p9YMc+gbc)?D2gtmmP* zs~)sUB~b^desT;GAxBS@xq-4r4RDTsh8kOQG!PrZooQU@u#`Mg05;| zVzrr!8QCKLPFM6;VU@>xX8T?h?zL6wrxymJC7*}*fKJNA1ThrYp!T}(@l&|?5!hfN zvUiSg=^nXtZrHi{O?Pm|S7yTElWGCsJyVYAH@!H@T*w-Vo-bSsK9vOa)XW=_J1#3` zu7z`j59FhSmGDm-Ur*qFsJA3-^n^|Huv0Z8P?$WZe+FKeR>he0$|F=uhDMz0Q_8f) zdHL01U;TbVq$;qL#~ZgeyGZsG+gMGd4k?j^V|NS0O;indiLhf)yjYYr#-612b- zU|6|!m~pvQn1P?w452~E@s^ovs_g6f19c}fdR>__>*o`&6z@+7BN{ohO8Wuy7>gtx z-Rrtl!=kD)kKpUgjspR&p9(#)OcIG*h~!Z%Q0Rl#V|9>T7-G@^7Ws@&kuT$Zw79M^ zzTWLB{r56(>cXasnm(J;ACSvAtaTW-(=f2z(FqbHdM0`D=8AjnKApsgQSk3~G}l{% z*8&f}Bf4Rc-_Jj_LW`Ea;*V-Hn1D*y8utDptJ0-ljEY{KhYsT225Dk4&4^ zi}A6)-#L&nxUbQC#p#*LIsX6nPCi}5v{(P4eyf~M;=oY4Yv!BCuyUAW z_ta!hy&p2rniVeiWJ7?9@Nk#1YONvEZzwdgry_YVPzC8}ean114-#YA6E-Lm)#s9D ztvFx*SlM$UJGG@O$PDQw84jrAbqywZFJd|hGj%6U2;6&^BC+V!)`yve*vm?t3}>h4 zf1!Y?suUPh+q3^%dM?LS7)o(n`M@*YKY>AdhE)$r0bIZQXa8d%fhIV5)%yKvjiI9R zN+@}1B6dskAvFbU#%LW&5w|yK^)676K&_yZft^NQ$jzn1Z0aB+=`b2j*%YIMCcLcL zGC7OLR&*`=gJkq*B1&FV2Q4K6i@qbhW_EYDo^d_uKfare(Y?XAGa9!1@X9IwIl(0B z#3vUm`}c(nq=5Ydj+0U(BQzYRsP+ndT-0^P5h?Qc%IiPFAJVk+!pWQ%z(x?sq;Pl< ztVyjP*e3M&pe8&28-qj8e!8-2rv(UJ{_LK8K0o%w)|>7}8n3^rv6ppOl`J}*8OF(8 z?D!*k<%D&Gm|KSwKZ%ZhaQFS+*y)-I_-*hZ>WurFrQxtIUh9~3yF!$aTmF*I4I8d0 z7SGHKl*zcfPTuMHNG2(96>0^+vwbSiS?D2;Ie<=sE9KS+13lUf3P2t@RRTwxpSehE z7TMNUnNruqtxrddt8zF>G;9!z2qinD+0Y(Y_Nz4W`rYTT2N7wayk^P8$oSZNe90MT z#gUt%Td?nle;8jpyY=n^3|YVk+{gdpDoYQM?3&hGxR)PC5kFMQD$Rs7J+ft(;%){5hiH#Yk~dZcfnmkl#=~RXxE)=cg=HaJG>oz+Q|kRwrk3*UIhkx z2FA9zG?3MEg@a$PZl9R%nb@^B-aFrN{EcJi4ryipqym9D>j5aRt-NV?{GZ-+3P>h~ zkum@9t@(pLe2elg-x>-FJYv1_o#lT2hnA90wXO-yO;0R6%ckwuj@`~zg!igCj~r#i zx|+;&33taM54uN8Hn0iyEf7BD=>?iS^$arv7m<0v^qro#uHD8E>GQB;P$pZu>rfJw z&(v2m)XDTz(Al=eSkdFS;RtDe1Y0qk_joV-cQfR^WR|wZ6Yq?CIKSRFnt>-%iP`gl zZNv%G@-gmF)(E+Tnkqnhqi#a7z!k$ZM+e}XiswoZEFz(EcZX>e1@PYL4IlPv1D>&88}}Fc+m+VD^jyp4XjRuY*nT;A10cQQ7*@U7_%E9sTj6L1 zT*>T7DTAJM(KaI$NkeL&5@+zv7EG3&MUfPlXV_zyDB2g zO#0KGoo^kk3pzXL)HYS(G;%vjOE3AEy+-)dJnUigaYLqytCiaEhTQjqN0m%Mf4(*{?G1_&VXWHZ0bY*x5UISxE*GUYv8RUy*yYZn)zK>^{s>(myLy%G%x=@lOyN-RrP4-3nBEof zW0cTDE>1u-kbvEOgb#>|MFQLGk_^ZvNL5Sp+S_o} z)DuKRzE>j0Q8SEJ{Y|+Tm_OXKynj9LFzkV4RoaO^Q#qwO09=E_(=+J5z32y2HLL-k zC#g$ry1_c**kk67kjALIfLyz|}ns_a5yABXhT0%Cg|X@sEs=$OU@GjmcaDwnh_9-kuXx z-$G`C@`BTWJ7g*2(qV5F42&v3&q+Pv+*^x+pD1j`lLGbtG6;NnDG~+VmIBn~suu-k zmVCZ&6)eap=5>u)f5VRbFW$K%1Z3ntPJ)}5K^Rl@c380z zPlkMkv@zV1!Rd%QMNt2`KnZ#LQY7}CXnUUJHB&M)awuzPLHx04V=HLkyuVLzoMd#T zV+;9ZTpYq-+y;eY`$4+j&~3)X_;`3YdwQ|w87RTUmIK$ZFB z5FOjS`HY*oQ3zV_F7ZKYXhzmIo|miH;~1zvx`3xk*f!Wpo%CqGmVl;7+(u*jLgC8OKOJz z@r}LBny6vje)M)4WcE+{i@@T=+&D9ozxR*<PS>UN#(f_EP-qQ0~(%av49)& zLUoTc5!y45{mT%fD^fq=29(e0{{$i6TA4XYZAR)j6}s!!=eM71q~WXT(Jt%uM}`qd>z)!af4 zMB0KfN``T|5A_NK8@0Ky`gjXoLO^d5i4q;ca3{iB+AHag>y6>F_BlCRO;bo6Q$bca z4eI~w{H1~-AxtN6?d%)R^d{P|tTzTZDuy~a>O_cZzFEHP@k@-3Ru_Z$Rsxu>L`JdJ zaS3V=8^b23rLY*BrStUtBU9^pRTo-4Y7Wa=y=%Ym$}R$$FT3BKu3QYHuqkFbJ2Xd9 zu1<9RjMsg2Qg}^>Dy=%bq?o+*)<_z|F9=)SpqG43+6`ECY;5Rg%nO^t^_K^0Hp))a zb>zKE?7uKrw|?)qJp+rD*~P9oE}MMQk+Iu!x_l>>OvT!s=KeN7?z#pkC@|;6=2uQOIx?mH{LPhmHnVvaz@-i2dz4a<))#w15wN_}yBo zz;0jL?MY72vgnmG5O>$6NB~yZ*rH`7zt`9p!wCrpH|(%=#tA|=r!_(c=@|c~*psmS z(f7*u^95QBc+ogtz#!a>m00~zJq9Lp3ejIGalzch$FR^ zj^p15lFGD}NLC7*$oWS`-8c|>@jIN`6m zZ6*XKLpy}l?Q2mCk_)i8$ubFaz+Ez+49)=oFDQogq5(3`s%y&rxxVH|TA$C-`(t+IaU_2L-g+-xekWYt$!QU)DZ zVyACIdZ}So7#Ls-uNu1LH50NHemwWJIpzeMeyx(Igptshm34 z&t#zO*r>y7iw4tP7g#Abt0%8nJz_*NN4?gS>A`XX7#y|1wmhe{B0}zw_p6t!I`mp$iH|7jqPPNOK|DdKH!)2ZCy_z0AR9V1Hg20zvDxm zx3`C478nN&(`(Aj77eu&W!s5|UaUlTSs)9()N$PXEI#@`2=Alp#&J)3>HhuE{K$aO2g6`^J#)D;`|S5xV^85bdTW;MG6NlCARs-ZO+@ zwg^L}XYxIAkv@=y@B(}4LX+%y8qypG4JGRU5$}D3gje}Ih-QB`zp&@p)HYieT~D_G z+NFpkfA@dp{ImkEO2gXKbD@7O`Q3tLKnVQu)jmhY1(!bA4tl;mE6`EKIu`62dwPFj zEPjygXayJxt2E!}stxe`1|b8VgggC`u`BM>oq)UMgMk}acai@&-l8?cA?dW)o+70| z6v~^yHL}is93ZK=&cK%P^gWms^*N}=dUMadp4@=6ZD~BV_tTX!5t?xbT~xR1n(ZFs z!6bWzNmG+9M})Q;?i5dJ+dB+-O-IDL?YgqBQvz1EZY+G+{4a*Z*Ta1i5ya;vQ>EtMJ z))VI#`P{?qY!E1%51l_js1ndDS@eav(Yx+gF4M~1m}S6euW50yzVOiSK<7Z}njWfO zyd5`}aRHk7c&`y8jVvC^$fS43xg<JHx7U$8`dI|%8W6^&)9AV;ivY?{`UtSe>$zfa$mHoo15MxMkGz*SMv{s&T`Ey- z5B{fdepVzu?RXBU(5dBF#Y!oEz@C&c%_&?`9qrm58$^T8G{iBn#;oAIxbBQUzbKh_0-q5#>E3bPW8}xq1d5&x$ z2nGqlX*=9_>QDgPTulFLWLcaovg>5CW12NqCYNIo~U;xQ^BK}nRC;CLDRu;aQ&{tspRnhZYsCVw}@B~znD=BnoQ1kQ49me}>9 z%Wb`;M@=C|dyd}r7#ZRX?ONtd{bn3DW)~%?EfrsS*nX7K<&}|DB3_@z@>IqlsV&YV zdgQBC%uH6QI+sIIJ8_^_T8GL@tF4?A#p3G+gO^?!4e6z+4sE~lKVF)}^%*iQGEM=T z<$Km9H4++bSX__0j(>+xGLLyGe9c6&Z8V_RqGr2nmx%DmQ&Ssv@#-#4ACym0z$6)x@wA_M*(IJxf3?4_PQHQ6UV-2%|#?4Pf^4^ zkH{q0Liq^t^h}~{DKg5ia?J5BxJ$Y6-Atz?)n?TXW~<0&DeC-3$05O1=>5BYAk=BJ zRamj(dh7Mu*Ul=QHH>8Jp9yr-F!3{=j#z)Dz$V)r?L<~jxbx8^s;*TVY6cm8)Vu*t zpwzn7yL5L`tRg49Ubiu#jN#J}{a?(o5U7RS&c_QG2kHhNHM4-~LjVg^Wv1`3_&QhG z+I_CJ2)EY>eO~A}hmkUUY}{M$xKf zdm?M5=Cw|YIg{lK=MKL5-wjg#9f$i^n!BYH#_Nj9FinO2*DTo`cJu=S2YOa_9I~p$ zpt~fD@*RF(py7GRWQI1v!3=_lrV5Ch$K*F%>J6pfY;#PD1*E>~puBw2TC%yQYX>Ks z(GA9xj)v#fv22V(=SV~z`H9J!jEgCi;oN1Z5zriAmx{kACCOlT|4uDRCxh!-g67c? z6Dg@|w>EF}=!jOa=fZANaAV?eZSTW6d{RB0Q1QK~-IOvlUaOOe@8C;psc1tN(r$l5)1V25M%pWh+Pjhoqx^A zhuWM7bL^9i3rlyvXzs1nT*=m=T=e;FkeSKy>tKP8PT6pGPFcp=8s;M+cnQr_Lfc`% zXQ#FO@@CvYl89S)^P|uDXLJPwlTMDDdJ>W`(t|-50kkR#kRep8!6*^%E(1hf0WbE& zbmG}u$LzG~iDIPZ3xg2N6YV&KyqSDN2sOn}bHw`lo>NOMn!S{{uy1(rlYst@R+7^B zXelUBQ>NeZ`qEeW=(!u7YO@SaS|88K)F#{sW7U7KH&|9@6B(~s${QkmV`Ur?d`3Ek zY+-v_Me14U?qv=+Wr;`C$vruA6}HbvstBv;kf$tnvt!*>$1WEnkM+p|%ag~HIt}_Q zNb8DPA_SEV;1hqWqLOV=*d?e0W_Z#YG?@Cm<+GlnPnbW<$8(&B^_DrE$f{C#Q`Ue zfuc*L{S>o&U5TH(|LQyIAA(+jEi8qw60`ccvp34EYr3Y&wE*ln7HjLZQ11zj`Zv6XfOtR$G@^^eo>tWjic++&M|HX|+}3SzNoU+Q z(6dxN4>Hx!F?vT1PtV*xK#03~&{&&*r?qQ8)U)J>*yeGn_oOk#Obz~3GHRRuq#5*y z=Y^YMv3kB%v7YBb^dlz~Ot@UXq`2NSRoSg0KZ0Yavs>^rz%#NVsFBeHloQt@JWE%sKm{BFf z=iY)*`VniRb>@qeqC@_~Qzd8) zmWt7l<*djFyy(bMIZ_5}vjd$e_+ns6U%SlZE`kcOyom6LqZ~o2mPJl^6>PTPb6oNU zwWrd^C0z#{r^+y-*P$#L-tF_8{eEM6HS|V19Qz~CY}a)JZHg>!F9&rw4%XrB#EdE%3m-GM2yMfsMM9WRmC)Utf}&F3H1x#mhhyh0fTN zdzT=Z`pDc&*`sD4D9tObR%=u7akP;2DM21nD}RK9AXEIu)vQu0g{{tNpY*jr#$Pey z(U%Az1Y>C7x}|Ce)o>A4%1Esvb=AaVTP1uN@DO_f8XBsC)ma@k+YMVYbX&0nsRxQz zM9x6*2IS31aj~68M3K|)wg;bvzc(vTY;k&fs$}h(x^9ywAm39gA*iEa5%4IOgy-eV z7qK%(_jG6FHTRAF-3yjE4cPH;u{TFJODQ(Ub#Z3qD<$!$ReR7EKRkUiHk^0OyP zl3p^is+Z$STOR+-N2K26|JM|NZx%fJ_j#r%7VGT}F_O=`8w@;r1xC&WBVWV#M5Ze+_*OI|)noxW4eYKU z!XM;^`7tkYWzNz5&e~OtrFs06+;`!BwA&I7Gy8LewC$hd^)8|2e2qzsT9fiKVcn&) z&FV+uPkM-2+FlGPnoo04>mseP9)ZV>14Qj;I;<4SU=O^R*OT9#h8p7MX>HRiASYJBFyShY2)(?&l~Ja z3HjUXyh4#bRa9sQj`)2ZyVdRX7JA#DxOck2L}R4S0Un1_h+5#2+IK8A!@#$B0C zKwv$_ekfo>U!&(rE7)ip8$xzj7^|L-W^N7m1^;H|(lYW&&mq&l9r?dj(m!wT4I61i z4STxS7#8TZJ~QwLtd1BT`_~3C39G9sn(9PL3tK=6eZ9*`Mf@X=JF+9?H zAV2+zrX8&L`{lFqqqK+VG%qF21X;cBRMleyl#|&|j5ie6 zj~X~p{UbfuQ}wU(#8lkkRS1OHyTR){4YsQ~Tc>|J@F7B~8Vm@holOVEM97i7tW~(a zIYNN&W`J2hHGIAm?$*Q4AtTizzWbdx+jy#)Z&6($iCdi1uV@Ex@PLqY3J{Kkg^y#% z6_qok@N!>64hkN*I8`H$o2=xm{5#xixc2AZ}X~R>4GW8 zD&*de18Z4nHydX929GwP3A95WBI@B$ zI1}qj0qmjCDthO~r*qfbxZHS(VBI)nQUL7f3c9S|(XL!AtiSi7UiAG@vY|ZuHq7k3|C`J7cXl-j4^YcD7@rbuPhOj47CGt0Y8C1a$8Qeu z2I&zdOM?Eq2u*l05%@Bgoln?mVcD$vS2^{HPLNfZd75QyVM4EJnOkR9R{GY3<7^b_ z3@ow{Sj5?Ul+)IwUjj5?TLwJPn7H#f`YKoaJsXsE8>fVR&5Z*QZZQ;HjB!A-PVNni zoY{$?()jrASMMc$VESJXe^CCKByF|Hb9e9$q$qM)X%ZHFE@8-SJn*H(o5U^hM#!-c zt7=svlg3kBP*KgHm#$~B!JglC3%s2ZA^B1`pWECGI?(uK zgS_^%G@+oavYNaG{j=g%<9wwQkJh-Ka5nhW1pWy@|FAsmrZmT&F_P)petmGDMx{oV zSPJXjNChM^DI^xNZikT-X|svKe8Ofsa1~x7%aLluP&Y9H>jZ^F6b%tA8bqQxW27p= zn}Nc!K22RrcB7LA2g}8x_#7R+QE41|0zMEZkNOd5}lC`HZO9?Z^FYeW4b*Li$MeiHUvGr?!iu=dy(g?4GOid79=|& z!n;h1+A{IqI=LH{w+CKkKlYw)vi=SJDHQ7YgY)E|yLov6m~708iG}eAcid>h!o>c} z2u}*1VL@IEtoeG48+mPD+Kc7;L_}eXru|Y6kg!dbh$(kw6$nR7x@xp0k>=}+In6o%40;E05z<_o#K{)b8sUMQDgd&z;Yy ztN^+dz=9YWw>7sRXz|~a^J0Lo&0Iayx}AnxnBtv$p>a04WrDoWx`-07KuleP+fHjf zb0c-c4Up?Lz5B)rE}VNX)WyWj4CtQ;i2Ul7b$9)9ps%y<#G`-P@a@J}0L-1+M#jDV zPI7)!5lK=lni@~JZF&i;{7{GZ27vtlwzlEfJ519J{p+JKHi|6@h6x~2W}toBt4qNH z<-3GCd_-M&!S5Xu@HTBvl3^m8x$GQ3imy2-5w6il>9X2HK{S{e8+YFX-rwEG4aZuO_qEP zJSuHj27rAM0bb>JEd2WHb&KmOVs9u$W^8qL0F+mMone7sO6E~55bP$7@Mica1TGvS zPr64;F-h{Rs!D^;{+S5ia z5UQXVdWPz1nE;!wE4jenYIfKUf&Mxj@tEO4Cw?cobE{Xr*FcL}KvkcM>oK|OD}}w| zaxMpEL2}mufgu}N7eeCgp^d;*mWfvQDLr~CEA5vl35+A}{R1p7Bm<^vSlBqT6jjYm z07y{!x})g-Q^i{8gz;iq-yHCU#&o_7!n-jaIX~>s<-{G#x3{rN($*ZQppF#Y249#L zQlnM$C%g*bF2VzF!D|AL81O2Ae{d1e5uzu+gI1R+J^>GAj-kI^4sd1SJa`8*#FKjO z8;q1$>H#1v zknHIj8>~Ue2JOJAV7GQF;7E#fJ4yG1Hz`Mkg-$oZ`VEkzx?H$I@?>7Ui|nNf{};>R zqPE2tVAh=l6d6@m$)E;&)CACpY}Fh=l2Q4rz-0*?s}*=?8z8RQ$jgjuT5>g1Hv>mCwstrnWqR^ixwIk| zZr8N@!~=v$Hwm?IkE|o(Avvhq0Bw}m9rB-EIex0U~zmxjrk zEuazo^&hzw^yYD)v1V$X=J4l_3Z*(mDE=iX%lnjo1gOj?pSb<&l196q3PP`AnnPau|bc56p^;@oq>6`({g6S~c2geaw zJKRK!e6IV~9PM-K0TRTt1igv#wct~46{N$({Z%lPhS-z?lr{VRe4}a{4cJ={ZETsW zxMRdjp?Ki~Qp6Yn;RZm4UkOE1hEn#+5SV8wL?%azbEDr#x|vmx;llHam;vAG$6`+( z8V9nrp$^;_{POj}$ZztyfIwHG99`JUOA0moy7+|Yi=4YblaA4uELsB+0PK)H?Q1V? z_G!SKp9by=lNy~DhWPeN90}Z$z7PA(%~fYr82f)a`;S(xtD#gFv9bljYjw z+szF6zxI)0HrF98Qp$DnQU`C>9n6gjLk|FbF-M+>iictrM@d!2fC@64XqV`P8z;alTMzhq$CI@I;X0=K zSZ#~z1zx!Armf?_O$K%y%+eTDek$mc(!&-~VQ$H3aV{7MybjK6RBHiS zcqh50VIn5IkbCWp-mwXY*%{gJwEp@Xb!^PbRp;>n^eLt5=^0>8wNAvQEn$DMo~0Bg z$!U&Q0M%i-X|<@CkbV1JwMOq;RrKZXemP{hx`wof0kXWFdc=CGiEySHb?EHB1|+NB zOO(xJ&L&&3?Gr7gJ~-nhrmibjp0k7rJ}$aii9Z3Qitzi!Dqk(iuJ6I5qS# z*YYw)123J&bOVYf!4#0SgJ{5>vcDkrqkmc6W{Z@@6O3^GsdILgUJkeO;L46Asp4BN zsZOKnH>nm%MXIZF)~QrN=B@_cOunOZptBqd|Al}gC@7S&O8(!Y9o)?XjCP%fcd@3-TScjSiU5)}jT525Zw&6Lc7 zH6(qjm{Zfgh!#}`!0F91C!U=BMXUm3mn%`4sC!XodzMba5agulnVX{r8>hVRU*F$& z)-St%2S+$*m+~;sKJW+&s#H6^woqN8zee6Q^X)7C^<{m676g z9Z$&_aRAk9p7%9je6$ATU-u&1(Py+4Owen(kZ=DIBcAFXT(PPs{N+iQczVNv&rlE%TV;tdZKvZq!d;&r;^PQiXhn5@=pcd!@ z9F>4K+^1{vMu0bZkw7h~Sj<@dJnnD!vXPD$C4Eoio>{^@ZeQ-KBfS=>g;j(lji|R? z2c*|xf5lQ|B@6XTXel(?BTHP(jERYPk`rTr&tZ5L$mbq%7;ZrrSf>6a1jLgg;d-+F zcS|cJF}*`6^IH4VO0DK%KLbZJ*5O9>(};PFvK(=tL2`JvhxC!64`Tj}$ayfjZJ`T3 zhf-!009%sIiH4o$FHl2yrMnifFyLLy{GLd!CDN~2X~J4-O~w2pRl4<-A~QN&-C*&$ zIOp%v_}3W(8Un`8PHghek%sK}UMqEy0%_CYJJlaz%s90kS&iZ}47yVi@lmWBm)xj} zo;P?%5_aZk0E{5Bij~6h@^$AT_iApKDu1lOMSUs!9Z#`RZ+B=|Q zQYknh9|D@Lbro3lLO`bM-R+}PMIN2xATDj5HNT9-*kx#w*D(QE~vp12Yn8gx0CELIvHOVJ7TixNTL=KSe(DG@ft5SAX!1e4^RGuF*Y@WO>OO8SOg zpnL>JnCA3h|J-wvnpTD?PmmKjP@>dCAAMxwUM3)F| zP4>4n0+gdpfK@JXxR`*W#F4tl8QCp~;Q20;-A&R^xA|#v`-?~0ykyS8(rUgE)*9`Y zZwoiD!MEvoAD(imR&&COA~f|CaLMZG(*t6!S^A@<7fxAV%#hqkHVEjHeo*g`dF)XxWKXp$s3+LS1gxD1}#>`LDL{@D@*waQrse!S^C1U5Bbi;hd)g^PqPGQGZK3&jRFcRYZf~ znb7VmD0~`?j-%VcjjSx$rx_SHg=4#ttdybZ5`lgx$KyQ2&;yMduGN9bo|npK+tdyf z|5cJ1Zk5FXc2oa3fPkH;>H;<`kP=}0dDZg=lX5(OfZZ&m-V#3P%oR;fd6s2FP}Fh! zR)7Y9)!}IxXW=tn-zyjAXa)|q?eOUxGARsie#!wJm@R=Vgt_;>uL2D|o9=3DiL~9R z=_|j@WGOpHkPdVamYs6?FVOuXL8Pq-{Q5WLD9!j+{|Jv&lK^Uee^!1O7QaPvXMbuR zC5E(zZeqBqYc;U9U)6QPUJcxlQD7;FgLPXPzS|`qa<-bj2@xGEVdLov1kUm5%lz=R z51&C=rku7Ba?ex?xfvKa7<>`eplV*#IV_7D{cN%q3f*MgC7;d7;IC$E@fZthkE`*l)#5lb=1M?9`|1} za?(FOLleLxqsa4aua}UkHd42nnYsS20cMz*tAcr*?p{M+V;r#mA#gIB8BM33HHp5ghHWNJ!^Yie$h02`jy?6-p{+xE6`t}{IL*r_{|U6}Ir z*l-q{3=a5hH-9W0>W3H}1P~6PROtz?Z)tk{36@2|dxed%@Sv>eRjQBteT+APN^^_cXL%flyg`^OC>xy&vn^uKVxPVpB1mGes*o@ z)^|#0sUl6c*vUPv`Q?a+Cyv_|&ZSX4)m(EdFu(qNV=BV>jj^_6vG4f$YRqUTkpH{) z_S?z2#KlE{eqjbkI@RUKjvRaWkL)H1B!y+>Z2QY4uoDPOR{*da;0?5>_wMxHim*K> zqZn>|M3J8&OnLn-IF&g;a@|`E@n4-4;^;m+n9FZ;Qex1%$>1n9l$+~c)(|vipUWT# z7)OKleyY83p*GhM7xE!I2Qr(8+!fig!$_1$|7L~qmY^=(G1S|l6X0&X@3DIl2p4km ztkq-f#E6tzwuWUG@s}5_Fn+6r=i_kYQep$S=PxV3n$2=k9&PbNg(jdjXAK!f6i+)8 zR0^9BYaLi`s$ud?#Fxo&kCV5QssCk8C3Wd~T8>Yv{4hYk3)v`Vy*4u8$ecuN(Sj|P%>F`KUmSv8t94ox=#v~1Q8Vs^csnY1a3 zN@&p71+O!l4?M*VpEB0Qrju+g-f6~BCp}K+JGQ0L*|VP1j5FaOL5r*wu0H!{G2f4t z75YKNs_PJrouypeE$GcDWUJcsL$85U2VC|x$976?Zq7(#J)VtT zNYkO!qsDXxS4Zyz)cXn`Otpjkv(1B#EKq5<`GbAONB+;H#0G#ucrYx`&ieT~geF$q zn$Nj?VQL73J&?VTa3f!FDm~21)B^(!_u!4#(?3)S1_<_(XXps4XrE3WfeyNEV31?) z?sI8DaJ0JZ3Deev6Gu0h3(Y@X_&S?QZ*t62d2q70whYd@!+5y0A^rS)J(Y|@#u?;B z?W=Z!Z^y8yr8{{1pp-X|GUE_nsM{i`Ya{F zhj<{-q36H@#haJvpOk#xqIX&*QMk}=n9*Q2QE7>d@)?7h0TM2D-NP?GspGclYudy42T7$Eh4@ehRJbnI>`ZG zb#ny871;=o16k?7im)e#Rd)pS(tlfq|Luo zu~#@tl!E~C353I{DvorZ$!24VLXwR78Y|fzIa#AyyT*@pqG3Mo@OJVjKuHs-*W^4R z%RQnRP*2kqV`K4^m0m_%ii`zCQ!_zffnL(KMzI>ULMKgyLUJur2h@{L zrfCP1^-PeKC9dNNyVxk3GrKNZB_x6Qco1l|XI$6WGTWu=M)ET|1PTL_cz+)wxlfc2 zrJpUR8h)N{s1M~nOD#@Xt>Rl5_aw$(`=3it`&G2G(-eKW%;}%b6egX~o&Hn7FKX%c zx3>YiLAG#S1MU>CnP{dJwm1G*nBI!Gm^&MEt?)(G8H%&d?!1QvC9y%`@Vd0ZiS9&r z_%J7DN?1%dqXkMnJ#NkC=V_0IA7;nJX>YPy+uIG{*G>fGXe_i%+5ogI4`pM*rGY~k z91EMYK&g0~eK6;N=hwY^q8<)CZ${U4FH1QjVnw#xn0XwMk+0Kmz5;|~-ztJc=iD>5 z(gKU1Sq?xkW6=;EX+wo|os6G?S@@{0J`Oe2L z9vystJyO=?*s~?haBflBq+EREm%Ahf0)9Rzjbz=U<9Z9jJn=$T)-!ctLQ|MsTY!fj-j>iX2e_ z28(Fx2!{hiT}GM6ml&Wy5wiPyF2dul@(imkaBxXL40Ds6vSR&8@1{LuUsj4iO->X; zhX#62p!%g{xR16iQ%t>-W0aI1BiQijv)>Ivqfm$5u@X|<=#x0r)P-!nTYwEDSV`D{R604QEh)UEXSQP{gmFUb1 zjvXj&4M7%-zPGYz=_9>meRLhHTyNs??gT@H)E(|p_J#Ec8{VdK^U8*E0QSlp6}KjM zEd;)-@T5YeA=4O1f8iqd(4!fp+Y38rFt3Ey&r!P=HHcEeSW|DYnT}lt465kIm^Phk zB`ef)UiciKEf_JJMQln6zsHxhPr|R}{ZhzmUye`&{2)gsaMwT9Cv0C%_zn1O`1`ZV zOWR)hn|~nl)DL8S9_SHxI?y4|X6lcfRzaCMH{%pN?wzLYG4Z9uI7W$ywK+`ocl*e; zC+*M*UBoVO38mZ+8}acVsZo;$LRryjh(>rz=AaWkqmuq1iJfmBFrAl*cLO#b4Nc+c zt2rP(*X>YEY~8uESmTQg6?1*Awqr0elsO?IDuRJQCkTHZt}KaS<20}QW^_&m={|K~ zJ*|R_rJJ%%cv;dwtLt>0YT}I?ha8va)w4)KuStrkd|&3q(NX98mR#(5fFwFq$GwR zq&t*GI)?85g}?iLp8I~+dcXZYyzBkMTC>LBy3X^6ee7dz4NmdMY0moLxGn#aKav&c z=Y@_dg^GP=ea}cttMl-b7Hkw8r`N4a$*Ya-v-hF{Pp?A(-qcnZPW+ZL0Kf7JC*}H`Ujr#^aj1{Ds|*?!0bRg8R7Z>w;g1qj=vR zr7}-^pb`D|-up~a@J*i;tkAIkzi~I=Mp=aY^5HS`KQ0cS41f!q3E1%T`q%&XSmf*` zM1S)X1m@6?`O?J}+LnYCvK9-oePpvlmXj7B4x(DiOUIOacCzAA6TYgk)FTw7ZgjnC zv|>!0V#oex#OfQ+mQJjp)EkYSJp)TT-h0zRF? z+c;w^ziS@Px+2fBeFs8U?jL#Z?FasSaI4l8u?V|o>PG8=H^AHelW|%Z5b~Vm^MO`d zpPyC0W9y~Di7x7|LiAn>E0eMW&ko~yDBfpUU5k7bEh0)OhHlRn;`ENIz$ncUerBUq zKpw;U|MaHIz=r#)<@Yy1=l$)S+W(2GbM1fO!T?m`oBv8d0ynU<#X-e)+yD3&b{i;( zwzgOuh$`Mu>xgiQF#Z2Wr;U#h4=0=fxM6ozY5zBXWLV$au)(r#DgPC0MBd)qu%9OS z|1}sS`bVoJ8z^nIav%I(qUC9LDY*L8>VfG86ChCAXW%J1^ZE6q65YP9@r?EN5l(Ld z@u$Y_TdvNqH$I~o@Vm`W*EP(X0@*L_y)gUQwA%i*6j0i-CU!}9yoN9m+n?+j6%YBc zgg;(j5|c5*dpQIalU%l(ZP&6>_pm6`!_jZ6{+N(<$c}gKEEM4WHUPioZmOsG{~Q9R zikl+@X`cQ4-w2P_4Z^eMWBRM+KbkYeznktyVK)d*3|9jUfx1$sR4sd_T2(mMCzX4T ztF9{iXAQI{C(~JH;ZORaZDwQxy!b7cn*RP?RHq8T)x?F1lFwUcpBo?_tG6-Pr=j7x zsW2gjm^kZPR#9{FpviG%sqc()yz-WB4V6pa3Bn4IR*>Q8w#zf0G#=kX?en?If2?px~lPZlZBTWNSS9|0&LG4+ZV{e8^afU{03Y`p!Y zU(0v~{|-5@|63skP|W&n@oK(qsfA41qm>zV4F`~FQCF*FwVkLEbDkl;Ag#XG91&YA zi0EQoA5zTn1II=@Xa4`R$lA?j*3@uT%?w}TeZP9+E6&MIW56aFY9DjCUUs#PLB{&q zk2g5{F}>;u@b*6KF>U&Oeb{_8-lNx?7GPDE>0SG$`Skhq3g*xC1;P|`ecI2z13j+i zxA|CH*5q^Q8?dv(JA0ruTh*}T;AjZle;%+Ozm8DG;F+GZ0?Ztr(WwQifFrBt*G4oe z>Ke=9Epq|Ro zVzgF@ajjh-ekHWS8`W2p8~zJvcSD?qoxBT z$7=h%8BQ$zt8eErV*>z(7l48Re!y6d$x+2JdjMvKpFr|p05kTj=}-<{0X2x9Pu?ozuZhR9S7#efQrwYRe2xb+`tzM-HyQ@jD@XZm!i_uhL)UK4k2fmAq~|)l3Aibc8_`usKqK zg&J=W0xzlAw+g&-viK})2>4sgx7TA?7?uf$ z(OAv35F(elH8h;_zHXV!_t&NyU8FAU5?MVxe-=E;cNS5+SAGg;)d>?(3^N0AWJS~4 zi>gaITuKu{A{md9J1{(g!JR3nNta>0EI((lls}43(*jlA@$su`Rk}_U^<4aXz|gmT z_fa$GBSP|&D1GH4(zV$y(>BjxJMUT**6jz(-AoBu5um+$*kEz%0iwv|E-kg z)PA!X7SRa*`k#CF03VInNfg&0V8ijUG)d59ROia>@E2;l;;IFFf*o~@{&^YSyi0M_ zdKPu(tP$Wr7{iM^NFcD20a6T!<5h>Pn6;2Qk-;W|kROvmZX zukC+9&$sMaH5nnaE9!p~zr_7h@rd99`Fx6c9nj#r_6)jiff*7n5Kmtd$2bOyx5jD* z>7(dppXe#k2G}~i%~*~~I5}WnAOcm3aAP_%`pXDP`6O#DUAJBs?jQF4F4B44vuV{c z9wpp!d6<*HU7&FRuzer|r;|Dvd0;~V0z}$OY~RHJ)z?b-c~tuyn>RRY!APcvdq_f|PeIN1d?RHx&1Fj%-biZ- z2%Pnck2}`)HT{|K?JJ$>dEH+LEOizC^gF+0)qi?~KTyS{l}zH1HsAI;g!A%Bm~kSj zo5%@^CNPxnHamnj^<|`KR?PlnFjO$ZAk)2!Of=g?Z;o~{SPz&S3!kT zanE;RZ%efc)#vMHEgwtp^`V(>hd-jFTKV}gVRF2%0=Rae^KIdUgoG7UJzAg@hi|`< zU%^{oV(Xv%JOSgB%~kh7c?wI#N}XqJ^0^FiAtgiQ>s~+TuXe-DMm}rK*Zs-jc9{7g zneWkQ+b1BjODdW1&wolvlE_I$*ZUTg%$U`n#fyfyk{^mhYmr)FNt#J}E(0x^IZHCu zZO;O;<#?v895C*Fc_ej8^|q1Bvdz^|y+OzUMQE)+;>p^l*zfic_xQuKoGpZ?#R(oT z#mxuL#S-LWnacTBb!kMZ*L3F(O(|9;>gAh134bjgT-^0C;al*xyV<69b6EuPFDT)i z%0mX?XGBCv5xn%jRIAr21q2^0kM|b)XffN8MRdo~g6rhV<`p(hqY6w0%$(E5 zWV&5i)wKhL(uEPTvjwQ>O3|BlR9?;qJhsp+*oha-ZN(oqFY=!s=8^e~mrScf%J%cgo!Hb<@Kg@6 zVCduvdYz9kew|hhr%W37XOU{n=EEK2)XFiM!mG=&^b{Ux+9d@50FnZdL(X+utFNy1 z_eV+yH+7Ua&&z^kx{NxNln@xZ63rx(HokpQ@ReftX(eqpKFBhu`eB1sVT|4>%DdSLdlxi^qDWx*!8JDB%Vjd}L4R}u4i zTXxl;f>KA|;+el>KOGVNsVGxt`Ao`I36vFsIFri9NhWv>T1*aWgS4Cjd z&~=2O*eucK=;5hU)i(RLC;ajvl$W-|k* z1cb#s2>>D~%=2vqvli2AevEuYy3#=d_~;>@_#R~(ytUw*cG+>{3^mvisk+_*(3adZ+E0=Ky-= zzb^Pd8lg4Njr(krQuG0sIu?nz`9mtf&m52vRv4|gaOsw_o7wf%WzLU@*SC9ZS6Y2%!)w#!V66}_wf%Yne9}T7 zgND(z?e~M}S9;U+iv30JZ+;(X@;?_tZvuv=uRSeQOG1;Fmll2Yd!G-7YPb?t=*uqc zclZd4*Ea$t#>=X?OzA)cCsryn-4EL6+$gD3H$oWmHC$kN<^gx+&m3<#Eyh~vJ$JGe z8jq&zguedbx(|BugKATSzcF!(aQtOR$#+;05UR{Zb@bEE3>E4F^-oGEr4SwvghrNHWM zbn-z_)+T^31#Coy(lc`Ni)_39D5`@+M)y@d=!^(8pg%Z?EH<_Hg!mrA@2kA|nBU#m zT9D%Ga}PpHY>LZ5D6&Hq-!3+5qFbJxsc|J5mRgZ-tmgDZX_Y-fiiI-BgyODLS^EU@ z2Q|cc5%ZPV)*8u6avZk^jNQ|rd3IVTlj?k-U%s+=Cml6WQA92>f>OTgLMTgL&3&r7 z->->+|1@{}MIk|;KC7?Gn?mn)+wQ>9j)GJw{!{cxT&UEj-w-jbLAIrmL1Csa zQvnpsiiGbvVGNH*cv1CGKq%7;{x@}wB_@`SYaIS)n05R)V%?a zqL~K_%3>gC8hPE_Q#j&0g7)=W!jZR&r>=umi5TLSQ{s zJ&MKy3Sar{w_oZ6Xey?#5IXbMOukL86+t$%=EsMISY>$^a1;prGF{lJ=;^b$fG2mv zUMtq@-YSYb|DCUrviVRY-VD9aPV1@4Q%9*dlO^fffr@VRy`HigCK0}Sp9cQI1R$e4 z<99!$A<0!q=`$-Xt$Dz+pdXm(3FyVA^!6Tk|N5I?$6!DVeSJ=Qbow`R|0})D;Z(8Q zgz9P(xnT$}_r?nV{9`c22I=li!2VZCQEyySyIkiX;98R>w%7>V6K#LM9MWd% z@crFK9QxPu^6DPAJv;cx84L6!I+<=mN;bwCV#;Hx8sN)=-6+!wCMo;iCl%B0>J1XA zY9b%X@odS2-L~_N-UALvajJD|hB{!mR0aEJO7FLaq8QfS=btcfYPn~&RXwiGUn(;s zdVR5fS3C1sSxK6MJHxObof!B2S9>H$8?Zl-0b7&}0J?yD@2-LZjA!$?@oQ#O znDgYJRmagE@U^I!BA7ja#&gE`72xx`xc{I=SHC~=iJ1(gq)(MjxS?aCP;W~A4q!N| zJy3Wbi@RJp%l~N7sTG$!?>j4GPn4NI1jOAif#2uRmUNgch&I1F4W5}>_a0QPvPRyQf(GWuD{cGFr+d}g?WElryhGOAdph)Y*d%f_@n?DP7@x`aOBM{a=++n%j8NQc|P9~0{ zb-!3rF?1emK@&YXP+HaYE7oqzZZBukWDtL`Mp<>iY4eQZes)(+a=hcuJ4VnuCVRKZ zG$l@p5ho*Ef&32k5dMI(x^nqd_U2oP{PfBTPu^bGaAUhq7nlk}mR$^S25c&upLg}A zlHH{@3#0u6ic!2;MY4vuEgjQVFyZua@+QIWy=AiOO+R*?Yxz7P>zIEcV?8hZI1sCH zNST`~#A_ka5!V2&&w!IeOn36N(Zgs;sApLjdh#% zI;cbGBz^RCs>KNAZv2M>n=H_e;z~veA)sjQ=?y?JhHrPVr{gyECV~!%C#JeMs7SAp z$C~@4_JMa~=%bb1JJ?a|s60}>iJhA1uR?vXw3z^reZ{suZI5jTSgJP3-HCqeh*gvE z&5=6kd$R{m^l{DfyME9&p6=c3=B0Qiizqxi=I8`$8*V>^^TX--C6QC{3gCF;htjY3 zv^{+O`uOE||6a1;J0js3r?w#dniiTJpk}?r`4jc`!pq~{RMg6z(|^|gE8&)xGY?RP z@QgV#3^TyJU=ob4TAq0>TEf$Ikh6t$&!uk8e!+qjAMo*Vc_7+LJq5@-KU3cqP4Fit;-Djt0>aZ;O$_#E>5lSR>h zYYRF@Zm#2pd!SWNL`W!@X*=3{NTH-zg!iOVV{cVkby*XC;Z3;7C(uG}VJ{7#ePpc3 z>EK`)=#-PsKRH0I*}UBrV-bzxJQ_~xv#h6ni2e#GyO_}K$D^S$?*z{xrrgF@#y;W- z;M@m<#KjJ6p1{KeMHZZjG>+OwD0eCLaKP({MiFc*jU5U+d~DnSQzJwdNv24*#d1vq zrbl6M{KUG4O?S8#oopnW^$!0CgX$PVqEjwfrM5mR*Lc{c5g^GZnl%CM!u(Si9L@Ip zH6rV-5S{^Be63_w$Qn$F!+WFj+mP%b;PMLh_+svy?Kq2IC84uLK+itzc2GOE8y6(w z*&CK(yWu=pL|-%e?xJ!?&BDLgA5A;X{-74XAqdbhH8ZcirW0>f+8E+vg$y@Jq0}j@Nkuv)W(>k<6HJz{LQbnA#TGIWxa)Q8eo$+{i zEG}w@E1&M>?e7~97T&WCSfemCI}qlF!PM->;Q@9l{nvtgEN-gDN>Snj61#6&(q-&h zns%DbA$US3O_*-(y=UbNzwl~akNf)o=Eg(G8%weue$9Gp>8d!MJJbKzPd2>zNbd4Q zLT19HhnKl-O|hu!XamT*+L3PP))AlzPA9ti7@eo&+0Dx! zEe_PX=S9@1wopqK zwY?-Q1orwPEW7k+^o}=7uf+@#3h19EJH5BYmJVkoZAm`=^sAErTP;gMv=;?c-*+8> z09&mcRSI2GJoSxAa-CY#tyIp8S9|eRJHK_T0#=vRALhInqZQZTXZ&$r`VnFI>lX*%EfX8Prv{$I$*p(5~Fm(8qk3=r}J&{rYP z?wH;)!Ji@KTVI&dcOew(RCam=k)@Rs;D}_WcEhQ`siBFAh;bWPrY|m1pYCYAAD8LU z9j0ZWXOBYZE@rEnhzN8O+`eUMzgnm+A%|>l)P$lsl0nOT=h=$8%)-#6xPTJ2cd;(! z!5jfP#hr+!JVQyZSQtKUlEQ_39!fc|F;Y)cjCPsan(GPWXu8Efo=|N5%5ORrL~oc~ zOi&TOV51s+S2|YGC$d@-8k4S%BW$!P^wyqeS?|$uA#Y~pvrCMQ5h}T?L)zYapo|ik zHg&+LCoiK*&DCVd#Ua>O9HVZRV8p}Vv7|OgDFi0Ae!5MtQ2ADe z7t#qc{yJfXTetDGewbQmom*idCl-}_v^B2!HWqwU=0)>c+eK*^&<>&!p0*!;6>z$& zSAlKe0biKM4~$0LZ6fp7GpAq)p{>yOlJZh8J2QND+Oe5=^iUBZy zk~o<6Fe#DqHH~k|hX$2zQSt~wZQ}qbrYQi@(5h?-p;76)W7p}xLt`+>yZt`jg5+bm z$L-)J_ZXx0nvZ{%oILR;&`o$^}CQW>Gc%Ll&No{V1?|aPp zf2$(=5eyQ~K&HM8_3aM^gBNCfHbM@@QqK(VAB(xY!2CH;B9CM7NZ|qnzkaU`4tWOS z9!WR%meDl^qY38^KK76dbvB~NB^Rc>jEA0hRenX1gM~EsX>ULp{ZzuaSr>}`L~Z_p zH~J!k)+Iu?CNA}>pQ0*+D0<0eCAA1ubSu!b71U&k zWsGn;23}-B92qRsLXrfCYWj+{!v$)sz45-~_Xu!=OHQ4mX->x3;H3&Mnvb0to0R#v zY|B=$h^6NbUZ@g_D~?G`Iz(1W;_|o3P|9NJJtjqE6vP3e@#SRYv8qXDWi3+~atMzJ zgM5|{`aTzkg@q_iADdR#KJ~knjdN#$=Lt=)D8d0|TGgtqMI##Fq``ov#KVYJL5L>r z`}j=p*IJfT(6Dpx^IvY-9uV`oCH4sYpTD{RH~FWn=2x|{W9m^v{YwE0k?aK&R--k5 z-6j=@qP)z^;?A7_PYn8bh3mAs_*Nbx+2$1La^Rga%^uE*E==-h!cCC*dm8~*V%nj9 z%Ij};c3UyqC4QR6oJgeeCBxc4oy3``B~p6vl95O`Z7t zp>C{3C)b=g(7Sg?MV4W-TK(f3N(#Pr{G9k~k$X`EY*cq>2qV+5Bt-@JH;I-9Ce~6) z&q@i7mUN)Xha|GjgGKzh+H@DB^u|Itl}3Z_? zwWKg%GFGBXH%!a_gM-R4g?{wIxR|M-9QJ|^g)UM3G`*6y&r`m~=)+85I18D)l#;IkgK+jE7C)rAx`L1~2?yz$MfBnU~f_ zTsGluhgmw0kD*;;2PoK%@AsUH(ht^##izfVVR{tvY2z^<@$FiRH{W>ZSdhplGVkfM zsbtE-5K+FNvvP)8$O!Clt>d3l(`R!n!FNnE^sV1`@diY29s1=xc*Ns{;!XDcyI*C z8KX|6yMyMK7hXa8N**H@#X{J<X(TaF-B{=X9{`OGL^G=)Shezh!XG3{4a9BEEnH zf`p+4KX}hC%f$Ii=qOuMqq!=$Ddch+q~co@SxD<;lRXUYh`)fKOcHz1#g5ck)EkhJ zE|-JscH)W;aYN-6{>jGmn0nbrC%x$Qypx&Xhr*wIB5Ob)CEDtutl|c@%@H`x-LhTV z#to3DO<==)QvH?EUN8OT=MEqCjc7n%%D3jq+LISpjqw6nVXUz~M6lM712$v`5A5fn zS5Lz()5d4b-1sTtg>FXhGP-D@A@vKh{Nq^IDunhJ)5EXv7NFG{i2$-D%kfE@EccO0 z^#wZ0onPEk=Snj-8JuC10!-9VrMt&b0VIUtY}>4PiXkcW`yp*3^Z$ONf+7IS$VH$f z+qs}GZhg7>z%!KgD+iJC*<3F}RZ<nAqBU`f9kt1_1cldvQjb>3k~e3zamY zIP3y{iB}gGD2|Q4I2q7Lk4JWgft;;h>CyYFcNf)|w|`~%z};A${R--rkB(AP~@GsL@}9{hKhwXY@Z^F2pAZMCnMjqv6RNz3o5148_GdPBBM-Bb-2LD zdn`!S?nszeP;50Lx!!MGj|0x;j_ixpC}DwRSsqmM=t!Y=QA`Y9Ol*w{A+-y+vx0)m zSOs8PSaB=oab7-2#l)%2L^<=FKLZHw6$APH@-k9gmCl8h=wAVtA*2Pmd=cg!@6!?e zoS2c-QP%f-%a`>qL)4X-=ug4Vc4CjKo$GC7pWi=4m*6=?k8nGQYoDU^C*Rd)t!**V zZS&RJ=WTVbbC;C+8R6*jHL7(`TdMGmvX$49W7dny$Tvw@i7EZzND-zuW~y0WM!%Vp z4&vUd&D(0(uUGGa(biSTQnIi#UXIisKQdcR(n~g|j`zM?qQgP1i?zAaJ{ zYjOW$8*mu%`8XI0_BzN?osa_+rz>D}Vf#OQ&M+LTGN6pl6LS=F*)(VUblyY06dj3T z4Y@}Z;Z}_sb)UPeA^x#ddM(-IiUE*qgCfHGp(%Xn!J#3*q===6hp`xhuu#D;KRJ;; zN(WsYy2aMU^8Kxyc)s9>FxqK0?t>ivEB6J45(Rd!Kx~>y+@+VyJUKk1tav*fKxjMV zH($mAL4}<;Qc7l?qt?6?ri!D8EK;xM#5Ksr0p0Kkn9>C3B7_Ow5vrJ*AJgF|q2v@n z6=4uugJcmodb^MCB(KL9pn2vZ|H4Fzl?^PW<_pP0I2+Y()fj$=n|<8fmroiQx%ilI zX^)AGg{_^A89f--7EYjXc0o^b$x&el=-6*UJN)2^^!|bw(6hBu!6M0bGqr9@tPeYk zR7KV`mRbRUHqZHwR#{4KJ=n`HkfBTi%U$*&uVu*5%YlvpMBXu(BUMp)q9G;bqGYDx zW|Ph0Ggg<9=JteTA8_Sbfsp##-2kI)5gmEn|L0cG8f9OCx)>*|&WB7|l0uOQTFj5s z{@Vz459Q#A)rEiHgn?b)K^9A>x`vbl4o1-v93n^{oK1pldeUh5OnMz;?xV>MHPxEa zQy;uS>CvR-ZTUutOhIO{2=i%yoM8&@<#t_Rj7~bJ{mh1EJ@*x~m>Em0|8jZZmnzv2!-7N1(IlnNWf0jPZDJDJ0UI37odzri(V z&}khE^hPS)S~>qvZQy2h%oK?uF7X7|Y7C|?F)2S`m`>}qD{B;Ps?#}S=rI&0{2}t4 zzj@WdVhQ-O25p1BQ(q>hWIp+Q_vSIw^z0I*UP?#{UuO%wl6o-}nv zrEW%u184ia?uXS}+PVnQw?C664Ncy(T&_>KmsXMJ7G)#@HC3Yd;93_u-nVFeGFhKr zrqwzouDug-8Cv3|nCxZ)iTHT=^fb8;p6wR1aN0CgfPwT8$fnEBAuq_Bdx$I6&qZtM zA(IU=xi_tKW0K|URh6)b=M8e0Ep#)A=-%eL)^n9mP@6T4z&WLC6!2-czLd=oQB6fdO@ZVEw)#ab|}h1FfDiH{QAE)oWFQ&i&U;Sc={EOAUgY{&DUhXQK}U{(hV(}$vq z^;|hY(0coV7QiM(C*w(;l8Ng+lUPmR^%;#+yu{SX>YCGuFyeWonY`v=EJk+f&jh;Q z7=SO=G#1JGHwvjcrZw`(Js6ab(_|0?^}AYu`WB{5eVJs|+h+RfTLR`>?2ZInrue)6 z)&h|340?qcbl==$nZKQkqN4M9j35`lgz#)mnnj+L3Lz&Ae)DFNkJpkbUPI0j2Qv(2V084(0* zt)buM2!WibR&MP1i*>C~^&=IofkuH(UBK$q%9g>%D;wKkreW&CMeXli@nE{Q`9-=M{qr)S=a5uZvfM$d9jp(IcNQ&-mX- z%Yf|-UBL32M~u)I&J8HZ<&q}p>ro2~7TW-Ll^f$~@!yF^o*+AJcb6I)^Aa^1$d>-t)vDS_EFIah4IsZZ4&2nWMG++yN+RoT zFP#fBJ(O8EOhCOPkv|BBege{~{3-FQlrS36r-sz1mm9$)^+=E6>h2B(h(X0`D7;~_ z^Uqxy92s)wRPH5i?m1jDWvxCRzKv+HBZB6ecE$IjKAK#{#loK`lK(e4;r2@Y_p1TP zm1ia-qGf=gV>7_AQh7(b3t&PL<%X2z0Jct>PA0Av=DROJG!4?foNnPzsVj@jE>d7f$unUPs-I|`?#XthRCfylwu@!8phz{kiX^(qT zTyqgwHZj2oazE%UlcI{_-mEqbzB)@o*ysyEh)$ z?eVee6J{1lO8IO|)TkPP2yTWV3+6d%ZZ=^f;V_J%JMrm4ILGgA_R)@x@h*hgKeW*3 zBh=e&Zt4^~`VV5GcF4oM050>X!6J^n+#M5%k@utuRqqvlCN1 zwx&?n=U+<4c^QkF5Q~0vE7CuK$rZ=+9a`!qbCnB!D~KPTf`Hh_RXEtl+Z4tZIReb_Ma1+8TdXXUw zy9}3suO<)WJ1Z2)#{~QQkAFSKrxAJb@Mfvq;|Vi%JvZZA*S5xTpMYr69(F$#5O~y* z#cE!n$)=1y+j9_A3?#Wia(>Bw73kDB>TE6k`kkvu%0HO)o$j9zI7l>TgI5ee-#p3#^*M&79Ju`3l0H=r0V9OVPZ{~gtCQU zUB5{=odRvJALVjfW3TL^$g{oWRtj2~=_z0>p_9TehMHDDkOK9J2i0K$;#%gWP8zIw z>GWAG@yFEUd*R15RDwRhVmyujZjLF*OQTb}psKZ8If!E9(s_AhI|q~ZY&4DG<<)xt0V8pJ`HHa>#tNAiw;sr@?HM>8 znwA4lf(!g}bI~RA-D9B9sQi@==^QoiEE37?% z28S$@x%O+#)R#TAW_~=6!J$jCxA5_!*??wy>}Rl+B@xxG?;Br9Y5+dkh#ye%wdTg^ zntm4B{c(FzGb|Z?IE;8l=J|Xh*)K`Mne!ua-Qn9rR>u=DCV>wV}ac2)&s$+j!pp z?f35~@ZWJjHY+1A`zwj!`_9prc>fVlblH0Wzk#w0=4R+!9u{)37aM@DU7(5!G*~W1 zj^CfI(E)cR8XiY#d0~cYK*FZ_Lh*vk73f^1Q_bA%k(bWlR4k0CwgI;b@yKvk7n4k0!6(Hn9e35vJ=%iWwp=4kxVvZKlLs3&OR12m4KV8vB7F zb-L5ID1D<{UCP+AQN>8G48GiAf{AFke4d`kS~)Yw2jG}_?Y`^m7qK2Le5$JrOwgG> z8R~Lhf+5 z{BNK)X9;>ppe*6kmv(5<;^d_Q3!g?&nDT5*0X&yu$R*Pz(ClpHwF}R@$f^p4VOK#f zj~)T9$Nsfj?a`F;=i$4;a(o?kyd%QjMfz18*04e@R~4y4)PyHlK7uZG+eSUk79OVg zAD6y<;sv1etxH`A3A~QmPGI;A-X7lJ_^m;``$VxnYx-@J8e!h%o%i!y+m9peg!B@y z>YEurT7)0mXA~v|kPW@@erG_mbMcYw7V&8;Gu!_0H{av!c{KPpPkw0+p9@u4%HLyD zC3ge$P8t^{!t+;+>pfy-ar;%Tu`vq5;-9|@KDwdF(HKd7`8NZ04oC3e9iWt|2;t~d z-&AjZXW%{mLM-Bmm`ndQu^UiDK(edG^6jf5^ca~$CdWS%GTkf9QDv;MM=hBL|zy%useS*H=UryRW#_@uK4 zw^IO3qwT;uy1jWHH_qzmO0QM%1YSKb1Dqx3u!#K#kt8wyG*&t(yQ5?Wke#|;#i(^M5g|_1p8pbD1~~2QLJ{y1aOH3k?D=T+W@;ZWy*)U_ z^$R$kp4F|lI{MtDl_!Ea9Quc>n(g-&cGm@9_qb4O6dni{!V=je)n*eIb?2L$yM2)% zH55O;ROIAkVIo+7P}#n2mzlf@pOdiRrK1fq}k&=2QdHfa8Jg=gS()yAxti;kv1b z5tcNLrnGD~RVqSKm4qRzTVY~M)GkJ!pGnl(N3qdoxz&%03bq@yvaFM87YRU=AFyc;cL)<+*&4O0x3^-gZzClrg}-MAW3065S7*rv{H{>Br^y6x zX9fmFfG=QEyOM@1GD!gg6PW-yWkkT$X~drmqB63DbmI+62oIeEW6@qRxw+>_P~K5l zfMgswjTau#Q!2-EB}^U{2-}|eE4EvNIy_%Lb#0``Vk${ik!{)YJ(qhxR}r=~=vg$G z-)3Cs4EFXckm{(Ws%#Q|*R=P4V1?v_M;C;0+ZBp=l~Z@-fc0S4UUyA2v@Nt>ZONDqAjizh%8E)=#?JpmSHWFu=20m_(_hez}# zjvW5jmHr`n;9RpjLHil3@z z6yb?q%(rD%?hSIndUL%_CVlJ+C=)Tv1?JrBmm@^xPJ7D~w9pAVRoiI^;jDubt#1}u z^hdDov_!eJOVu%uF{bJ3Y)l)a)nd4Xp=t!{%G!gGZLU7gGpgvNBtJXSf*0X&zE(j97Sj*dQD>{}vfW0i?K zb}cn;6UWny?eAIl14OwQ&h?H>Yni^-S%BQBd2lOAH`F={hF;g&KP5)A0<2y_BBEra4~xNAC8W% zrFH@n`t&I$)Jmr3Z(PqA0puKSdD=F=xC#&{aK`~bheXs}XNTi?02c55&GVC_B4RXO z+Ua4tAfx+5m256po};fTXy}~I&s6aBRY!ERuzH9-DCe}a81toHNm6P_EC_wIHhKY*Tp;Fx_|V z@`t=OOL6yLTabV8LM0ggNfJ{z&u~K1>lyzlkL7ZIFoM-0L*MXkT-RZ6SZg9bi!wEZ!|ZL z{gHc}m!SRtU0ci13_E=8(32+sTb(dU{;9k^tjVQoc3Tz3Faxs zb6O;TZhu|xQU6p{>3DIB7r#;4U8bEDZaR~b7@dQp0bzYO} z)uTVznB5Rcu)^B$zCO6K7m4=>cZSq>SFJpUfDb_1KfC6nEV-|zn6Mr(c@PowedrC( zbcyKyU^ewNH$KF4uB3#lbyh79x043KX+h0mOh3kn_!L1z$O9=hA9h$Ngcv{BakXWi*jf zyDdQjWK&-}I%(?*5URc^s4m151C5fzHssJnh@Qy9#Mi;cC!O2z$24C9F1F~;2Ly%v z9p5Ii{9Ke3I<&w9RraTu$7bQB0KNyNRSVzh;ScaV$o4b1n8Rt6s8g<2M)LXy7y!E* zLwv7+{@+&mIUc7(RplbNxYVd352M||D)&O43K-Y^_#Lj@o8ENrv$qYJykzY;z)j+8 zbg=YiDB4pX_m@yjnd*xARmdPFpvTR#A}zS^EItLeVHWRM6x7>^mr|*ZW$@Szo_*^| z*ijMBwqcyB=us#@ah>hAGEpGzb)fldW@G`naLd{i6hMI1CeRJ0#vt_1d-fAVJx!0% zmsYo=JQi8@K0LwL-DjlX<)UqeNL6h)yHaUKHHhJ%_ zgaWy|;Q7*q48uwc6bhNwCtSbqYVia^;cw7A7Xezyh5y4(`L1t%wxNFnVf*SulI2rOI_`;XXQl~ z+Pa4|z?n^m*O}vgIW7O%KLV&N);u!gu0|e{mUpp|fO#8PiH^;c9~eTx1be{E3Lt6v ztJB{ctKCIS=tA63Fga8R^Fu~fq)DC-zezMCoCSB|OY_Atf7?pBV;0J)7sgCZq(W&< z2b3`{hNfw2Cv=J@q6n788`xA+;jkW+zB=#;U-xUeSqB3P(zUQ(r3?hixCXVA=O8TM zQUoW97e>+-$cggJZQXpPGP259Jaa?n zWs;D2Clu$TB5J6_pi(Qne;ud<5VQ`diL(>Zgcf}jItX3^SuFk#cax^%f zx9FEjQXBOelYh|=U)>Z--EBRD6(>l{oL37gQPBhFgCH1Qj$D~AO~SQbZj`()|5<_9<)I6peW9Qmkj zd6(xu+>4-&qID40U*o7FwBJoqcZhjN?XSYbw}%`|H5aNk7~$Ph@)zb8^II-Mswmp? zEk};NVh_XQTBxQ``?tdNpg)u>*!V6dzU0MzpF*asV{+84H20#GhWrGUO7H$F^rX=x zeYb?%4vXr4mY1R&@SZz4>G`HUzSKltT6pUemN`B_Omy(K_79gobh#9a{S98uo5k@n zG~{$F+&iU~0jgmp;#S#bwYw`+weT|G`FSd%ROWg)o$r+BM(b%0lt>xe$uce<8G>Tt zqf6b#<2uclSbKKoR0)g64(=N-Y#R%-lP9B;<*(x$WZ$j$cSv#Bg1 zDqkab)X7iGWFQM#r!Q6H?aPp+Et5>jB@T2rh1p5;?hZ;@LsDl1wXNDw$;$_@lep>XGU$hsZ)O{{rMrDan%#bR3@wVr&@VTR; z(4kTuOmvqY3PH+@tk9HN8|k2@joe}oBs|NvD#w2D80c`C;F}NQn?zZoJp}FRI$Azqe@GP2&~MD&O+qpSI`)2)3X6PKa4iL!+Lix zKSgUedWuM;=ENCdHl;G^+4;d*Fc<(aA4?r4k}31f)Sgsi8YW zQeqGoT0o?`rID6Ky1P_LK%|91K#`ON=^PNGd!#`?VxRHz`TlhG?4FIY|9a*On+H+WEW zTms*}il_sxQMbl7K!wO&1|1F#^E9w!kt=nJfEGgCK;F9D>trE(bP>vfzk3mwb^E2L zx$Ncf$L4}r%G=3%AIv#g@paGTTjEhd!sJI!uoI(&HVl6w_W!9@Iz-m&QWLErSMO-Z zd3a*(@-hDqL%)l@k3W}Mjxr(T0yl(0$4?E9Vi(;LqWP&n!&1-f`Kd_54BE?2V+7YH zTUo8m%S3!^g`Ai#2vZ)#{gvX8|1hI_SrAPI3q+1EXl za|ETRDY<=Fb^A1Mr^npcpboI(6PMxmAyumBlx1_V{p7692qWIgbgsSfqH^IBC-Y?` zHseDI2$MJLfo4~@@aNs+^8MjjfB38EULIq`$j%Pm+j4#w1xci=(fnBLCTywlH`)wH za=G;r6V|1NI3U4Qw7FgHZ8a~yQN5vFR&C0pcFKvvP0 zttY-HMdj2oJa#oJK9uV+rMJNOjr6YCqv_=ZDOG&4QLQrG8#i%vlCtbF6G+u;ZaPb8 z@x9n))t8%JUeh!Hm&- z*;vJT9Z8p&a^Ntol4pZ9W~?+3y&4F8)q+ZLf~etR8u`so=9sa&}eCY z6CWq8^8A(qX%o&{LYT*Mon1*VRuVDDzFoRU>%AAO2sbo(ptzdp3L**?5A@*+bp!uk zRloh!fuUsJqY7Mqn%k>6} z%XL%SX`BaI(7;{vLG(arDe5P;FVbR|T5n$%oRoyPO6fCshj}kwtJ@7W2<lQ>c@Q9UYByg(+TW;bOf zU@$840Cd&6Pu%=B&Fsx|T%&W>A7#e@0j} z{qb3jN8lnxJg}+q0M`_Qt_#_F9u%?t6#C5Bb)0!EC%}I?G77_qto;C;U0$ECoR*6k zjF(LD_!=}=stIKX<*ib2!P6q?NTgXA#pV@JFk(sm9eQ)$h&!lgc&Bk~J z2%RLs@BhBxklSw#zAT!sY8h)oVTSsLiY4|VCzY|zw9mqvhYNNNMdotFmpc6}MG$J| z+mwy5<-DdWjf;!n^9)~P&9(&NI+dyRtjf6Dooymw8#{}L#ha>`HuIGYUq05RI#L@^ zg*fv=PjwBE+_z(Fi8B?7B-uY5eYrVITcl6z01MWJh;$Uh6~*g}t=vc;d}SYpctk&v z+|tQHAQJYvbaC|?qA1>(=msUX*$2N{-W&W{`}rTB6zUpQyellf8YCPH_ebwUWU;uI zii!|drF}sFi}BFmVo2G$t{Fb9u!kQVw=n(f4J+rP-KZX0evgh5kbphkn&2t}Re!I% zxOOA9?et(ReCmT$I2dF)XGP!fh?tx_`aNM-Km9!f;T3VvMa$U5kuP`Ac!YsHLee-M z4Ep|;haLw-``R|uw+$##`Sm}yF+w+4)A6`mSP25!X9nQXXXzIb9yAa{Ljn8VwTqro zaVl$GMTmjVmY8mBd04yqgTO=m%A-TiGF5XVS^$u0DlY{c^rrV71RPoo)4q56*G5YG zyNdLMCDhP*<3^I>q!K32_c?u`8(y@8*Se)3OyeJicVm!;id<9`;1OWxCpH#E^W_V# zFO!ri+{V=3jOf=bC?4S@*yjjCT5~j0N1q5+v5-Lx5Dc~D=bGZ0UhR`#;t;(&l!p+8I;y{ihMTjdwuTA(e zLbVvW5?{hkw!#vRLLJon&$=x`btpc{8&|PFV4RDk1o~$JHx(BZRjKLXyS3Se?H*BJ z`bEj$pAXZGl@1J-j0|@gL-Uss$sNwSTO;K8B1x)VV|%J@{W)jlsM}Z5!)^<}>frcz z2fu{4C!nN~V!&{W5s9)1xmC|&vt&Nr0x-)SnB^?bhS!fKjR}CBbMP~Q$POjra9ta~ zLk*$tD$3EEW3oQe8aY$pNSM(kbkN31zMOtO=Vv$5!JZQ=G^YFJs!QUMs56c_!(AV^ z87lUcx~%*JG=VQMIfPCk0oBWnKgvqb#3R=J6Pxl72UP*N)}Nj}{(COAzK%NA4H+p6 z7Sy*J+am+p&?eEhBRt+n$w@HfK|NXNwT26`-q}ZTNwEcVFc7$ZV$_?YkKO{_B#1-@_y!TyW$@RBh&;Iz zrA)|5At$@=7$c)BKP^+q2$^ab_JSQrsdBM`4mGa>jk1(?plw&5r@a`K@-ikYkj@8b zQ6a+HQ*2PHf(tX($nZ3XlI#g(l_+pasp<+7-c&bIbX%T86nvG0-Dkl{UE`;ay=UA6g>#fi&rnz8%it&j9}` zlJvMKErHb77aPzMb)RiHAKcn2DSfXf$ASW@$L;?we-{fB_!ghL7qo?zi>-o9E=8HE z`j%;zE8@D4%mY?;Hg5QB^`(fCK5|j}UFk|SefZl# z*lwU`{y9a3S$7zGSnkm#1xP&MwLzvNoqG;_bGEkcGj>ij<{cYY(+FVaEm0V&FiANT zxzs8Qyf3V*b+KNwwc24ze6t5edw(GwQj10c*-Sz7g3JhRUuyqQhji{3jj%m*=I*v+ALKh@alRp-tJHX z;3v9nhES8ECKVRUYjXMSwH6AR_i#mzswV^Q4eP@`3_?YzwY%Y=K&y9$&%6SLP>!B$ z0GS*WwvOPh+>GS-(|EtZK&97^xqa|0`nU7>2j{wmy63(t-v_P*PBB&^C%O5a%K2OI zGU%+ESCQ$$Y??S#bHuOaYn|v0dyGZ4RI_mCph4om|Dz!RWBbHW{X=Igp36LsD>8eNXZEV$To{ClCa1b1aXYMC8Iv^6MV2Zf$D&?>l1~AK6iznCok-mnrjO zi4xu%Kqt(gmB8+>x<-b3NSMZ%pZ>vz{*D2uYPilW3J|qqS#lG`ELEilz|AI~MkQbfQU&Wof=@tPJu~swlR=ECYzoi6cKz*OZ)uH3^{4f6 zV4Qigj=_QvhgHDzP_mO4vJ$N$XYKms`Il_s%Uk|fepn8hn{8y0s?>3}m;^V~XNna4 zm%AYP-UD;%f+*6CjVxBRX! zs4uO)Or8Xu;xXgrR3jeBqaSs`O=hIvpAga14$MY+Ui;A3E zn88WGK9YKd)UBk;R@SBUJ8|KYSuhMEL85pmRB z4iesOhinoTyB1~Q?l6xOgqlmFmBp`ok&R)xc328fs#GL753#%ldH!bV8YyqB*Mt=D z9!BmnMW&2(s@XGPTDze=tgT`QV^*LRZ|a4VDil8Pt8JG{N3s$nW_0JCR269WZ&oqY zVrf=Imh?d&_WVK}>b|K_ky)Lk(9TzX>!nwZYdGpaL&ip-k_3g;eP&qE<_;2;Q|*DJHZYWot^w) z&{`hOdn^kUPeyv`FH8%>g|aimzD4SbauS)OCu}Eqh1|x|PU`Dz_+M0=E8DV{h!*-y z8DTu&4w_j|z^t@w{mF&3Bn2IJ=qNM6%Yv+Zek|-SDGP@ZPYp?KPC@n6~=Ki5+el2y#=4P^lx34t^l*!wyl&18Ri4v9K zN})QhCR%pOldMlzmssAwVr@J%93Fd^0-R=N;4&JjfI`tfJC6yFPni@V*57vF`=Dp_ zhZ8u=(QyO~WrA606*lMkuZIDZN@WKFPhINlxFVJ=Ytqc}7gLVsgkjfcKJH;qP;j1i+0zD!4S0b{B+oL7 zCv!?v{>#M=LuuSvIA(cW1D!8Em|^R}U!C7gM>;(6jrj=2{OOV+n(s?fj4rCMyppHJ0!9B_^3q*?MW59FEPpY*05UFPJ@m%hwkF{fT zlpoB0p#?AS>39oyq76+u;p@ZGKjE#C3?Gs$GkP$@N47W=PeAVO)~jl;iFI*EBn?Cl z2Vc8#V@-@TEFM?$v8O%?gquGkgSk-%yW5kJiy}7)$Cihs?^m_-XeAdy5>+)zdsRW8qdFBiQBi!T&EM9$}F+-pUz@`ZRtwi#3aWi;XKR%1Y3tu3|US?dy$8B4To&t zgut4r;gi1aBP0?yL%;lQTc1zdA!XxQ`dsHn6#;nBT(vr%PFFM9KYl)DY?y9Xk2v!a`w#o4@;_wjshQ9eHXho)b=b?ns^+b2qoKyoH$vOXthv$x9WM z!;PSv)gztR{xFe6hC`*H1stma+r-)-8gXaVJ@uG|?`N_fEL06*^_xy~;oh4FlISFZ zz8v9{s)BgokuKZSd}osi_((h})ZNS}w@vNHrdPvNegWgCyQX#2! z-?Llhbx6O>5-j;qL}3H_p0p~P#Muy=1XB>r@XHj4u}_cj@ySs9d|LzELp5TYT!>F< zZ)9WnH-EEx0cPEk6T@uK0$+0h2DjX$yc~nEikOfxCi9ID&WG0j!Fm6x(we`kwBs{F zEL{uX)tBb2AWMl7XeO>g>7>I#Ksd}>+Py?Mn!Dado2h36!1;={_$1Kuz4Nq9VW{Km z=TLyZuu!>=sp;~-%29Br@0#cw_7#ZPYSp#MN!Bo|>^nwx|G(yo`rciQpZ}lci*jNDi1oo3JB5LA7=ktT z=3Bv@^~n}ig-2`>_Asraf$8D+h$5K%>H5IbUW8oUK6g*a7O@baSj2W0k7j^YV19 z@RCjaT?kMPG`?xpS^AHZfnJW6tX^FkhmJG3=sJ8h8cdr$n+|R_+q^zdW9-&<*4NA*A%Wfql6+ugz%TNmR7T>G(5O zYy7A}UUq`o2vD(9mH^~R0O2;1E;5@bQ6FKkj|jxiRlyAr$@h5{oJ zf8w2TMhkBw%AST3VS*978}>J`jB^(pHob1g2!gJ^OCZ^A-)4PaSi+IlZyOr@Vipi! zI(Ra#7qvx77Pa}QQBn(H{hPwcmZ8&szEHy2w3rvn$mEZA(N0Xqq4j}kj8xiO#;WVR ze{7_GEKyv{{!%>TI41qGF#l^Dzp)inYHEj6`0Eg;8A;o8K1(eycFI@q<}$pqx6vla zv?V^nrYFP>do$T_ZHR;SIKphS(0el?K*#3{Jp}`eI`8~-jN6Gqcn+5O37c_o(w(X< zSs44GH78*8Hf7swiS0juOmbfyBVZ5RD~>6#P=%nu6_1x&R1PA>Ih+2C;e<)0L3FY7 z`WeBb%{(t&{^z@?*82^0mzSfobtq=y1l*?(D6n+242O74nFQmFIBL&baK|&zJ?vXN zd8ml>sI;s~QRFh-uq*)>!h{S!G-I(5lE5QcWFiRNGIRCd&FT>OgM8&mq(v2s-hP zGa#GGonSfJUFyYb#%X;kA4~ncW&kW%b`)>y80lVr-E9pz1T3IP*PDM(i*U6i!ONc- zIYdtJ?JkZ1Jq{X=gTOn^O&uZTS{xrFaEfx2fvi{?yyzVPB;vcq+_UNTqoQT!`HihJ zg^pN|MiDR5@RFX+HIO9tMlhs|Cl7?d!XNf_kSm_B*(!AfvA<j#$98aTfCNJmzznMBTJqpdzi$OFfKk(XB-e0rsr$3sq z%E>wx-jC0}+HYN42bnyrAYLZb|6cD;X%}ETNFRBxzQP@c;vPhf;7oGk?=u7KjNzeh+I z{WtI|DoqE|)h8v&JwbkwKl1tukcn$)eeuxz!ldUXSCf^CnBZK2Ug;sgk^ST>{Tr-z z!KbxUABQgha_8wCV83`*@vK1qqod@U(hl%19g2Ty;w87dT8fu|u7@vy)YI~5waw`J zg37$lFSAhX%##wU9KTv5xt{G={p9T>ZlSK<(Ss`I`aTo7R;gPPwn!D>g^BJO$TCQnh(X>tE!%s=!Nl>t(ND*+t>h@{Ipnjjui#eblXtKDi+3tW zCJ?oob0t4>8ku}gMy^7c(u~;b#Tsn0er#1V;a)+XFYPv8`My5o>?OTu{>*CrcwpwY zPKCgLM3|m^A@<>f)IaHluy;ZKi)=$-fpt;_Ep^I9m|we`YQ_WF6Jki?ety2O-+q29 z^?$`1lEh>B9GQk2ou;Z^z&Sd!{gK6M82ALd%Q-u$4kC8MTYVvS(1X9Kf(eBGj@B!I z|A%-(yw3lFc*E-!z!Gp$$Ipv`AkA9Dv;Mjmy}`v;<21Jj1_5z5u=|;_9$B>jtlFy2 zSX?zs3@yRqry@taFMF@v1l|G#AkpVAoCfh(;5y=$-E6Szi@Sl8uc_us#q6G}UD=>UNxZ6FCHC7chSsuYaMC7{ttZk=83ISdFSsVaHH z^K-78xmk_Z)ZywUf7eUfuXVuw5t`*O&BkYb5jsf0xX#l=7|ygc!2b1povzNa$E3Qx zDl=2Iogs5i{R-H#JSd2?rraKG`fqIBXzk*o!J9KIaX>78Dpmj&meewsG$Z7S)95U| ztV5`Hgc)`<=Q~=s7V^09VoK5O||Y zm@UcCoOanR9<#CtM(k_XM4hv>(Hknrpau1+T(`-eyf*ffxC-v4mW9N))?^T|h;z-1 z_rW!pvH!}ct0^21Cfr1ra{!b1%H*fWP?NS$8hvzq*lDWtsg07=+M{M)Qf>H3sWV~5 zokI>;fM5A_Ywnrm;-!KNw8YkeNK{Kpa$|erPjC2U95tM11w{J={S77wqj6yc$^<6V zEQC>pfmASt*;F|iFUA?*DaP{%2c`}88RsshAPFA+m^-|A(>j1m!ceIDso5?Z=dmpR zv!Rl52c%}^#BpYVT;is0-(pe1J&L>YPw{s`%33KOZ#V0Q8Yz#K{J6?~cUQ(z_jvaC zT;+hs7Gt48GIMCa#g?%p=DPn(bKCPYJzn3V6>`(fsoB;^<4A@l;_YV9Tr`5G{d^0e zbNbA_b@NNRI|qVsF+uE#lHc6VLQ(}0Tz!7tzAt}n`i*CitHq)K`MrOb;V5zlXSYJi z?o&?QNRYGy54589QJh|f7ibtloI2DgA)f4Bzls!_Hb26P_--otrlu2bN86hVj0-&N zl%=LzDa7NEJ+&m!R2Yhu%WrUF4eyN0u^;E*1T;UpM8R34Bp`MbL&O#jtow@FF6qom zIW#9x@ns4Y$))eV40mDcXSlIn!&fH3G1=~t!8NY`Zu=33Q+nm5bKlo%W}c!) zgTrl_z07Z3py#-;OEyesM^x` z4`HL8F7EC&(k4VlW9GLmSM5XQepDJ#A(e&WBh0m#9H7CJ1uo`sIR$^;^+M$y9ZTsP zVSeC95qDqF(B}oB*^X2royY7FO(RRN**FFF3~49@fxisK+G|*#ydpJSQF*?)KFM(V z7$zZMBobC>nlvFN`1);sJQuyhX1h$qIeTgj0xbzayaJP>{?au~7|rpFL-Z`g*!;2o zf=tHCeY!NWPTS4VhOtiB^iDbb2N8G=qJ|-Q)&be&kJA*}S6D}DKiH!f zcjbFVgM>txYmCUt!Pf$%oeYKGzQt4S9+`PMkg0n-yn!NAz_tN@!ZaPT$ir798?5DG z%+=Z;rR~tm7wi_WI~OB6;40ww$!FA?lfV2xHk&u~*Q--hU;PQSwuIYEh=mTP^;&>c znxV(kq1P`k_9!ZU95@5g#&F9tUFO|qKTvqY;)`z-c4b6qdbY*8pmlz`r0`XtWlsAt zYk5&#{jy1GU$3!zj&O#1nT%R8^DLk)A%yQt!KIi9N zw4p)hG@ji_Hp^A_-NeXa#OO5$mb4>8qn2RGRcVGr9wd|UD(vkpnK`9I_>RlrPkoh` z3yC50VjJbli>a(yiW3b3Y3JQ<^-f!E5QG5h3eV_)w39)+YP~}x zGf$w-wG9-aKOVt?r_g-{pf3m~ey^%cfc*eO_Y-(t!oj4^QWftD#{7i1r)Sn?cpr zo@jm!r4d1wA_`$-O?aHAc6pGI?6ZfgnRF~%%@iASFX!V^&8nN6{*~gF^9n#$lg0sl zQ6IeQjxr8nf*CCCZ)SUM7Mq^zE=0CiYD4*03I6m~g${*WSh_9kv#w3L|kf75U56M{xeF+l_q2y>75Z*@u%X`)4?r6>> zf1?Vm1PJ$KV-m!p)d|FFwOgDmfBW8~gHx3lce(5@%`YyeoaZb?$w zB!}FG^7`%1OcmOhEteo5S8+#;NfPH~f883rnzMvgJa7t&e^{fDnmAp{$w>`ztDZFS zDKOXKvqV0W`V7Ld(L(M*+s?psg~CfM4Q-Dp{UqQz#;BDHh)UDIpK{`*Vy+3F0W_+! zcM-d!blTLOS^kiJ$>-*voe|P*8N5GUIF*Y${po^SKd*V`*in;ZGlZyqR7Ert2yZ@H za5tz*>RqC6rQ^Ci5VcQD+sUhKR4PLs(~SagnbN(Rf6mX4?IDBk&hCkMt!gdc%+=9yj#`=Y29E|n{ds^UL*vAx zQ#$w8zFqitpE$g)omrn4+xz|PU1nmpEQ&=m?V7bcN+LfVSb&Ks7pJ#PG_abHI5|RX zoe=4yZ@uu=nyTI=CKh6`w}xro>D64Mcsgvp7H)e+Y|BpIz0doOEYJ6FSfQdWLG|Ec zQ?Cq_2YS{fpRui}^q`K%CIiAj*)3+6VZwNCz2@flW2pUlx2XfgH{X-A$Xn@mW2BNn z1{mF;UQvx272M;YRJ=rAr?%pHakwW|YM zGA!tF`#Vp)&M}!3^&`uC8Gebg<;5os_U%hwL$l9%sq633AXcJ{{Pu^N882IANp47( z)K^QOWd$a5@O%Soto=(qE0wb^0}8r7t};Dk{@hnZ5WroG$EW)IDd_*~`f`YU=tENF z0Tey3J`+Rai}r2))MZpAC}i_1KAR=j$Q5~y$*^gq?HM#8y!!w!GUE0?D(RJOkDIs( zfPOy;Y4#Vw`2^d1ETe&sA3D}EC<{D^@OT>3Ctx$em|Xlx|A(}*Ul9;gSx9o5uvE}5 zNZZJZ4vHN-dUc8^aU!XStP^Smd3C*u>}(W`LW1#r%wIF2Yl|B3Xp$w!uDV9r$JGN%2p+dwC#8pDCzPLD;bg&+kkzTv=H`A>yAAi~{a z2BhP|qi-|Di?Ow@E*!i7{Pbu^$#KT7m@VA}uORuGUkc@Q1}i{MUQLoxBOMh2(^fzz z+mzQ#D6US>TI^9g9q=}Es-TT;~3j@ z&X-Zf$j(EBQi)uUC1xKfQD}^ZXGv z*d(OTT=@~`y>{>ciNeBbrqgiplqru`jM$T#o~6UFYU#$*EpBYT(-xWBczpk;GkC^X zbwq^TN%v%JyIO{C2`J=|(yD$i_sXR%8Q-S(xM&^U9)>U4<{in#b$jamXX~2A?st-d zqeZHFWpX^xv(6NVnoZJKvweHH^i7rEwt1nYSREKu%uiVqxjTyDA<(oG4I8?BHOGwL z2DBt76fF+!ve;(nTI8?6qQ>bQv9D&Fm+_Wj`F7=DBwTP&<6GzS%%Omgt<9saAVRFf z=7-02x~!De&pT^?09(Jdfg8eUG6j+pmv~-c7D8;hVjetj!2WjK$xGqSQFB7KMKKkx z3G0IYZX!^FiX)aABM>k@xf%?(be+b-$-{*7RpnzRv1IygC>h_HJDd2J6gw;K4>B{} zG2l-Lgk`~C+l$>$kKRRTXL){*+w&EQ@IRii`arEhOSYTKkLE1vKBXK^FhjRs57aP` z*9r*8rm#0aXpbtdFPstAgA(4wC8*eKc1h@T6OSTAUd%UPklPGPSdvqclP;RqAGvws zI{N;N01mRd1?$15s9>!X+O(`{#D&e-;f5*jI4YqFy3m?nbRNm)|CD|3W6!YchSUJc z|LKtu^oWJ{wgtYt?#Y;|FFUD=sz5q2;%XVGyj&Z?*&QhM5v$9y>ISjgyCVSP5edNf z>i}XndZ832(8T}qF8LH}V=6JyFi3bHxn{S)=HusczP4@SdEoY0hB>_`YO}Kgo5{NE zm!AO&UnG+`?uY0kmk47N zln2|ds-H3?QIPd-VD9MUw%z`vKw}r-I%Dk7 zzNEV(Q2OgDw>4^iQ+0cFMqWg41C1`vAj4Mhy)VBQf?}!By#`a3jTvU-7Tq=Ic5IFs zo^4zN|Aa;qVjUs&2<&^l@ZAbjt6-CFrC+qUklFe5+Kz~>^!tvu!(NjGc1G;{z`@`z ze9^AJ=nMZIyUGZDHeCDq_O*2U8*u^b#Zb?c%iY#g>9Pk$zo_p)IX_+w6kj1Kgs`t( z2^F>%0vK%ILv}>HIMhRPCe+Sf$1kI;HOlz>-J@c^ozVK$Zvjn==fB#Xx9xB3+@ARU zgXPslV)CSF`};@3*dpG~*3s2}46&_Z>7KWssbapzDvwY)Txh*#WG|V+o9-#TPp3sL za@PK^HBS{c2#>Cibi={1gH7x7E=RL(H&YhU*Ibi&%AR_aB{55f+iaLFro5s*KHhAv zLsi7(F+r9Kd%BCcdW@cZZIf^QXAP_(CU%nxdntWfV`U0)bcSoUC9&(t-ZVr_qTMym zmsysJUUoQ1H1=9gj*iayc4^T$G1A0akn>?@_yOrr zC4&deVe05+aV}MFmyYXW+#l^HZCZIwzwmX5V(}9Oq`J{4SS;OJZY(nW#e|yzaB}>f z1CEJm3DC!YgrQC=%NXf2LbgGb0?Spl1B0sv)otMPJx}! zj@FZw>H>ooCPf9qjk8+}4ydnBW>QD_95z@bI)?Xi=@{|QTd#|{>MjKPLJwsS{g^@F zZw0V*dy5JBPG5L|vhc*JoXH}P=pfM3Oa{`IPbunQFS|RBB_1IqPZVhW8zPMX`PkeX zM`8^9jY9PPm2rShFF|$-uJ&doo)7TXY}?(6GKR%0eYe%-oU*3F9iOJdk*MDyG7p&z zghkW=?&U*3nUz%@Sl4{-^u+mGUrVXfMHwxWJGh$2l;ORH;F7?uiuH&UMtLW_HtfJdJ+p=jX_7 z4S5}MBSiI9Eb_Pp|3N3suXlzaQQh2RH$1HBS6|zuRD~p9I5s?o^SuuFg#|CR8hkhF zOpCqI4f9|W0p_t}4medf3w`e5kJntCTy<;ShEHzXCldX!0z#*{{KDlsT{#1tx-YE! z6kcn&}6xm6fnn7II9+A&JFh6^lB(>@p#J$koyJnNX#KDOAi|hYv$66Y$m5!x7%GA znL|4Bekvl5wB7b`(NsFp$8^0$_~hP@O|JbkTYLN$?@fXS94UO zbvV{PsOr_D&V0L+NioX!yK!=dEFE(ox5QoMNJEnNSw>((do##1$7G(ak@P83rgbUSpOsK5c#?NJ%`uAOU}5jQV6Ofls z*KIuX+gRvW?Rnsd{#=HO4o7X8**Fj-8TT>P4^BvBF|p1A`7pXCokC5CVaUu*eA@`7 z(%Xr+fLhu_QBgnKl36TlJ~AC9bkh>l)M$8ja!tLBNa<|wKg@>|EG_K6#Y*HVA%cN? zA_~+IQ!=kl!M$FVseBzw0)8%CEDz>uCpJ- zZVFZ~1xa=WIi;qf3>m(_0<63V`qg8oz`oHlcS3z-FlZeqM=6wnF;rNkJ3om%DN1==Kvybv2gzSostn*Xfi}Z? z^L)0IWk=`Hbt7?87$vE%v%r{3%{E^Ib*}~lD^={Q;uy8}y zyc+kVN{y5@j}7rd>id{45#hsOPtY zH|)WhZ`)^2$Ru_TjCId>gRa;suc+0x28h0rm7be2UqLY2tA21b$8Z6-af3X-f6x7o z@-uKC791dvpBD#He=SM&chLD5yK-4I06KICPp^t#P!l-a->o^-CxP{ z?TNs)_6nvWuppX@#{XntEWCO@l*gCuh>n1CHo(JSv72)lBxw)`&H1`+YX2I^^x-pU zc~QBR?engBW=XM~hngXcC1dROsnU#`ZyV4{kR$wO9l%gg?bnyv?%DIE*lY;e?|VO8 zv)z3d4cRARcw)ttJh)QjA5Hi4K|h>3K=KG%@g0}C;(0RJ>ha;f2uDDEQ+V%ZIlmk=#07E^i{(y;_-_>3fE(y12eeN5L3bGZ-8Z3Dl|2 zL2~9hbAxEJDbwiL>s*&!&9d8dt7ZyHr@mLeny)hAI3LK4O^f0Ec@ zZP^M(h*{5l{o$i_siU{Ah=S580Zd+)%k+Iipw-SD)O9A&P&O@x@}FEj1`ELCMEPlx zw7j_-OSk-@Y3#|&mjVGSU7&;TJlVfe!9j)z{Oo6GbtO3-pq;ZuJZl@Vdq#FC8ers! zOt}p0x;a5_;deH78pwcoFk*K=m-}^Dcu?=G_cP);>a{S1$8Mmuat3sqiN2M_aSP_=I4bI6RTX-N{V;T6cTsMr6UW zHAc!y;_?1?P4%;+G+0dt`u>MxGQy~?a3$|E_JL&?5wkplgeXF;GMhtPE-r(k)C}Px zO9ri@qKcX7Wwi@Lzaybg*d6=j#AVlB0`aEhx2i_KZ{WSj5k~eU{Rrd$T0hDWGl)Q) zZK~?_+|id!Bw&RlHCt9<0)|mq%2B|T&^!CDn-eW56v3DTiV|+$eCB#7tXfh$06FPMsM#Z(@c-$Cx$(vu6DIV8DT;)_DBkfry5$p)C;ThSE4m8`Ma(A+b;;)7G%{8s8+zBAL?dLNO={ELC&ghWoD_2ERl4FL ztC6f^qEb|O)9ZB_5K8z7FZl$IvEE8Y=bhn92Z)3yOY9dp*DuCL#Vo*llT)Gk=oM>a zU**FgDM~B1eAwhZ(WF>d>lr?z4p78a+!~k67API69BbgG-id1<2s#G{@T*ETs zO_1f45)R)4Vr?ug-t#mWYGiNmnIMZuN2lZKkNuIcp6HF8%T|7`m5@(8d^K?DZ4Jl* z*5ySV_oUyVIxt;qU0S9m6Tfx>2v1}-P`|vuHMuydyMtf9zc+*W+q}GIYKDs1=gWbc z2fXrUYw0AI%iQ7w(dw6WW;35Ye2p;LFIbV_^WRUts@M!@(hb=8Q*&BcgFzu8%l28| z`%|6%i5?fBq>C1<{qDULTH(9G@tb0RvHOspeq)f6g#*_NI2y>s7B!8ub152VN;XjL zf42AlSxlbu_xw&IY9XN5J%V}M*ErpXNrFV;Yq+J*?#X~Q%0{gyyriU{XqW7#_83}8Z`a8cBS;^Q;^nQmS7T( zHVzL>({MT4C`|uh^3KN|-b4Ia#SSctb{VuIs^Uy@km*KyE&E+{mwaMI)Z-loabg_O zr>-%4T>dd?OGZV>nm}INnD<;2Y#i)7=SMj%Z( zrt1L+2ka=JZIK5J7i&tbCHlBHTgbhGw?3aZv30TYs(2bO>&9eT2&+tV z2x7@4?)4cHVoP917D5=UhwX5?mW^@T;0oSTdx51=&=umfn;HF~5W$U}Xu?9@-cTB2 zbR(Rjm3SlG!$>-oAOgXSq5R|=Gn-+K!hJRsuRNs^p8M(J3)-$&2wx2& zs3F`>fk0G+(oG=0N5W1)~Z}y{v=TLYl=u zw3fdSmHJK7P=dO2oxBaz%TtDG&}dDC| z{@_-8!1)ranw{Rl=CV2g{^=Re#W|c6S|xrcp~kRY(%+Anlon*8w;1=aSO8ly$x+k+ z|LiJp72*r>S->xS4|HZvsWM5cf{`u6na0+^6#83oSQpvmr&h&w#zcz`8hHcv`JkRl>Pf@sWQ}bERWSLI+VDRcf?`Xw^_s0XwzsOBStnZ&#I2olguz z)JgJInRfN%`Ok-x6>9=ljkr19Sh|ARO24mgR~s%VvO2*B`%Oa*r!{RXAB^!;4J+;F zttH3KerA4bBeBA3FL(@;AXrL3Fv832f>G##Ma<5or^!2H--YEmvJjIw{-f1{ z@vlT+-A(4fQ$s96d$~=#mXEHBQM2ZXx$;?X0Jhl`Ih0t?e?eG58_kKP1{XF+y z`}JCTZ{=Lqd0xkP9G}no!wg0E?f=--b@;TF6wY|R&F#()y0F}8*0Ci^C+S+se6uhC zf6m{${OjTi;YSYOvA>p)sCpar@XaZLJ4x8Z?^&Q^V!(f#J@NK?rBCcE*-nvMY6IrW z4oIOb7SMH@KGuHjcPl>G+^w5t>=+8)9Yv>f(QfvKTW~TQGJV8s$N5?ji+Qgre+IEl zD%`~sr|$!nRN*ZV`Cm(cN87#Sw_gE&Flb)Ayf0yy6?WjhRv7UZ(mpy|PU^&3B{ z+H0hF^1sTT{VvRoyPyH^YQ}S^Z<>PLxi4$fF=kNH*Q_;1VS1}` znfUPq@~oW0`zP~_Ta%%yrGX=KJT^3iRFJn#^N9pt7F}XyW$u6l6Q9W^{7lM@x)^|q zg&pp@!jws8Rix<0rb>@uVF%O$;mjS{EIp0m)`;ko{FO)xsjUp*gBts4*+y6Ei<(s? zyIF8SKNax_p2xB;BU9=&M4r33W%g9onV3bbbo-?upC=o2YorpLp%O7QqZ#dTol;sG zFy`cRCh?oF)}!Uz-B(mlGEk0rn}Lwx?BXr2(Yf8jj^v|jkIu+7@;e-#VseNoEkzU= zNl#?J5oQk%bnRVZmFX+Nir2Y%r>)hr zK9eGK_1zO{DA1?DdJc#)7>q1@m&Kf5V)Q2NWN?dT&!W=i-)3LGwB`a>C|B-Hi#Z8> zAmabU=6#E@f%WW`qPROqgGfD&8)qS!0*^fIss|7?lzyT#lB{`@LRPI%M0qZZ+3YJA zn>q>MuKoDz8pedYqv-mG3<`+MSo#JspQYcE=L1=VoH+nRJb5)4kXB4$n)Ch5cCfDl zDY!ISLNPC=-H8Z#psIe<0S4@nT1Xg(=y3dCAkcBf9Sh{*$(s=K8idl{UMY`v9gt6G zSpAqTySSIA743~dk+TbrOvUT%a)Edlhwl{AYi1f4c4AIxjOX>dn_a8t&k##&dWw3i zyxT=2GYw`y9q4KxpHP4Mkm#4WOE~j^? z2>^mkogtBwML7m4fgv>E0@aU@J+?T?hOD1~?9jFok*|3Y2s8D9iUZ^_%8oh&m}){@ zlKm_=@HMLe1Mi6lL{w1x&Yksx5+6Ay0A;S>hw9JcinWIf*=$=`%F&-?Dg(Yb#Qfk| zvHIOBegPa7eR=%h!pvih`in<82$K9S?E+k#DRwS2C*lw8ZqNm+1AcL~v8(3}Kl@!vWW2yvRkbLG2s=loC2>W9Rnh&4-?kRm_|GP2a$Gd_l9C zo354NR2HxFQA=uQx+WT(t%4xKON~4gk~plq@5D#W9Fl(|UM3NeaD+$1?s%w_YkF{5 zlw6r$cj@zC!y7Z3;r6L`WNMr@kcJJ-NQqnkaRL5^$+7`x`|}>3#d>et#{pU8Q#HcmM6;2KTkJv1<&)d zQ>qjJU2tKgra(uCJ|Xs)aDjM7)l3P){+Z<#=DjNJq)Yy@_qWe-uCaFjkJeRl>AZLQ z$T<>q(|JvgZ*kpuulYqOzET7YJ#K#Eud>z*6o;L_*^@q40PWA?H~BO7G21|^Xrq$- zoYhA6A#m=i%b2e7Y7HU>3(#B@?b%cEa_*8Ifc0j09Uw0-fr$FD&931?4?4$Cc01O+uB z4==*CH=;O4sT*&7_Mq1-@{#}74sv(Dgud64`XT#VK|#aMYBgFfM{$<;Sa{rd6R}Q`7q+?Y^I9JzmU1cj zjS_$L*Pm0p55eEWdNL4*wU)>x#P0U9?~?BvG4Vo{11pm`TPYU4QOX#u4kYTQM8b*| z3n0G<2e>(4;sA7%Rt_D@170QUNm&8+(cQSs-!$Z2@&66w{f$yYw|rvi4|3H|7OhbflpzE zwnr&Knz2|))hk`!4L{T?I$0_?82m{~o;h$O^jjDhmg?l>{tDNf{Jxci^ZOL~KrP9-R(;{o1VXBvZsXxv~`G zE@14giEOgle8Halr%!EFRf)ad_X;huX>j=z+dRnT6%sXWtpkxsruSd%iQN$VC+BJJ zV|1db`*l%bCRc^$i>8<9Un>x{0m}i^X_8SYcuq`WI7P395_u)}(j8)+){lBzL3x`i z2b&i@(AolkI+NCMdy=%vBu|l%7mCP?n?k;Qw z$b(^^9H4okX_gemdc!S>%xK{v@wg3AHp!{__P$x}CiTFM^Mf77KDj!OBNX8MY4Lzk z3iCb+VWaJh4^G9BuvN8u+ERh=N~L48R@p=A4xDchyPwp) zq$3w;vXpVb5|?#G(6_W4Q23-i(!N?L@trF+A7^D@R?0slk?!f@zpHd)Ti6OWrH8Gv zu2+XuKj*YwH`>y?5ahZ)njxX}OOET+boTvrDHl;W)3?paQ^F8SWmK3pjl>iX3VaXe zXU>^2IDh`1PS{H(XbZT%7^efTsej^5fB$1R3T6)?$^Zl}(VMo9I@9|TfZ*l}f$`fG z;BciC+9g-3hQXzPqZEH8V7>n<~AIoK?s92Aj>sxBB( z(9>|8X6{|Fouc!evNGn2ym+vOW#-YAT25`;dA(A}+)%lh$1&?qs*NKjdU6`wyZM2m zPGF>K+BAV(mct9KD*X%{VoA;|5nqRE_mdAUjx^J97XDrD4~cwY{lP zJYwGG_>;|kq|qZTu2cwlr;WH6em~=^Su3?(lG1S1n}^YR0u@o)b`#z}mdt}RvGf)+ zb*gC^P0E(tVV|)_X34U}m|V93FXRUd!4Y=3Grm4T>r?!L0X*IDrQNb#;p(Y_~F2Rj&@+-VPo*D)f#oRL2_#4GbuG1C^= z(KaUovgjJV*~(gfqR9IRc4fc*=0geum<*M?9PG$7*}O>f!41gBHKuUh=c-w`WaCm6;LNR7 zWyW@Cr?($&UDMWn%QJL|{zQEB-V?o#0j0uWzZiUtH-?(sJTs5S?Y_lH2PUruTi^SD zCYyg1GId&Brv40v%vW`wk$;AhODfj=pjac=4UEBs*}$|PrF+;z9zj%l?h`Cht8uM< zjJ-jSEs6S1ior7Qmh`G z_tDqZAn~oxhNX()z|3P~HPECIp|d>7-knuC+7h$D+${aOb@GxD+TKdn#xnl8CPL!D zb!dAVJv?>hNyuV1c9VokSFST6&7c0lxpN^37Q-F}Y;Z@95(>~LDS_jRgP0mqj)FJiu!^wr|ER~5YQleSew+NB-%mFiWw zO1ZC6`7n`dh>!D4A1{65=qvzlq3HYCRX^D4&#d}=)8%N|2$&r;-)DI<(zHh<;yXL{ zVI|;IUa{TgCns=e+Wf&aF=_UZ>cPYYPVk#$+j~~$)$pIaKU&(ho?XB`?;fH)Fw@5L zbLh!Rgb4)BF|i1@i{L})bEt$=THCsg#Kw%+_tB{w)U`o%kMgvo)zHuH zl|8JF`>PK73*Fkwa8J9RW?^b=8V?ZLM&(ggr38(NFH*_V0E$p zGk+Q#I5V9{EX<$g{wBMOu4cf|wqZa|mvy;e99Ao!2cM?pHL;*68xkLLfJWTX{4!#W zE><31-dt-=b<*Rs@meKTc;Djf5JU)OBUKz26JU}zdSZEm8k6b*hdI|z+Y;a(7z+G8 z=IJ6Ul@O1l#fPFS_7h@&)rsrrfiP>JuKWMITbP31L!%ezp;!1P|J{)G3?Q6dRBowF zD5@KV@v1&zPQva*QM4cUM=UNuHmrrNuf~V0=^Uk!X8pGF$VU&)Cy_Ut{_!1H>v%a4 z0!RGY48MQius3wKLOAbvD13U7%0U{@Mf#OQmZ6z_%S7c-(U8>QLdhMZicQGJ&hR_> zZJrW&2s))e!XW>rI{Y#R^R-u=dn7Siu5_7fXWcTel|JlOwcOs<)8Fe(=@0^xM;$@_ z@$n-}Var@`)9}jAhAPBfb66cNi+FpV_I!_7kvcZ&iW}`CEWv>)uRL}Aoq~w^l88rW zf9q>n^sO#b67Ejbheq&0hI1M%k%e`KvA*>7Z1PWqfji*jQADoayHKWaPKx$5!YkHQ z32&E*>A}VHzK82Yw!OY^3W+d8(WOSLGs}wF`>3SEwC|jg40XDzqwyr3+)9(c7nk;Y z)%i;v^WywZNk==Z^!Rr44GZ`=73Q&8Cv~ zoJ7JRGU{6ogbPT8B;}8%C|~11MV;ip?|y6c=buq>y(?sQ4gYzvkNaSK@?Q2Bu=A@q6)2*d4+8=a3b*8jz%2&8<7Igx%tg&nD&a? z2mV?SbKv2RD{~L}eMNpLOK`|CwM;kNNdzRGZ&A{ce6A|?f~U`4P2cC8Mx=_+`O_Ua z%-2yy+)<_<0|gSHT!7@|#(hj#8%SEO(2;H5;OFszncZToShwhdfvR}7CB84^v zdf!uI3mvE#W^p*NJti$gpnZdO_wR6=ZAe=Y2%1+CXm9L7D;p(X&+^y=EB(~8W3#!} zG?6}EQ5>)FaXg;+XH~Ra+>5gz%8$v;S^k`6;iI`_tCJ@y<@))Ga5?Z4%jG%^d6zn8 z_oG9ng`Tkhm+04c#s}Wh&oc>r?f1%e!cVq(J-ub^+P{JL1*?PQ?06M_AkFLqyL3m4 z;_v=oE-~#C*+FUZ0 zR=$~kZ9HKnb}8&Nm$nsvN|k2W)tPYmhLe(x$-Oe z7os|lPWp&t<$d_#Kvq5{wRGxN`R~0?G_FcsRm-u_4^x%_0SN-0+4gJ zFdPYzh2^)uDh$!($@pzqLGx?ELG0YAGy7n1K@U<{XQ zk94nW?`hmvxWI$lWw>STNN#7B1$ z+1P0v(6NS*Ic9_@Eh2m?|FQt)^{V4fH_Rvq;_ug9i8s6IBATBy& zqQ=NFaO|g8TH`fRV?+Wb?%aUqu4q^sM(eWlm}fnFK@>QiBIvCjaOKU=MjCO@VP}Zn zejG?-dtMy?2Iz~!rLSOXz*a$`hh+A$X$GFQkDhh{F>*4d%pUJXtj4siUD)N4t%Cb+ zDIN_al6C@uRf+Z{NGNBTy#3<-w3O4<+_y9=J{01`El;JtZy3s#mj~Yf|9r-4CdQS) zvG~{qzrRSTxu>BG^|*D(<8M;U8<>d!fPzgHxt9mz{y9_UNE#`iuY_WiiS0`wJ<*UV zojDAn?N2E@3Nxn?a&znwWP6Mdbi>X+f1|@jD;Lmx^>KE{1^F<^}qrDhBFWpHsKu-<=#p}`T2z9Y$;5+3#bW}`nOOoZ@auri! zLseWQimf@zUTGhbK|o@?o|#D-dI27{$vK{(wY?T)RejXB)>jjVyBi|xYi|fIcCRFo z4K79a!WLk=l|v?I{M*L~yNy@_%kLE$2(0ZQ+i+ZQT@!{_ep!u2E)X!Io#jyUkf=Q@ zKJ~o{ug()--~yqqU|G?-M9DEu2cf%l=uRVMXX1 z3VrmW;m>EkJ2MKW!NOfW)ou9SpASMCW>4`qtxIXyGX?RDg9IRrI#m61W)#psXG$Cy4a7wi3e4PV~8C>P-E0v;>DUL4Lglq3$4-2$c#Vt__s9YuN({PgqAwA$>;(+D|IXmNxYqxZi2;M!21FZB3(4o`8eIDD2-S+bpvbB zSl9YuRoni2LatE^lA;eoz+)-MB2$!ErmLT`QI&qm>PFieMIDxjDcKQa=LYeKsl!GY zL(hRpl|apSy#RcXaezDPS{hP%zF?6W?bMD<&8L+sGU?fOlA{Ks0X`;x$&|X3;SD_! zn`F%y|A}M*=%`>Jh^hGUNboz+b9MsA-jB5}jvK8-Ls8b5au2>i7pU}5W+ggY4p9JKGx z2S)B8by&<6QaS2gphpA`QjB+u1l)|O^AIOXMWwV~cqnT8LHqR(JBSjaI1)F;MdHVJ zi0PzJjR>;|nGEE4X z>AW3BUW-vRyzHJl2cQn80n~x~)Qskz%3dJ@TKu?~&j8UN&kP$RwuPXW`$IvyPR4F| zU|=OcMt_Bsfk!8gY2|(HE!^64I7=`DZUnhGVR>>7?|K}A9yYVK+}^nJr%&%GfJiYl zV|4@g#hrLBAkz~riC^x9rt}a8@IrU%vp?e$0dsJ0IL*I=BN+b-UR(*Kf0Ks4kzZ1p zM2ajV`gE8EC$NuF*LXS>UtU};SWM^!0w8N2Zpu`Q?Y&8!Sspd%r0mA3bjhpO8cU}1 zcSMYP^F6~<<)n-O2Z^K>WHtC67l{Y^SJ{(bp_DpgHDM+y5MU^-YFC+yc;ozwo$tK*qko*#%j2wyE|K~p>dN~PrMLZIdHP(W$ZTf^VnVw zn|Tn*b}0`8Doc7g+=q7k=g5b0e}4HjKwD?4LdzT#!;g9EHL36*H5AGSdhQqkb*GI^O7$A0~)6lfo=tnGp?4kf4&q+f_o6nX5)+`80fPU&&9t{4Svhsej$e% z7COw)xZf$LONNML6B)To?0s+@Zulet1!#)GZS?MUc&>Rb-;ISM8ncT1yPjIb#*xbR zn34LHatKSPw9NI}YpvCb8VYT8S_}?`!&7c20#7%a8*Aowh0=oZx12#eon@Wn?%9sUtsfcdU z+DIQBoHmyQne?G6it^CaQcNv^LMbMWG(Or#tPvkIBfwG{jprAZzOJ`0b%!T|#1yEB z3hJ2lD<0>z;(U6Ee2+Ssjn0+-j<48+FoN z!|+-5*ecx=@6e_SzJ8VPl@RwMi*P^*Vaz`4qkL@=9ANu*ktq<10o7E4KII0No3OdF7BF0xsNLJasg#W{B^7tWcdSFTOPanO8BJUn)5Z8Ij>jFUj7)r`L`S&3m{tYiJZx2BD{@FUNgtXG&aWNgHa^~s<~+Dt$vD%NIai~H-4=AEIM{O>GcBI zV?O3idHX439laU;iroT3)!6`?yvnT8pLdypF+>NCo0$OJ?=@gV=f9C9_VkJ_aI`_m1iKp({O>?5%zRH0 z&}cey1`WTjkMVedz@;1c2ss7LXAS!cF%gDFrd-vHqZ;!7@n~0>{{wyUd{S|n1JGj_t8(th=^#jKisWo`zbla>3 zLKEfP9nxZX~ZTHEnmJ$bOYZ zmRf~V;F!(m6T`AiEY`=(EK)ZIZ>6sdh)Zc4-edHyR3z}lcJD4xqWTgn_C~BSwA^C1 z-`+hyV!^-G&+(DnA9xJ+n=sb;P|UY%9B{M_k?^E0=D#Qx>2XAb0zU2?_k-@D6s?qC z*^<7b2u+ED6nzg?i!P3ZwJ~=#v&7vj#+GK2>IH@|WTbJx@@U*!q{Ku;Fo<3@4?qS^rVXHZB(vG5j|Dy2XXYAs;Gl^BuLM?E z;EL3nn1Cd9!K5wVestzQwNsJUmrM`V&_$&g206d0!9x^Pl9IYj`g%v9_9gIH_G510 zq0D4G0UH5+$`)4KjVD)2uRNC$-^{87fh1v504kinQaA1IbBJTjVE9%D)GtnZ9V9WMS#j9J#~el74UPQD(_ZN z1XD%M_#L}?Er}1DRlmS}I}F%sMZ16N6aiW1Mv1HiHC0|HorMqEC(kjhb>HOAf5Ch} z4h?|wEiM}UeWEZ0_dqKj;KQIq`^(nHwQXOS&Y#9d#8tC-Ehf~uPjQWvze6{PB4Br^ zfGgjBm~EeZ-(7$mF*;)Gk1Io1XOqHJ0xS98W`nm|0Hkg(6yY`BRe?BSKy7zu=le&x zM?EY)?2i+cn0Vh?fQ;n0<~FYDkK=Ypa9jwj2pp@Jt70O(p{{y5xnJiTL-7=$*j*SN z{k%f^gy4~hkjeqksTLEaN9+y7L#woF4cqIXd*ws2l!xq6T&hP!zKg|&Sr5i|7_<=k zg*?O|!bOLbg@>`F&zyQ{P24v+jnP@eEg0(mO1lv z`A-kAU;wI(dtA^!;&I{uA&sD7k?YYLLXlO7?4@oJli2j7w)HW@6yoHTZ{B?Vu@e{> z^Nfv|AV*%JUb^Vt0#2=Gxn<|ySpl2>^^#}oj4zM2 z!<$I%B&NQxnXESD;;Vu+JO^)(dZ1fQ+yB@BMym{yAY!xxD4O@a&d7icOhqhf8Ix>l z3XjhFE6PJ(E$&3r_do*Dy*<@10q=oJ63!+JPi_V_0-@PC0Pl%6^!haN&hz&8kC*1V>Z(y)+$k{{PebldtDaZ}zOYNbfG{I8 z7qqwhldoHj7kmZTA)qg}9;7=eUkrBs1yd>SVCjWOj)s|Za1don2yRw10hb)Hw{=K; z_z?t#r{>XqhswSs`kEV2VS~JSCDiq-m3j%A=Bdu-;Ey4Wyzf+vR?F(GdGYzuXK>(+ zN4z6!PYY{mXr*@_RwU-qqn2@0>`_L5qtdgBBfvXqp$*%Y2$OE`gn*!*kQufPbs84n+c1Irf|Qv>UHRLY4D$%Am_+OFWjZfqC5bg0|m@ z0us^Ha|hxN27H*n6Du5=@4t0O(%RNd^E|X>^ZQ``RENyFr}3R30^3!nYbmk2Yp8F% z99hQM&;P2vz%T$+$`je1n{xR4F-i=+a6Wv_u}I}&X+q-ocMvKQZg16anoxzkmD1m& zBrYj|*5S)y3~xNbcciM_Y=Y;-BhD8p;;Jr6I5+=poe$APfi9M~Uk_Yftf=RLUACD+QvB!~%JDf8wy-2~Irj1U_&Ab*^W0)fD zHeN6j7yI+gE35W#CK>PQvXp61*a+`_nG)V}+Ke`&vOmj{=YwLGcl*TA8f$7*&gzx|LjO%C zOH#;Q*{9%?19cQ$`aZk}E}()BN@?M+6gjnspY z`}cwR$3?Y)1ogw7RT>mXSUeZCmXMcNIv4ZCSg}_XZgDPfw@D^#uj4)TFxp3zsrO=Z zRgqaEd&qp~?Uv1)VG$k`adEgiuaO9rlCiu6qgHijgbZ{{(hMQjz7SX`3_tjQ21cJ9 z_Wa4J2@_LUSgQV3Em(3bvr` z)qCI#*}}@tw$_5_P?hz@JAAD~#$b)mOC0hwE0^Wn`x1=yo^VJAd76)dhPD?hRJcZ{ zdz8Jh%I63ZV=nEpHTU(1xB+g8CA|JH$O}x%Ilk`w`PB=me!t1S)|2oiW?j^-9Wq~IHm?Vxd@|&uh#cg#x=~vQt)-ZP9t2+<4 z!@GJRA&s-iU+>K6RKf zP`Oc*I8%7OlUBx5eL5@A79EmEe849R^|vIyW3A6DiNq({WB?bxQu_6W{#Qu(YOk}( z)qrbKU+U{wpf5I`b{j<09WeQo39b)OHAH&{>XR?89)!7O%17%4e*UYia}1Tpfz_YJ z{uI;DOG*N|e8$080Ml`pNOwz{RWPbcg|v>4IfU7TR50gaob|OhbRYclxy3e1gVLil z^job$;leU}0T0~Tk*yyI&)v-;JrE1}Qf1y{g&cm0*eRuz*p0ObVhw7gx^OebZkQ7>km++|i3QM}S-)PSF3R0A zS)O2z-jA*bv+!=}(!aGQeyxWjaC}u#>D>Pf4-MVQb2flpaklgrD%^frZKnPC>hFv| z`CV}{c1gx~!VCZ&ka7lWBfby4@F1r5AP%q5$$$%J*s0JmFn91adkp!x_I50BNs+)C zuG3Z4rW5GgrwQrSr6+~I?EoO&HJRG@Lsj^ZV*mV_(h^8xA_3gRZ+gD~(Oerjf_^sn zv^+1%bI;#FU8}WBqj&bhOr8*Ua6H5ERwgFHsv*|C3@VxVt)v9{dOXNAu77uRpyYNV zFm^yi$feLX;TJdiOOJ3xJuUzcVWW6z(O0$k^`}+#;7nrmcgZIJ-(*b(rEC=qd*&*1wQfzp~zwxn9H&ux+I#7t;)3fy7OZ0!VlQ)T>=iyAr8VV#}cFouO zbZEhJ&#|17rAtadT?78U9HNY{cK^AeVI;9UXwhp0n1z}6Zzt8=iz=2t{J+t{`%nb3NPv6j;dkKgUiUP&mxj~E1ANuTl*{)-oX8w&6f_kPF^YrwdJ z^!NxGBNH~RaUpH6_tWjY4wf?_pnI+>I|z%j#RAY*$|f)mlR~cL!hAzB{HUSvZ5oS! zJwqq$09a^08O=qUD-j#n!h1+{*M<#_&aK!;Tbbkxl5-;9*;1O$PV9EE!};}$#JxV8 zs2gR9Ztr5wQ2zG$RZ8DiAtM#cG_d}RkvmBOk_-)>pFpZ#EOtKWwJ$Vx8)Ri&aOlX_g4xv~`;ZiehQ}3$F?` zh|aX_QZM?vT|(Y1y4!e14M|?3DwRem6Y?50e%T1&sQ>6#NkLHe^cOqoY1F>s=o%aS z=>ifBY}2V_!!}wBJtLqMn{nQMJ499dUv#Eby|!K5wB1G$^mv!CN7Rh-jkZXGeS4v` z4+qh0SeOjOVZXy3U|%d-S4;6e_C|5q2-4j8|Mf9^UR9q>g4^vo$Tn=$EKEl*`R@f{X=}*|FUO?nV?1& z-0^WDk<~_lPe z*PdqQ=i`&hZ}1vvre1vA_L@5;PU!~0?ZB%ys9L#MTGh9dD-`oJ+tY7!7g0KUlgGAD z;yv7`4e~`={u}b+`2P#?bAt4kW{dgd^8m=1K!f}w^Wk3%%eCp>4f3D2;u2NMpxFct z>`gvC45ZKP0Z-fmtmFHn@HB7CB{BP(YhY}dHML%z|9O~P4ODRCa(=tK zGTy>mRrpdaaXN3M$zWm@`a>Y>H=6y7q;+{VC=pe!<_3J+NESSkcAjiY{|uk_M60rq zgTWD(OfuT17J}k>6HrT4O((@1Fd@AE&EuiK+ToZfTjDzEXy$+30nlT8LUys@FtnYI$PC zdCYEIBiB^z(`d?%b0+x6^PYB!J|FNAsj7%HdW!@_)MG{oPCZ7TzL?7U*Z0*TL`d4% zWk-7R57}==ZCx}}H%V~kBM;r}RPmZPPi%HT6``=3JeLsZsd`~~*u3fNIzyFw-vbOm zdptE5r!#%G`0%IFc*zaU7)M+?z>FltEiOu`2??hsc5iz#c|_Fz90ysPPaf!4dw((m zHnO+SNCc#8-&#vCo>aD&21WW?av5Br(tRMw-2&D7(wG5L?`%{jhU^fA;Ewev<~@$W1{K?s>|vOKHEOkK&^-s+5V4S2Pt5Aid`yR7j~BP;3Mmk-atm zr-_)yJsT1_FFY=uk!YI&Ivws-0FA0nB()8)|C;Xpy=#e}4SJg1_)nu2n)8a0LX|ji zHk-|04D9U!7ZvP?_BK10)uK{KXd728>B$|7M$hD^)1Z0b&)NG)G`5KOy;i6!?1|gD<$X}>m79+fdCnv4_g@(E`ilqqZy5y zm0X;O`MHgcZptFeN5_oaxPfGWdO5@(%-%|?c*xOVzOwEUJI99>$|}FLwCr@*N_gvs z3kyAzp>da}Cahy`2bz&et*02b@2l$sbPu!dHv}FvQ^u{QM3CyTpw?1C(%lXBOcP3;zehY49daoxl{4ko(NOu-=1N1Lrt|o@EZko(Dt0cv;_{;@w0n{<~ z4&(xErgXi71SpG?`asNG%0$-W+=pLV)|+3Zk5}7iO#m=eBnEikcp-ptmdngNaezRr zs-_~B+Z|3N6=1DYRC?x)VT%ZZWFt?pZU>-`IrI(`0UTc6_C_MOStDV3io!C7* zPoWB>W{KX;OYF|cWF$~0YsjR@8+l71FAE86liGK0OeteRJbyq{VQDt-7d3;n#J!F2 zDbW+C{R*(N&)$7K|EIag3thjKGn;$<>=~#!Klt6(#*wjoDW-S3-Zt07N}1ohZ!H`| zI6*W^2zPc>U$ZVA3b#m}>JxfpcBG19hv(4TqL81U%vW8s*N~_}@>s;8&>UTCm2r8R zduUh;+{5Y^UutOK919!#@O}H4$0)tO7~PR!zTfC#)zQIWS85c&0I=&}#Z9?-Rp4@} zycOa0h0%o*Dl{DV{;@3d2ff3b`yPraDD;x9kSEqz$TM;Qqp6Le+$BKz(pRTJMQwfs<=K({3^Hk0D+$I39xD zz4{B?=6Me~?y<);z@5?q!1wY{5Fnp=9stq!gs6lmn1__?fQ?3Ua((o5(622B6ZK5% z$yKg406}*!|Dq|k#O03VAY2{HrUS8K>E8VtpI<$c_Dd3HeRpA$rsN7C6@|>_L->oicosxrl^&MxeQnV!03E{B^GbLHKp5=)fa@d%KVGx4BUcJiT(GKhydMdv9Olp{$*AWqZP#rZ@$ca--_-Jv*V`bUMlIUljd`E;fElxjQ+4Ik-CF8+jDKC zPY2z&mZpDjv0Qe9YuiO-rQxuMexYwL$H5Tkp?5=!YlI2!_u-il_29)8aw7GjkgUk_ z#mFt?Q)&oy%6Uy@|8-^Ag`NeT>{E&H>7*SIChKC8pSB8Vl`Qa!#ZuiaM)~brh`zgD zia3n6vsyiuR`hbg4a2Au%->LMB#jWVXCy&6y-oV2n`%lRy0Nq+oc>lKf08JVa3ri) ze^K$G>b6QL&}Z5cqiX^>ddip!uU5(>KhTdEGoxB4Sy;Xxg$}5Clfvat*(YO9CjU=g z^0r$qbH?@S6Y&BDYTlF!Ywav@qji*pR0npexev5U7&paAe7tL30{YWvt@7x^*z`;R zG_%?QN4+swF?a8KFb!yptv{1={wjUzWtzV8{MD2Yc@1}6_CP`U5R9K#xOMV!VE#76 z_q0KYK^TAQ{wuG`0Bc^-D3ejsI-AiF@oqyPM{T!Fs{SPS3~@SBXrKIf#qmXw9*%fP_U`(()4&X6PCFFu zl=!ldF`cQ|II;OFXrw1UBnpnZJxuAi#bl5SZll-g8PoGT4wABOzW_DO%bVYXY@+x6 z2fJaC3Upp!rZY$uP>ONoP^TDCCTqj^KDc!_ugTt{@Kj2`#*lX2e zUQ@Ql(Sc=+5|x@F;?+E?ANnaa&1rP5BeZqfaw5>iN~QFFC%L1|`$(!AnH#kq5X!O4 zy49GWz_|ff1}5GgYymOt{_A7!M>q8owvf#6i=nu;uyE<=dLw5|$I1TNgP&_|y?BF; z^~d&&1l?n+z6Y9uXrj9}lMU|W1@uJ7F!@9! z9}wxb)hl_JSX6)OYC4HNwk6V#bTtfZwo7u*T;G@9CPC+S0K4z85CNL4v>iw~iJEX) zIq3yT(5>Hyi3rsyqW6?2--wxgi?vvz3AHHl&!YAlOrl>_O{m*L8gskziVECJWa>yL zy56p%yQ~`{jLtI0-92Srw6?XXM{XtrP+(LCS1_w8oRqZvUlAa`i_^Hfk5(IwW z=au(Euw0?RG@qnSgBVGSVdRlv1g%VaSD!Y2_MvVX4wu+;5ddj{d_IP{VH)mHw+604 z|9LKNLv3lV&7WVY{%HPwtJ)z^Se3_&aQ3!xeyYs59Q#AWyGlo(WsSm%9?uq0UW|Uqo zO~9xL9Y&wN9(m)r8WT5cUHuMq3NbUX#?W`i+TX_7V(Cpp%%}VWI=^)>Qo=ukF2w+NnA$~NOY` z9X_)M^yT|eqA|jZ?O1VQK)=+17sg|Z9Y>tBvxp^@i_UJZQ67#Xhefz8M5q^%!e<~R z%XMOPJ64+uK%2<);1e2>U|9i1rgr~EfnE2&pY>7*_+3)xd>Z(#N*k;#1ypac@IJio zrz!^`B4+67Hv8&5tl@DNuN!Kv{*8FBOc8U%uvNLLO=tu=ibi5n%=VT)%&eOq?zQ$& z#0#T2pqhhXaB{(O&@x+Zbb2Ww$;}95LMYf@`Qzx}lA_}!_rDZ!s7V|dXnK?&-1@cJ zP+KGBz~Zp2noyB0DPO5`iw3H}3 zTPIBD|IU+`_pA5w6NN9PX+Hwbuv_UxPnO>BihA47Ja_qWh+Y$E`D9^}F_9j@xuSQW z1#_Mgq|u^8#5c*#RTPXrRryknGkj{?e7lt0kP4P|)v)`j4vg!;ukZ6e&_fTjlR32B zOU-Wos%`>y713|M7@On{Rs+yz+SLoDG~o=Xx~w**hb$g$8qx}ynYe&1yGFmC9fS>^ z;&+55ai;Zm6u)dQ3k&mSSR97#P2a!VZMS$s|A~xsMYp= zKMGNxBq4al5KP%{cW126`LB=ZQWALz#!c7;AFuuRe9?pb51YCZWgZen z`2jOgT=0$_6yodD4?N<1G@LQy9yTG)wx%>KQT+ZyrJ-$iG|dFl6Bk0Y@I)e^G4=jw zk0HA>kTBUO7jHX|o(68W_g}&X!vdeVm7P=Wp(OmhPGEIXDI4$+|5?s|KYPalt(4pl zd&=)s{^#R6LadZZljC_PBxWHcoOB~ZhCt_REr~3xr}NtDr<&U516A0mKhe^L4Ef&+ zKu80xl#(oZ7d535;45@2a2RFF{eDH}miPtdwMnIG`6hnTmU(1>=r?8Bbrx&u{^PE+ zs5a7{^|iAnyVg;4fvc?fSaqV+=`OZIMfx04)_~A?O_Ti7epl+1P4E<_?X0V&&-Q#% z?nK@j`u=TmLXK6@G=|CZr^gD#8JQ&>uf@uz-Dg+=4@HQ@*VLI&=yO+AKU*XS_AniF zCC^UH>4)u>(~9g%h#87>6#!Ygu z%+|loGLv;n%)<#Qo|l(!9GT4wMEDC?S3MoX-2Q*Kd(WsQ*LGdhsVFd!CQ7fOU_lU( z8b}00bSfYs0@6W<(tC$Y=|~q9sZmjS3yAa{2nYm~7y?M|5PA=7Kd;}keCw<=)>-51 zG0xcgpS)xY%=6yQU9ao9TTBI3h23R%Vd9%Dk8Q@=o5ShKu|;t>t|F-%ZyLS7FCMxC z3LgGMhC9TCn|@GDONT!0LrCM*_5%V>&-OQ?bJ`aCaHz}OqR_a+bA$y=f;U1td<&$8 zH&Pyz1dY)AJWJyFg8~oobUd`=|8>WI80C%;O<>HLcm4CBpQj6%E$DqH5$_+U=u`k$ z3*C;G$m4q_Qw}4kL~qoxP`e*a^3tY0B|PFiavW~sVAi6!)8^$9T9Rp7C0Dsb7;ZmF zji-CV*MENs`?++(92eZVw>jLpx-=E)NXBA{$2ivZtnA!uXe61pldMth6LrEmIEixX zt#eWd1W)wmKWr{nb+x4X@>utAzrxV|jcL|wy!pmlxO-3AR?6LXS3Rmt#_g&Ti$bow zNagP5$afzC&zWaGiqT*Y9{_cNd#R8kKBv=wBEwZta>_)z>s7SuTwIXMaWwrt32Cad${J1uNZs~2WUARU3$or4E z^3${*1*hL}bbgxi=OZe}oQ0Hub+_IQyYTx<8G3vYatSe9Cm-o6sQo!AZzHaaLqOe0+g^22Y+t}n0IPSXQqIkc*}8X7 zqEgPWIj)T}s#M7L6zBD;ucG8!Lz^t4Dkbi9Q#rDlg=Xwq1^q2atHMonjOpm5t7ftB z<2Hg;UbMlc33Sf>WqSt+7kQUsWwmYHwnvLme5zHhb8|j~E96e(!Rby8fmBLrR*r7C zM1_J(nz{46nKw!1Ja`f0;8=|eWje=dmhlL7&25$`T9kEF&`#XG#lNb^tm%nY#4YKA zX@3Di%MCry%C(kV!m_j_4v0!>8?cEQ=%#{o=Xp{){&X*%gH+#s2(dNh{v4eC=YW;M zWxo9-zVSeo0U7*J$Ju9Ea9!S|P}PXyjgY~;_0sXpQH_W06kp`b>{Z5}wx7-i;#NA} zip#&b7Mg=O(CL2_VDSdA?WfPF`|feFUV|~w{kz3O84vz+v~WBjP}VLnG1PohAS2Rxd_K3E378HUtpX}rb|E&)?wD0Z0Oo#;gs z$q`ScZnq6P?pbjXRB@0APZT2H~uV z>oFg4yBi62bCS_V^T0~J=EyObWi{HNl8G+V^7VHzM3unge=oU1l7UaWw`Zxx7$sT4 zzC+nm9tu$25N&2c+S>Gn3G&txHv~hR2V%4pU*6!bP+~31v%W(F3h_SiCcd*cHZ}s@CiEgnX1m~5%EeHe=xQN zOL6dq7K!NJ4>ja zqyd-c?tIO*oxwQIf`_UnKmm8JrbWqB?9AxYTFD_iyor?qYxp9t*C`(IbKm+(h*Djz zu0Q)30!*$kg8+MNSYzeqqu<}a&&zU!>7^-EFrdqSbsT$Lr)?^*cylPW%sl>P0FPlk zQbfv^u-4^|b@))TM9j^^y3Db}BRmtIvXXn?HPi8Ck}KSu~HR4|cfb zRjE)YLFc*{*QkWEM9sVr++5OZ+|%Y6qX%n(nGjj*7qf~vZ7oel*fXh_lLFFMtPMv( zah>zy80AYdk0pq0qpIy3u*mVAL8F5W2|o4p>O9*pVYg5rlNNkL}3NB+C*^3_e?IuG&6+t7=2<4y|6&u|l6Mrw=Wc1uwGE=ym!`NSyba ziE#q0t>*y@at~AZ%cPdO!i{%EE}`~n@}LQ)CL|6?>ubDT6#oLCtSfso04u8@=|fCu z?XK-Ot%iqESGPD;gB8F|6vmI!7UY#SL2m6*-UwCd~t?n(Xuy(K}SYQ_;dF4=+T z{yk!L`jXN}Z{QyyS6CjD(YkSsxSw$g4lx)zO-c1l;k?8&)6<?*BU%UfQGM)$0ywg&-~FS|2?+XEXP!75f%TS>Q3pPA4$=0k!|+i!vPr5}`y z`?Yt8{~mk)Gb^`bJjf$3it_r{$Vyg7S9-xu!rO52iD9=jcLZ&^- zf}Kf&;awU6&3jl!)(7sC-rDR7M@}B!J^f$}d&Z2CIChf!4XtZc#DrfjiAU~`f}Jxv ztLNGhWH94ZFEs$Zq9i+47xRW!uq(3e3|K!o=(_>Iaq^rmv38o+j%7sqj5W>``)m0c zK^Sn)QLe$uG^nnm0o@(G*N-vh05eEqs}!~EC%eD1(gx;5gOxD0NkCBj%lCxzH#iQ4sLTrg2UzGuXQBCSoFja;ts$%BfOK`L^hoURx;sEnm7x}EbBCw&^m@=rM! z%bN=xF~#Bh(@sVQ_rJ_$SRT&S9jqYn-)JqU*SJ8dr_Hl^rSypS`V_Kz;ntXp;Hd-K zaT>f!?ct&!&6PvS(tJEz$c=2NdR1Gi)g@Avt(Z@!8?xb=nz^h7(^KN9&9f&%k1H2e zvLC373{%aG)Tox7iH7r{udH1$Q6?`~ypPR@l&94i>#=u*Nk#}?J9)x2S;g#lCF7fH zwNTR@^tODN=n4jg_LeO1@S(w;8=Y26-pHJJRa30jHz?bNz5c+ z7>vd2o0o6oM((UmNY`e`Pv6k68V+aW(Vedd-{$5{M{x=(*z8cfx z@;P>0bJ;m`G~$)uCez$RlpbyeTa+nm8ZK|vpCgx<#luUtL?ee;ea*1;UavIq$l4-? zX}hgU+`b(qMJ+`+w>q=^vQeHCW}zCPEZk{;CpI17Q{`SfyO}%KN5IWd<=+q?FlI%* z?m$kq-#$7t9%&JBT3~2`wrcH<6PVO3N>;QwqmwL)dDYgY9`@wswAc`-!!(0IBCfNC zcWRfTRx-;TWxHOGFI0`*Yqz0y!bZqkMX$V!PSLe`n1=c%cLZa6ml%u(ufor??IXLO6Zvb$Y z_pR5`>y<*>kJ6u?CRZQ$;`^l@>G%KBfcMi^@Y6)F9#js@J?!dLCggDS+i>I+qEcb; z&}gCH)2yKc{-=d4s$+QFIEgQlZI1+S^0ULmLdl$DVx|?$TxV624~CroJLaY@c^wyQ zjP^_pYwTW$UIh8b1r1)tB}ynrti5Ln^6w4qVbd7txOuH!BFOg0Wb3E!1Uhl5MtWn` zBzVYU`7sBA>9j;@BK}GZR&e=Kk6tL-mw6k4nWNr{Y?|O$-{5_?jM-|>Ap4|yP3mnG zLo2461vROR!5+?G)2`0b(NWR&@$Kd4j_uoh6=N6j?OS?n{%JL>u|ut7&H z%t+`O#ZqJ`qgzvz=WEmtPy9A#uIlrQ!h)xJmuK8p@GC=TJ*}fSYKcwk93;V4>^n?n zEMiRg5})YT%#jffNLg7bu?SGQEx z?uj>tesDD2C&+WeMmf$DmqWRonkz6`F4N9Cr?1&vLogss|21COU zJ=%dV@hMVPy}E+=4xPIhv)Pu&N%7uK9R*fhvKu9#iV?*b;$*y??d-8x?y1!v7IW05 z#MrR_z7(&}lCc5OU@vy0c*B9gEl}PnPL*#Zr*{*!e(DHjpY-S{`iT07l@RA`f()Hg z^ZbF-@<8$Gf<*nQ12Jt%xnc(hBTi4_R?YeHFHBLqjy;zUr&i**q26&DwJN^uZf7Nc zEi8mdU_y82Oi}n=3T#xmyMidyEt{!EzXO@fs4_k)FxT@;Tf7)D{FcPQG^Lha+tQ49 z!DxA>`z^Zi{;KjL%;N;D{d|Q;$SWJTd{!9;O17eiy`>Z5ANuU9*GsF$J1jC%+^po# zB0KA)wOs?xN}5=c;;YwtbI5=;(Lp`D_(_@ZJhWpAR=eQ4aG}q()UXRMKYN!qQ2XV8 zQ4#+PG!!bxrGtYnG8E<>b+|XuOA}zxu?-h*S){*s$@lY>{7=18lMyMpZm#&yHTk$h8Wu9Cx=w2wC7%)=rx1bxB<<=Un@*3141pc4MjZ8+$i_*)qHb^2|ifTYdE|Sc^E^B zr#BN8V+j6HmKOvA#Jg zr}WtfH_;RBA?|zNkJ!vw8gYZ7PVwfO>$_np?aENGQ`v{^J$S>mDfMYmVO$sPcDN+B zH8*@47O>kCE+N_R`h{dpug^f6gt+MBs12i)GX4!d;d#tgb}>)odn)Ef9vr99gY*u3 zwFu1PV114fL}JaLe>Yb;m|q3J)uPef-$p+k;aXHJdxqK!q5Fu0uO!qT{oY60+mwDL z3?cyw&AqDO85Xpz0R+WYtoqmpl(?>a^l!JY^{I-SMeMI2+A0TJoyq}zi=L0HmGFp( z`}EKB{3SD#u``ppF8_S=Pet@wfcXBxENP)Au{)!?cy%a+|6kmi`evm`vGFkF5Sym* z=%sJCzp73~cOF01Sj1L&^`hCLUL~5AOF{sM#<4pqj4D&)k)LsP`vcc}y)FIO;b>-ddUL42U_VL}cgh+I0qRp)0c00dZXi>iG&9>{7aGdEH7^ zu5sDk-5b+zI|DR8_)0Zc_I4%_VjJHYQG@x0P?x8n0>G)-3jEe`N`wiaS?!nKDbfD< zv$!P6Lfv8K>slB8yQ95E^S$}95y`L+SbH@ddrJIctuBtyJ(x%R$z=8i3Ao1@Y$I$~ zo?AyP5AL?(p!Mm5*L`Z(noJiRhF4B%4zHvzxnQ2B!s|zsv^)L@r(Udz+1l zY@|m^quCcs7-xqYuSE__mKUg!sW3}asz`?^JmE;gyoxtpN9+LObyAorH)l%Q6}day zi4wBDC>LzovGba=m45Ea)3zw&Xatig3a*;Tq^#yMQS6*9W~R11Yp$Bim~vmldsGmu z%j!naugpFqzsMDCnBp~s&IB=-TNNxdy|@d`dDT2M>X%pjb`2CV<-0!4mH*Moeib|a z`i-sxR42}JdV;K4>(se=!N-#)WwWw7G>$$vUv_G$xlTn9cLbqQovnscJ!QpgZc`hl zYCqG%RlC;OsE)$IH^aRAbnlP>!plHtHP;9y9+MM%r-M1 zehulgXQY;_sa15@sEst)Dmg2<75d$_N=Q@Z7FRg?$dygJx!0F|=Fd}d;sc~O8sR)INAjU^)U*JSlUG~pzzHilrLmwfrW&QMw{S}W^2%cJLJIA)3iPs$C5Xs}ueBiI!4GV{Jt!voEBBFW3 zqj)&hnY&riK4mqHbm$*=h_WnZlxy>u`$`~_Y06hm5%sd=Wa7kPpRgnA@ks@l;e6AR zS4u7IGeRVDaXlRErp8b&hzM|E|DTT|3NQw&YAc5N>zKFHpgQ+;-Hm#DRN>8sU*JAM z>Ba!~0y&w6}FcWm~sT-XMp9TbL6q~Xjhro=ook-xq=U4ZnwC;VqoY^Wr zHa)u%CWvMyud1j{we|3D)zmC}0dA>O`azy9<{;`pBGfHR{6pi{6*0kow-gk%+~mKt zls_Iv#WV@iu@Sy6gZ+ifm%~i?9+hXo69uSK`hBeU$=ITnG*--nzOu1vWKO^!XLDVG zz+g)1W@xd!c9KK0#vpu9woo>y+?QuNN#jD9RPuDE-F~)|09u~a-obf~xC3=*HKwp# z#$TQXW>{G@_~u&hGR&Eo8M`~0NWYM$dK0fCe{%W>FVW%N!mE^G%9knux=l-U5T|6x zU9vx&>B}TAWs{UfTiczW`j2koKg2LCWsp7O<#JFHPKVL>h2Ok$49@z7e))v~8&EHi zV&#D$%g#=blOrXJVU^)BPGjw>YZ$$Z1#^XEuWDX>L${SFb6f8bRn^RTfAfGy`H_@X z=fRAEj1+@aKOtZ2`E?$6pVoF+ijpa5wUqF=Sr=>JKnGTypZBQj=G1Faw1nSi6`kbgENcy=Fb-M}_#KSct-G4@Mrq!v%*QZ({wG4@x&39t>pnak%km>2-18`9`VT z-u|$7l8OSzLJ=cm0d$kItE90#PDrfTV28#tv>H=Pj*d1Mc^S0L)n;etlgx~qcO9W5 z$Ol9hGufjkkA#Vo#@*Hgej#;-Z^*iZLRMT*REp5$)ssd9ZZ~R4+{kHOq5~bO;^EE>7WoB|} zR_AW=yX-><@%0A#Xy+NOqF$8w1>>6JP0(ltuJ!VvRJUKDCs`GQ9@+g+=lY)>7|J-A zmB3?WFI^7FpY}y_Q1EY%o@#kt=Me~(elTauW^n9=_M#S(jYuF*B~nIcXZ8vF9zxtf z`;@)5Yh8JLclSw#)CjkklZ2wwl0ug7I_uZ9OQeoicV#tjo`mUbcBCi_Lwuj=Nz4++ zt9_6^0N0Che_-iF!X>o779Ba-xGrwL(WMCMl6f9{9P>JW#17VG9+YXm&VTX+9Qy`9 zkL!$#8~c^cH9!sV;X4 z(GwpZv$7js>su4D!UtvCd`RzgN~R|q()UNelFuJiG6_Hlz?bbh>e2hFSas$F?emEp zLHyx=YdC^*g{kP;l&J;bw<#$x|X_XUU8AGh5XSU93&a1!7V%!v?)5t1BaD4dRBRoBey`!T&&C{A4c#%$Cpl38(jHukr9F_M)TiKcM!Vf2Tt~#^2Z^IbN zHw$5CPl`-hUx)!~179i}B#=*W!gSI(-mP3kS4=6V19PWw@;tu|qC66um-F`4#4qE5 z8dqsS;Bneo)g{~Ce6%I(`{B@n!&xuTi-{TvtqXXpad6>qEPGHCTEbubXgIg$CE`%T zd=VUp^>EUAn!nhnKisa4*b>*~!O99Q5%~vnXEsK9_Q($A?H1B(l`9x?RdSX(gR8+9 zhcyE4Yozd@c(=nsCpmmuS9P$g-*Pk}j{6L@kSyhNv7wr#0`oLxQGhguyR85+y@0<1 zNsVpH;p+53+}7*6(`|ZA&q_iijS-b@E)nCg+v7?CoqN*#NqMzys~umP)|?&=R^NeqNrJZIE-0N88P_{&Z7RkNGcJ zL65C8L{@&Q_)OfOYf4D%WD>BhO+2hhl}dm0jE4{n_c532nw#F2UId=q5pn7tPIhp^ zMcs}L>hzddFDc|w^)rr>vB9f|Dn-zt-A!>(k@8g43#KSfna$(Qg=>;?VznX8wS`Fm zhL}_dQ}=65x#1}!IBy@7xQYKL{7@6~$ipW`XD^pT!7yWT2HMmIWX?#9=n+kj3Ho1! znjP5l!#Zj%>N?uBxj$|_b=5Ta!m;+Ou{M_e;DWD@doiMBNB`vYsO!af~ zo%u@GsS>c(V(?UEJ#(uTe9_&P8RkFD;9@Bh(d`g}-$Z{N6U{+IllKtr=6$M8I{m?4 zZpsF7Q&|eHZ_wxotp|z>s()nx@K6sSRzn6lc)a3@sLtGZzH8zC0ag?rQX?zPksekv-(0RIGzpEC2egF(1tXgK zaWS`)L*9F!m5+`vO;txqj4V}=AmuLhSQ2GRNZe)tg2(t@>0sXYZ)yBd5C+2DOr}1`O>LdWKFyk@%99uK_ z(xSatValFOCk}Z8JHabns98RHxHZ2?_6TU`8eNtV14s$~~G58SQP;Zf#TquGhnK*mA-dbGH z%5rPNla{04O-oSu^!~aR&a9C4C8u>X{abc(jS2F;i?1!le)GQVW>5yu+sJY9!G%mc zr+-kMBV3t#xzf zQ6ZF$zUhCtck5^}hu52p-NM+kXc=!=!QIwksjUg7(Odvo0c5Q8rz_^D^&3HflC+V` z)J30Px-K^xg?_8SAl<}1_ht5MEFJ4TT!K#U1RcVP1DY2jgz+A(R$sb|s@3VS912>| z7W8hcW+*pXax;rEkMFt#?ivc&O~l=&=CXDKU2)BqicpnQuQB`cE1IZ7V}fL#-156W zFBCwo)rCTjL*Zo+zp^2!$9hk`$L)*IgfY<(%)bozFV~+n6#%@4r!U?!AL5`BPnB^o z8%ljunQN@37W%kYiN5UYx{149{C%QJlojXLG1a4> z|H22N6OvO5IZ~;;5h2BnsM+2@&eW{F4Z@(CKk*dhLNh!!Zm^I0*|1G6A6ErqLADzE z)9}sUGs~eTZUK->m?RkGgmdF*FcTYot?H|Hgj035orU-il?vItF8Jn|;sW4}1WCH> zxLu0T08VeoT)B{b8-vL$d4H^EBJZCWVm!h+xZcYC3Q>}C3q z1@Y%$0_@cHL2a+Z42_;ok%J;sIkncEc#QLpqTiKvZM{(+eH~g?ptP7!kk_e-6dBkHF+ISeO|ab5*lvrf7h@$6roYlDq(pP#l_K0t`G{+M zXg`squM6B`EU>I0gCv=&2$}%rKi=A3^r4-VxWahEjppW_z>tlNc3<75@Ab{hxt_i1 z>I&*pXRKob>`?d}QVU zgp)`3{G&(#JjTW$J(=Zij}=MfdF$2q$m;*UFQe*c1b`{gDC9=`jwfTj^4$-=1$Fly zl62~Sax<@|9yrW#6aMjIwqUZ}qG2d9q*jU7pK&-MKU$XxCdYlk&1@CSn(p)NwhG_t zPh3?YEosFYevYP3k;lr8cR$Qvlq-G(lZIiIqsa^H=bp;!3om#O zaI+;0@E(7B>bmqZFum-80(AzTz38ur5){A9pvPv6BBQ_jl%mOt@9~@W z6NulY9sV|N>l{t%IUe8qvVg5OtWO6pqSmm@RGA<~u4Hzn<1=7XXRX=i;p#S;)tI2d zkj!=!QBm?KEX{ra7e$ZWU22S*9{tQbN(wVawo1(Ge*H!!Fn0rSYT;P|UJ_59tOUYmIeC51cQksLZE$aW7b<>tsyBVOP(cETLNo%S1z_Ng{c_5D2~jWKFuC%k&pg^EOv!{RDdr*>#Joc z0=~WBh}G{Nz^l?@_k4t6WMu`hT7wdl~N;JZ18^>x;W=HCXADlzOktye6?+N z>;Enru;Ur|+~n_vy)Z$qmvb-g-1&RCnYb1g=(W2DruzL#TMVGIrF<{Yx%M|_L-kk_ zIwDQ4`w72SSH<5EgzFLDh{CN{<=MW=&@Wy;#Z!OUv^6VMUx`5u=DGP@g`N#oQJy@U zJ|xH>&?$#y?wn*E?qI@kAeP8~dXid99W7N`Oj+^Y8V$BJ?&0oZol&y#cw@By$`q;9 zkpsuQjuU3X^<>(k%=7B=2dfi>*g$`u;c5it@)a3t^NV5u(d?bOOf!^roH_#%AeJ&d z04T1Kh%0F>x+`)1Z(-dTf=Y`jm=YA1HxCP5gTdh2vjyp_0mghN8Xt$LfhP8m+(Y>%zGhWAiX> z_^}L^;Kk(Ff%zs3BhFLYJBHe`b#IJ@Q=CSeNU${QoX4`K-I*T0PYJ9G{ z@A<`(^X#i6b8^0ZQWvR^odOfcSx878DY8VwGG+*Kl`Q;C4?#f3{9kgx6dJHzm2#&dBJG7CIn#Ngj% z3MPS22@%M9@7nJr1kHC61n-^ydvR@mICEh2{VxFW#AOJqGmT4X`;`>|`-*^2u#u!g zZDl`=4PY$Cq0=p)CO|`Wj_?`(;)8rDUsx)oHmo=ooeJwUO_2i0!wFYzzqz+CYaZt$J)?Sv%Va`*XO{nR$l5W z%Od4 ztjNLMQ+Uv%+lRRP)#<5tFsuNj_HcNV zUT^Dx!1eZ+h=T&NXEi+klASLzZv#71@2Sg8zePN}L%eBBd0Ny7-+qs{0Kq*@XIEPW z?~T3v)%z)wgHSj;moWbU?=cMp%71St@n4Mp?({WE1t0WlOE6>tA@wSj0rk^jN4VsY z*{OKu!;v;ve)6WS!`-pZgC;k>Ytxgf^R^S4Nuk3=SEmA)iWAylYh z&1l@%4w;mSFNKyYWl5{HNG-pQ6*he$zny275xj)G{`O5&@%0F^ z4aK`9wBjP$&S>gx3%J{)Gl-4RjE{9KvwhiHNJ444R@=&2>XWU}^%S}|F(Y9L2=1rsJr$q}j zpuu>e0Q=)^zodm~-hb;l0So1)xfKOUqqxyy)<4}QR45*T!bsLIk-6v|VATEpi6Hy? z)c4t;RW zLn!o=$TD-e1aT~4bqk<*#5=tlY-(V^Q1nW}7(p2NYkPyxZ#_c|i$;7uB6G}(x9U9}C(mPH08D+U$ zbtw@U=@KzwOQG^EZmc6g?_pdex&}la{1naBdg%+sD0bg<>E^AJ0^z%w@toK%IR%pe z0s{tSUi}7?w9&K|63+9;6*%F8sAu>rpoZy}SZV8F%v2PvrE@*jJo(^phf8dc<#_?? zihZBA#y{<7aU05b7oznp{ac0YUq^xR+qEE@ncu3SAx4((Uhx}DiI^g3ZfXd&kiD-9 zf2`l26d%wP7f`5p&)?nbsGOTsp;jlm4Go3{$kGq4 zVXh1=l!h=2Vu!;itUg*@0ej!co@{Sxw$$S-Lk&~nEon`Q-qN<+;qg8eKtho(w`v>` zc9dkHKVy}ASk~PAK&L^&%K@E^3q}W8ECh&b2do@rTW?S>jNPm*z6xO<6J8#A9d#ScgC8AK0&7IW6K;dT~z`Qc>9M@0y+@8AR@$ znRUJ8V1DW|*O4&c=YVHq2axDDcqkP*W+zS?soxu+Gt?{-TKeMiQQNug@Cc7hSwP%FUJM&K89C0te8}l=u_sK|J zb{_|uzl;r zbuN0NQo8qH+H$aTRm~zIipypQCHc&0qu)Iqh`#1P3Z)i6jMR>H!Ed8dKX1Djm)g3s zwfzD>wsB5F6+js1BQ?U~uhZ^^;)NGa*2EFCkTT;`h9l4Al`? z3TQ9@H@+oSCPrt*lFULi|EGP~(?g9>8lc2;8U2iT6k@NW@D^;**jyKJ*`439kdX`b zkhwr{ohrB?a#hPE@J)48M={%y8RfvilbR@Iv$6+h^N4uzHcR-+5OqWHx_c?2m7W z+|}$rkylTjxdOp@siH2x5!fHR<}ln4G!E1o2drid9O{dlz(&C5fTJsldvejdL1 zM4m&P5Sa~v{mt!&?JtW(zJJ$M0ff!;1yw$qUwTY-Z5J;{8uFJv5@zFi@bwH>GU(%6 zyT8kK2CVaGR2QVkzWkp*V|~hFPR|w*>rcr!y;nDKFR(GT2Iv+c;Q-7T1b5uOVj> zCJhKHyx3JY-}VO=Y>29S!crVaZn=x^m1%@Lr4(@mB#+IaV{y5vyy3&3Ok4Zh=&=&w zJ4Qm^FFI3LoLPU853!cq??=8~n{-oQrWlsvNVpW$ztGCOcYDy-_I!sZMo>5jxmzp5fO&csC=P^3@eq zH3-rVY@-B$J_?{oyDG7U-uMVqAd^0thVay=Um?@#w7s}+9;~St2&_QwjLD8GGJ4(K zemmF@6yCfAq`PoVUv3CX^_`C2(f0()LlBD_fg*5fkHz|si0!~3a6ygWJHw2O1IcTj zqy66RtRPUO;~LLn4l~b2NWi70!l2sZ=yl6RG)#Wun}&1|t9_AIr}u!wuybHI>xFaR zpGE;*3IekhV&2n3TETu_9GP^VD>KNJ$#1o4*rj(@&y)UoSXu3^`h!zRL1<}2>UB9kOc!ycq+L@u>SgM)_Z8vn z=5sYiTn`^hVShYoqh_Y-OTVq-%;MatoU4jz3VFb2^{0rOY<0A}_eQy|tqU?O9_jW% zYHppp3vQ8)60s_gO^KDi{qJ^AR!g9_+MT9ehdcu~=p1gBPZgery6)2Gfps;G<4~pO zZPkdrAWxY}YqP72^vz$4wDyux_3cE)n4?dSTeZO@ zRm`UJ)%F*B^A_7LajadWRrV5WZ#1Am3;5t*0|Tq5-EPzczRf!7B>2wgY8T@EhhD23 z%XwNoG0)bUAAxpk7a0L8q7AI3$sZ;p|8TcEiqLR_k1&e2`0?m_Zf^-;R6CZbpDq2C z(f+H+UqTJBwRMY!rt40a#+L=+jjf!6wfyIwcAFn97X=y*R~nQy#BfXhN1+X&D~Rrb z6kGcAv(@2S{c%r|cxiIMxhqVFM`w+t#ogZ;?qsEuD-9fR1tbm*X@9WBRcmE(e@+G+ z0(DJ%C|zhPoOOPAdetyJPTKbz&>HZ%AD>8=M+B8^3>2Ib^X_T8-!jsKd=BX!2S@is z!{$lrXH_G>H5+C`d2D?Oncsgf3bHIsez&Do&|D+Z zjH1G0R+!a=llRgLKWyJr`f#`#rw&)5$8Npv3(&n<>083AiXvls1H2aPraHNkm&$cY zQu4xiFi}WrPGkgfy{1;zBx7OGhxiUp^}44Q`vyyogNeX7#i>3Fo3bCP4bUl}b)-@F zq}ROu;GAgC&@6JOT`9A3M1X{rD9L+-_M4yK9easmNO)3%S7g|l=uPTRAcGElV!Lu` z4IC}A99FMx>=Ia$+>aTa-4;zjp!~d*iBC?PUsO%!c&sS|G0*157aJM%Cm)FL)`Odd zP4S$-(VaRASC~T5ZFipV0}Cb213^lL*N0+bpakiC=LrUG7JR!nB%{u%IO{h@$2rZ~a*ZvoHwAoNDD=Iy6{ zd!rXYe*(1lqu&5tLuyn}oRaF|oh$*$B<=yv?4*FCRP*5Vg8X zkuh7G))A%_xYxiUx3n7Xa(Xx`G0}m~Iw3^4@+GO;ked{Fn(^_}JErLC6>mZ$lfS|q zPUhBJwg=+LfGBwSL7v7XRtZ$!+9&=2MtNEaHu&e3eD#QGRoq2<|h-bix~w@-T4 zp49E}VsttFpGJq{ho3yz{~8VXU(Z?I{oe!+O}pOG>$`y@NSpK27!5>>7r#6wFe||5 zd3}q7!#{lF_u-SY{u=u5d(lb|ol!-Ly_D7l>G#KGLAw*$vgX;QKk#kF7$RQ1?}8In zhxvS7#B{QpjAJgMZ03FF&6eLN@63BpG8rENUwwUu&3=A_-YE8mQ*ws%tR|MbI{JUJ zb>O||A@4O8W-;*NgOK;K`|iC~fcFA2S1PXc){6Xa%ur07nq$4Rz!5%>9{5a&kUtix z)w;QloOaV>#Q!x204XiVB?H5b?mkRwxHua^iPy}YEV4Z+7%yWvyw_Z$&&G$uCU~cm z`3ZFnjf!9a2%$HuWX}QRBorFP!o9(<2+M79d~KdVOJ5zzCK=MN*dcBygF{?w?j{If zi}_DF>dolV0X#OV6jpxbP8>H?<&bVj@opYq-l;QCoudqurtfYilG^jEk}3uR~kHSBhTU|2L6P4Y#?)>_Y{i>$l~=2KtuX zTG6soPqT+I_({4nFt<*JTYk>yJiE~yY@K#&Rgf{B9-N-z=6fx+*YUf#K`FXaMs&N8 zI6DS8Ss>w2pFt0k8f~}0*{RJYAX7NMP;O4l%*BnzXxLg>mPSh?Xc?*{o09TTg|Ml* zi*G;0oRo55;xbnaRX)(nPJ0#mB}CUHR8?MgWR>=BDK}Q7qvgHwFfQ>`rOcbYX31Fq zAUdV6bi;U%jjMbDRw-pwOxF6EuGP3lI;9pHt#MR3OHM{s!gYxY7sZ&go-NhSjbAl3 z0E`61gP;d^_`5vCUm(psY&Fz*pr$tn6uJSv99dFO2YnIe1gvem+!Ae_05cTD4 zAQxA>{1PXhzPO&VyRQFfeK;^R2B@04Ls|6uT!YqqhR9aSB-?v%%ID~3YEr`pt9P*& zehY!wfEbm25O!)n*b&VfhpM>!RgL|-Ky<-AK16|RIxgGkxjv*7bm7(B6s?}Uci;ZG zXus98HfV3|a+Ledg40|{Hz#p@uQ)244Xs_X)nOmCGWnxyHpzz)J_GMJgS^jlr z1TV4#iul#KPo`ASnCyP+N?m_n1U3@B7vcl9*t;-Ew8y#X`w}LNOCP@d#T>qP?)$V% zSQ4a!Kt3t9PQtWa=W&uh1AzC&!FK?<_oMUhEm41-l*7_NJVtbqJz3#)^fn??MJ$p_ z`Woo!Z_@!D>AXrBE-!pDA4h#shQYQrQ<5aAI4It#?mjdyUkXPu3ry}OyqA#nLNd7^ zQRs=9FhIdC zn32&K%t%an8KO~d$-A4})W3&U7KM}X$W#D3rA8PE^uE2D1W zN{4T?I{#Ve1lnqC;5JV=ej8vZa`@)6a$y`?%X?dU8)6rLxUKarVbJ;G3w^sDr_HLt z&#HV9{BC(-N~|3|T{_nCt&E}fAgb!hD(JBPqo38mP!9?HSbHoP9}@E!ru%5Tzh*3L zQ|DOkzx!RNEJ)>tpKUjUylG{plr$YQ2Kmvu2U>#Z0WoWUME)MsDT)^0zihqV@^p}8 zxv~)SeX^iBWE>KJY6IGxMfiGeAW3nV|G^wknr88{FUND`kNT&<_vL~G$AA1K;36Oe zxh#cDNHa*1?h7+Fv&Y578#_16!!!X1HksKh%rv$UZ``6EAW_jqNoF2xwHQ`i)C!S+ z?T+E@x-v~hVD$q$%(Di=k=wc_F24p-giU*ScJcMH`GItknQrAfMb?JCRN6~q6 z9^X;7q(}*Mr&mmkMSU&xG#e+Un*UO22r((;Q(ogY6=pbi%#2Y?RYXqmxKnP=Mur%& zRg-v<=(9`i{XD%8K^`mW;&be_M2&_n4K$X7o<{c@;UCir;1ZLk8ynOat(-p)A@+@Z zL&g`Smh8;-zrn~ae7|UdUL9ykxXS{utWsmMThw=vsas3y*RpH653`9_2c``K51?K| zOE?<=>D^40t4c($Md8k7w-c9rJ4#;YPx}tJokhWqAlHXGK#CwS0buZxAHs zf&}wniPQ?;3*_e5L4cu2a*hpW8f};~Bw@@285I}2NyfYk@Fs2>U$yPFh2d{vI4Q-WFNexHuQ&$EB%W-PQ_CAw7b$1Z`TEBJh9{98FC1rl zc%ay+xGKBcBFK3*6s0L;SOhlNJ=Xyni^d%Rsdk9%-2NgX+cQXmh~*l|b24QXNw4wH zE!3QjO*D}yO%X)7S}&j;qBHon>s_eLhf+(0O{DfyN-54fQ5Lv|?(+ z2`uEG|3=&eLU)=`vJyZv4ceZ zVF43=LUsFd;RNp=*PI5r^X-SJh{AxZ(#Qw)N*sE*$eLNDO`wQoQnXCeBlybwRNyNUVEZ9XUWZ?dx6Ja{U{=)*n-?;sKG>tkc zB=8`CX8Oi_lzqkw?JWm&c^05ia+t5&_oy78n&-$(z2@U`&5f)sn7f62R4VF8Bm1ZL zUj-Yk$w_j{NQ$mY`DKF807pM2u1)VVj>GWQr@XXifOwpdL3>u`Rp96pt&cr@G!?_T z;2f&ReXzRJ@fx=gpA^v3r(_1%FFPkP)SIb0X9_|gm@Nipj3FP7F=#?iYCWkthDYD zt)h|S9wfX`wNlfC-rquZcR#JINZH#$*Xq+==S#WFkcK@=qX#70?uL)f-Thz0ef3|| zYuEKThyv1$5m3P=vpB_It$45g&f2snUrGlYVYA|>Sj0)j|)DP1Dct&%c~1H9LG z-{;oz`~&Z=r#_zf?rX=|Yp<2`Vxvv?8c_T4?*G>KeLi69I0^tR1rc{}~gzRGZ`T^a`* z;SAl#QcRk*j0(@l5WD2ilP0!Y5exe3pNO=*6%5^)%DkUTQ2z*)Mjc(pG6z3 zfn60PCL@xtuYM!pyA-W9%;wn!u4UZ>9KboT<`2d68+OdDYlgKkKG7;_m>jz_QO4sJ zE#mRZuIE8?Cz9O;aZGf3>cMsA&m78;2 zuU6+$n&XQh$^u*49CR%=Dh*6zq!l53Cf}yB`=oZw;#gMfl!iBv*2}k>r5q-7={^kb z5c9L&;AFEuJr0Rd?lLc9HQG~s6-Ev%NKQ63@xQJ(xn)~C5VZE(VKTU4sy=xYnA`Be z0i@ksJO7Ws?92mTPX#@f8&{x>h;heU#@{Uq$4*6F{c6DU-H&*HP+$3uUf;6AG~r5z8D8v8~|Ov7Cr!_W{8n-xS`e|GW$i?ve)lQcO|eBr(r!M zRMqIyRiMECWfCO#@vV6vKvb4(bG^sd{Js%dvlR$jj-4rN+KYD75oq=X?ASrfCB7gI z_P?K>eJ^YJ=`MVh{0c6O2CF>S1F%6|OcKv&JJrw)&97qN-&o$Nbn=1Azq>2v7#U58``AqR&Wi59L|o5WKW8O5h5v4o=0zIK=! z0D;(unLqAOO#~psYWyM3$Jv!krT90-wKFkYiPKsikf$>|v{aLvVyaBNs&2QTVn%HxlJTTa(SXeL-)}U5PWhtye)^T1<|K7wN;F| zBtC~T>CB9$*_P%I7iQP;E}VRV%_VS?ML-7SER;VTlmFFTJqn|HD%7x&0+d*StrJun zIDR49PBTDBguv^7_zKj;4_J}beB|9HrpM_mAWr7iq2EP+YgLNiHcd*8R~YdB$bDcr zK@oDK(hJ02nhjYFUsS;xaHdMDIQ7h{ZvG#n)@kNTBX&=q^8#N6-sBvW@6S#(*I`E> zr+RKeI49hJhs_7sp8dSV@o&6L89{zNKbZW!}@< z{pI|Absu-aEpOn~lLqvC%5MoNvf49)unn8Gxu`#G|K{pLAlqMeGsffF`WMii444C7 z71dHIle0bkPQD$0Ue$7Se+7|KDZAilBL2 zc@}U;Uf%gb$>Z1Ao53S1a4Koi%VJ7zK~Jddu4zi>fS+5yb-(jgw_-dGSvEsG&xX*p zi2=3kLiwEw4`St}Ehh`p#Iy4=E;V#gDzPZWJGeMGsP!(M+f=q3z&aT2b@1r+J>R{N z`sNLP$AR_tb$5wxZk9jIJ8t;=%)xxp8O~5{>6(u6*?*K7c0DWM$WG~a(WsV4$&>O6 zg$hems0QE=R{`3SU2?}2wn^-~@Jx)=RwuPf@Q0OUhqr1*nIC3M1AqANq#^Jb<4)?~ zUj}|k@&~yR*4fBQq}8Sw1D3-Xg#T<+!yW@(&~}JjP(Lq304TX}5L|o!lzsqm-$VOD zyw8=>eh;;RUSU6nx%spQ>!b_GH6nn*o2jMx|7v#VEfvr-V?}>e>fdGi4M7MP<^yKO za*XGH)V;0MQe=QtTDQT3--B%+%{(^T0`!&_N0IIF=aZKaMOp>Wm$WUh-|m<(vTeucB5eJEh@S&G z{M14Ir`dK)elA4DEj8md>vd+p2E0gRCj7o?I~(9{&K}Fh&nZSh-v~K$>iVfLyA(v# ziearZtG3rT&E8aK^3Q7a+gma&yNMG@N^s{2sW>hP{^pfi)&h>@|9nxuE(U4|0PzZ; zM0egJBzvWveb;ojD(}2VNQxIt8FSm++>{V{P3>;Ay%1ZPW%~RyXh3{e;wV0mx(z&S9>UKoL79H*I~BnPyfTlvgLHMhYEiBK>=Eo zdig_bjM8D4h$Q_j%%zU>O6Y|{YhZ}J0>S&xZCpzl|0OCMIh*tK%crtOw?eDwq&9x6 z4?-^a_UdkR8yUnA$YKxe$ef2$r8{k@tv@t@6YzK`bPQJus;!uCQ&-S-mu(|jZhG&? z=UGCA79U&L=~xB;d!}%dOI(m}1ho_Oq%%K6xc*e>0RX|+eibtC{pt3rS|h~g?L?>Z z(XX-mLHb~1)O{_8fSrQXsolvy3wEFyOp|rNRXy9oK(r-TFK9oNf3~HwaV^88*e6Hq zpQ%nH7B`E>>I&ZY7pHL02!E1*jTmndB>4VIS629l&4eUsx*1d*EDSf^zA7suBN;ysp+O*Qyw(nRD5DgP^zpgsyy_DyGFd| zTBtgw-gt1})X`bR#TN*IQBvnyA4;SvQZhYEn*f|FZz~5ApxG~7P^zUYh zGFC5-!+g#bXytQhALqwn1awU4juEw>wto#FhtKqBb&9Sr%75v#Fq3J7SJaGZY7jj5 zWu)}p1M)om+l|Ily{WF>_6xHtI5(P|oK-@zFk6}|8cFt=-P;TKB9ZYb1CY+#Zep9k zi(f7V!>}<*m2B~w1Chd^IZ!5A7{cCQ{*|W3I1dZ_=xORZLP6jCQB8X_wOmQ%1AFaK z;5w|T20tk3GQo08Ol3J$xv-!);%Un=;%R%{ixp36H`h#8EtZLQKG4?7%Shu(XuYFQ zwUqz@jHx$g%n0Cp&CZ`gwLk;f4tH>Ln{R62V(le z5}`+{cI#2v>4<#3q2yYMj)*(C)9>X25S5e{W;DIhTHM*_;IO4>U}NGMMqPa??*!Q6 z4Ivv$y#MiuWD5C_0IWJ@k57*#r2cV4`DN`8Z{T-mQQa8k5N#@=as`We7_MEo;ORd1+`&w_4EE-6|CpB{OS+g%mFjJ$RG zQe#K2G}#DZ$n4GWZ_kq#39Jj@<^2x~6O+UxRTU&sT0Is+Z?r?+)^(A8yDWWVcauYE z(JjVcdbllyO;s@npYf%|N?Hr1W}k=LPRMrQJ!|!ti4X>@H#Iww-%*5_UhFds#zbQs z_wrY%KK9P$OK*;_ttcD9t4dL6{?^ncYIe4Jyfn1DVnX`PczjRXcne-iAU(?@Z{<_} zwf__%RilpCh%o}j$I`XcGieN#`}r!$4_-#@52PC(Z4RW*u^aaBlveuzM~~Sjx+fES zJV6;K*Vw|uHC1?na%*g9d7|xTas)$G(#6X|!oc({Xz)+dyBar~2}$#J6zaq8_klA4 zyw5gF6E4vBbKJ}!o0bK*PX>hT1D1)9`+H_(&adyD>PjHcyOp5b;S^Wfl{*-`QQ}6V zot9J!WZI|-^>M=3O|n{)belF1K+(^D7+kpXYGpp z?b`+e9(2H+1z=qRe8g|DLPpP(cHG6Rfq#|anW;tvx$P$~ygg9TKL;Muq&RQHEpp&{ zKKT4bamL42dim{uHJ{}TycQk(z_6|lS(*c~i_b8?q|-$9gB7DJg7(8}8>a2)JFYGL z8*;zxRvaJT%vP=}0WWgkcqAM}tP|6F%UzfC=7?vW31ef79~T@Z)cK>Ym;u)9Zd9P= z@U`>0>MnId|JG(lR0uj^p_pl7LJcYWGOH9NT7g0L<(j^J-{Pqs)xdU0x&KO+1u?>_ zTCv8UEw1d+lOhGirOKj6$lG5K&Jv@J$yzb1_NjED1?N-Kc@W zOdEc|ETZ0*R-7bX&^s-(%f-Y~V*5~{{#^ZC&zhY@ijX>9T*84}*Fe+_H7&EtZ}rhN zmOvR69FF?K3iq;ev+at&aEJ*wff>%*by zPclW1ksQL7f7tHbXT!bQZzkZ~a;mm@ja)PVV74q(a^gaYdyE0c10rB;8`D9C)2y%B z*yK+WouhF@vvu;42cbK1qHcyk>~_#&n$b#XB=mN$aE7(^XFk`AkK*>P(VvyWnOKJ8 zORKSmBh>j?L4!(1RWWh-4axAM)iS1<>av7VTekWvM@4jRIv%0j=CfyXVWg0RubkuQ z+It%@Hs#owjlPPYoqM6e{*FeFe9zL0vLS^~f667w!_tqYRr?*0$itdxLpaFs(CNF& z3NIMd;4aDJLH!9j0oYx&;hBI=ksr*}?1X~6;Dc!#Hr4%h=c`fs#OUUdf8SDc2vfSH=cn=e0z7Yc2pN7rV#F0jzGne`mAX%50o<~1n zx7W^*l`5}nzq|;{1=ZD2qjiqQh`g>j#qrAC$=yjsnw z!pkLZ?+t35N$^yyEVL8kA(7pO&mqmRPvz|nVT?zs{JF0*8)&rRtb1BsvG^)`wW=MB zq$;`SYahbMPZjmr6_?q$pfH-i%kHU$cU1PNZ3Q5IcQ8~12r>oE>k=D~F0l%iKt=IL zA^4EhCp!M(#&Pn^E6TeZ5Z@s^yVch8%vhGZt|F#byZ8iAMV(dsGy7=yU6o?ler`*uWdR9 zA(XIZ!o$@vu#>79=jV;9sB}e}qlH=v>hhgLX1NhTrZxuSj+0zaOU3W)mY0~ z)kLP}U+pIh!^?q9pm?TgiBuqio5hH!7R?LFY_#py}uv<)m=5=)OXfh-$f&`0x$-eQTb`IH>dlk8mKqjD+Va@B}gWPh- z*OWEjm7+N8=g4+nm{xGMokCRc$_oZ4SH zPF|M;zFcA5h0k$joi{FgTmAi`zxa$Z>+}td3k>IH}75JF(?J9#&;`IkKQ#UQbi57VDA;d3QPn)|8?w^o%SC%e9|9rn-aQ zN3VbiofhYXag#Tw$5o2o&)G;JIx#d6^w@BsjUvt78e`v}9MU+7sZC#6)g|#&?z~2L z2ait97duhPeOBl8b;bI0P_3#CnJB7QW{NZXtgkePJF87jnh>o6P7dL86g>8|e{EQe z{?1Ud;<(x~^>&K>|J0stT9^5$WOGUpRsXfZgC)5S(QXlRt0f`H!bA}zkQa8zjA|HpsJH9W@8Lz zz1(uXSNDjpkWd@Y`tJE+*<}1kfx|JbH1Vp+cOxN?fFC>0Bgcw$$-#dsjh8u}z+XUj zyq}40CpxJsIRuBaCA`um+WDMJUM8!x;w5*l;Q-(3;-4z@!=qkcwxES6& zd2#_h(Q2jSevM~RM=zGQf%|TpqwUH#UX2KLgI|Z*gp@AaQp%90G)074RhesBSEqaW z3EY2VvyHW}A_S7Y@03^?Cj7F>^TilqlcSolL&YlEc+fl$<~o?_C*(~S=*fCWxoUfx z+d4=IUE@jCz5!9L`IdZXUes%CB{w ziiq{;JwbbIjCcN!tfe(9ar>Znkxg+kTTS`0)0Dp*f!2GApLG1S(`YkwW^?F7_T%K9) zLjH+_TbatB$Uproq0|eb;JDNUu0#EJc67QJa)_ic?zR*dcet2p6uDwtLY(QIqvI-d zqnT{50AI`g%P>wAvNOUS9U;nU+nZ$ya49hpZ{Kg#E;`fVYOCq;f@g#2P~VwhoBYJ3 z&3wCZ3Exyl=t||;MqddK;oB7F@m_f%ynI#hj#QftRfzg^{3app$5s)0YEKw5F?|%l zropaw{dgf{dVzwf(n|##iRYz`F$PWg_r3eDdz8tVdxN^2*I<*Vlg51t} zBQ8PC`FtmKO033xxmVGm#+IuNw}V#45mmbT9K;-#1+Rf*ps?Fi^ZUcsXyKB9kXxB> z|L?SqO9lz-!%xBmqV8ZXER76GRB)}H%Uu(=^bD(2vW@cBX`0{dNsmLYyHZA>W~YZd zHFdSIlo+&rl?rC(#;CDWgt#o%wcy1<(EpRBo=JNWz!2Q~ryurB}Vb*l(s! zH}`7i^=`GZ*q#p&!lBt1JfDw!hhG^QJyYOEg$AdNnzmoZ9X|9c#EW#0 zCu<+*$p#?$*qDz3qsj>twPLBOVN`*rufNOISDY#qmkRt;W{-5&_!vRgF# zgu%&b*W}YmT_Rz)BPbk(bGOFsM#?R*mXayaXBFP$E!N35K*t$X9#j9pm zDCtV*JJTCxbrfeiQUX0YJOC%OOtBw7jWO6sRkaC3Yg})@+K%)U_1$6_UFq%M%Eb1S zNKptcQF?h`TyZmcLp~4$d=%r$z$d%M|dun7%^u6Ug$Pe5$ZoMa_0-^_UkGS!u!(W-bxpz_B zl9bYSf9chGBNI#UTFOvtWT_y)FbS))C zOUZ*HO%au2Jdl?bOY^UqJ(uIOYY#*>D3^M*nS5vzdxNh= z(I4;OOu2_Hzoq}}QXSHTb7dC1baN*C4?k;AcZTm#IO-@GXa3#Av-SH~gTHYHhw>R+ z@s3QY6;UMt8I87Aqh|M>fM^UoYah3XlF4uRYa8>mui^Jy^ z1glE5h>um8t1>YeH@xzZ$gLZZ^!b?mm{QJ-u6#X9lG3~eY99DZM8uk=S4oMD@F7brByI*ESOti#O+0~A zxc1*SpP)A#Buz$kkLK|duc6U^BT8ss{!zo#NPw%Ps()f$?gfvX2 zwZrWJi`6h~rmIJHm2~0a;>L-NnlImv5);EFc#H!=H$F*~xVcZsby%e!hP6j3i0$< z4P1@VJ`yLGptp+eD`D{Db=cv~oGcWDz7v!0E>(EYYqrwBM^*i2O`W`SF0m_8$Rs%LSJUo_@{)&hV`a7j^OHiSW!WHxnXg zy)6zGpDw7u8x71LJMk5$Xp>Hl+j;eTr7HaF4AAMPpFR*Vdnp%(uR>%d1S=7 z)|9&WtQ6BVaBeJ&FBD_;lXIE*bC<+~_nny0rcJJc8V$p|@~6%(*(aVf{GB?p1Nf;pH=}w8vMr1T@jj-1lmHV!Z zk{OMsLmF1p$}ni_WyKzqz;Ia@y=cE0+-_-@qqNKqQOPky#w1xeMx`aN7+%gNn{ir9 zU7f+~Dg4K)`pSfhr31#Df#2`%S4}j)#gg`Cq1^J{Ef0t#mS3?H=NVoeMz7K)6H>!T zl^U(LL9yfR;J8@e$b@^~ESJxAbr{x9U-GT0A(5m-Z4G1v?Y7waOEA?V>=}?iPmdA_iKV?&Mcu&F#Lpz;JNqgq=*b40`C;!?XxqbH zyofb=fF{eYS&jVenr43ugkO%QO#aVA|7#xl^bQU+|DDF&@nJadxpar@3J}O=5WQyQ zZlG)!s)qMbWu;(R+ZVxV-o}+D45`0%IMSx8C+`c!T~K@>C$nji&Z)Y!Rs8ZE8zsnB zWWLz?=#R%E9+Yvy{+wv%a=(54n?e1$5b$is>^$A|qKq3hsF5!WYr__Z5K`2Xx#5^%7!gl`Ap-9LlFWAJa)c;XWF3~4`Q^`)L`e$wtLjw%)} z$>}3Sv#2odI=7R_tKJQd@LZyz3tXabC6uaAM?wN^X^Tx)9m=sFH{a%wK`=}tw^S&R z#_V)@#ykwmt~#nci7^mp&bTS<=_uG=VgZOjwE4zW`+AvpJLGuI)U=gB5_y7=DDDIn zU?C9uBHWVrj#ZaSNPN`@J6JmHOJD^=W1$W8)BePN8Ra&VkOc~LX+exMbmJ(rv=QRz z(?i{zaq1Dswa}bwR4+J2J9vT0GS($sy#wve2(xwM!9j6V;GmDS<}r9X7jGS>{Qh4a zevJd?8k?J%CI5^PrVxop+@5lp^kDOM`T~^>%oJeAzS&Dr&3c=eLD=u6yYd;Ma6QNF zorQuI#o*U+Oo7UG_gJm85oBY=^_XgVyDqw^G&WJ@cB-zzesnHgzp&W$~pS;t33O4p;yOdG3|JAJ_iQ|R{P@=u@l^yvG93#YL_Y- zcZiVu748^IYUF25G~4)#k6duAB3nH|2^oTJ3&N9zdZN;g&*u6|qE$OpYd+{8J-ra@i*4Xjl2 z;4Kv$0G(ni(#f91r-Ol&n!g_BA*TZ-$sw-Q zWx6DxC_>%Cz2atd6Lwh@BdW=Ki`WjCSaAzZmFjPrs)cWfbK2b zedg-NsMP{NifU=0F)43zn+W{To%8q9&FHMDqDeuAERTSVi82#34sZOMfW&pLFOf-# zovIpB;7`Kn>-g-Zn^oLLC&26?qqmZT4qeC!0;i@C4PNVY==X^K{e-uaaFMD+dFc1A zxCV3Z9u6m3w%L6C?-I;zX6vMt?yjuKW=&|8tD38@M}_l15K2y|^k5rRn5UY$7G9gKcjpz=z z*XZx zs_==?b|ZL$ifXkNoAJ>w|4l)ELwVmfjGYN=ml(x4OM4g^u{Cs_qdX|YUTO{|Hcw^u z?kU=X?dlj0IsHr7&S4$`03?eQeGkV?otox==iLo!T7O4W6fAq}js9M|V>|s0@Dpmk zK!87SV)7#pioa5zHZEgIe9!zi`@6{C@Pj~hkTHMw!vl@}4B#3XTsLwBKe{b+l_hx@RVqSY-buzuC+Uln ztB210DWXA}I?NsIC&bQIGtHL6%kN#98~EP@T|tQJ9A9QG8vI^);yOpu9gq+vZO-eXEt8UHMtd|GCZ~(nyE;PipZ*2 zDMT@C)KjPvtaQFcRF|Z|wpg#GlIL*;3Qe#P1cqN79iu{89^4~wi^Rb4VXlM~tDmnC zNF1&#>x0*e8Pp1x;K{k#$(jM5xOPn4;~8oR)x4J7-I;hOzQ=cS}8m3M4@&e}`kBXNjrRo)bqhKJD( zQ>r9D-yYV3N!Dua^su*CpT6{kjhH3_4x?ssDIsHS$7H&u-SRvC`nE%}tRfBL1%1Z+ zuA?EctBMUc;*>b`kA1JY{c2kGr_GLLV_L*)xN!N828YSmT3Gx!h=EC7{#Teh z_|MK9cgO`Th`>2hP=emf7dVSSAVRjCsd{AHhd#XWcFJd<`SXrop1*7d+Y*Iz_33&k zqnOYG=~!biV-{GwXl$X8K)?`^PVQyK7PS(KWoMts5yPi?$=h}lCIS`82exwk9Okvg zU8TIlmpE;!YxoLc7GFmUr=!%>rzs9gdkO^9H}=9Fhrf!XixLj>RFBrvG0%M$uac+_ zdH`XWio?Sal+-AdmR6v0g?Fj2Jfh|sLI@F4Y$P~zfmt!$^Lh~(eSmXPW|gP*RY`a2 z9?=-#8N-E= z1@K4KCawr~XID!m);Zy)d;s3rjFYBzN6r`L0g=$X?c#FBLR*+3%Bl&kv4z>awbdC) z!pZ=EM%iwZ-caN@IPyWde`~PQN-0W%IhVK}j&O7UMiEo%?fou#IQ|xrCD51D(^yK8 zPU-{nk+%f>RxV7`XbTW`f#YQd@{Zr+H*lU{lWyrtmXyIc2T#0-J;-$<2E+^xecen6 zK?{$rr=CQq+}b2bpIH+uJ^Kn5pV;K|p;bs>Gle=Cft;?m?E8+@=0SSpEzC|E3%m7p|>*`nHQ_^*TSv5I92^emR(LqCMcxFMFjMdnA(sp)thzoR`ue9t1>Kh?)~NXa$|R0pA04h zswLHlNbkCG@w@4bvgV3HNpHfS{i$cOgwXwgpCTVVQf3PcJ@rd&H;j`MG;BC#*wA=4pHTI8U6!~j9w))b2)_F^o|bC^!I|2SvCr$-+FfA=jrhMuBZAfPtK0g z?-_qubcfaV)Bvg9fdr~OBxJ%ER|Lo&s8^<3z zGk=d7Q?e1;4x{(z$5}DcvODeG<9Z#$4+lbJyI#Wz@!QAhJ?O)EauL_PcvX5s;{ie6 z;ob?3q38~<)VuY*UuVUEnQBCcWtL`N#oIF}EY7<59*Z2Nye5-w`yA{`%aZd1*j$!6 zUG%>pp&8U*=UwS6^<(}KsuHMk8ja2Tjk?0K0zh9_fRh zsoq^Lo(`!L_gon)D{fKynCs8kVK^K&XlmSgy+UC!V&CM1 zl`t~-u2}j4;~yI-`_qz{=4WUP)cbL@UamGZ+n*B1HEotXhjQUS52xM)dHR6bjhMRv z$qAx?&U{uCuHb8OAlHf|%i`9yLJg$Yo`q%-P9YMfEq`02E1=0=9?Zx0YO^s@)~{GWRgcYNnNkC zld5XWsbyetyR8=%PuAgtI2A9&mY~z?FX?;eSpbi@pl=1}c@g1M->$xSGp0mtGywvI zv^~u{NVvRi0fx3R;X<9`lHu{sPvP z%C|Dax4-1MeQCDIypOpn<829S)QJeN6qKo@s%&7J$+HO3C%JGl+E!mX7b;f^7Nvnd zAFxD{LtgKCcd|*QIsma2l1#UGp0Wf3Ud1%3O2*04<1e|15%|l@59dTHZ$PdGVbQxl zwWVJi+(MIc_!1O~uDk;qKK8};gV(d$kDK4#oqO(@Z@)aBBPc#JshBOXZi@=#A3$tP_hETe@lYcG4 z&)$YdzFLHRR1p`6Wv{D@P5Hh_*ILidRoX!+q*>Ae0KU!_uJ0PE+NyTAkG1SH@E8#N42V%OMrgeOXVN! z&A?f;C!ge_#_LX?yVFy^oI|4}0O+|*wod@(mzMKDRY^dc z(ud1WXUAHWCb4@?KLqCWSslVD%rD2;qDZs?gG_Cy&>|-4w*DYJ+L{Paev-VpJL|$@ zLi`!XTaJo`>!)#0@~x=-qXl5E(D@F#&%crZOXQdXbOC+Hb!JJennt>1z+>c$mgWA5 z41Vv%AYy&%YIW+2P1LDHQS9Vr3X3<2^Z)J79e-{6jJ~ks{+qtgYKw!Q=-x1X8}Rub zaSP0$F~1cGtDQYh+OuUlYwye!UezCL_qsC`&_GR_RpC`)Mg|n9u6umC~2Q z5+y5`5N_$~l?tiaU@)Lp#FO?MW}l`+P;9Q+^`KjygYMm&oLRJbu^5)YaTH_lV2L&i zxpuWt11TJ!T-zJ>3VJ_};*QR>ct=G(!$Lu!@{5!%#4fkXR7{zr?lTK2281}T40;WB@DlDZkgez-udMbbNpXjzJYecUOF40b=Ahx4e$ z={So2^(%I2g_Y3Zh&j-3F9L}L?ZBU5vmKG7T9S%lq4D7>L}ol$?ud<lA0c>42$kSR?=uNnQZ*l-&1{~x$S;QuZ z-|atgA}9w->hRpta*ST2rkHJKbd3SsvVOS0?%M->0W}82_lmg2J^DDNggp5hkoV9& zrH5l5F^D@GZmkDbdNHW!E5HBI%REUN0ByjfUJiMiE<;h#TMrmXw z5QL_PS^(fE4)?wAQ1wV0zM4et)uF0`$uQU{l5+Z1lY&JIfAV*HP!9Ju0_2qsQ%~e- zC7)8yJdKz5!ZW`mrpH~})t{Ky{J;v}fhhv`?9_Xmi~J%ndAe~Zz-U=!j}#3>Emc_B z^Ej6v<(mPD>bFxtNY) z0X@yI5zx~F6?#KWCw|HVX1JDof4>KN_F36Y61!!>69IJLM21d53r+}89yLk6ogpUb zE^7mHV2&nCB7{6{3ioO!WyOYD*1c{ydv~b&^7C_WgBX0}Fm4+Zwad7Dx1L|#2dZk^ ztXK)Iy|`OIag)soKC5qk29AlZdxPF>W?#mT*BaQ~lYqbCd^Pc^INuq^?(sOiXbBCQ z=AKG;Ic|^y42f>;bf70G^iA5QZmz7BNzQNDMqcZkJ}@9YSW^j|&6`*fdv?7r_V5S{ zr3Kj^hR+uWhi?R=md>J8$B?TyPC>5_jqYjH@DQGQTfC-dDtLccHTT zs!PFaQe@HX=c5G&rWPp=w6Dd(Di(gvNd=euG= z^9`rbf_sfEuKK{Lkg*^D%=e@R>m4QT9{Bwn!*u7|ye%&?i~&&CS)iW(v6dsx%ccfG zg9HBU7h+rODF2Q<3tr~ZxePdu-1UMMgc4m^4$GTfY%6NJJ?WU5>Qu>5D2qc{q_DUVT=vRNJ092;R4Zx^A(=9Wp)lh6&BBda21qS*|7(8=q+6bK zxwaUQ3?=smJPLEx7Q$5rJUWs?inK#kYk@D*+SJ{zGs6?+u9h`VsClV|>I>O!ltJxS zNNSRD$J614T*0j!I&y0YWX>rBaBsY4RTDin`+6k4h?uuhlCepcm39I~MTj0L%vFNi zi(|c0y%)w^XVV>jMNDWY{+1R+wdoQLHUSdNJF6dl`sw(c78Y?FS3RO?ytevKwI8*N zJ@`mmR#68N2ge&QGpak#v_0{u+k{MT#~5=kWtx?Lu9%!vIT2tRn1uimBw*QH1iioS zYw>t48idz27$CZUL>Vc;gd+XplCoSIo%KVF0hOFn+ud^#okjM${30r=T<#8;R1v{qa|*xm}q?-di6@uZmq*D%j!KJl}~<(~k~SkmMP z(5;MW{N5~M{zkeY`S3-9xRH#vqbQq}8l5N8G`M`dy7nPEQ#+4J;D*C@L!}p7y|NSB z3t^WyhN+G##hWF>Y1y>=rPhALf+okK1q9FqDigzBJpaF(L_PX&E8V+F|2-_kOYf{h zw^=F_gWCvB9;~3pWkzX9QSkJU)=E#}=Jri;jn7tW231Ia?V2y9Uj-t+1(ONzo;HNY ztPpJLLXshZK{XbG5tvDqC=DbTWuD>@Z5hV-Ie~~FH!4xo(L znx7pwEY9!A7dBp|QHDl^)jl;7OCKZI>PoF=H@~ND$dr%j_n{}`HnUmNjIG$yj< zyYm+Rd2y&ygBCM|W6UE!M?yVFqONXkZ-4X@H@)^(Ie*W=rH*U5!9!`CCr*yW^Mc+x~eb9;@9bs>pyzM*ZpQp06P7PzvM5!?=T zw3jMhW#J#ZT0rKdw862Wmn(~YX%G(^63uXqUJE5Z8yDu4d_tY#$e#4rI*IL&x1j5~ zF`K6|CEA@g4fTG(f&LcRi4s)*_6~Q`mYqT1c2vuLY2BI{netJ3V&K*d)m@&J?v?-XIIALmZ+lb;<%Ts+#%Y$Y?JP`vlS^_|_C zEps{*VGRvi+-KAz0AwS`*39jFW52&YQQe?H?)=1P@|*kgo&9ucVLrRDosjaQ`}%GV z=y<**j{*X<&*G0y-(MwXSe8!@U9OU`7lnef-VSgIt(#1~(;qw3Ac0RXKM2mP&vByz z?Fw%ozYRDRBn4s|tp(?&--B~~3#vU1+3t8enFlPo$i zmFm^+y^4wX1rqy9alz#IstKB>Sn@>8mEKNppZIGIz{(R7P7|}c zPb-&V`6F>>CzW=Ww@Z-og1>FFJ8V&tzv79|Ji(=&cS~){iK!&>!RMzmZU-i# z>!O`{ak9<)Gg3miUPGW=Pz!Aaw@tM2m;77OwwsRUwdkeHLkII~E5leALU%GYu z(qQB3?MbFMt4#Yh_m#d?b=9Y=m-tpMNr^g*a>^uJI(qu{wT!)oA_>Y1)${|_b)3#I zkCvORb(yMJ{0rXemM}Uzg-WwBP|68Q5I^olXBJegjT-u6d)xbyhA68eJFlHpj(0`9 zPs(0M-cWL^=d{2?@c#Ge^Mf!wnz!?1G0L>t-Jo(aox-C(4048TBXqkY-#xuo3_J-E z8HBoP2t@}YM7QshZ_%&n31Q9TkM_o}b~gufA#$ScR(fO&A({1(8H^`J@aBF6{>Ir? zd~~4$G2G!u1n*;!w8R)E(dpfhX&uGD85(2`LwCP!T+ZB9&jW6BN|f=DC|@zGmD+SG zm7a}70fmXD<(GFwtLw&TAKgWku7p`iu;9P*IIN{RSty>{DCi*%#?P)$BeDC!#veMI zG76^E$vHu)^mnK+egt-rz^0Aopq+j%H(3~Z&hGuS&cf8@sS$r@g!~Gd?NH*m{mr6V zuCrbrn?~g|f={>M)O(RwaI#>b*<-dTOK}J@YNNQ-+0_4pUm?`Fp|8`3t=)ga*G#WPBL3rGzhihNf;WH+wT`D&HM1 zCDWwP;kVSO5z@e+5-xBEjw-A$1QF0}YiLTy1#&{5LxUXM9lGfd0WKDGipu4HfJVn# zpqwcN-Rn%PJ~33h&Hief%*^!@)Nl92|0C_KqpJS4uwOc*r6e}p2&f1m9g>1{Hwe-t zA>G{)g0z5iiXezcxHsL6bc4VqHzC}$&-tD6#=T>__m2Cg4q)u~uC?ZT*7JPk`wWN~ zKX1x72+Ywm&Ay(m{q4D=CePYeQ0EC_T3YX&emy@3XtzDlGbJL8NE{!~M!7WT!$hLq zrYIpL9c}18PP5=CB;>&0;xBymzt^(=Dmi&faGp>y;%hy#Q#DQEk^aD^0b1~)EKv7i zMn_(dz&HNBz&#W^4!Cc6e=u;gp@~QWz&Icg;{I2kw9MQ<-sH7x1|gjYMtjs;g>KD0 zev+_8BGG){N%oSK3d<}|BsxKrQq4JSi{!c?#FrXBef<>K|FD(k-h(F`JYN^wW@){N z?x%EgN0TW}EjhLR8B;wsdmVmZ0?5CFLuQ9bn%`&msfog6y+M|{3uqc2CXlHb#2Vy|BO`_Pwi1@Hn5mnV+{MZnu31Q&E(W4{5= z@6F;Q?P>?<3HUUcjwUqKSSdHl1;sDdQx(60->~r(1v4$ocPGj&J;E(>dQndvawOWoY?ciZs&8RVL)GYtvY??g;$U6^i&sv~L z8cSPcQJUaEZSQCY*TN;fzt;A_q&>w%!O4NINoC##X{0cRkEg*$-ZOyJs}ZqVQoN^p`aljjly4}iq=?r(R-Qfn%^T8W{| z{^7CTAC2Kqw_&M2b1h&}(CGuCA~UV+%Z`(1s3fb#{1Qvry6qqFE3w(Rt=X}Yev*2^ zgp(CT-2cuTg*yGJNTxTvYV4K{SWUDv*icu6>r*LHwobYgLWeh(6BU$UFK%kp?^c5|1k3p*iqnE>PA9%uI zsv!C}z)i`k2(xHGIs$5Uv+RqDu$KN_WUmCqw!40rGq7hje5N37%r7zUZX>PM<(7S8 zVb_{Q;x=R-!ghmLCT3=kujP8}w*|9P}m$^{Fnq?xRsHSxF+;&)QDP6->7uwj&Bp9WfpJ8sY+B zdH&}ur)tOazV~o|)FM)H%3CT!NS%Il^EoUt%oOz4P2isokQ}EG-uvzPO+ZFrF|;JD z2T-Z4#(t{kOPMp^B)}&UN0>47y2`HpD|_tbJp62H!Opo}yZ#_zIScQa=-*{XuudX! z1N_T-jQc;kCzo+}Uf?_tWW--3dcG-R62$KY@6mp~wZ#~*jl6thlfWTplYn8*`AAck z&a9(bdYW*u`VkW-?ttE>EI@kUW&8TIGpTB5{|#q5_@zR+~iMM{v?v^4`puxLdJjmoHMG9nsl%ox4v-D&gNFPD zxl*#@VH;(ueklK@nCJIMV@}4{i%&i^bipG%Tj)M@!(XW%zYarQ!}Vf58dI02(>}k% z_X&p<|K^S56FUU&hf_Y+s$i~-?>i96idO(HHg~b#24xmG@j&ezSb6)5oU4i7i0eHh z?q@r<5E0V>C3wS*4aR~^>moUOeK)4e7mkFV7|@1BEXsJgRfq_NB{JLNCGx_gYuc~u zURvVDn`C>pZQ$ykeTQ;sFKq!?KHdMIPUnC~FM}+XOeW$U=Z=L}e?5RhQ@+14{&`po zI`B_e`kB)*xnvtK?(+-jUPazVl15?PVMo_fq=K_Pd)q~cChOFsm!sl3mpT1=bTyjk z9wKGrDE5VwpDM0FRcLeUAnyIA%M-=k$tB)5v2igctIc2)dEm(dNtE{P;N&>kls*__2f;^0B zJj%{YiQ|bv$_y+qf83{+g{kpvcXA|{kY9a#fg9b}Ij4v*-FyBUQNOj&>F*T^`?b6$ zd;Y1~?;+eqkEZ>|5?mIW$LW3F49#sx!hSAbbP6I9867Qg5ECYmj*w4t?l_W9X0=)wmXJ-Vmkr_SgOAF)k3q`h zpctLIrZzeBa^{Nif8lF^|7N@BQ-^i zxKsVQ#^e9B1Aswo*_H>Vv4YsN`Qvjhr{%6!EO)4NyN=*E2VUfWH!xL$eQ7OOn1zj} zzjse$Gw5zy=8U6=;*itl;v9aeJ||;Sd3E(_w@XbyJjtI}TqS%))}$BQ%%oXRpKNG) z&RhcE?T0D!I;H2A4VGljg(lhj5QI`;saUdhj1(65o!2D;=%d&_-w+2%@)wCi-Z!lE z14SU`yUm9?$>{@%?(2diM-%Ur@J1Tklh=eekV2V&pQWU46c!6)DiWAK5hk`Gg?N$* zkPcM;vuM60HZ+H$|MusjfT0wB{pqRK?6gxD!6++#Umw*bq9&uH$lRdzx&Ytc8?Q$< zT#WU$)6{N9GgcRD$48kPb!9}=hd@I*-O!!vBMV~SKGs_i^ND(j3@D$A``-${GTven zJb0fRH1iAxIKAKc+|v)yD-PpX{JPbMW8ve}psZu^xxX$3heZg7$Ipo$(3awopaz*l zh^imAS3BZSmC(Ik8yTj##g07E>7?~tgu|9F(*>dfIY+dDge~6AHQ8a#1N4hm!(}%^ zvcw)Uj*5pX?uSv~w7=}B?NfQxTs_oeSYU#p?cT=0N8FDb11=u!O8&Cgk_m${*1$z?eN~p@r z%l^{QA$-CGQj&~qJ`z5}Qy2M>F3w=RaFcH{FAIfFV^)Yne<3X8KQT*$7>6Y233DSD zryycJARL|0w)pGC*L5|MLBqOk{knHoh}770gUUS7#^atB^gCex85KR6HmYOpQ_G_@ z+Kw8%vIUmu!t!s#dfEJ_tob-8d?6;7b@m#KD)es26z2AGqNA*2$KWn&b!422kVXU~ z=0=#aQg_Mh`Fi^EsP=ILDrwN}^R^K0BPz6C-Z(DJ_5Qr-Ezp~nFTH7uiT|yYM?pvF zX*c@g=`CtX(=vF0oa#|nKq{l5$R4|&}@})G26WsmvkP?}y zjrg8S4mSFNU?D|>jF_5J;eDGAfR5@q3#sC|19mxiv~kRpCI>F4{wbW&9x)=17H%eM)F z4{D#PM@`%Z!%m?hcQ}7GK+MvWID6P8#K?WFRBT@U8`_4*#g@Cyo?g6FKtP(ksORsSJ zEj*1q{Q%Q=}*NEV;ck+T4|~XN>3G zLVKDMHO?ljYxfQbHhUp$iT&6+S1Eia)$vKimy;2!huRR&8S~zpxg<2Xl2-}lT@luY zhntFc29Mj5<^X6^f}^r9ov7I7jygEAn=+tEl0V2csMeAkTBgVYDxavI@q!Bbqjo-S z_ho65!;bBlaxaFF82w@;7Df`)N7m7V!#2q?F$ugAC)4yR)_KmvsL(`6-lB{y?&8*_ zH@|;WP0mQ|JoKFm=+G(U(WRBjW7i=vZ8|eKkud8-Qvi1MC7PX$f2+UZe}trjkt}#G zoX~$eaFsb^tjQ34kt8~c|GT>N;DPW5j1@t&P7T(==@L=JV#W*ML|5ayQXg=kWf{ya zzW^68&{a2SW8G8eR&WrJu5GU|O_F0YW|SM&7c=!9n9r%ykc@^9SLmUml|2e{ zC=jb2A)NtX_bXbSGrg~x6H9z=Tjb>eQ)fQ@DX5t~KCewLF$!h0f@5zddBc_I#bXrI z8pq1w%i}Ua2@~*mDLVn?0fW^|Kl`lrB05=ho$YTCL&81JJ<7<*&5-!3Bx>8}@$mR| zKiC(mHrq5I&xV$+43g+LsxWU0Th?x-dVvygUXjc4bb~#}Zw=!weLo-Ak-x0|SVZB> z?#v!!OjcCPU$vT<1XCK*m)OU_&oCDF_Tho1uK4+!FX2us~NVL{J20-=4nC2s@qjV(x7 zp~$(dRD1Xn$GN}pV)5@2B|>x!tL#dj9uO_9+N-=#HKK7}%4{S&t+&gLWMzm0 zH}Vy!cSor?RWs&z=1>Olo3D_`8oKe5V>i6M)t z<=-i;3@F60F0_;JLW`L|nm(N0-7dcwQkoh*r%9P6C5jRMSeo$rci2TLO>C0&AqjL3 z9$;s}a6$(V)I0d?#Cb@_%>YmzHm!OeeUM@HIQ8o#W8q2eAbs!93%Gbs{mX=YJWk!r zVIQ2)i;`?Bjjy%W1cia}W*?dVzWX1byC_=SJ8l>!KAdJo;!9R2tET}orBRtwd|32E z#q6u-r#c*cup&q*t1Tchw48kj;yx?xs3Z#v{``R$DIDDxCZ^z4Ih9Cx?e_0=>F*>e z$(iwLdxGzgyvx?hwP$%<+3?S41{&mOaRo<3a z8T4CK#j|IO{e`57B(XKV55F*j&VnGG#6^C&u){p~u{2}|mp23u*(g<`Eso3wurC_> zf{n$;WD1`JE@o?Y*c?idE&6a*ao48^<4tf5%{FSjE912S0l81?syzN44k3DGMuiC|z* zW&FTg=?)H9*85H)rD}Pn*1Z0b<2MaQ|A_(qAwgbM_+PXx5r7$)?jihYFlv#;U5@9A zPzzl`@rg-n=p|kKzL=Rjou^3%4yt|>-}%{}c_Dw4I7l~N`>Pne6dY3yqc_EADY*v3 zPh!MzB$k8F>zTg`D^=rg2gti)FfcvRe=u=e1i+s+k^N7g3uKXKDA2f|*zHbrhNJFd)5;1J2`pPWw6VoX6wa;n@D|91T@r!vc+*ssMgRKzz zVCe4;-aH#{3eI0Ci}yA2(&-jwjANiY>!?xq;E(z!SsyavDZ{wrW=5QBJQqcU7%~|@ z2AL%us`SZ8Ft8$x@@hq(RcFu-!oM5da3$&O7SH3%huY<`)Z22EG4c)j8z@iM@<{89 z9tbxDl(mZ~B~If<8K>cdVZay^TCS0?%v!*nVwWIU0Jj~C-;eyHz5lEVRw^I@KVD}B z4v}9f>BbFIuyn{D;>{(?0W0tss$+iwL>Pr2eG3KwQ3fE?I$Wl8pm0>>k2*IrsHff3F%nm-s}bBZCd>>T z+dK7@U1|iT03lI}mmOptp6!2kdxJ5PX1CB>(_V$vkQew$0+=7(VRRA$0O0|sGh z>@Uz7(p7)kEq`A|%V-a5JW8#)B!;T{*h}YKYBXI3dPyD(4eN3kIc@C|2rz3z5ptVR zZ|LvH!sNGiEp>$KlW}aDOj-g0Y>GA733?6fwo?46G@kd)5FPC)!O9z-T45^SN3s5n zO485Vf0FvXWNX=XwP8Hh-hsdg-er1woKYF^XQqf{ zPa4J~&xsbF+jgz&^^}IceG|DO|na8yPoH(A-RT^ipr|%vb#Kqnmizqj8 zc|p8+LkGg5nkPqmn{Ti7kbpiRiQ;<8gzk@GzMlG!xX#ce2<>FdlT&)3Qy;EXt*p4q zpH5z)UVGeqhPaIV2T!f{fVdW54yNiTbNw}`_tsx>`wKX~97sa=hEd93N-B~MHq&CC zD0YrREP=?uhU-HUb}y=b=Oh@DUm7WDEKTz%uYQqrpwoq&L>puK_*ZB#n8*Z4GnDSk zNGng&cQ;3fVwb6(>d8BU6e>l0&6O(b3NO}8Oa^xKS zYKA~8!^8{O(@tZm>UCz}8%%jPhUKLcfg3E5b}<+){5>WZiQ30FowZmYt97o7<$Spb ztL2s2doScah8Z*^SY#5t^Ls;bIm)hD7nep!=SRB|^fKh-WtHk*JKls1+300qvsz({dW*70HHX+x~i~8i57%8gpQe0C2L@G#a*dekE2w&nz zxj0k#065JUdIfHmWsE&LS690XqQw!f9eN4sE37XR6L9-u#iQg*3E9Oxx`!gWgq5anhN6_o=a3xDi)UR6ty`fM&G-(pxj1axJ8SRU6D0Cgipw>kI+EONU_7}P>= z?L26L@*kXar2ibJnaxFZqLU`LGCY4PBvB@|BR+T!Z5V?DH`ZHrfqKI#ZpPcyAWHq? zvAL$|q&ng8a-<0p&E@Fh*9182>+&^M+qL~A!W%uWFXd;_m_0RV-DP3iGy&V%rh?Xq zCF?a;i1A^3T6#AQac4ElxQ%YC1_rjD>&LNj?AdJSJ_@PKL>Ugp0NNwj7A4<3TDl?K z$gm?Q(V?6VGH80z5XN-S9n!A${~*X23ev1HEJ z9GDq;xyShRm{f@IAZhZ0so!Ipp*We0O=PxXFur-Z0w2wx;5)d%2?uj{9y>M+LALx( zwgJrz|Aws6eRnTq-2XqRwcrxuFTIR+nePL^^QN~y=DHj}JuZlZmV^6D;6fA=v9RkSRKx72qS3Wvoecdg7 zFgr_82+>#q)f&8b{{XYBl62)uRSGlytPf=;Gn1R4%wa)%4IjLC;(>Cq)&sXhnk!Lq z*O+Gw+*3)6GLH(26cmf6G*xTb;=jvK2!`w4`j|S2r_G%&1>XJ3Jd?ADKub>G{|=nb zNDBa|kN)$QFSDL-o*phq@cg(r-Z^3Y;~-xZ(H1~bbKSSK(8hM;YXznA>c0Q^8hA`U z1sDf7fV(xMkLM*Lts!iW^OGWrnu!Ct~0ND@Z#>C$iDBQ(-e zH_fX*;j2WN!n{Wo%jqto(~#D5+AzX;(l)Zo5qUL2gX3Oox)8n)J}A>FGo61A6u=9c zT8^aFOS6s(CKu8Sec+R#+nSWBal2i4j1-Xl)80sc_AZak`xoxZ@~gqUcVT|rWHxJS z{BSQVGKlP1#S2V{4Lvg@F1%!|03{gJcZz(0*rdcSa&M0*QM%n2`}j~`J*%>+DRlng zUnMgL>Ql~2hee66{>A$$@L4Om$`WcJ_G=zVMgK{u?mzj;|JT^8prvl*G1pfMK_a(Q z^j5cSrw5iYY*163obCTJq z9`~sD8CGzAq7{aJ0#;sJN-#Ra2myxEvRqV7VlQwg{YiQYpm~vzkbvg7YW)ElAnDE$ z8h6`clUyN<4xRXXZIWNr0ehMrX%l|CJMqBhOv=UBYqPfdYlg`?PLd!ymYT>yMjzl2 zo^NdBu>Lcu?fKxT#03cT48aD{==Jr&iv1TBz_ot#Q3|Wcg!wcD4nFbead$-oy}s~& z?BPm63obGUpz7;awXqJZM^m4%TB%E(L@3}C)GF)?#Gf%*&C(q(w8D!q`R}icO*INj z5`PeK&J`?e7kfIGQYx&J(!w;i!cH(i)Ea7NNmhS#{wF(GAqJMM5^9Ofm?g=z_C@+a ze|^I30`<|r3mV7wI$ciw%aNemC~rzAQ&yx|kuRGriC9>R5Lc7?NO~D_@nGhI>L){z z-@D)ZHonNa%+a2^>Si$G_X>Dyk8}{)v@OQdi+x*c^`5=_?2IdM6R>eXjnS)K^rDxQ z?k}`DMYI%=({1Sm=3J}*hg+}TzF5`X9;M=pirGlM6epzSZ?;3dq8^ywiT?aC$i6*O zG@XVlXeLOOSlcMU+=!t`h0_#bM7t-n>jD_+ym!wP-Cw6-9ETd;o*9bERehHL;)k>? ze3TkMlbUw{jHLqYSv1Asy^jx?S>kqzQt9cQUXB}>?#D1wsEfx(2bXrvTtUqr^gB8J zA4qOx1#edpKSyjP7`NBYQ{9wRAg%H;KBLH)0)(!8iPaHim0C~CQH%B1Y-1~GdIi|9 zNW7m$Qs`}{r}b~XNF)klMJ>)cE=qgZ;#hHo7TdyjJgO&hx<0XBJNrD*`*N(jeXz)2 z3h<;fD|bOG^O*gIpX|)4R3v>~v??ryqcI=s$e2Gb#{T072Z*1CNKLl2t?DlC`w2=z zA?zxk<)AtfQ|`Wc2&t9{`nT7*J&k?#2F4w4waq*P^38^*W%<##u#%2?ziqx9L{(Q; z*B7wxd`TtMT}fjCSkOn#d*`R$$KBZlx}FV>YihIWB_L;m#t?yIKp-%sR zif)zmLHKdQJv}TQ^z`7@*})N5Ry}EE-ogXu+Vmc1xmSmQXWopy{hd?{XJ9kanx!X} zMDM^-7m(DsIeLuso<9#f4XpDIzP=e}(;DrBfGlbv{U4O4-59TAw0)54X`oN6uKf!B zR0)L0qmjdcSd`{0@*`z`dc`=Vu}IRiY%pFSdx7j0q+Kuw6(&KhRNv&l!>=dIG0hjm zLccGw{((ydpMpnkds2cJPSjB5QorEVk7;tX;>9Vc^R{Ju?(wk(foRd&|%zsnr&cbz{?XH zYQQmjFdfv?@(m0z`wfhZp_zN{?THHes5&w-QDopgQbgtUk`z8HdBpDRyX6(MhP6FF z_m_lvVR?W%pKkz28PPt(h(6Wz%>u1f+FC#y9YO!pK~F=!vT5rTir%U1NEZ0uNxL?`DzC*pQ-yW`t&X3-Y$@TRB#w>Q z%Lgwq{A{mfx%yF^EL4%3>1Q|2oUEquZ?J_+)#cXDGhQB!;-T=%!K>SZpYL}L4>jz$ zFkws*C<8N$kw3T*4l&Jp9bb`33SSR?s+uByJ_VkN42}3NI z|48R0y2BWsLM^veGbvUC#fMwl*D9u0rz_D!ix`2g971U|&Umg;DlluL^U(bRdX?CG zhw(%`7!fI>q!60*xHlgvJd(6;kEe^WxX*_{M?pQWARimIR)pW1ARe&7-EPnW{Yo0` zoNR%&fC0(Y!#1UTW4yzt={G0^PviTAcu&y2KJFE&vNuLWN0$Y$?CB6%=D9K2L)BlA zAg)N-Xc)z@3aWge@GZRY->V9>Kgc>?-=+gafAH#b%G(tSR_@w2ke^P?FR8;zX1ke= z{DF=~Bm0j=MuK=qKmYN6KT!Fn5#xrl$(pev99clqibf#^<#vWzUw#@yhe`7V=qXRq zH%+WD@_mYIKlR~InxrpZYP20?a`-+`tV}73svs4fUs*08#dsDPIi|H3q=!$W^UNF8 z*Jb^gYMT*<@|FV&7Q=m2OR*UjSe}AnW--qZtP8Bd4~6WfDrX!=0~~MY!AL(`v&g*! zBeVpw*yrUXmB>j`Ms6uzrFC+R?B;pUy6aGh)u~^9nbg6rYY6iCf@#(BjQQ#0EQ$oG z##%vZkeLd@UrE#H*CG(}di+2fk1ij25f59Ym|$`KG8P$D+G@TIJ<+zUpFcj+N>Vfl z*hUH1w=IX@Z&MI!!#?NB$TOa`tsJXQnzyWkRT{dfV`qzFMHUm&6;_dXz4jh z=jHc?NgYE>l=qvjQr)%ilD+^nGwe|2ri8npY>u*?ih%+>H8vQ#?v27DNu73wQWSmc zcib*aX@OxnA;lfBLAt?EsXWug?NMxp9^t7`;VJSXyys1vvXL@%wwM?)*dP3$?jg{R z3_Y^CBK4D0)c5D#JWLto3K-~;s5@c}!7jlP>&ZwsU9G$6RXyp2)>~iALh37vfkmS;4#Fyxk*?&C5>W7+Pk<+YpgS5b* z8Yr+yzNp*f9^;NL~cjaGL3QE>29acV{C&1G_Bv9A?_agp2}|?l@b0&Q09w!WgB|}% zdBWHadsL;8z^y$m-YNa%?K!`|H!muam+A`Lekfblq&vPo``&jL=TZD}XEgnq8iNPS zt(T8jQm&IYdnV);Y2zQL4B!eshF8mTwvUCdgG4#7bW!y-ymD|{in$JY(!M3R$DicP zWP)wgZ&nSpp3uY=^B|1RDmc^jXWF*%gJ&}o2K<~4uAQiuQ^lLfe!USJ#=Bi%-cpWg zkIFnohXlq&WA;M)y;toYB7ni&__CAm8HO7C17BUzPaB?RaK?3474NtenY#A<6?=jh z#z5He3Um4!+H0Awc$_ZeQr#n;m~}FV{dk|GlhDR&u;7YcC9%EC>p>AAeKQtU7rizf z*{J7%sTIQ4Vz3`wg#fHk9I@2~x&jaJ-_{!}>#nT@CIe(e_RrDK_Sh__at^F&zdhidogoa4 zEIz&I{0|F&+~J~wz?2Kag)D^E`2;B#VuyL14^GlWCL!M0d3$NR_TH&qMOIOVK-P(}x}sr7q(V}RTbJV% zZKO08YORO;>n>{=8@(^-~=5%NJe2qU?wPYx? z9h7gzWGuK+YX9o1I5fzoLRchllx*x-t<47l z7P2LVsLW%M^qePN;(-+@S+?Zu?b_kg z69#UqzgCXVb&MZIV=`0%d`UrJ^l{a*BO%eiBD7aZnvSUYh_x)6{uk8^!cV7%!L`zT zt~z+Fm_I!xiqaNyZc$U;nsX}%DgP=QLC%eo3C~BIgh<>HdEdaH=z8~hG$hNpRGG1+ zr$7!dt1`AqOxZC*ju6qRlNPuh^Q`XA3P_D7X+@{1{6S7BxTQ>hoLWNfvb4xS%t9>G z&gd-OUUhOC@dHi2rQ6_gDdtXo?F2@Pfb4@k)hjRX)~Cd`J-fO6GLMICh=#nO`8Gz~ zahUP0^$!3JXm=!aZ{CsI3VrUqtD5{*J)3d;jGTdc&kJiS{#gZ@;k|FX>F)5Bsb*{` zL0SLAU-JWQyeHR~tG*(OCaU6~-%PzRi3#pZX_#aU80#>t=59}Ip8n}2_cHn<{||UM z)JdvYt9{|FJ;i!83x_o`*pu+)JM@=1B9rje>ZbdlNuM7+Gw%#bdD#E=p4(wTVPRq4 zh0xvj$#s-_#@SzEyGO;hYz3=}KzAi;w?yP_I^R?O5sF z4G7`gx&wOj!~QAQR^iibcJD$LppVK!?@=*S5T@8Z{O^W@Jd90HsHvMqLKR_f?(n+1lm-}^X?xHV*F!-FJZNQ6j-0Sv{ZL5zDlJ z>gF9^Fzq?)WAT=JFjNYB0~YIV={!OutENK#?ilMwGAPfHZ<%M2`ZJ%Tj*L~>56jE>%pW#=K6=LE&yKw~h=wkoM@7zy zz8^NUF4p2f!4Vz6Tt?+D6OR&wU*H5r4t{vdPWI%L>Vn(fdK1S-BdgGgf&{B)2&85Rm8!Tk?Ze`?>e!UeXFT_Lqto7MwC7^@jRwy zKPx~lSWcDlW2Gx{y7zFX`5m>Ss!3eG%tinfd{7J*{Oog|uN*^mqU!QbO($Ev`rP%S>r|kGNW1WM(%= z9zr9jcUl*kB!!4m^gG?QwZ_)B~0}#>xm!A3zkbWNo{J|iC;n4`wF!b9Lk-$*&1%Vzm>)95mp_k_xMBlt?J7@~#cEho`gRH$ZKhVUs$*CAQSsXLq zydrY88g~mN?@*+0m5CO5)^d4IAQE|Nh!TU62829DE&AP=I?E(M38_GS@>jW(iYs;g+_0b zt12f@1iyms#>u)HahTgSXKK_=@t=(h85tr-^Gnr5ax3K|pM z&6k(6UXUSuN?G6d|Gq)`d0e^??MZYVeGwT1 zA%&fL)tyXNchrOGB&Xe&r2HaQER0Cugv?Z6B)nVK2tL9r?&m>{9=K4;Bz|HRr&4to zQFqfBxh`*c`99aDW~k&m%MeT<@J;e#P~y=0hxL zA|@<{4**HA8W7_S~`&{9FjeG?2GMEutt)04vr<=m zbyia^&DixF66w#kJJ=ukM>WSycFIsdbGAv^3#6y)YraP;d=7qmG^rck3Uxx~o9@*A zAJr!K#4eCK{wC*ZL#!shVDH$gPpPV0S8Vi#3@9n6DAJfLvpwo%Gw$cJHrN!-M#m)< zbwZX%Y5bL3ES{e+%Obwx;t9~~Z@|86+G)^BGuh6Om?!rUKS-Zg2)|+R zV|D)-ZW1POqB6Ki6L|I=}P4E)BQSzj^vBw)92V6@bpa(IYb|c zJn4OFz{3ZBi|OJFq(1FcoTQ#J*&!eF_kOQ~zm`*Fm_51AV80eGMA%}(6;uEc(eDeV znWwP~qa+0{gECBGmDz^OxTE~(Go#7 z)iYO1-$C@;O}6=&#MOR!Q!_^@vOFEQzYy{HjH@K9r-+qJbUlmAk#?F0UvUVpMIzAx z+ZEC(-27|%JrnPJL*7@S6fa5Fm1D=y6z=&eh-9T2cqA!Si$5hk?+)57Qu7P0PU^AG z=QFK8smw>0pwoqKgzAXbhN8TS9*M;G#uVXaTWt`Eh?~r_C9hX7T}uY-J>Lbz>_62y zQiI+^iqez&ZEm5s`DBvW$W(YxQ9X)!ovzb6^|w(pCMbZ48HJ()uHbsrG4Wj}4a>B* zY7DqvG9SK7<2 zhX>c@N6OsKS7Bc*m`aIOLeb+0ME6IgKR!uV>%Q%VrU!_!_l{6Cb_ z`0hQX6t+LQLY&tg^4KRhA(I0;pGg6~g7z=1GQO_gB?T2{E`C!CwrTqtcoCvK`y+$u zy{E7!Mh($lu;S7$%cH`<3h@Nz!N=C?@LBF)_LqOM!tX1{-i1 z-TQmsupiwu_3^XbK~4{IxWw9y3wYaoPUo;DFUadg51u1FEUUVzJg$Nsfi-dRK@>ey zhQbidw?RT1>E+reEw+qJsaoN@1+a{>(0WUWne@*V^8R<3;q?4NZ-@dIq=_VDLh zO&0xv9 zz%ntYaRM_T3%G>H7iRU#n^0;D)L^vt2f;}hQ&J*Hj9TA*5`ub*GL44nw~8XuIVeQ8 z{BlGJD?Lp7(G~5H+?(9>)e1S&j)ynF`q66zrBs~_w)=8Y6elaVl+1?f#GXkOU0bjG ztY!+KMtVOy-fU1(TPnCGTyOWdk7eH2KHTO8$$5F*+i`eZne?MdCOw#Bb#LD@rmG`d zX-QsL{4|0pHZGc-PmUfx6_&EGz-<8oX>3oT-%lBe>k#Z-!XJoktdN>@7?EX9MxXJZ_k3~Me<1*dKK78!&Er0Pi-pR$vr%M>;ahlYOwbF# ze(+xH()q@l{!`;2HTze_Soe~&jU(_jbd6lY4Z#QX8_>3YgXz)+96SQMz;W}Lqvs{u zdtTZx@uHhdtr@@>o5LcdNjeCEo}+mGN}$`L2Yh7N;IAM|WM5NTY<@)mljSUuNh{{m zEWzM^MZr*EKV9vFI9fqHMaPMw@$uOK(QVwc5GP;}BWA8KrvDDcymkL+zdop*(ed^1 z%h!bL#iHu#YnRqXXFPP8s?>J^qv-Xya1&2{wvA6hF=i^>sD4KA8h8yX;vIRgRitcKJ@2+h6chKFV!KKSts zxx9NyJSFBB?U-M0st(ypsxm@U*TSHzD73D~kx+#=4-5wB4B_oDZ13)9IkiWulA;EL zICKs@<9hBgk$S`d@Wh18^;Si{D}f`$df|tn4%Rg-v60S%J@DTn(8$#;GFv=ftG*SD zcD39mHaAQe^t_L}SFfG6`y&M4P+!TZM++=iJN6St$PeQGQPjKH62huLPANYC#=jxw zj|I4&cag{^22x1_=Qj9@2pw07w5DeDAme+-8rpdPaV>&kCCDgg4ldOODwBGeVv+1R z{WRa1&7?mlAVW;n6j;&wv3%SZ93~5}WM=eCZ2obOxT|>F`+gdF1-@to&PAP?1Prvo zEHdqy7}TXzI|BzYe&6%`?k^}VS~uS|(hW%ia)-d+&&|(Fp5Xeg*>&v~D;t`Xb?_N! z@gos5D|n!%BZ|IXZa$EyZa=D%{Am~#uNdXIj60sS$(Ct)et!egDhJHSI{@uNihi|@ z0BU+2J@Y@$fLGJm3**9#Kh)L*z*(H zKZY2Rt;s}IM{sCC`ym_rLk1!yQB0sV_{onx^#L(L#Z! zLihnEcR#AM<+HZmAhw~^k)Xt^;;+p1RkMCnS9te3M9M=?2mR(a=e3_xiF9)i|jdf@YK$BQmm0$qo~iYb1+k4P8FF7HRwhGSTy_R#Lz~we_lEIOTK7C`jValm033kXqA|J@7nm-|c8`6apCBm^!?yX`)D;$P4tx83Y;{)}H~FbMf*{ zGi9fim*K8qAJ~TFD!5tu$`Ur;W16T>vT}uf2bNRL{xO*#ML^2eBtN2_|LF)ys=g-RvdptmY9?lq)n?<^XPCO2PWNPx&a-eBGM&H-f)mjSTF&-cI`qA%n zcaqy-O|e)Y$gL2RDb+t?V(>n!JC${O1^djmEGMtb=RutR+;wy?90s=}8-JQ~s zD&64k8n^q|&;EYvUF%!ldjDeW*|_$0?(06U^E}QYPL*`7JCv1v*9NN@@9 zyc{0TPh68eL06z#YtrOMCTX`>l$dm)1#P0K;Z9Dl*EWfed*`Al!O(=Cf^B9X6#6K{ zn_6NwuvLsH?%LB>GAFnz~{8#24r#KWXjjpDu3u*`suMB{Um^sFkPa^}Gf2b8vGmO}u|2@Mm>>JzhI z-=KSx+Bf*8HBGSqWq<6!z}vp*e}+J`o~HLH;3%v#aE+pKQs#4!n{C2)b481$@K=w^^hg+ZR!2?=$-o&oLRGkuBg*Y!@Ce;8x<+=w}_-{(l&Wa1D>3vd7StCMISZU?c z?~kh}2}3?P^*ynUM1=1_D!Z{9VL*!O0NhrcKu%5EBcNL+9oGH(rdRlV)2~R*-22x} z|KQ2*n|_Fxb_>Umy9sWj31RYkvj~wuhj!lzmkx)WUH9^RYNWExki=>FjAb2vTMAxG zaF3{+x^j0;bkCpD3s(sD5wYO77~(VrW{Qkndo|#q&`!NBv8%nyc00johfd@~6R}|g z?Scyr20zIAXlS-4+lb#K26nkk{86srZDDwZDK(;o!^|*I_6zwSPUk*9^2Vi+;1GtL1l^OA z_-}p+4IzF)f+51YbnX!qNqw%~Y%%23=9vRB3@D7_&Mx`*KgS#J>`;eWq-w6t^*Kt@ zn6F9dNSr(`k@*eeO>YHVqxuFeU%eN=c847Qc|_fdpFjEm3+uS=;ru6mA_10)Pr&kS zE>52FW;M5hmZse6FqeEyDXc*qwn~pj zlbf@}s?fI>aNGv2(FlC(Ud!&h_x!^?q_W}a%=QIHcv(BTg9L8+efE`IOb*i@tsMZp z*F?|uPZbZB1y8&xIn_!p_s=TjFTNpmH<+sSZVO;_E?E@aT-Vf!!x2C&j&s9MV3(5S z?)|oGc!z&*q}lqN#BVZ)?G-A|sf?`JGlzvN0=O!>u{UWtZ~R>rDa@b;bXbKe7C7Ut z$|EsQp7L#ih<2xsxVs6X?)|;YN6exWvg-G;qtgz?I+(f1*nTWy3{&&8!-Eln&Z1$; zY_Jj#)fsITCQlH3l2Y$pQF_s|OzB8gi6Flf3tse)uA0IBe$jh=zv$Nbp#7Q)z#~CV z&I3E$D(t$pD^zb+8);B5g;u?I0z5dW$y_DXauu8)ew?){H;%y!7XGd%XOBYfvpHI2 zKC4t!0pKz7+1V!dEYjyECIQDqTY&Iw8Rbec=`EP~FgZjk{d;9EhvktGeMDQ7-#?QFEf636Mq7jDXB z!7d>>MJ6F^U}*`H?}Lflt_$4iNdmhUUL#9V!~F#4#@&ZzC)s8Erw+;S-;~(o25`Iu zp?#5uJ!MNh!R;H#alzy{s*JU%L%HXZ9fFFlyR0kXTC>XH*XsR}83|MZS+)l??o|MT z_0sK)*5#%k?ts#5)7mDbHdVNn3t2k%QKvOo>kEnW3YXhzPr=0wZC*C=F6N5LIkYP6 zTol_Gc6O)U;~B!J)ZO8A<=1m@7kOOO+w`8WQ@0Q~T)N6yGM5MM--T{`GGnzKtG4|_ z-ow5ne7=Km+{dx8y0C1ooO9QN1Zj|z<*%^d72F(E1_PPB55jbl$mc=Gc#s@%M_=KXJ ze!r=Lxi#O&i zhoLP%G%PVSX5+sKd>*<+&tKOYTCvUZa6r!e zU^Tp9d+2uV5&^US(^}s=;R+M_+;73qJ}jD&K;F5er@NsYnHO@U9!Aj)OmxLj4?^AP z6;iQ8oqP}ISJLs?x_qHVvJ_~h8)pv5cb(rcnw^Ym@0vDHFw?S}wgfdS-T!8ifpwAH za3ILG9xu4kW(qr@W%3>j%)`7Nb?Qy&V&+e+zikS)lafIoGW`kPL+@a7R8E2*fHklQ z)Sa&R0c1Hj+%^k@>|wse=1GQMU4JzA+0HbmxqDt#QCQU0STvH}+b=S_oc?}r{?)jL zk~5R*Tc7KI5cizdvHhwn(Y23&%itXF?b$+kk+&&a0ehe2D3Hn=V5o12>ic{@ zLCD@Yci;H|PMflV+pLrH3lw*&P|z;vXzs=5Q4OII(3|`K3JSt79kNPwYh0A)W&f{t z$4ZAv6gD62rtaCj=oCP686#5>Dt!OGrSI*-fjPiOshv}LqpBli2iE(Gj&}&ROuYbm z)E-zQ|LDCxzz*red+Gudne`99x-&fQ1FB7YkJIDEU*91_W7*;(00P^XT#8MKF{#fb z>=XdpAL@r=Cl|Z?#ds=YQF2<24W|}OCcuUMr6Lb2)?UElC&ZT6&jHN?Vj(gC39mIDkAA&z-d0x5BFV^~E|ggd4}5 z;=p>SgGd~kJD2Nb-F3v7k-F7Ttb(@?+axjE(`774c}e_Z=dL_k95u{qo3>BwPEBEVQ!^ zpm1v4*Sd=0@uYBgg)oWP?oPQ1$b#72p{tThBo70j%xsP84DvlfZ0lJ#>$1BWJy5~3 zwj?D%5i^18Egj>iVk|16kdw*W!^JFrLaHXsln)096m~;7$S8cBo|AEi4r3;n$1jJ8Wv`#* z+RoKgQ3<_NH&X3#Txe>YoiOy#cVoZ*XZrC&GW;%=9@r6BA^5lMTSUC&wbxzOI`(Jf z2kgn05EVl}%nYrAJiH6+T2&u@)%KFTcq^&)E zIk$nuVQZ>9+G`U-`{|E(M!fF+I8Zk@Vn>X=bn9@8JOErOI3pWyKtw z+fxENJy~S2prl3#7^eA1)+b)0>8O)tRZ>dw@E3NkW`b9x2h9dExjmeP8$e{n@ilVf z=^}+c(H@{$F6wmI|6I5izdPrjsWV~!>YPU{e|OIHK=$C{h&3sL*&c||i>n>?Ny;%a zQ1I~bE*gI(93wBL8H24uvin`*-e2Fh(_Z%#QMpX{JLM)u!*SG-R4{;o|p&Q z?=~pgn|gr+%X){oIxHXG$N38CVfo%tWb7feyTsM$SlKI;CW=*D%W~eK8Ky>ULP6Bub z@@!eaoNCBK@~d<-jE1#pm!|mzmd{VBKTH3nr6d&W;=MMjY4DqbH{_t zq4$~ZolGoc^dmqtj_Fv96+i%ch6=TMm=wpEY{3!$sz^Mh8X^TtE0924JSz=x!rs=Rw? z0i1{7KY6FJrM15TKZEt68@<-}^7aS(svAaoE3(Eg@YwA0eaRdd{C#oE?Q~8CCDi6H zpn`+z&#UqN@PnG(r-N^N?1CCCb>Sx!gdM^JfF9oCiN>oceD_yj+P?|tARAF4#)Qlf zn6B0?lu3n?hc;3yb49o55Mbk}u+0jud$%{TQ_yQ5clhrLZbkk7%xe1#nZX+agGX>Ir7boOU zWpM*EnWZ;^x($G$+Z82g037r?W28K$EmfxNn%tI3KKRjy6Ga^WDu)FE6D3(j*JJ|(& zxxSys_UYyUC4+RjW&n+#9UtY0_~c!R_F{?Zu=G{whC$2AmL03Bw1ks9D4dFB*c1lN zoi=sfwO?Ue`llHQPfIM#N!oK{NW`VI1cneng0C+Ov}j zJtd#wY*%ZNJ>AY2e#|g^E_n({Q-K{=EU3GM^^6<(eA(d@xdl9}1L{F|To~Kiw*T}! z{HS+5HB_#k3iNF11H_Xdg^%FgCz)VD{1ZI{V=&rR#J8GBF-5&noY)&OfYJid-B^G& zDfwoX<0vrtus}XzKUJeCxJCLBA_RP_Nsd8BjFoQpf<68Dw_YcZ45d5CdM!isjwpEp z04pOX*tM^-zPRCUf7l5%V#I|d_`tjlhVGU|!-0da49GANc+ z%I?jlwj1)8cYE_yvRX8~k>6Ccwu%Tu$)ArVCLK(f5NGJY-q(?6%ud>nEImblYV7d! zvxhO8Y(L2aH7#REx5DSU%~h$nxkQ~NLOEdU4I8*Q!Q~Y)fCO}#wfx+~+|R!3+XdQM zDk{Vm?ek=i1&9NBcfiT4mX<7=5cF?~kLW&X6Pz;7Uq$vW&XiRzYQi@>Qu8hL|3Y>` z{EW*;`V&7Uwv^Yr;xnG5EctYDy(Z;Zv-b(`Q_{4+3ik%R1rp(x70|nE+_XJVf1&+2 zu#MJ3Jj=isl9o0->xJr1$)$56N+M5&6Tl^ESeX+Tla)>e<UU{EB~fnq7-Qtoe!%IVr>;?-)R04 zU^P2+s+x(*FjYUksZ9#ep>n85(EFffdAtl2;d98q7%aTj=ds3dd=bHHvrJ#Z0VU6; zZBqONA}HEGbvW1f+Ryo|7-%d@)$*dQ6fYcS!T9k;-Pa0NlziX7G_v|iyH#ZSe7NEe z2l~iX+_rS8zsk18;$(ZT>8|2u?)eH+>0dEscn>{~*xo?(hj}9kB8C8Dy^|50s`{O6 z%TF<}#J$Y`1Z+rN);>#v!7neSWl zJ_8m2`W70wAHD56QlsOQ1iHY2^yQm1|B@SMwG~n;017m)|5T?9fBqhyqypdszidp& z)qvl>ka%e<%2FA%OykT=>B>V_n{V)Ho%hwjPyGpU%6clknAhESeE_C@iWk5+IQ)SKWU@D_)24a{Hx=C^%jI9?&DCpuj1-o{NO0b5E*?$cuDRbcqw@D{8*sb>j z{|usBFrqaZmNFEM#n_ZPzu_HJmDzKReWS^rQi9u%d*MFC1#L%=zpx;(gUbt-{~m$` zta06}MIz`9?#tr85g$;$%l|kU4=Edv7dj%X_iAe2K*a>Fvjnx4y&OB8Z?*+@IaG8dSM)E~k_i_}wD}gdo7K zpD;*A9n36#ly@0^2d;fy!H=Zr9;n2#tH`Tgcak6Ofi(FuIW(<0)Tp(Yxmt3hlEqq6 z{6@glMwgwZA ztYV6$X|Tp!X#fzkHtE+-(Q8M$9qA{*rRU^=cUNAb0vdk6XXjo|R(f?+&p5AZE-WLLQ8tmg(G@>EZiM$LBG+9+Nd}My>WR=d*tBp;mTBlFq9h+|ZUV&s*N?#`5`Kgv2Fqp;2`PV=O>w%^eB9j_TVc<@u?!#(H zAHHzHRbWuAgEpEeY)_z$q%9tNjopC#yeLi+H-D!-g%_^XMnLsHPnOOL(D! z;IlO!90R^ZN9Vr>w{pT5(AZ76{zt9&mw@X@5(nHdjPvhU4@A-y*4B@lb?kHjm5J75$(;#%G==}2l0E>`$4sMENiKF2TY<{q1 z&&Rt>F6?|T#>#Z&B$Bx7e|R50)$ZjUL8m))uT;`reQ$w*nfy`~7E|@wu|%9))(X?c zPIO#%%f*SxuG;)t_f*)kc8TNq)8|E+d^Te*HELFs8heVVeLwgp__TTLHG97C-g?E4 zI5}NxmghDEGkDsg(-pPC5Hw|dkYlgW^h9+ zKj!M|L4;q#<;n;MsaJ7L48*u@f8S7eG9x45D$NZqagn^7EM1$QsQnS#MZppgpnoQgT{?*i7tv~SiwFndt5=Ryuj3C7<2btr>T%x z3$AQCr5z!Mn?QM%ayX&aGwzR-hjV5>7R)i}Td`YURJz2~F=i2=$^^=FVL80x$2N4O zx~GHF3lz5%OY>h*SnckvEaTBmv{~UPusvd8ERS=qfH}*E-bVC1W>zybtAO@N?7HrS zFpEp?4w)7+79sNh@o5kZR|=uK)X~Hu!oCyAA=z^_gk;8P({>`0H(l8o=I!N=>Y)@` zP26<{sA&*BABa9mf#2eB!M;TmGnPB2TiP++SW=0^^l-O5lK%mKQ!+)_iEF&h@9G`3 zX@4!A|D3IN{QT{!w|RBhO53W|F{!^tJ`r$iY0Wfg4We>baGSQyd!iVcf8RoI6_rGy z;9Ii>;ts>IUy_g&Ip|!%^6*_5AXn&sl28{_!1xg3P0+q#X>;O1-5d@ zo*OwybB^903eG`XFje)LSo={RbDDN7l6LuE_JlJNpF;0c6lf=FFc`68gF%MP8LQsB zKq2skn6@!Ke<$qq5{KWn0Qf@RJ($AZU^9%p#){oJ4d7v~G;ACi@6Q)|J#=|bNl*>Y z4ET@Z`@X>Llv6dQ`8`t&ZlhX$3!gB1KX8SMVxTAo*HWJm{6)P;(LtTsUZs4Fj{nRE zs9$6F%}h`d#gEZgEOB>-l4B8u@9-KaEr{*V>AEy0c4E`C`zBkhV$`~{9T!VV^R_I@ zP&_3Rj#;LvMcjW3rP1wE5oj5``?%c?W?F*PxU@)dlhM$~{3DZl=ZG!6(zfCA@z135 zMOZ?}Y^mH6-SmT^;^1@jGFwn75Ntmnl7{B}w+T@5(AZX2#H)vR(>neg(Mh zOYWMq?UT6qq+84J-1knC4Bf-HJg6mXV?_E?oCX6QBtqR&xV&WU+41dM8w~R(QVv(B zZN>pRTVdL>7zB4awhuk4*;Ha+_hW{Sk=Hs+x`2yH+1xL?>OcVGn~Gt>zN`@)SCxgS zMN2SS!kFd`i~|vf>c1vzCAN>_)~<| zH$CR?=lncSKlZz{y4|;vW+^8Xtj2D8IMXZ&a2m0pUwl_5%X3U`4{#+Q@{lAGn~BnQ z^LvhFMk-k0C4^|gNSCYA)|P6%9l+7K3HrQ*8PZ%aWz!A=GKg9Q$K@xRNwC##A@{H7 z2LjBs8ht^batH_5>t<%o*Eky1Oc;0u3EMK|IT;L#Ru5%$F!~l9%$mG0F?`niYyvdW zcR{3S4@%$45Q`IPzoH~iaAN_5bD^4Np4b94!WiUuTv4&A4#zg&nm&(bQcRS!dN^f9 z;$sjc?~XcE#{V0q3aBW*>K*KZA%0OQUkOQ>iYItxWI}spWcVN`m`E}_0z+@n$|`5M zK2!+$b=A;&5iRaU12%sHX6N1-sNIC++Mt)BQ(T4{U&guDtZ>$~`vn(mw254S5B)(-$>k@mB3YS3O zYvN@lr=E)I93NHB!j!`OaB>~f{2aP5VnC;{ROsA=Bh^xgRPALBFb@vjtS_b0YM z-ktozx8A$qx95I%{Zgkztkzo2i5Pm-qK*~}6SyL*y7?h}WqrdTH^o3cpEJ-8yR1X0 zczc0i75723pmPjrR9^28d3m_G3IYc((2F?Hbim?2cn0)${_|b&%=Ms_a1l|RsTbD$ zsM|%mj;&2#L`v$P2C~Q2q69YAo0NYg^ErvXF*b&jHZ%IlM;Y_C~x!@dSu zhu^v6bXs=zJtmC<^=`5@fgPfF4tqOxr>bUg)o(_1p9mNnY_8TOHLXzWH#=1IDL<{Y z`aNA_)S?JrecvOdU;ayj`oIDFS_0QEuz;3!92$Td$?`!UzVIP!!5v25_c4BV#G<(w z2O;1&PiZ={*$=HYr9^2ohT+k#ErLy6%qryc)N_q{EhE`b;)(J-#msBPAqgsmXy zr^FRYe3iz+J3~2v+0yVwQ}+@L-4~o*`7f^ZDsLjcM1BG{l~) z1Hjh^`yodVVL1}oOh5v-Q=X^z_8ZubOb@~z{+KR*N0(3qd@a*?36?cWbZgm4KM5Xe z-H34oTex!%$Lkm57{LEsUaDF&J8V4t%Ef3fT1?pvONOlQfeI4;E=3z}C|EXI=;o~R zDI4V9a=SeIHNa8Pb^~jMy#2Z7)hWen2r)xp+s1TN(WCS259q(Z-g|HVGw0A9;BwL7 zwTq zrJ~xTZ!Wy{9RHp~Q3tB~1(7NMWImH=lia1ZX^w=9zgl?i+mRWFnTu|TPUl}99Plny zx&4V9mjVHAWxR;l9$qeX1LDMivXw$M$mb+N2P1&v3JipTD{);>+%G#r1_aHR;b~;s zF=Cy!TcHT#KxJUw$@+*g2_+2CDa-*i4ai~PwGdN?>&l@ZP`;;#y%WO}3@7T!j#lnN z^F)gV-B=Hrwb+ua!^x6SMWv+zyv1O5Ri2rMri;{2Af@pe1xDdcIMgMS?0h6t%&>aB z&1>pLy6`=Ob$`Tit+mieqTzP?Iau9Y9E>Rc01?sq5?Mk0qNW&?iP}pP4&M*QUx2gn zoFma7*XY!-;o_C&C320xeK%t!NN84I>z8sbzE_jvhcx$IFM+j7*2?L75P7teZh5eP zDlOY~vB}SVVBUS$ybY8eczW36`+hJ;b{(c!B#o!}q*81N1j@Idj1&*%z?#y%{{99z zS%t}t%F}nOZk2$}c^0NCjiq_(fOIS8oO`ga?la^B{e%o-dat(xz{$psq)hVGGy$U! zm?IwOacTyv&Vu!uL-*^(>?HE`61^HCJ?(p7PO=D#_)ANhVvec;?8-$P-KfsFjSxj= zZX6vR=u71vQ8^s{dymVG!Gqe^+Qe~;{8dc;a}e@5!67K*lt|dajX8X`c5sZ7OnjGP z!K5ki*&qdWaKkg^9S9qDB9Yh0Nd_|AWkGCRd|kB}i)MGd=PTfcIBgTq$h-`@1DY27 zhE)pvK7V1S<~A1Llbd!!VoGqI7(`}S@_N_9x=ygaC9qqNIBA8|Pkx1BcuR8+`H?m{ zzur{~yZOF}{<=~Qb8y6>E!wRQxEpQv28hn&Al1|{7i?%JCQj(gvP2@^^<< zdNEp{XFF0AQA@U8PhJf!`j+u$5!`7oVG%anUE*O#D!J&cvEzXvmN9Bk=aj*p$x~F5 zKmY|vM5lc*6qQVUwXger^ri?q|KW1x`Rqk)x<+h`&6mO%=RAEcB%^+AAS+iN zqWjD7x2?cl0m?|4N8=c8H3`!y3r+7xhLdxM9~NsFc-*$@!`ZO{an}By1Qv*2Dqf4J znzDH75i=E2-T;&cbwC%uMs|B97r!%1%;1AXpIo(}0v9iK;Z0h$cQk(irhea0R5zaa z=eBJB8g9VjeEC})^2n0c^bf@UmpUZe8CBDNZcBn$IdyXlTF&YlZ`IuATYx6tk}NE^ zyGR!=Y+oGy)NN9HFOQpdL7lSW%$u@3uH)WWuOGP{G6yS}R)7AQSKpgj0Hp5T^bc1- zY=F-2q-BVO6CF7?TM=Kn(jE9s?kO@aff^n`hs+BM@uxBEn|eVY+Z{N&9m`ZK*_9}I zz{7pW!{0tBnj*6;K~gfBe?WE~6iwuN`?ef+jx-yvQ7Tzt)9Jky7uCMh+>!U~@wu&! z5tqI$GWwE5vpBEeqD#|>vcqk-qtOL(a_PN)bU!ALrm;Vu=i#NbEg+Y#r#b%01&OH~ z-WgH;wT2pLKvb4bonzzKGzUQEOYP5z8t#o_8=u$Ny-lB$sF`2!?wwS+E8ocU84&Hp zz&24RnUM0yVgoQ^o&Dxf{jI2sgFu;o)eKNP#vFC>@r{tx?ChF!wx~5d39}Mztvg`d zqv*Gqc^;vDdSGbiK#4S(eM~hv=|A~C-(MSeVTbWX3blNi0h`WOK-aEw^IqCtTAno2 z)7lp-t7iSz(@ONqMd>wp`t~h8{7V{Do^OGoF!w89cADt5_>=3R*`Ys2_tVd8A>)t? zS4gIAKgdyrr=2V)?%*JKJLxnA-UIub9o7T>L7Wl#H`_vNI{^iLTsJv(E5!Pf6Kmyg z-rRk#DUY4rU}D1#Hz1YqMrv_dk-_zLx!=PFWH0%G>>j|k@8K=0GD>6SKo=kUXdTfe z7;0f;Acll41!lC;n^J99#X2Ee=%$7`xDZIKqLUL%`dtoH1;4iorX*Vn;S42gLS|uQ z{45Q7NXqoe<|M?KLyWclt*k7GebZvf6YSK$bXy@>TmE_7K=!yn+|fy2_QcOaiF);J zG!q45n`jPV>b++t{>QT)M&NkMbypR@Cchpvq}7raV#OIN$VE(4(>*;OF=&gb zi-Yq{FoT(tS>aQ^%FPH4EVQBuA(NEJ%`zYt`(gO&jJx2yYd`K9UeujGC*0;RVg1c&)OPN(nR#$@oP zcrOpo^thv3A4IugeQt@e#~)gJ!mf+fJSfIAzni+i%`C$`ln`ad^B5cHmJ)9EF$})H zqs)#7UGOUqQ{K&C_~Op)Q#tZ^C(kv5WdF9Q(jJ!b)doe(E7H4a7)&LyEE|(|aJ^RO zv6Q$pn;1`9qx`#u#48gbD2J20bb}(7mI=ylVE(@wlZD?-)NX<3B%E69q=%!^h8JqR zwX6R!pYp8q{96x}!=<9PnhRTt3Es=a4d&U|XknKUP5nNvtBsDT(x@sxQK*~$Zqm>>(mzwW48a% zPtr5r3RIKc#?=c5+w~w{_dx-DRk?>wSqe zmN_hnwJbvz^pPj9?*eUjiEm?S@e@W??|k8hfW zzQrK+1_{Pou3mq5FJAd1FpL7Rmkyp2AJ&L|BsGpsq&@#1@rS=8gMS2qET|4ooVh30 z=D$x|2HtNqypk%Af$WI0J!AGw#5B2a7atZtZAZY7Od9F+Fe27ZLJU5OxBM~966@Da ztiNI=7k%zUQwQACL~KtQ)SDE7s|UZdwHnGLh?><9-{jfNc5ccmA#gpYNnoZYPl~xb zPjvlFI^p-+PeROZbzBXWi2s5^AisWTOWoN1+i`3A9Zs^w*x?by7lPsJ&}*-mv`Mm5 zWZSrGE~K+6uqu4N%3|7ZVlTpxM~@KHu=U!|Uhl zO>DoLloK!0?t6Y8JNE3j*V`jJX4j|65m3yE+uHu&p5Pb(B24j;N1V`YiP)L6hJL;3 zZYjA*h;)eTc^1P;k$0a}mshMI+v%vP&!M{4(z@Xz!5b#|p~|Pl+pd~pW|~NwT%+!9 z5*-6sU)y5Az?ji!gTvE`(P&a3p9ede1J;6e7}N}pBaEC1j4;6zXxL0MF)~$N$ z>$z^^EyUYmoyXTM2Zb+JvUqSxrP_Sa9_j(m%(NXy{%rkm=HHqh|MV$v{XWg}gMvfX zOd{yB36L!Y@z_l^fict^?51oFN_4Bb`}vj?-rl!Vnw==p8gOX5mk*{B*>y~S zGBNcUTzEE!=yFoCwD;0>3ozoVf%iOjJ3FA0qGZc=kKa}UUy7iw=aaw{B4IV%^9PsR zkJ(zMc_3suUxqt|2v~mE?|+nKa1!_l=pJ|x4i{PWs1#>+RD&}OQYOqnh_iuak>(G> z1TdF`piK3-OO@UUV1JFIdKl%o*m7Z13wmd>2HAL~sna#X>&qvqX;al-U)t86ZHly| zf}LJ7pco~u{`@$iX!RjiQ;P3xbO8HxdGv?o68)(0+v3Z3s6FK$k zHm-dq`SZ(sfBhM|kGP|y?^N&ePII$)-Mut81AV{}v{xAy+W64`2E&Bm2~r%@8d|Jr z9+)pKQuMEf`GvoVy7o2fAmi~nGP)#f6VkV(D?@K758KPmR*VNOTh6zHPePaJ8lQBu zOO&4B@ZeXBO1)OTJRmGoCUiU0f**}8WI~Ho>6W14P z#Gm^WHxG*y7V*T?;OzHk~+}Ng>&YLf^$nvk@Fqx7KSDdH@c-ug7gZn9&?d znQ%5;;|T8(8)adNsR3mA>!I?t5}h_f@1+=dG>Y0qYzzrjZp$d#z*VEi?Mf_V(<~0L zRD9ko@lrJsnCndf{kKiv^UeVQAd&*oIEFA|{|Kx*1kRe)=yaQ@&-*LPdrp2@DRtkU z31T$kMgqDTd8fsE&B6V^2+%S7#M+yntzV9sSuR)V?Dn#_8bgIs_&H*LEU+_PM7Q_j ze~0!dVu8RGd)D;V0~>$E`z@e;H0An%EadKEezNP8N`yK)E(>AhVV?qsD1w9<*B?(X z7(|xBneh3-Fsbhwyj~v-TZoLWi9DyGwb9dRETjezK7xK zHSZ&9JKc1_)f+{%6)F;zDvDz*Anbs;q+26mJUPaj&RFq1w)IopyY`QZgW8FjaUpa} zbSJKmF^vYIP8gi+J)dUwp!8F@2=P2}=tLJJjFK-m-yh{1r zMG+fD+4qX(C9~@;!v^(w;hX7=%v*&W2KQNlU7ygJjS&>h$6(b+XIac zo4_$pcN>E>ZSS7Sr#pm|q#%f5c!&Q z>&;ZzT7rz$sESs#R+Nwoz`2-%7Vk3>NJz=jvb7pjKUHFpm|L z^A3@#SgrKFCck6KnzwyvLXW<>YtqwF(#D~#{;!ifJczQWTRhXB0@;x$00H_id$m&s zY4fS?Pw3nx?Lt6t;l9q9?Eg_*ynqdV)rL=yH~N2{Kwc)y;dwPjh3EEm9~cAJan-z9 zFn(f3;c88`(D((TGh;nsYhe|S-wyON84ea`Gm2M&uMUOl3hrpSgp+%pYIjNJ`&kK3 zjrnU!x*aA&@|~G7YYOG#{0zG4ZHA?fXS9FWG?7-9_8e1BHTh_%cuqjDeZY~b>{_5E zZdJ{sqOyd)%)>5xiyO1L#hCI&BR15Abm{s_aISc7t2wb?8VX=|!UE0&5xAQJY14%T z!W*;A?^ao&$?lPP@!;^UuxWkK;fX)PQPYg~=#1y;V~#?Yl#fu*WO8|yOzz}(;ehOv zM_*$!WYFm*&087Dxo=c%KD0Bd|GAH0J8HI%+f=B*_C3%?&_*7;8EfO?2+}1 z(&YM3dg3Fl5)}nY2ZyOw5FQ`zT`kpn4w3Vly^k3Do2Ke_)$+VBBJ-?I)OC!(a(0SLy`3ij1uK^VW*xV zn8#{XIK%HkAvz`vqC+%(-9IAvcWAnu04^V$?Z{~{LiJyd8w;EQjRxgAAP!RgYPkg? z9rIos<||V4JSe@AJ5K6ef#^_}7cO^RQdw*r6Vy^qQxIbcWAX$C}G-h56l= zXwZDQ#GvHme=AVP`z-e~1>>!SnuD(NWr8xtC*JLifx;`XNO55gL0s=C?TyfDjTR<~ z=Rx)j`PvPKTl%`RV_ouZZIu;t-uuTDVRW}=s+q(Q%n6mqVJF8(o~Qn@G8f zGpAkA>xb@;DyZ;9+uVT$Z?{N#RpH}kBIAOyxukBxh&RGug_%08*i%#T@a>0YXojm@ z?J}J=ZbiQ3{ZOsvXd6z>S?-kexYLfuX8hyPjO)iYBe~O`r#{@PXNwY*qJIYVcWrOm z*SqYkv<$rz4Ll9<-1~U6Iwq9G%@2P;81$16%Hr;kdA(XiuK8< zRz)#O^D@5Gp8mpMKIgVKvRkHV?>Lbv%+BTz9G=_@U@U*&R|LadYF7L`Sot*AZa%j9!vMwD9YD3s>JX8SKSPc zhnvR?tE3*wS<-1;mKX7|xsHnDPvNxTNDv9Xlo^c{@ZB8XqJQVejj=lLnfN9FqI5K*h0gP-7v=kAZ0y+;w0?as5Ay z*;WG~t6)RJlYX#2n<3M>c&ummC+Mb-4_tzUOYm~|z~6~Y;BG{dHi{PqhxqMi$7<_; zAL8;M22jfOyd?4Hwu)kg9t!U0UJp?gd?vGyyYA;GPAL3|as6b_qg)=}ey^uA!JW81 zAII|ccj?rZAp`Hdo=F+nbTAo2IPWs7&}~M(1M%ar^3)%mc_S+eIfaixERjRq?8rfNvx>NaxI@RW*p<&IOt?vJ4Lx?c{~+&9_Bm!_{b!@ zN4!0)mcDPDm|@{ciLzj` zJC>RC9!LeB0W+lB^ZL0z6&{}+d@ZaenP;*8M}^lxozO0C7vWF;I*7MXF{JYyan~z9 z(QTdVG~FgH!1u;~6^UbvEES@T&ndDu?%F58(2`o=xLBH9khdicR(9K@KTs7JYf)lv z;qu)mbKmY3V-8Ni#Hb<7G6y^zz;n7tzc0MimqD^!pcl=9L0`CN<$6G>Y7MB%pg5`s(qx0Qs^XsOts;)J!8)@4&6 znH1vsnKuB!n*bz|idyx%s4vr~>5G1XLaO>rk)&m-o5|90Fn)g4e zJ_pV>K%VFBdH%iTJAhY;oh^?r`2T9PUq_-Eul9~F|Ac$|F0_B%_J94*pz=c(A9q^( zxFfUhW~WKZ@9it1dC4~B(;a!s+ghL{U!k8I@>s|%Z?Vl}VsjnRz@UPnPlcwOXebLG z4$HwMJvZqNB-d2nHW>^DG4B!(7b$OrKHogsiqPGqE57sdG0%>19xVDG!{YLdyxSpj zI&6hDg{y|`M9xU(l_57P%iE(B(<~=}0PJS2N3Hih+LUizU&jS?*Q0=jiU)sxGCuxB zBIYgOLrV>jO{=tz%6FwzV8VF3t3%2ktTcT3Bshh)Q8%MuT=8TjaT zj27aXJjEm<#5)FHV$4Co)VpTt{z7%IG0SL{w5PDx(w$a4;{iF5UDH=7NbAQ-8vgD` zRS~l9W9eiL5zaaZ;rja(Ceov70{o*x5@{x5(OxMO)lOws-R22aoc&n>d#fcjiI(h@ znb%t@3uCbvp5lmU70bw+T;Ja8cydQ(GSuHUAU~K$nq7d0aV6hkI=x|ADoT~ZB!Nq$ zXnXx&BBFSuau`0u`u2=1it=53IeEp(hr*<9O+hhPDL{$p{|+{4QKswfdHh2^Pq)fO zsS`g#JqSd>+XE8Dnm1CHAw#AjVI_Ll4HJ zQ6;^49dWyb)Enkp)xvLFM)pWt2!;sDbI>KIU+Pr0y%DVVJU0A#7EXG9OBfB62ky&h ziA!W_GqVa&^~c<^@cC9@uW~k=ddb5FByN2&QJW^rypbK6;-pVnDyBu90{Bws0|gW{ zq}eJ~Y(8ZGL%t_=ZTtDyY|+mCx1_l3@NG@h3=!*_=|`$C-T*$Nt+HbPC6cVYoGX?1 zEv!$jLB@Df3bw*3xx3jKmae_GVws@)@~)J~L$fi{<^QE)BZaFYCxfR`_m1`U-Dduw zG;J3r?VV7&Y)ZSfif;I51e{TXcQf0=+I}}QBwpXOOCtX^-Q&1TYnnbqnqA9b@axw3 zik~e;!`?kTx^X(0ML^;*78^|_BD`rOyqZ(J&`T^|U2|{i!XLG>Z&3y4dhZKfjnUUnA!KomU8t&ekbpn+nFqc0GQfcc+Q2If!(o zr(KSE7gs=%^ApSZ30V&ehF?MNnHhdROJMRf$tX*q1UqP_dUc$6`^9|5o=|%pDq9l6 zrFTc^gM-}}=Zbv#eUL`d>e07AWhp4<6z&T$5LeF#VBmg|+Hxk^Idq*6 zX%I>FmMC1QbV<8ngHBplMjD+rUnRIn(o6FcO!!Oeo67JpWCu*e2XP=5sGFjf&4nC+ z(vu&qGLSb~80D01uj6`2HVlX9-?t`06iPw&D(Kb^q{}Oq4f!!z*$B4I*a$G_6Bt3o zW?cAE^3Tnsj=Ih?%tdrXlK=Ve4?xx%`+W}jLJ{q6WJWlRhMCrw~DZ$<>}T5e>m>f zsYqozP$-ejYm@8cf;)v}BXEB|`%rQnUD7YpeTkIoUCM!anR*`f`1{(Q@{Vo&zU~vdSwItoy!)C2`q7v)Elq>p;yY;x2Hnm6!;o7-b>s5_6Ft z^=QLaa30hN)esiog*i_$w6TgDhHp!9ZM2aTU2S)D3>3n|A_Y8=-FXeVp||19?X8GZ zuJ1YfR+<-+*X;tm?F0*X_^wxOmI6TXaTN8F0l4MH)1y`{_`5a^Sx{ z{GST(6LNGsx^OLW7zOMT!;aZPSd*z(M^M89!KLg4X-TtJGcEoLY7KVQ!U9lnFOYV> zfdv20$mg<_vFX|tCS`~|a)me7^s5FFl-Y&G3BI1i4c3(XT2$E0VoaVDDxE-dE3pFiJ(E3$aL_Zsl!f!4aug$>VV+ zqq{7SA{54?0nZU(O=FSuEkm@kkV2D++XORQ9t+h;<73ax{ONMQ`y-lwnjE)&GL&ix zU9eQxe?6CW4S@xRQJS)Pwp{GLg%VQ3`6J&7pvppQD)rk3^ z%+2a`Gd;vl((}!pOy0}6=J_Co^P7JsTKIbhZaLRXmfD6bds`9Oau*06h0gGUV+11q~KY+aCh^kLtZ(S*}r7tVBV9yI)JTYZw^G3975{hx$ zu~8q6|A0%#)23^cg&j?lqak4>GgT1VexEkD<8jo%gS1vt>5usAG_T$J+6(L2me~$) z)FPOPhU3q&iimh!&e)jVLDOMKY_-(b4>7I&gXyy^?%Qn(3^$=x{zxVa5XM4Bp{p9AS(V6o+j(_a?Z};XV*C^7p zX?y6|rOvMRou(p4FDYeRYlnHqdOv&^w2Ic5z_YH>3Z~Ht4l0An5*hA4PcHIUo*v67sr%@_{ zYa!)8FTx~`Ymp@Mt*mmpoJ@o5_7He;`5A&jpx`Gt0_S<4) zmWS~>$_To8+t`m3t_&!4Ch;ujQ6;+QiC)UncEoUsu3=bMB9U`3$l?#4=ep)uIp$Od zbw?`IKc1=Ej}6fcm&FtUV+T;tK{gw|J5g6y$gBh|LW8~VJd-VMnqHNa`8(XxA!K+; zRRLXDz-*tWA+kCmU7lVThpE}}4Xq^aX+rm;nGT!ixju06?tk}?{`-*4n+8tatt77| zbfRE{19VV)?+`^gQ!#&`YgxPgbeLx;GNsCCKE9)Me7cGbOG{umG00CB zwARF6ZU1v=<~b{!<@Q2k^#ekO1<0b3NBQ{pLH!l|Yi<$GUnB}NXV!r|gFF9Nhkttm z6qwFpn4ja@?&Ss$i(t(XcFVzpCMzHE5R?%0_4;QCpue^CrcA?)WUp4>(jkPk&nq+A zf_+Z|KdMiu;R=Ezcn}Z|_04wH6y20oS40-LoNfctIZGv2)2es)-TP^7D*&8KwzLT; zz*CG!6G7=xdD0JJ3g@z@g8#GC%b9P59@qLHh!?#yjcvc>0Mr2}Fr(gif`e z>g+vjZTJ%~k7{*Yzo6!_Jcg;aO%wUW&p~UYJ6JjP()wDirTyopyP%tLjl+lLm4jTZ zTkG=BD*WnQOWAdWp2Ko{t<9M?-FKHIA>LnuMf-#L%PG?BV7g81o!97fWUSYjy_<}h zs|r^GymXbCCGgP4YILEVcQ*^CdUmer;_TiqXfr|9YHg_N@UrQ@lH31Zhvi=fA^T$OhA-RQDJ<&Hx6*bpuI>5w)d7@F>IZvm*1oA?oGwnQ@ZcmrC|`gOf-cfk zABt%k1T0xX&0?d1BPgklfm{4nYl`DDjjJyRC5|QjW}$N2VcB`d``)dFWd7$ps7#> z>Xx`;hTz79KSxRSV(KOtyN!R}8)?sPryG?Qs)dL=Ydv|N9t+S%d_qz=DpMmGfu{DY z8&@xb`gMn$tx+e>uIi-@n){MnD^YmsXaB_ zXs^{ffEQQ?ZGU0#_b2`Ds%f0ywx8dpqq@dyAgy7DN?S~Oi)+zY7@e%?r0zfmZs9gi zqe2j+1~yuW_7{dG*Hk?G5&JEQxawtUEm7(?V?4P~JMBjMN9cfOI}jtbUAAR)qyaPZ zV;xuKWb;csHN4tmNc1H`cgf=<%Ltck32jJ9KKLS_K@mEfK4ktgI4j6PnGesS1C#9d zt;Ix38ENO{2b3uF3KN<|It||+FEbIIUwo_`$`Y4|X+PFh^0ZO|$M8(Ci~)A4D(<$u zUnZTGuU$Yxg~TqKRF$smk?bnr4qXiNqUALXL_oAKfvwAbzL_drXlx4`2g^8)g}9mb z6C0vG{e~<#2LNjYgjId!L#?)=CQ`Y~hu4g=89dJ&pVZ=X-RL~(eU~3iPsIW4f7URwRp)ci4Di{Ak({dXl)#rOAJSmcDI(mCuJ;p zy`FGS*-BI;OupROzbug>Nw93Aknxb)q22wuk-&B5NT{r}YUZrH8mSMr2y55=@oa>F z??1xS@)9%IS6nREqurBTjQ-fc$%*6QgeB5p7z3?yucUnmtkd=jp6ZqbZMSEzVd(Mr zk$e2~7u{oxb49cd(xi}#6Ziy`<70!RUQXfxKbr>b_AfE2%ay$}BNZQ12E*yTlK7Q> z;wtgD0Td6SN~AdUG~6Pmwf&{yBYF@{q&y5oAT8vrPDL%qm`TLff!aI8UtMvj6+&xp z-Dyqn^z}~`K$Y;9iCew%csFt8B&dejHz0BKjWYXstfTmP>`iH5q*beEi9&mc+kUZGH?w=Ya_I59umgif#4T&D8=)qe`(Xu6h*Gw*i z8rGnmbFMjy50GjxgsF`}ZOSf14dZZhQ#0JOp3)LwIUdbleAv}!0}=Ac=139d94wYg z?%c8J^Dp5wo!EN0FKU-~l-eijDZk^cXVLE>%-JO7xPjI)O2`q8tl+>sZG0D}3BH+d z19_Y_zq;T}=IyXR&3u}Q!_cF`bkpgmI~4J1$!R!dnQ7XMu?HVsU05sgeR^qLH9Cy! zEMJhCIBiZfcN8!F*DB|Kj28d?txD7J-(qStkngqc{WQb3m+^dh3bKM}w%8&SInY&bT|oT)Ol&DJ;Ew8N=C=lf+ZG`Z z@v>J!EA&+KI|<`hbP0+IUX@>ilhxc#OY^~OepJKnQ3^Ka&mj9Ni_+c5S-dpO{J=#P z{X%zwR8)Q{`HxicUO8v0g295>G}8c1E1}cPKyO=G;|{RoCo%OmnFQ^?KH-nLYN!9w zL-;=ba}0a4pR-a>>BghK(?6|^Cg-s}`}&~jvM@obO+HtMRE7<^`Lw%p*2lQQ)^T#D zN~`M%{$0$Z-TGp3Ya$cguNzs-*&uExf5B-)fw)QmD-PO zOdpD=b=dW!>>(0VDz+58#J4_)0mTZSyUKg6uxaTwSkpnBt6AvfLxt^iywL*!<7G46 z7J-qzkH39QTrtukw%I=?a+nKOP$_p7ypStYYBu+rGcM}amUK|p|B32{+sz>I>Yu=g z`fN_CHHqYWmr(s6R*Xa7GmpwIzUS-Kt?`1x}dl zKOg$icAFja$klr;Cm}`>|1CTD4;B3FP|{M27T5#^dwR9qGkYKs_ErG~H^<2dkN1xN zpBk@M?w7fYmopG;f-wa9|jQ_$lgbcQaC(O$FJK;S~Sgn z6$lwhsDI^%XoK3>oyBJ2s(73~4swu7)dqc|p=-VNSTIps!mg~xnq6V|s z-y1DcMY;`AUndypdG4ho%e!}4j9C(#j4sr&eA-g}S!&;% zWYJ!4n>9>kohEoaZR1NoaXs#n60mMmwyn<+p?ZnQdQB>2)1ax>r353IXVwDhYDp5n z@>Uk;GI{&hq`C`$rqol-&>tkIRZjyU+>&#%{tQ&jzfkik-1Jj*zjQ(nv%_4Imv7p& zh0Me}B^ivX$1g5hwY_(bCQn8$prs{EWaQ3X`A?g6>r;~Ir>q9{d}acCRxw=;E>Qn? zA6q@Uy^pWNXlfYjlom^WJ{4WZHPyo3#$+qAd-qNJvB%r@umWGmOE`uKNhalacG;d@ zo^R^(sale7S$nC4RL2L6CnD5KPC03vb#Nt8nhb3_6DMY?Q|v*B)QTq4ab4he(&Wb$ zzO7A7adKcO7I=l!r?QxLOk_~Gto^FG;@NVq$#|UqpbF=6S~a&rFTOcd6Zi6CedOWr zNBrdLl*H}*{3ev)D6jveIqs6HsseWbZdu52fv?cZ8N{xb=L(d(9Y(*Y{w_q*EdJbc`ZRI4>{?oTyBfUzPNZ+Z z>$tJJs=!I06&{scs_xqW@31)N4VgKq%trD!2hzg{+JBTV`)F=(mX*vjh)cbH2hpl& zvgyu1w(b@DeCZ>|dCAxTRp!q}q}A@=+1&G|49IG9#LxCYJe6fiRx32+a1j*oP2Ia``F+&;{~>Y0Tc2E+TzAmt~)D!d*?D)>TPl3tG^~PsC)E%8LK>pw`(Ti zk1-%-NuPunZANE`Egl|dPB_j-9#6HUR1DsD`6@3>KbsXBKgU=PPPHhUA?4CdK(kAA zD;u8o_82bIZ@uCYR)*y?IAqFsZOK;-j87+3mJQ@KQ=V`y_|W2!`=p*Jj!Y0oUTu{j zb$8d!yq5oO4;q2kc*f9jz}_ClkELWgL1GVA=E)%>P`=wiD!QZ|w}wH3b@xAN5)+QG z(-eoH3OPa7ieJfj)GzXx#MBkbsW$-SL0NWrUrEBAr4&L#h;9GZmq>_+)#*m2r<2t- z&|ZhFrAv`RlM_*axY2st2AMgAQ}K9TdkHRy?ilmXQtRQ~85%VJs2ygh$RnWk&<|h`bdJGsmb5GhGj7}RR}Jhcmh2rvlJ<6 zAzI$2!z(0Gz+G~ROzWg>w*Vo=8jfhTOW5xh^b!JHG4=8M)PL)WnQxcDH|vS>w6ERw z6s(8GkW61^&~;-LpxKN7sy6tWg2c-unpX?w^u{JYR)>s?(pF3q8n{kOc|qCBR`Z*0 zENS!?g2QjRv_PMZ4)g0(^#WkAeesh&q7}^S0ZEzTEVFuvTJ@>6D1WE0dszR)HnFuF zSv)#S2K{;L80gkaYFT@pH9E6lW4^l@pMx#i^Bc~Sa_JG;w2%|cMN}^=R9$ZtDbbuv z=7Vgvqw;bg1!^V4HUaK}1c(~7?ee|nZ?mM5rN(zi`3)yB%o(;vFCr_{*qj*LwCNxa zQnB&6UwuTaj~o`ec(=(;T`%+Wl${PW$|gu$gpLgg7hG6$%05PVIrM#!Wv=h|`-}Mx z?f2vxOvV5hQ+fv$Fx{$gm53VA2c0rTWwZ~{MGE^xE{Yp#*bF2d684D;<5zVvs9P$Q zC&Jr|=z!&BoXA*uid6x{do5v4p^)=0xtR?=czH2E=kGRRkCh_dYPT;*69vnsI7|T# z)+t}>oz(lOs9eyd8=J35=%bh4g1$vG9%xN*6WvQ=2r~)%%=j~wWl@br5g(z_bU7xS zivd*mN(~45hj?EWbDRI@DyCFNz2H9EM%)vgTh@>R8hI-ejjob1_$on*ryJk2o$kP# zdew*}jvPL`VB7tORyD`UDgf5s#x)}lFyR9$`lZj;(fR)RqxGoJ{D1pWe9@7&>u_9i zcX8kX1j=ta3f1&CS-y%Y?;nLS(_;gI0R{@kn`k#yOAqn!)_vQRRnnQUxr}mz)ewCh z=sulg56m8k2*n_>w5}9e;52Kb_8MJi>T4o%5Ff4)%j{MTJZ=@91niR|vs;)Nf^*8(Q~kas;G zRkEe9QMRPEQ56??T3TPEDa3^ega{mYKWn-!jY`Yf#aZH?fu%#IXJ2v!Ph5HtLDV!g zgRkoF;N#Bv29+;n@j%S8MCysJx4Z)?1^0S41@1OLOu zb?-f%C+1m54R=8gwaj6MIi0jyL9hZ3 za_oafL|Uh?OQ`2q*FXw4?TRu@{kc&aSL(qeVKDUiSGo`aGv|9SZVMNUb7`SZnXVN| zLC8J*Co(Mi)+q@+Uw4BwE&J*Ng;aNsYj!VkWT_L~GptbiYFGbe#*k&bx8P`?@rw%@50V zda^lruQKy72a_>JO3Dql<{U{f{Fj2wG}G*_$`>=4S=Ab={JoQpo6#3lR>&hVy01!F z)t2~^XBDJHF3T>+hZS7br#r$%HZC(N-$SR~#kgFYRGZcxh5j}`s^_ixdIpY}kIW0C z?44u)gdL;c$?%h##7~4|{99t(+7oVpYVM|_B87~akHJoRvEwHPQj`>fg$cvJA9jCN;^oF9pwklW z_#hqv=(oZ=4UNS$ycIJCM2aLIXYip_9~YWxSR z&>Gf;`}v;?p11@ES;R=wtYYvSd>V@(leluMr-u-0wiC;}PRmCj zBjfs`dsS2w@`vJ=w$LAp;N#ZmyLwIEB(f8}-%F2tD?g0al=Tu-Qkx%$*XFOsP533R z**y>JF*U-ytWk_AsB+-JsLc0;03(%?)2NHPbcLL~A^5e;4VE6s+p_LOK)5a@;S^ z{c-3`p$_l$vJpTPt8P3RkxdwkjUe^i_1g7t8Q?eTx&zQ)OOAJaZakK$##tQy>O4=S zZf7NzrJ`Rqolu7_4c2acm&;ACK0co8pb-^{XG519b%l2U|*CQ~`y0_Il5vJC! z#(sn9DN`yB$zMRn$NQdHOcM!a7~X{ZhuiD#bIKPd{0;B`QfepTQC|YOdQ@PStzzXP8dqAYxeq-guC(yaqX4Zp1`mYjhb>3b=+C?F zYF~>@d>G-O^l-q#`8qz7RvV&QQ~?4$n;q*JT9vZUvmm(`#Z~$pM=AUmZjhT}YE(o; zeL&n-aBWV7ez%-enBss4_DalkMX^Z*a5Qa}5^{HAY268Y_bnnYN-fhJN6`CbVR8*e zC+>|=X9L&v*^TfA$S-nB>qHx~i(PjZ&jL&?v?jJtee&mxu8m`JqEc%$D@Ct(_c_2! zHw5xWUU@NM!7@&m9sZL>sk_W1EiiH!%a3|8_pI3Ak%Kg`}g zzL*&YH}WKQ3Xcq~MR*81o&Za_vA&z$)`RA+#q44vywT1gUT?Rlz)+o&Fh&|2^+t8! znSBkK&Yh!A7*Df`D)HyeRp&KG2B^@m2%n`NlNmd>T#riFgl>F- z<}vXR%F7U&L9uuUnY%*vI9;@mdkEs&@Dk~n#R_;q}DbMRTVJdHa)!3}pV(L)pxpEB>;9Y|_08F&0 z;`%lHdyXv+NGIDvW5zYiO9=7o#NvD?{+z`qqW_w~cJ2U!MCyJL=ZA@-^tuiCm!MZou+8wD z<7W1TgWX9@19jSi_m2ZoRKG#CE2GSHU+OV3cxHP6>38_euAACP*S~*iK8OB1{;MYc zsL=cdj&lD!vwvK1fS2$ssY$>Qc+1B#$=JR+%X6+)*=0v=8w zScpu4G&OEp8GUaolsZhqI~_`i&LuHsx-W>!3WgAC}X>VpPdrC=IpH&*F)dAghGZdMoqujUE$4>P3l!a0ge_(}@V*D76w7@hwts z14WhwF^N~44V^22xYTerNPjreu@y{!JO0x0cps^M}{F@%tk8lYz7H*j8}R+w^O zZ!p4rWxX~e{e{FF-{!3aq0Kw78WZz&Ymb?O4#)CIIHs1)wp&o;^u;Wh;C?=~wYsaY zUV4a?>bA3YVA-}TgRyATrnl(t*zGSlPs)e=arsMAivocyYMNev{5}gEI z{ARgcf0cwDW=Oyd9JIe(KFzIBS(%^u92{-aKgI9bfn@$Z1M5_N1!s0+@!B~HoPmLf zf8j^63q=~8y)!|jk~ur*4+ivs;lmHzB~-}{Zqop0*Zu9RoYxLX(m|)S zlI`@4qUBSOo1tG#uE^eonQqLyMy(k;?n&8~E>g6Ea{69}8d?Fcb8C0aE|J>u!Kc?; zNqZ%ShD}YdzJ@V8^;J4!`~{b0S(sbR4z^X?FEUH?%x`0C5f4PCi2ExW(tm6j(!_4n z6I9K0{0)THZxk7s@iUKt15S}urL8iuTf3O%_Ny@&q*lBQM5AOo=t^JW!QFS9!qJn(WYet91OKoC4QV=?%dTtFS_=rD86lzo-@66nK{j5=d zU(BEtNW_&q->n|0=d~E?7Wnkr3Lsm-xtdNh#(ttDyDdg@A}Y;Crvd(^^&#Mft6phl zr7HwXJLB21q_@`mTUI>NK${y-Qc)D@Hzwi$MzJ`KQ6CN20Gk*0QZ<5~P{F*f&ZF2N(c{YUHZ%0S3m^JShO#oj$ef3 zE7dQqpUeI@*~A8UOoDd`duX)L+Rklk8!pvSGgq{;0%L4nSY6mufd{R>p3-XPW*7R> zM~n86oY$2?)n1>0Z^Nr;S~PS--# z2!Pcg5x)h0TsmzRaxK$<=hhrlaBcTk;OiZyZcpZ5z+WvKS36ja~bm{YiB4sS|d;sM>r&|bW7?Oc2Bb>+jVYo-e zYbF0vV$!(Ogw@eVN~|xiLe6!lgad$STV@F*! z{&3g0ybfu5xjVCCw?*!~smkH)vHAy~rWqy!{l@WFjp?%9M?qZ1inVyhk>l(uE%C*0 z)^hM5lhx;vN(%%Wa(zHLo+%A|^I~a6h^4TVD;%I=m;!KQul#^a?g75G77To>%ZSVs%x3Ns>cD6WP_oXn&ObFBQV9aCZ4rEZDKi;@(RA(qqA^w+I-_`o4mxhGEj4^P0Iaovl)KJt%M3H#~b#^_T;< zp*PXxCZS4lLW>4$Lzvpcco-|$P5&{tNkRK|vf}zpMnTV*8+;~hdXaPZsPKRQ{;_+< z&^ghD&_kTyVkIYe0_DL#F-`oBH{}PazjTJZ`@!GsBsC><#e%WhsO7Qhs68i%#EYq| zHcsgb07dAccwR!-c6)kEq0njpa0zR?e_;YTqkEJGT^bcRit1M2#H|Gs8n+&3vj66R zR<>S>%~Y!m8zvV!3=H52CC{=qZ>e}%MoupH_~9Q!qFBvO(&~CA?o2HkNdl@uqVo{h zP^FErCEv0;pHYKWDF1;>&nbV_X)Sz*O&ORemPHi{MB=&OYit*rri|k6l>gZRO?caD zWWlktf_I&(tf_3U-sB7>S)Du(BZ2F=KIn$J2oJa>8<@jCZr=4c_BolF+~eJfUcOsa zD0$lP#7jYf>aP5Oj9>a?0X zYxP`_l5V`Fu~OZ2OJRLQD!H>3Iz|Jb$o*M+v zaZ<1Lp|up;#uHC#<-#c{Y2Aq*rA`3c662$1ax}Z~8+>IFdH01*A=me)FoBW; z%f<<R||W4(`_c$IUQc>qx#{z3LGgSy;3;8u9~GuG$qU{*AuEb=GP?@w58J{ z#8Rso&&{g24Az5k%u5z5u$gZLs|44s$atv&b#XWf08bj&wW^|*vsx~9kC*Ol~|niW~Mv32W|Q)cWB zyo{Xd6ZNG1W{ksb%~O@H!|l0TRW8V!(td$sWeZ(5NrtSvY^3R|;ax14+~6TFCIWMb zssgmXp23@WlEHJBW`Q-ee&uA&M7DalXyisoS~fB^TqS7sL%FmFgNp9V1HTXDZ-^vB z>Z(>wjCb}dI@CRq&E;H#*coz(3E)ke4SH>C90}!nL2$nJtPt((dEQxi7lWgLN7YXh zJdeYa>F0m|xW7Dd|M3qiO<*cO62N*Lg)@&s8J&$p#&=yhkjXy+-~hzlkLf*-Dc_IM zpS+yR8kKfC${@jQ-ZP;-TQy>$Nq?AeW~_m0h(CqU04?P~lQq$4)D0Bp+!!97+WzDx z1z)I?sCLv;?8Amrcy>z44RdXgo&~bW1Y+epp2JQl)4yPe{Vr3zQ7sd$al`V00cQL`C8Keu?|&<)7N%PpAExH&N9 z!zdOAkO_X){vnr3Kn!xMU51pscmg1&KQ*YEt#r>?(qTH}^WA?Q6ICf!$muevzit{V zhouFcu7oDHyhd~WTVLckiSFV@b1VBA-02jivRSv*N00?q2`N?eYQ7-tZ2QWIA-0}e!phENv z@<4j$81Tj?vfJumY7rqpFd#dqa~=S(zkMk9yGCRjruCb-Y^vNWI4N@=ys^gD;;^3= zcO}DU+4AHCFpx<0r93t{IwTi~&XG_Li`)y;;1sj)3+bGyVG5tA0%($n;V?A7vzP|5 zx=8fVyfeph)ww|UG<18sxcTOa=6E9$TA&+BEH(zP7KlUjHh-Bf+Il+%?v#rECN+tg zcC|JH!rly1Y+iZ*IOZMTb&qg%Ki)PM+-*<+EdW=d5fG!${f;DM9{?9XdEF~5Dgz(T zn;-MD`5rd!wH`+2b#j;h$XaJ7-!9-wC@wv1Y&*eQ3V=N((fG4?%TosCvzBvU`M2!O zt(JupR>S<4M~cD?Vm9A6QeKX$bLv$5?ht=q^SMC3Fr`Sl47S1Xek)r>IY56_x5A;v z@6GGP%Lp5e0(={25yG|aRD5EDAIUS-*Yr+6HKmtByHfooJ7g897G;9pt}Hfg20i*B zu2HDufi99qSZUEp6=C{pW(X-4x#JWf?63=`N^6U>>z)zR92NZJS=A`iXFG!X}!Kcp+a1&g~FWHf09-YYch5vO&R36Ykl%LumksGcn9 zay)`@fur?P!%Z0|aZpI&KreSa(|%sd7%FcsLU_}6o^fjTvpU%Ixgub*B(|;1AStOA z1n{+o`Y*dJ&j75>n`41iLWOM#ETwiw?6KpSPZE`mgI9raNpba|zQO_N;7hs&sciGn zQ-P)V) zvu`gNm#w1e?B990)gg@lqz_=C@~(6^?M!!^pX}0Diz`At$hB$9k}{wxm39PH z%qZtT);nPu;=tc|*Mu&%9g%2X=z6U17L3~(fTf330mW{63V`kVm6{Sg@hYbl=r~J( zQkH9~A0i&~7;B}n*|_%Er#W=|X_&+dk>g2`rwRSG-M#)jynmI8GPjmECa^kq%>7Lo z8J(r@H#ET=-&?8d`Y0rl*V#U1cB3Vj|Nk;o%ccXKr?>z*c}(bAi9Ma8kZ%D{jA)#L zxEjuOBeN1sr|oTIPFgu!!mPMCF@My+L%OTViE;lfF zTo)%lFhE`Vv%IERidY0|H#XlN;BzT0v^Ki;rc^6`loPwtku8pmxk}i^AXt~k-SAfW zaqqo+%;6S?`Vx=LMO4W&JwtYRRH65zT2ib4ie_y4-jY8Z28}Qys*AdL$%(`wLq(&k zy+__>wUoZy!F$OSZ)Z5a%|8!dRE&LK!c98f0IaycMq8DH&ayBrdB@D-hJJTrD=A8H zzh&^M(=@0#zqx5;(I2;JzR|G+qhUD`988g_&!Lp4v9%v2Z2a@{onyddFD=~IVh#X= zj%OVQB`*@2VAyn90QjXW$#$Tzj%&vepxkyO)s|iXnJaKsl^o;Wm2}3$UnAi3qP|CJ zx$?FpW`#$6>!ftwNZ+sg!lus7B|7${9f#s8hC@V}Re z#9x5b&{Dxo6Vi9W?~Uh@ulQYFNnB4t!@U+J(XQYDe?8@oF%Xxc_Air?!hCGz;H5Ef zPm&#fwsU1c(7xffFEn(xO19fVC@55S>3iTITb!CRphJJ{SU?y*kR^Qjkz@&x>J29> zJP*9;VWoS=j?}dNSz@3@Nh;uyIHZU%EE?NZAR3$by_M3d?U_iH6kQ4iJwb4Gq=i9S z{CI27GicoyBSs6SooaC7d7%hDCL2Fq-iAMf2LUb$m8%tvaLnb|kA{AjNICzZP=251 zkPx7OA(or$#MK+@E!#1DlJ9<2tGInKR2u2FGQMy=E@9rr2Q%BKE;)Y=905RL0A5>v z7(nfF1t)#`9p?USt@US-+ARg`7Tsk%k|pypXEGi*LV%FLxqTjwK<5ke76qgv>K?K@VZ zCm)Dze^ZgKe1IL+j4~}Os)7SRK!D83Qw0pFw3a&~$_G&ZzqhQg_*@(mkExZNyq}X~ z^V;UUPMM)(!yPtR-J&1vsQmHr^(Ol+4wHs)e4wEWXledytB`%`K99Y2y|UZ-3`jS| z?=&bYf4W2uoj#JUHS^j_lk@!jY5M%1b$F_eZf%hi@JL)-U4rO>#a!A+S3LFY>9&_z zb<-qqLg1HnY7+CUTmv{w6(shj#<`qgTxb=J?RNS-?T!B*SP^2BcVC40zRtR{A^zD=pGEGWR+dHuhS4xuh@*{V) z$OD5+N2d0$+5|)~So+`VUA9|v1Q&ZLW)@Q(A2qW8E>iIfGJXd}Q2ZmQG+^FM>6oOh zw_Vye&@bQ6WZUh28cSg{60T5wz9n9}Q>C+P`Jhk7^73@wWxpfd7#XkYP__vcNqG6J zL3{7&1Y9aj?Z(LPyStea04Pb}MLfy|I6W>yq8L(#fX0M2c7M7P5K>7Gf^WoV&2ZQs zpGjR{b2SXPOtVUd$U=1TCWz%zg!mgA_AeWz8y+599u9sf5eyhpOZ+C){d^}J5NzSd zRR5a@N7vVkLFv1MSuuS<33y~;y?8e7CGj5(FNxadvE3J-bZk~Dndy%EMQL^`KR1QC zS`-}!PyRPe&;RyjPU2y1d|E>8Na4XFv2i^KT$zRT)E0Bn+IaEzWkfDVw0ejK1BGib zU7V=B@qaxk2~32INowF&31J$uSS)D>pN+|~dExEk2M-Y@OMB({Mh=O)s2}WG+8pnh zZj^8XUwvs#0|nw|aI(7)U>ic4aZVvpJ>8@HKQ_%4F9MP$EborIG^^2}IE`Ar(!pP_ce zgIjxAYALeX(?zZ41*j5E*JPISvNaD}O$@F|6M=EqBVw*tneL^EKRfQZ=O^0L-=Zol zgK4Il=Afk(h|@S$&fB$$Mk|-YHSbzBnceJlyv~>YX(_MEG34>-R;|V`@!++odUR$t zr;A`*0r1lDo(JR7=r5^x3cEX1w>=U31%Unp3zfugCRbj$3D2V^7Vz{_PtxBdxR30% z6JD6Q%smQ3emC+?nSzR(KNDPu5?^Wp9=?UMflsZL=ME)VKq?vO4gi(yS<@lS2B6!= zKpqok+>j;q2{2M~`CZGeJSlwgxZ*bT$g&K$DuQQf&%1Ogjqe*_+5tX{Y5+oId|!~o z7>n-T$enRw;HD^I^Gn(N$L8(Nv!j&tPZ^WQj|U_8l=!YM_GA_tY3ZfXm(8GQgl*za z*jDZ!K0u45(NhdzEb$m%zf^&3txXp1_lo6w{cjsA@JcjMxfzY;$dZ+eJXq%|`bl_(? zl8)2Id8(sFC@1k8RAYp_TuVp&r?=HC?RMuIw^R$&`vJ+ox8A5;W@8@9vFS)$iRU32 ztaRAy+MxLn@1f&TCo;x(Z#4V z@vzp^uVoV7TL;C9)%jSqD-EUdy8IRP$K)&xG$_x^<(5j#IUVo~j}}L@G|P+_a77h7 z@|s=wP8oY!;>J~d_B|$Zaa~qF#OI}$wiZ9_QPSIP&)J`R7jpL z)JLW`T^!P}$A932MYvKUKCCL)C}utjk~5IALVdy2yBgK+Z41K7b=}#Fz{{*@B|8q} zHXO~=>LF!)-`L$(Ce;+FL8E@z{x#Pfb|8bBv#}lobGQ0SMV)UYM#A#Da`ff6QGH6) zt65j{zFEnXPw>qs35Q;k?{L}9K-F#}xV#f5ab`A zvoo(Qj91@ze<8;9ivO@gVRc9xw=y$Q;8k3}>|rN`EiC?^;T>*dRu{#=m$ehq7ks9chHQx>w5Dg_m@U<1&XM z(_t*~E{JTf7zftNuc``LA8k+};F!*gFS6p+OKzo>9rBzWp`P2roB5ta2W3kvkpciA zD4(O|Ffa`sU`%fDmRP|tMD+E2cMBuvkgRh?dbdcwxW<#uqW=e6O3eR9TuNW(n{Gcv z#O~(>on-C(o!BblDS8jfc9r9n$#|=dcTLW1ypHI^D(fw(opLVl6VSC+U{TOc!yK+P zbO8LMmY<%mqJ*BT(V)mmmfMRTiM|lhg zpOAt+{hn?!@)ZWkd^BgS~B1^aB~Wn zgV@~SpV&#r8@W|9cOYrK+S<6f z&LqJKEMo(H;>HCn;i@u6wrD}Det7E-p2Ovht`lh*NZ7x>HZi$-J!v}Z7w5B^{> zTc$h$rV3>mH%=t`_CyLC4z3~6BaP?lLbW1GTX@peXbm7P5}hadBqQO`*3zie29v~t zcYFl*I#^-20hBl`irWZ)BU8Gu@;s6_iP~Ys--+=9uvf!;KL${QuKZaCGOmx5^gOrm z(OuFds(IP9lIO}oSG0yo5D~+D%ZKWy-pI%y=@qu3NuHRspSjvcv@{fc@;>(|JPu;H zUjUBl;%4{@T4fnHuy*DfR|zwl^z?SWqIvi?O%voF$_6iz}tWV}X zL7Q52a-SzgIRhl*`>&=Imf52QXtVxBLFQw~i46u~)Z{2`vCGRlYD5&=rs0j32Y5*W z&IP~&tM67~?s!G@has{MLHx{lx|z9DB^kbWLU}bm&3IUGe>PR(%1U&3yfQ zc^nCD3kBiZyG9hK6hZ18gyK|ZWAVfkS3LDr<}lQU<=QSl0RK!i!-_qC-KJgu5D$K% z)x6W+zL~kb3Z*XFbY#)`(z&yZaqIEa*;c$;`9GzDRYAaJ5X?Xz_x(i+5HPz0yI(@O z0xAT439~9gfC=r-kRa0p1kg`)kV1@C;+ba?(OuyAkAU11&GwWnF$$3(`Q>eh-?M~A z)$XE<;(!j3zSwet(*=N0Y8!BPegzgW!QZc+PGNg!oi4AFz(u^y)1;ohG7gz@TZdHi ztDi$0dYG~epU4!d6;hV#DhJdplF_+Pik|8}_ly#oIbBlV}4_{j*D zkewdw>lRj|=p@6bg!b16vTn_grBHE}Ac$$^--Mt&YXiUKV!lo{QM!aJ`!vs;UEqj`CB}GI1z&DW1UV1M3!{m) zfcZHi77m%+ms_^D8v@X-p>L)HabE})7Fd^jli6*&>l+pDSrqSqYFI$Q=ePKDcm(dd zk4ElGJcxdh&P?}VBjnLL{L43Q3hv^+^^KYrKhKJ{UGQ+7-*#O4(epSU0dKsnm={3C zFRZUz_&B-_%)7KaXf7?Pnl7N63MMT6U2A5?r(_`^{{-M^PD?107#Dxbs&GeJ+~PGG z#%%|F@bkO*Kb$k=(5ZSYzbpW(yCr^Y4l@a6DJF~hZ$S$UI<#YY-yO+G?D2r(_WB{kD`UI&KsXsb zkiuv(p=5}+37Zr|h4sX;X*_h$ywPO1T0UKdmIFa`QiK{h4p&SE$-AB`A6#6*Yth|BS}?Yat+TJE>s9K7;1lNiX*NB=+s1ze{v}uon{J zM}r@YWrL0Dr*H<(KHC6xK=@0c+2F#c0`QeM=R5ja5`G38(I9pp?aYL#^{xRf6bGN@4eK z`~DA-%J|n~byvrt(PJQwV=KYsaBjBe#9rvFiRu(#k7<^!%p+rMBXcACKFSt0szefU+}yp1yeC z_8n7YcCi=PjMj&|rW;EcWu~|Utb#m!PS|tv#o;%EgBRzEZ>V32(f%C=)wz!Y0#I?6 z=Wycm4gEB7G+E?VU-?iy5U#XU|Hgwl`9C};pd?WI$%Eoypr&F(7)I_5*7iR{1T~NM zE$?kc?dK*e;_1j?dF&!O^MGr)^#MpEMmo9bw~%hc$)mp&Y+j^cqC4vORutF#zbEht zPq4OdVHYLTfwigTPmRcvzG%Kmw&8Rfo*Vqc$=9+rbiGIJ4x%j=He|sfx8R2o6_R1RF=c(e)Ddf#$r^HIOLNLYxqh%ej1#?S^G;B;Z zB*Mx%#d)aE0yWb>g^YJEI=0#wrPniEatl>>{QGORSYt)vFgP`TDN+QFHq1|dt}UFM z6B+dREl?#d4DCDUFk)3Xu3J{GZn>}YXURK6&zu}?ugyiuAL7^gg#M?fxnVB`zB3(P z`H{)q|5^6>ZLXj4g0pwtdB&^SR|ylYg?mmViCOB+Hx%$>hdX7csnXp<=48>R?pdiA zw8k8@8-^0G*r=Gw_|9I~yvzvUDUxl4u&2hM3WX7NGo2=U*jBu#2rs}hfb8LJ0t1$+Ye>D&0=m`SViQ$VDw~Y`@b=5SqvV!e z`MM8ZPG5*=nnG!3dVMaT{iwU}V4AwTV1TK}KF1Q%HTv%7THh1+8Dt~Ipn%cc2hCSE ztUvya+yh>I2E4!ZSHU;pNpK!ij4W`I-}L<7Zo&VF4HcAd=YS}T!1l9k??ot935n3P z@Q|s94L_wDmUsXmJ~!<u(Sb_SXORh=c_)G1^bbrM$u2w%P$5t~EXP*TW&Fg{E7p8F1{>FPgz_1eS19FL zKVy1lmfPxF5!79Ebs&ar;F({>Rm9P(vRwXamZEee3P$>df>UrE@VPa&eGQOD&l6@+ zdg+LqUR&~#7^=SgmJj)bSXxgn+jJ&oEG9~K6h zA)4wJzdn81hClYMM>9a)EJBumPLIe=uS~{RL@yfQv^TtK`4<3@_%8raZKR9d(D4Tf zQZjaMh93uM<0oRfJvPl|KD<~A4SKB`n(k1`w|Bx<`_3f{$N34mo%m%lLvwbfc`l+> z6+EQO;xxNJ`Mjp$r6!^b6#61a1v*!dwwdO}pk!nYywuEd(?;h~XNLqa1R`7(Kp+B= zWN#`W76atDrHQ^@CzIC{vpvg0KlcAv)TkwoCw-<~YWgV};ygqy=Q0-4O{Z@*xFH{~ z%kn+cqnXNabTFnn@kQE?QCBqC1n!+>TUf1Kot(=L8;#O9xHx&NQT)1T{t*q;MP_05 z;(YarBBvtPfBEKLq)9V`hS}RW!8R2RQWbT08@Z-sb@GQ>G8#fS8?w~Qw-lk!%h#H; zcgYIl8pzDRa#Y!TQ@N2{j3Y#em8|Cvl{*Qm+A{MOZL0ov643k*h6JQQs_^X}NkFwi z4v(c-tpbppvocXi6>ObK@ZD<+tL+qg!#QcEaU_DxnPpjawaJhyeBBX2MbTR_IimK( z2vHuQ)!ZBLR^N904|uplkj5<`w_}AjU6NA(iZ<*u&~TPiDnGz*v5h|0CjKJ(neSjE zZ>IFt>qWw>Ax@#y-a>mz3zSv@TUPT$43Yxp_oB;<* zr%mRY1H_{-8uib_2P-IoLeL97X17>Qb`xxBzyI4cO^tz^npwYF9p3m1^9*I`BSDy} zd$G>Wzwk;NXJ#upy>tLJb9w-2?4%gr$-=H3dqa>~tVZfn#a1FyW7H@Dp2TR>^r z5U8v2{ew|yQ!KH6&_5zxTI$qQyd2fCURDNN*xg#*SUz{aL&+8li*6NTVr!52GA$#i zoLXVCqiY(&6)Livo7dQlsEtDxN#$TDd=&i{$wk_>+thdkymR@ zHk_VAC_1h~IX^*anFkG%JM*R1FQ&d~4O*7JQl)cF(8wXOAcgGdOUB?U(1u~6YmaC`Q6|#6jO4xAJVhqjc9J4CPT7}J0zPGw z&Hy()=OV_X0kLnyNIm%wT=fG!#!hf&`%_&5cQ(<+#Gj5culjFywrX=SVCAUgt8%P3 zuSO1j=#H@#oEfz+?>0rhzWq^WE#ix6p%fHBW)stsY_4gq_Uw*qTdqo05|WU`9%=cl zS+y(KlDJV2CKK&3U#X}cD`d1Z+N^@%^Q%Lm z4nul*AsLdZnI=8S@x6EMPr?lC=QO+J(i(nI1958U3FQiRW}_{ba%^CS2=O!m(aOLU%`$ba;5UPF>L*jjzQC0!T_siQHcO2{B5Iag)d$ZM`!i@8g}P zP}1ZmU%FSFa6K^8edDDD_hxs3bg;l~@mE(ZqhJBI8?AK)3yrF#<`ZcIF}*hq!8+bGXbWjklO6_G_PbxgXWHb|Rb46=%&_E~+Ce;HLJdhuwM%*wGM|PG%8j zkExTc?$zh0DDIN4$C{Si732M=0W)^no6+4avvl#BM~Txqswe$-pnCOMJr#qKs8{7H zU#O?`&kc!r93_j64p0;lH0SLc2acbJSC=Pu@*%YP?p~|)quxJgub7%WV~Z`}6py)U zQj1pPfAIX}bS2arC0bCDVcTkG&-i&);LyiBxvF28-7Ua)u| zEcnzzT=iTEa|<4f$G;93$Nc^Ucm@+=Mw!->v}8|M-3(K5%O{s5SBl1*t&iK&ScV(r zPjAKYT*;!ca9-76BEIv08Q&m1^evr%tPwm)jg8shksr!>RVQDY0h=tceYz}Lz9~mB zM=TfR+&FpBGe_U_YcHc+@O6ime6=P|jkxf#q%B6ydV>z4_^)NyZNb-Or)6%&+_&$) zcp9d)toHT#m2DBX4rU?PTP;R7W4uUgMyd2ja~5YA-NiGSCWh!>nlcT3@sTQASp4b1 z7n|maGA@?)!JigofXXoFr6p0DqOiOhCqaAfV(>}49GDq+PjFv#h+ZplZJP`tOZ{L@ zOruu1AHDj34PX#W14{NDkM-!fGjOs;k0%U;QBC0W); z?V0EEV$n0SDd2Ok=gNg1tOnn(P(MLnRT0julR$10mF04vtmLljCD5!J+a}|_y6TMM zt%lNv!p#rnm6A|1X`;5b<$2z)E=)^objr}KqI7Ok#2=A_CUIFgWv86D!N+Iw9`_k& z`!QbUJTv^Skde#n1tZxlO`Ug=g$2axju0^-e0p=BC;!r;yH)$%qhNYaS$n#&?8T`4 zsX1L>bFNQ^@+JMVd%THq>k&X3rsLPGJcC{h!Q53g1@qXz9jrq2yi^z$YVK5INi(EN@ zH#JscPj>ZQMYQLYTdWS^vJ_T0Nmf8hqaQ3_VFpr*h}xzE;?R-wEG|`bAw|S@2ulk(VV|yI znQPLVEta$Bi&n+QukKtW*cPtRla(?dos2l;lZOT?MJxQhIB!d}t2>`&h2Wy=bk`h2 z+EE`zg^n`MR;1%MN7ob!yXcQJ84QByw)D-;zANQRIK49HJ%Eo5`{FD_<@kjmokK6@ zcYo}hi3K@O=>(Ng28lM|&_#z*at-utA<>|6RqvI{GLxln200FVC}i*};EOspKIoO7 zWIe0Ak7A4M>U^v#SM}qC1`WT^D5GY#+dR1j-zg89$spqkk9R!l#l}0)ZkTZdeW?<5>TI=11C3b^LuNyoS_eK9@=f3#x74X1bYu<+!h zH^|_oOXMfAoAHnSzy`V*56g-4oQg;SiT;3=IDRSAM5#?D#q(p65h!+4 zFGl@qa#idnDuo9tH-(MSh7?0wPwta1q^E^D?sUi5p?i^ort!(m=yYSwa{hJUh(m=@ zZ?-Lgb$gStZVxj*xx>X#rKkYn67}7Q$tpT4t*-Z?M=)x7KY<)>RHYnWckXIcqg%<< zZEo|SPF2o0GF%bkkz6vjNd@L|)7W9&#S<3o5uC%NrbpGChK;(0%k0NfgX_i)Q4wE& z<6rW)QTbC8HFUSzWo2Tib>esjnpUSbZAWdtPiV0lP|hM|t)*8;lJvD;gL>2V)o`4O z8)30!uMiWEfTQkh_={axA&cBD=9F%GGd^%!7OM}r*>dT=)~S7P{OXyj*{9u5{jMM} z$@tUtF&pghy*ItqqOayAn{w0)=SsO>tn};nueX_~>i-bFNtA5^UoAakbX4pAA?nAP zjKwt4D7Gpdw?E7_hys19v*G{YV+p@ib8CztIZ`(jYG4O_U1k-wTH6AXdd>fFLix> zT5wd-=&ooEMh4%%CrG5+H74YeMw5{|Q!MJ2SeFt?rHiAj*P92!5Ltysr5*AF$QEWD z1%3KWXYL1kG>kbVsh*djY_8w6;M8g=X2I!YFd?XY0h5IN8~TLezoSo1`*c~1vO!r2 zpXWA+!5(eYmj5Y_kNPc-NBD_q`aFC!Fj+dMKAn8!*7OeIEp0`yfNpe<>yD(xM!W2& zdZAUm7TT)zd&G5mtovUZ-V3V?=x;_juBD06C4B;0t!mZ&efdP4P7t;A8gGRWk7!v( zbiuK!=MSSUG$k9&htCH(ybfmlF({p)p7kdfbqxbH{Z#BM3`vL!#u>LazMha}r zp?lVo`^fx_?VHb9(}7Uy7iydSkxg`3n@ht6zOTfEZ+16?DrmS-9)hu{MMgSEpj!uF z=1V1l|G!w14`G_&zpy5|OfL5h&s|_rJYs6zh%gD!+lerN>k-eVC{a`&nW?}{FF!Vw z9Z;HMUY$$7H!#y4szL)Y!Ye4Qnqeg+{(>(Wwd9D1G54Y-$7`0fyu4WWTKS|Us5|()CsFlo~Ny&&< zEQYs3-n==d`gqjbQPKg`_s-SBKvo1@sYwZ)L7ElkAT5TwP~0yq?N=U_LR`=8B!x+B z_?dkS@#fr#!onW$?~mh41od)_O?*+ktqgG9dkPE^HeyT7ceidGGOG5~1lo@rm%L1- z!j&n#u$g^7wdd9?gYY2%&FbM>VI4#e9O?%>!sG9#Br|%;Xavz(11fWvoPYw0yg&9%y zO+2w0$%k*n&6ih0gAg|)MbEjgPA#>Iw6uT1YQXGIQeMJNbF>d_w%n#V*QqG%(5yC68vy zbD2IVYRF-PpvlrI?FwBw`ZWjoU5O$`=k=M9jhRPF{He_RUup;>%y2y+NpT-$W3#PK zI|JUOyUcCgrD03eJX}g~nqNF_Q-qs7QWY=SR`Bw5I~nK)?q>n%2%8)kch&A(VDJ{A zf__g-PsmGmbYq~`HC%!nK{sE*ghIH@WCvaWX0|$B>eE!$>Pw2QgrQFR@nFc{%KiWF zu`vCC;GYINYb4~GzIi8z1v_E7y8Tzfb>q?2%Sg{=WoeNsL+1-{hb}N(!h=muGP{3; zizZ!AdGFHv>}c!~FN@}_+a|rX^k!$Z{TFf&SvU#06lG9b|8swIsK$U2vbE{SUbPanMlep?}qI|{G>X`a3cV)jS zVG2I$lO?uBa`M+ZgC6;_RJd;#$D@;R%%4n<`I#gD7TvEq_8+bf1v*b5@xgn^QlAAq z%Whta^iv!rI5Q zbGlW`6i1k-E`$mWb<=Y$>engviktS-DIU&HB19*FMut8OC}R4cFxDEP3lo3prSbl3 zD3$ksBBr6ONHM6b#YWbQJbI|HEoLd6dAe;HzdQJi20r_B47Q&}*J0kd0BPG%o_;C; z(N@3S#;5PQj|d9`!)+ET+kxRQm*P14CV!}XBcAL*7J72MG_tynBt_Y~zgCqqkseZ{ zZa^^hio^CR9*lDNd-~XZ{+fdfc4I&1{A1nDg`fuov;(Y4Oi|$)<`B0U(bL1UsT`K;{xccMsK2QqVE3_ zUxNPNR!3HnX(!Yw116P90VRpMY(Nlm^(n{vW0sJ2QBlgPQlx34CIl$_$98&HG_J^- zZ&~tFPQft!r#Z%48Myy1r}pry2@^|oYOT^;xArm(x|8KS3!Nwc|OUv|Gm;D?~)1P z4wE>EL58B^T4KhY&<|F#Z$_O?KHrxbj*a*1S<7Xqe4S6Jn^ZZt$~Qxk%`+k=LZC;i zAGhi1uRsq7{Kj^?*$+#35(bbTbI1Q78BEV{oKuDyDbd@} z&3Dp0>jm>%vhsR7vI?cbhfL3j(_lrmTV(%W=KhkwfaeMVLo&by{C=Ll^816SewKA+ z$u_gVA$+Q}SH-Pq=%~ytu$VZ_yZnjGmg;uB9m;jjnol_Q&U0XyWM4n&-5+ta9Mcs! zD;VP~h|U?SY1OV6k+%#^!ITKQ-O_@Jq89dq_6kQ--U7*bM0yp0#^|7N9UTW7Ii!>j zXN_)`ymqf#4(_HjAW8?S<`B*sUQ$gIClZz90Ep%h=?=Hx_{b6J{Iu=qz3cm+>hfYW zaGn{VQr%o3vJ&hxGuSAWeRPuu@w_+M=dy^)#255(*??ifVEHcWmGoE;eA1|2r;fk% zOp14zCxGPC2K2dhyC_)yJfy84fxELZ)N_@8j_7!!iEu4KmNO@XwdPN@hCd&Xja>}N z^U*s20ig}cDL-~X!f|4!+g8tuN}2MQxZ9KJS(rgJ?+Wkojv`%ccFVLL!S4(LWg~BGi@x`g6_S2- zL?_k3@5FW-!xcxope7p@cQ{JRyQcH-wori_?_r3Abu;?CoOd2JNA-x2@AvC#+o${9 za`3f1cIggY<9dsPi88yvm(;>@pI<`ciM+CTj*`$8DwX8-qK&@8U&OCM_c$ZZtfexZ zNF8b30SFe;Ayt<87xqoj@SJq-JQumqG1V+ITNOXr6cnf4MrJN#Ojop@)_;uAIO7{N z!V*XBh~+)SjCN0VwC}$f;kTD^kAHCSJ)0&yo~LD3tuI!P&6x$P&;)12V@E=@8sZ-R zaEmqmR;A>zlAhLKPTsoeQ`tp@dFQw6$^4%leF?ypTCs6J{UBB0@rU? zv^;@#v>M%3Hjv$@NYqVr=m$vBR#?_B+hoj)yk@MgtvDQ-x zJs;{5ndj0n?2|H)b>=!A^X%;NQ{W3yA$X;1L3lr;E{Z`VOPgeDA>m9?aP9+Z&)Fb( z2-=w8InPI5H)w4=1UgLyrH(S4Gh|_n|Xzr32jWvn_Vj=#ccfMx(3{oo6JD)&uoC;~$ ztG%cyKNs~355_0pV|IDW!@+`aNa8+x`Cuqtd!@TE=vX6g!f;63W_NnY)k8T%xng&@ z&>+1~{_I#LUU2Kx<~EsU?qQ7Us1Z(VcxB}sn}zyU4Hqwug zr=xp$x%G@1sqWKXTlH3{j;JX9=tRXZE68VsDc+*km0=#ud0IPjrwwEXoJ4g8EcJi# zx^Y8dG%nCJl5OW-YlWGN;l;*;OC=j37aMO}BR(M)X1X=q53>446K^ywtb04Hu95|Y zB-ZMwjj%xuOG;6UA#T=2eMiH}ENf{la~UqfU#jvt(n3uUEFN~=R6u8O!k9taioXj#_E_J?S-Tw@VLM>ho!bsm$n zdc6#V(9%iTw*dzTHs|3o8Q^mBKbs%mm1F{PrhB_0Xk?J`_9i{tC_`zYor(ul8Eh|# znqDQ%?+U*im{ns&FKVUCfXqV^tKJhQH%aJ1t{l`GOMXaK&J?$#dT{XCX)7kE>W9Md zNx5C$*kI+#)n34Zi&xd4f2p-!&nqfqOvrD#dJ%0g-*;%X<|#C=#_|zX%5hv!PWJ7~ zrE6nv#EcMmOSUiy#y}U^I@h@JNy9Z(y+dzyy}rn<;YHcz`(ed=ChR%_IN~btuju3T zlPDg;NKRcWjm&DbL|01o4M*z2BH*Ui;e{?&P6CmykogKuM)4;fFR%6Q1K-s5{eOZz z4NqYRsMu%3hp+z{Dp523oLF!Yt{eCIFRJv2SN~O&z99K`Rr)@#fke&dhrV1;X5mbH z;=0kx-i#1M8?dPEZXZV~L88>YZoWTX|5n9Xb7|N_T%y)bTbVzPN|`^Py{A`)vc-4c zcJsEFiYMtKoqM;a$j`=g@EG)P^*RhPfo`1C5)ouetJ+^#$@&$d*U9XFA4 z19o`jSt9FMus3ms{)${DC~F-s8k9=7Ml1KaXCXc#0`k2|weLeXhgR8#IO458 zd2~(TDidI0C<3m68pKeI>{k^xpF8PU*P|isJtB2yS^T}9-jaOc<)4aMHQ>Behz~t+ zr#b?~p*WtCNKR;F3~}G{P7A^w2)+^)ie_pGv|nnlRI#)L#~-lzu&qm zukPj>B5E^pB$rk= z7xe4izCO$2NRNxK3T7;^nJydePZtTyK|QZdPeGcEwwpeDY0gH`RWzURps7B45J0wM zH!t8gg2j+HxjoBJ;>-5w~3p3w#=92WCCg$56MnEdVpp zbE8Fclb41yzS#X;ad1AYt~rM5o%-_rECxujUrIfnhj2l@rh2x4 z+IT$meq&?)j*e#PFG+k0b9LQLbI8|=4}HkAFY~~10t=`BCZP=ij2T_Fa$;4F7)F%{ zQ&AcvQ)lE?||9_7L$X?pA4Yzt!1E^JM3_9 zhF?<)pMnPAcVr454!=yen(}C)^J~$Se5yPbJUee8I`5i+kYK7q=hgNnc(NA=l8;Jr z>Fv4YM_Jyb-6l-Nir-qwf|cdgFECQjJ9K9W9S)}<2tNto!kzm-`7cJOfZd!_b(^F_ zEak{h0*v;U4G#-gPCU>QZPH1+539KwR>JJY^8^OfwEnca)O(|@t$MxAcu3PWSlcX- z&7dIuRUPY>M~?-U(<3dW8+}%~w$J@O0Q;FZTN^VNRO{sW@YiR*b+4JQ>YjJ!+sG&=z$ADYz=GKQJ2hBff!AXChway{VJq9cc#ANe!UH$x7kUsOXXorLzEP zOt@aR3gSTiVoL^4)ehFVySnc5%2>1nkPQOW!z}vau-;`epkW9Xby!uaUd}98r!@0j z*CZ5Ny{l35!c!Q%(+|^~Sp0mEuE~@2l>#jZO<2g3--amjbmS6zJb;qyS#J*=V+q@qf8Mjen0FL1l8cahK_zgz=rkfe->b{@nL_SzNB+Y080W^PN3+ z1O?DMH`qSq?Z}jMWS$1xkX}#J2~^vHA!Th}NVF-+?d?oAKnP7sq4}l;MBRqcbUB&SBiyx$nV`ONspm()k}mcIX8pJZRnd@IPXSxbmQC{FTBPW)hF0pC`C zT(fS!<{VS=QbU%bZc9k85SH*-%IVDXROD?O4Rs~-uIR$ZKWXAS{4aFyi#$-EVGPN9 zTnAA?_C96*M8%nX{Tvl3^`=m6Lr2;;@Nm2me-bx5KtW%1lvNw$OTY-(9POuOl(s&+ zx4LcIoGDWp(W8SeS=;8N>2q7#U2T&@HtFO)ns@-OH$U+P&SD-T3V5(v1XSu{1>YNY zy_1Jg8=d)A!%E(8L>Dr#$^u6`%};$lfNC{??Xu&@{ILTnC+iCo2$5NuV%Z2Y3#oU} z`;(&Dumiw+bSuyqiDp~E{&kAg06~J$tX2Yb>95f`jb~5r=Obo=wbC9DhZ%nsD$)CI z$9Dh`VQ9i>mLUGVVE|w-f2o*oF&ne^_&x8DR|);Q8N^bQn;xUWql8pC(HS>Dsk7Lc zYadL1Lb5VZTfJ6y{NwuJ3UGz_2qZCN%@W>ufSbj4Ee|*KE5>7nj~=UpQ>$wDTZ)9f z$I~`}?XCxFZ>cT)Y$cd6+_@$~>B-r>?aAcVLHV-mBWS=+roIdWo#k`7E6ibU{WU>y^+T$VF7TUa0oFERKsi}r|H zmpu6n=OQiEYxhG$3NF?h|ETV4d1MJlSiXSBTLq+y+=Bb#wzE7w^B254*|2b~P!ee+ z)Lc5eqXQ&ursBBTM5RsvPoB2TjEduGXv#SOX(DM&OcB6gI3QJ^QZv`HOnuh(W|!4l zP}P6cw@$5KAXe&B3VggmR;mol4ezI?MK|;%@Yf9WZ$Z4z+4*S#g7YR@jIa=?p46T= zg|W1K5fIuaD*LM0-CTniv6gPq{iCWq*16-zuTX-f9I10}m>8Lc&F^Q_Q5Yy+ni5Mw zb{q6zNVAGWh-|pAB#NQ>EtyTJkqACjbCtM*QfPAJ>s)oGV`XK%7ow9a=vWX;FIqPhd)EhLgFg%~ zQ+f#(cs)+A;vc@!PAN*|J+iD`tEjMBe(rjP-tTPLToDhETg0`WumH90dA;#JM$ZRs zV(R`tDD&}eS8Z6}XW%5anK)LY+mr{;>w7>KKXQpeGi)sTGo*INn?BO!0$J9}j7HEq z6nhKAtolQTXlksYSMcMpa4hmVsJyI{mNz?ZVa-;67971hulL*w7ghpF>^xuFpJ=tD zJ8v)WI&DljJs$)}r5At|tx>G-2P^3}6oOkY=Dy!0R9J!=H0pYqU2v3SQP6Gb324J1 zlxn`?CSY<$%U?<@y3l3kk^KHn3MU((bBAH!2&oJw@7|8j%9~)SJX{ZNN=b*7bXUEp zu5Tp5Yrs|g&`*i0`!Re=Io@raC=KRCwbraBGa#ElziZ5K`=;_uZfWi?s%Y5dhl7`Y z)2?%ck7mE$>y>TeROo;Io+TeA#sBp6?YpG%2{Rc=kx8g%)PNXw+TOsdB7rI$u+lNq zR}s255H9ZyEAG`P?Tq=7dzCk-0Sr=#rC=LMFd0bQSN*81nk5NW>3j_h4IK7HjA7siJfOy}|KbXMXezuw-&TD5$H0CzD<&9K zYID{3+pYgW=mL|J`@ys?2Fepfn4K;)$LitT_CzHbt-AoQr6wn@t(*Ob9RQza(XM(i z$rXd**u-xD4Db7`(3ee)9s-*I{W)94M2rX!XoQHktnHinnCb#zP#`%6{-nuO?z%{g z*aU}BlfjR#CO7oI zA;QQ00Z7+BHN~G{DcIwr|6PN>`RE@s_=mq~@N4Q(pltdwc~a@L@|tpZTcKXwp}=8| zoY(yXZB-BRrK62ER6dN(#A-xykurIoZ{j3ItAQ!>Sw>%B@w_di`ZmZ;1VpG9h?w0@ z@=(MB*`?4tHxwdTZHw4ksH^ojqjpCGm`L+tY1GkEhnjw;KAj$Zt%Hk^XS@UQ3{L{! z)U;%fM;dronmIPU965^zJIQ|&rBe7PjXQnxG0aWze6fFdm>6dqzisBD(V6wVaGAZ% z#=S{696%M@D(epyG*$ruBT&a~wRT?{_N;Des9wZ`P~_kRHzBRS&7?0puO{3C=cANt z#0iCWh%js|8}sG2BsCSIrihm=^U+XSk6MRG_a-KPGmx|tdpuowYGy@+1YF+uxYVx{ zLPQOBB3yr5H$O4ujGjdQ__$fdW;GN0niY@zmI04RU$f<>`2{|WxMUP7BNsf zz)Mup_Gu|Ku)`gI^vJWm>Nt!Tl12O1MTPBxWMx=CRJh_R%>_IA8!Y2qg?}ob{;X$& zg<`f)N8{-noE$3It2ftTdd6+&W@8x@ACTCzME@9b?p0=ft_p zzD3gcY&E)YS&=P)}3=GR+Yw6L-TYGqE|g(q=d zZhDvTzuNo1eT<`PrG4%R^<2F->VX(Owgay0k?d#f;zz+3XNP>fLq|sua8tq`L0B2; za~}|*uBZ2l#62PkDuLGEwQsUV*CPU#=e}y@7v8y>5{^-((E!9#^5E1R@gt=`N;h1A zRJy!_K7lUjZlGNwgK>mOY39;<5&&7%M{W0&N-4hU2u?T$eqaHI`J{zxys(KIgFt=- zuT~YTiMcyZm5)>NntVsxUDdJOIvegof`^)~FjSUue)RHutWL$l38yBP{T~*frXhP% zFUQ&t7Zw)GhhEm0Jc^-pnmT`P7jWC|){Q^Pge2KU4d_8bOMF8 z-U-zY*U96gwaQt?nR_$%x24-6lKYFaU6yaf-_v(-%F@DwL0=2}YnC(PgAQ*l=jep> zPPnYBIo)(=dP}fcJ&8_o-;N*qqEK{zUN0H+b??xn7Sa)Qa zfcX(ahm@hNukjk@ao!>w13Vy%BSQCt#kUWSHfvRSpnvQ|W{mn&?!yn^zX#}zxOs%) zB2BT=^sw(lwp5EOUrbg?cP?7<=qycqe%HYJ7hXnV?c71Sv#KL z9>yfBO@ce?fTyG%ClU6I=OJ713_b8{Hfky4_mdfBg9?wZg~E`6+4o||L`C#+6qN_E z)n0#AkeJ!B7?|pnH9-#ilHo;s#RVIjy$oM@#aS9zqU!8{rob(hu0QE5l^j*_;!?$U^yT zFn;ye>6v)2up$A6$qrP^=XEwtCIkEB5tfMJ%wSqW1k|T~5RCdB%T;SMWttTZX>dDM zbSDYbITdqFO%LhRAGGx7Un=;4!6^hQWjz0MdbEd~R~(`btF6>id``@GnQ0I>ALe|kw4qID(@Q|LENfp&END3e zG}{M{m2+r34&>K9cwG(11W}StWNpU;u>=UPt6BlrMD$esZug=rE#yp`SuT!d<4g)w zLF;g!+Q#Pk5LXK%=Helfzd?t=H6vz^F~37ek01ZNiP%D{M(@pDw*tb%vDNJ)Tzinq zX~c4BH98u992Esco0%rn#s?tqaOybW8PX(y-;B%j3u|#S1e{Y@txG@-bP#?EdS6wF zPwsN+D3GFSMstVS{~-_gnRUc5097;!UW>Vo6ApW#>vb9OENscPu^eY zps2y0QAXSy3s`;+sMgr2wkY`u6Y^VW6CL)dTu$UW%Jcy0#~e`)r~4*C0;zneGiuK7 zd`@#j&C_V9#pNW?(TG#^_ZO2Z1x6!fpFL8HeDk#@h)OJY3rdw^qApX8)a1HzjugRX zx^%0zI1+LCD3~{YD}#;S1vo-{)A>m?*h*oG8D&ytWqzlZx7WP%y{J8@V5xcIrFQoR z&7+Oe;a(M4th^T;N4Hr3*q{jy_CW#tyx%)7Gk;8d1rlGd-J&F}`rT#Me4)9x!s&GU z-B7w=yp{T(5kC*J$3{rLcK(@dm$iFJ_h-+GO(u%2EmS^jGJI6rFJAy|bV&U>1gH4m z#xy)g=XF=I=p;nsFzU^^69|b~BTKBn{<*iVC__tI)PGj5pcV#9;7u~duyEeXcNBWqzsE4^EkXMB zl4yEsK7g&Dh)%d7sJ?@Z8}3oF{`=MA$wdO17w+$uTr7USpZ+6y|6q!_jRpZH?-k&v zJ~8hiWJTN&J?ageadZrO$5)&CZfCilC4ukkyVC`Df2LeM$QrOsaXT%CP{ZZ)9{(eW1-th15H)5v@AYf!v-5GjXMR2S$yh(| z=9pFKR)MX6KQzE_{?YS9mkwP+d5e+a3=f-;8_oWj(WAYGVB)o&sQXSeO1JebFuXGB zxs%A(64@C^Ul_Mz%qw|D^dZC!!*1bM_kZI0)`Gc&qlmY(oIy838V>5MzX390g`TZTXq%`feDx=K8gQz&eIE4PJCOL#aD^l$#+dD&ozxEm#aPuu?rQh6dLMuyJpKn}ZIXqe|<|ULaWW zqe`^-o^%i;F(k37>f7T@RD%+PpZ^HFeqetXuq0UNHJnU0bw1Vs*o}|2U-=(?*#V66 zgva)p1Hj9G_;@?{O!Mx3*Mpui5I(aWG1xvriF+I0W1_qV9=BNQD*_SlEhzU}QLrV~ zS999{9q*2&^FfMc-5;13B*yhOm)7Rh(%(QQq*5>3iAwgqJL&)vYbS0n9FMJkbCsvnuiH$!Z0 zB5E^y3^=FWaZzAHZ2lmidRV>}Z(&j%q2n~KA0gk?SkLT6Tx`^hqPagbbII0X!Mpfy zdBp0Pr>HJ!HNJ51m@0ljpXz zVecYRlUz`&)FLP6qq|`IDFKnWVR~RI5eRK}mD+5T9nR9Phw9*Gc;}UV73c&ZR4b*; z;XHJBsW*)*sq}Qi_xMsxNJs@BClCCjEe3+p^3&yZ*wY0ld?%l*ATuuy6qew{zH}~? zCDU|^zi)~>M@+Y7f^qlFuO`%Q<8_PDKljP7KB3o~_Z4d1ypB?(cCC0sbTv+R}QHSJDZScq$i2&cXCijJavUMpNIVFV5nYxdzK zPZ!-yOPPa9Lo{|uj)FTNvK_u`5yi|N*G|c|hBi8hJ)8&2&0^JR;Ai?lvo)97L9ft~ zL!G;jTzt?d-hx~{PA}xAdBR$`VV2>1PdRuua7vKZdru6BN-(G+fQ-6#XfX>WFRc>} zXG70eN7*FWs6(Vi@%GF6XocSXCmM`oH`O zpWnU~qhnlIx*G{*@Kl_LPMbu8uKfl75!;_hq&JMHn^B3RG%q0u1kGP0uIcJ|LTp94 zVxe4r`aUraj!k2yhkDbkx23(Y_a2)L2@SvZ5jbd{e$<+IIv^#pF`M=l@Q^w?3jx@! z?!)a5A0AL5pZWOfe;}1Kr=m$zL*5E;I>~c!UJVO+K1GU%Z4JGhWe$zWIz`$SRm+}KrQqpjyjOS3z5d2Qn=_NWo~&)hj z5=Ht3t_Eq&1hSbhZaP7GwRWXoH`h4oMm-^Wo{u)|vbW09NaQ(GT{ce#bXC|zP;GPr z>@v1Qg|N*VxuFmOI`g?Dv>F&6dcz8RtQmXvHU2lO_E>2sX`btG@NsOpkr+nrSco zm>I~o^XGJpRp>;_Q9S`KWVj=bBI89mphEly#KdU~Vt8t+2mV93NzGX&qqCppG87ZVeF1X?UJ#0!8w z8>%yKduneCr-e&zI175AW3tp({uo)v*;#O^p#u_tlaz;BAbS6zvz239Wuw9bWnLgD z9JCiF=fM>2#%ww{ZhZQGgq?Rh6@35y8WpBq;_TD38 zL`e3Y$BOKAka;-7@%x;v>b|b~zJK@kuP%@4(Rh5$`@Hx2`PzJIgneB!mSc0}&%jV6 z8nZsYGI;py-@N&QI~N!swxqKFY#6m(^yNDs83wU_n6V#LJQ$MaQfH`mxeAJT8vtM` zd;QJ1-Q#p!pB(@8GdNAs;@R5AkvddL(NpA|(ZRH0P5=gK3#mZ)aVb6}3-G_O_N z#fCb$fdq;mdavKh{4}mV{@!g9V<92U-SpIS0_@wWk}ig^ik5dxKG9gce4^=0c(AQ- zM?(=fl& z=Y4LD%X<(iDB@F_dp<=Um*>)LeeUwO3xuh)DS0iPjMqNlzW|7IA%_?%x$9aR+m~wA z`?acCx>wuuuDg~ohmx@nYF5H(x#t~53&o_-WnsVYt4$porA~8!`|9opkcXmbd@%8< zzoCuPJF0-N{BijhYG)xVI%_u@h|+-GM-^x)8_xmBn}mAQy!_mgd_RE3ulq{pdUC_V zAnOenN@URGdfB!J0mG=C1lm$tdF!xL^#0u+oys1>)xh9zCCk;8f}xz=P>3o!F3uy6 zeN3W%Y|$$MiPtLqlX>!dVFad>wobIJ3Obe|*R_gfRlY;M@MmI~R*PweI52FwH(22O zJB|x#?Up+BFVE1B@v~b;3e_<&++rwf3YJJc`++09O>Z2=&ata(4zQj8k8&-=V zgnP4RzW(Abc9y&vJv!Et5JGc;!@ec1tl@?z)$(C0%%y56xQwW8AJ;bGFH9m^Xutc{`lke<90a!1X2;=`25gD=T%0mFXTm?pfkDz2jum&9c zfd>WiP#d72QU+Afq+P*2V;>O9>^nZ#q+Yms%56S$6C)IAU#u)XO5jN|QmQ{=Q;&>$X>AbwmLGVC2YjxB-&|k# zf}In#h{wFY+}!*#NPilBiwTB5P{e>o3(~)tAMO?Fg(!ksKyJR%*r$bYpCYCC zr`@2I(<=kF8>b7FLac^nx}%Q^bynpct$OS;jn)iTRat$3+InFP=}YA)A+9m_^yByZvvrx9O3s!gKbwfqQzN-W>FB zV6NdgER4dJl%C+@{NVfBEO}ZG9a1<{*D4|lEdDEV5|w)=ARj>SdV@KWbv=50^?ANT zs(S8rGNm{Vwx$o(%}PKa0Bi*cZnLyd3=zyK_ay5!p@bv>o`_{$Ll7>Ov-$_l5ZK6PlJm`R4@=4Rhf!Fiq--G z#yr))IaSYZxq419Fx@?Kyc`M`ftO~slM7+)A&!NHenmc5ojNlt_ z`EpoHxgY9M?#S|<9gneYf*2M0H5f+=E6J{_^8oO<#puXO+)SN*Y*t%$M5Iq3z1O27 zq*BqRKfZeW*er~@G}h!3FuvC>mby@Q4J0lOk+Xqw^2K0X=%$C>hVJjKzgL1dX2o2h z;V_>|TW&bK%BqhQXdIswV2r2w?0f#GL43JodEsubrAFxoqA?rY*cgj22LKEFvf2Cl z4*>%q9xRYKh1dZui z{9yoLea+*tw;!w~?wv&J<)G>r!~z!!K3kT2WI4IJ8SrG!NVs{$`k<2sXk{ z8B7cU&(C?ue_`^DIw)^q^}5dNfp5D(WRFG9SZCK=Wa44yoX7fw%(=w^&q71Z(TSsl zX|-i2Kxiad(E+%f0N7O(kUKrm1=6>$X?KKzMzLZPpT@q)UE7p?-J3SLea`j zFGf&?<8h4pa-+*28=oh-Ur%&kSkwca)o|RMgKi>aMh>UGQ}>}UkfvcwT~-ChF!>DB zr>DL}=foAe{1rMb#EWMYwc<8+YLYZ0MVIYsCD{)JRe{BX_UHn@(l>Ply~?F7En)lB zXFye0RPSB%k#^TD{Y%dC$g``1)?Och|PR-C%E_ft^WBsF>-N3p07 zp(VuRL#0%qm835+B{QC9?mMEn3h#(Jo{K>(s=$nus0v6x#t92rft3o3-s0r2vRHKM zBO)cY$dS?+)qCVRM;F#X_oFpG>$4WcFRW(XJ ztGB8o-sHx`7?~Oe8Fvt%uZW3%8ebK(TkLSUEylVj%uq=4#OCMz%^wox_#4cY9g-k( zN6ddN@VOuV1ufjBzKiq$q+Zm`o_7PxyaRo+&r~_Thgy`&47u5Acc`Wy=F}9Cs(1)O z=mGu4L@~3aDu4}rx+uB45U>}jVFR@p2&H%NF-2C*0EQb zlTJ_LXk(CQ7o_$3O+-wo$L!L3mJKl~Qo0s|@}(bAAQbbl@(Km)@#s}lUiQ0*+=?~# zyyDtLJbYGTUgC7d4b0v*UUI}G8aB2ViRDsgKEd?T)Wz;d*S0@qu+7F3mJszy7}jT z6b1$zb1!+XF>|7&fSPe|w?aO0*H=BF;-y^kElQA_as6}Ts;`d)R(6C}TSLg9lz|}q zW=*lnZdvY4{EEjv6_K1o&>6gy`$%4X;m{x=JAv1d%)yRDImHSnXzTU84lQUs)JaN{ z!vC`NV`RP^G<%1#t*X=7;U| z>Mg0S)Gt1ngQ=!b_*wV3j@yn@Tj^2+5tFpGg(C zn!SYA<&$`cU&|+qtl_&u886BqI9mGGXM~Umnm$!eCxiWlt&hCTrOX@x{?(WP@?tc{ zXB+jG-zKYnM4x6U3t?Tr62Fpl?jd38m$Nr%jAT};JAu;T4ig%G7rue z!MV!!s*TZ5T0Du;QQ;RS>_7VBa_gxVHpaI^tUjTLPu{M}hz zjeJC&@%7&9&w=8b-0s91m&otWV7?5le^9_6RkjxWkve3wW; z7+Eq3JY}cSe83iezI%Cym&VMF&`aFI{?{^)H>BUbD$QEwhAx0ZG1PA-+8FN91G zwytteJ6c%q9egv7EY);Ga;@h?TLdT_6{5K&v(%7qX$JtNO1x zS#3`3Ci&Zx&UWTjBR4vxX51ku^=Iu`E8SH;8h9N&rY8m~&IW?57yKQ{jwdL&SK|6x zf?4Sc#^tlk8aEB&nIP0)iW)aWvmVD4C>8BVvWIrEami+E%tgh2kOY6xT>)uDl+-?* zhzM&>!%nD^&2De(VsF#ynPK$xdSW8$wSBQRwL=}Ux`w5~*sV-v7@C3Zhtw(b4KzWU z8)H^~+1LYi!daF=upZ4m^A=uV*8k=+5(qT#JBJytKUx|i#;jjA^=eHOwQiBR^SD_? zybArxD1ZHKGl{et#m7r|v2faCDUl?yqnK2Mi5#l&C8Jz1L6l$xPod#zoc&LhBFrpY5K^p_AG-dG7vxPryO+DCg9Y56@{ z4FU^^zKlMTAh5Hr*}#BHDD*&~!$NrV)1&R-RERJbhYecY^UdS(*a_i&wQSVeW@X;K z4s?VC(5Nd-p6O#rptKOR9h4&HU8$P>^|Wt@#xLN!jezqJK4kjfl6<8$z8q8K>C zi3oZx+Njg$wR%rt^f0lite*`1S>bA3GsHpesrzuRZl+QV!!(&XS|F!qU&1(HZ%}ex z`yGxxm!vkZvDiTMA0AmmFp~;2)kR0KngSEKj>%K&l~%r>2zb)nL!+@&DtWVSTBJjn zug@slzl4$QK8f8sx+wYKofrh7`}{zsb(*G6lnT3b^-5#WNaEhtvmif$lMhkVA5q`q z1I-BsZ%iV;nO3iUt5D7c>kXv0ivHn`{`rF!XZQm=hV}80b169g0^ew^Za)f?2(W7X z7&`bdlyoOpL{Cljntc7Z6c!V9szp4Hff0+OXpnlSokLqdjB|n%1h@?AkzDf1o8u@6 zF?a&>1o_sPsxJ)TAZ~nbe8VYR*9Q)l7EZRoNFiZNlnUZL5 z?pa0=PODntX7Xv*(tR;ctnvms!?@PSvq;cQN?L07509zCkZ&CSBH!p@$TzsuA!r7X-nyxcfr&Q#3Dmh?WKTf^OfQbK_kL_Odh)Of z_x>@B=bRT?c!ua*bPTj^`^4>^{S+kc zxH)Yj>@z9I-cE)x!3>o<$0zaNH%`e`9tKrQ!WzCVc3kqTV~(3htBZHFFCNc>U!g-<@}M?i(neSuMYsFEpOt{!T9t0Yas2g^KcCd|81Mod;Ip zF%MV$w!sRA*eTJ8iLzBv856LXvUSQ43FNjxru5qI$08Xk64eEk@GoiUxN3Abb#x#0 z2Wi+&-}ojwNlIky-HiypNtM7OXyR!vNg!Vo_-K4-ObJpC*RQaZ4$KrQWr`t`P;~1u zTT#%LhlFe@GjIE@kAC^%{X2T?_SKecZc>gL_)>-@~%=IHCSex*_8HF1#r2T6g{mJSeH0( zHQR7`vcR)F*|7#agU+X{wJ+{V7}WY%%&2X3@T=K2k2aIn-*)E=Sh%=qUBx z;4zjg5ncBmHX4kX(dgX~-{!ocwRdLkA>wd&SZML%U)j!o`RqT3_&j*np&cuvARD63 z7@UU%!%7M1kdy26FuY*~#HpdzbgtW5ZL4Lm@~&^-d~6}k9JgbIeQU|%_kgn!2%i!m zo0MrnPPA#MLv)bJ7G#F`A-7VG3&M24biT0h_+<`u2xOzcPYL3!=)#x9^&6Y>I#)|R zy* zIIHqPvo$WWvxkhvyjda`TFS*1kOZBZ=KN##UU$OYT+y=r;grZ^Y|V2VIDWdiwP@IX za(a2E#rmwS^Gjm1#GrPDO1(5Nhy(P%*50NPd#Z~-j-m^+eq?~B#AzPwv>&ilOg&6x z^z@2Wx7iHIa4Gdn!jPh2)$~f<_~zz{*^eH2<-qJUWI#vBi(|uUf@wRHbm-B-LOr>+ z7l+7gW~lBRSRd8Qek(LmtTn-9vrTb?53c!_q{^f+xSGx^tic0Aa)Bq>?Z$0_`f>ys zoSiJo7X%ua5Ul^P+yC}Gw$j3~z|m^YMQq#82EPxf@x>?i=Sd>A=iG6*E>S|pXK#1I zAUzta1?Fi5Z?vRG7m6$uK+ND!g?s8&yUhWr^sVvks|=B;I&n_?D8cwL6ZhR1`J&}E zX*|&oivltaU#F$#&=SKBE55t9R}zVNZ!L6roA4O&-gm^2K6lHT*hBOU;*yiXZnGIm)1 z#(p5So=($Xx-;c8f2dy+PgPgH;JrFn=V_%`ErfRdhITO0HnL)8SkD*c3O(|yH;&G( zb68K2HDMYm*7z#f@82|-X`o_NahPZ{s~4~`)$ZZ=nB$$Z*=W1l_SoS2(>%>Odk>e` zIfKL^U2L2cD%&p8^Q{;=fpDmGQsd5Z;J4hR)DR@I~d1#u%b_=?XHx};THe;SqVbPG#g@S+)+ zxH}oW_wlQoDvJVT!Pj8dc@{E;QpSRKenBHg^ znR_44rin4hQX;{%cpkSE>RXf@w86_0*}(BXzm6XWE?i;=fs%zQ;M<2^SMh)oiq6PGglh zJ-oW#p*IkzBOHs-?c&?rZA!{kC|(lR34Yo_sn&wxGojc^kCH!?f9z}daMMM_4*8~h zXW&hmw#zNibDz_gf(I2QgPK?y?d=G6k%@Np^J`o~qz${21M2e5oiRr5#}3pz;m@FW zyM%#y#PdXvC9COF3F`efgw58X-6Y7i9g;xKZ9869@uyH3;3c}tP-vZMDeud18;KCR zU(dKD%58l1T4t-MIq`a`Yq#0_#N|RcRqI|N)x2UL?OR7f!6df5(50|A77h9Ooo*e< z73Q#Jnnx){HO7XcwX{yl%fn-%S-~+{s!iiwMXkkP9uz@3UE7LIb-ML6KAXD2G%K-U zk`W{%m%XP)y1!9a#@%n2R6&ymmtN5lAFBKFZ~M={_go)*i$)P6&f?mPL`^RSiP^5u z<3{4`l1&jiv9=hk6lvOTB#}1vY1wwgC+mg??6$sRTQ^cmE{7o^p@_A&>*ee)NI`K5 zYLLj{{p|QNCYV!i)~ku!B39v#t4j*IL|m#flNByqdX;L=)x^)Y#!BGgERi%v{U)B6 zJiINw|12!m6FKBl*k})`ud^HA`m^av+sY z+SrHU3yX8~E7RZ(QYH&={6#zwb{@Bv=4W8{8i+I$*O1BB`u4{pA3!C4W;O+hjK;BW zmwieKOrb8J@BVmy+SaNSxm~SCyRHF&3dTROw3EE9UAN!4Pu0-ey&v4r&sJ?BPEo3q zK-6)c@*X2h@Q^<>$PYGkoqFum zQ>V;plY6|}^P=%f5`Gb}N=Bg4qVoSvyFSFJPmuey0eoiflFXyS!<&r4Lum;hyzy^( zuuGP%ab4F39fjRBfzdxH{LkjhKfIuoAm*bBeuDJ}<~SCVmENdL3eW zw^fdfDDA|Pa!XddmOF?hEw&#-xpeatt4TT&(8;nO@=To*9Opn6BeQ%lh+U8oSqf0! zEeL_}WW1A4uCZfDZjz}WEJg1}g9V||O=Tq#RYQ{YJ?s-IjaJ)qqueWa$Qv#yOYbdJ zmTu+n$;{jhR?gQ7G?JfBY%O;e+o1Xp#^z#Jpf(mOn(qAb6sW@oKR?YrYX;-k*nq~lin8hM z@ZKCP{v^7PoRcd1F?eG41UnH7`{o5=e%{l)Pp65CyF!ieNkR(-`L zT=`U21YH=Uj?}|xU@=yIxaRY}zLNZyz{YP(8&9S~99b}%dt+P^N7ylW?(MdIL|oY} z;Dbml7H4S)@T0o4TbiOHlWTD*pD0%XX!vK#^v3xz_RGmM7K|;k(Rjjqt!(kMbruCF zyH8mC7SW8aVh>z?0zxK!0zy8PKlj(JJBiix(YVHY6^|{$pGq>UjH!j;TqXrkU|=>u z*(xCn^(-h_`CLa^pLiexlrNc=ntNY7Pu|_|zS?8<(?R+9Xg3pmtHs;kQc&7D?)WC} z`iP3B6{BJ#Oqt?9PDsGq6fqB_5r$ZmgM_(jPT`ClK=;Ahcc4+Pqft zmGW2Rb@zfU9j2dlKos(_!ey@Kt=&W-duQ{^_D6~co94+H8Q$9$-(_C0nM#`x&Z0kdIS8s3+yAl3`!aXD#z0r( zWYcGuoiKjUiKx5_D&e>V7dsF`v4c4He-)$;elV(lb;Z=$ zW~MpvAP&^+mudrZiGiq_^d4&)i-rI%g(WP6Yjaij6PZQ18o4g-`?7x#K^%{72>m32 z$h+rxg%3zLI_~aR+VpLku9ljOgcBHWIrA5I5eOqShoZID`gO_+#g6uGTpn}_%S|Z7 zs=A3H&Gar`Q-JVM#Y;Q~Ts0mJi9+l;x(l=nFuw@kN>nrXU_64%26Abj;pK<~$LDN6 zZoVR0nu~s>Mt6EY1a!wl7U!Ewj$&Bp&Fqm3@qXLAYHh0WWs5sqUp&kSW+E+w3dTjMHS_OWOG8<0&RjqR9#YHNNDY?4dPHhpIGI`j^t@C#4n@m9JP zLbGH1#D}Lg4)IDF$VAF#v7c;f2viKioMUnYdINQN1ECy9`9Up*@wv8J@wy+!dFh26 zB}KENC1^P@h>)c2Pxd`#01;9L5FsJ}5dtqURc{lz3=ko8KM^4}{)GrBz`7!AOBg|j z9BBT92+;zF5VPNikUKvSA;KRw03rm8(E%c)U-v0MgiQQKg!Jtj8022A6f7Lg0;di1Fg5hvR!L!EbSNmbO zP5+F&dg*%kyVn}qx2|Zl9IQ@@fi}2_-+($-Ds_L(*>jzur)BTwZNej@KFYsTU1T$x4F$Xl1CuZ2+`!_0Ff zlwq6rZl3Tk#ZOmZs0n^gp)Hdk@G;I5yOv6-97|uLI;!omhK@UD&m<*6-sug$w!x%s z(}F?N5jLTdM}hs)GqeYDnnX5JE(k92cAmr2)k~3Ow`$fSQ$rX)r>T-2G!6_GTx_OF z;!;liTgG8%Uh32uWcN;wSV=zqEhV2Jc81rY2+P>9OY`1t2aDGFVeo!YI@kKM06~{! z<#1Rw>`XuMoyY8YweH5Q|5^U064gE=J9+DTeq-3j{MVdER*N<38E4z^m-tf@KW->K z%HI&C_t3cJ4i7rgaV42po)tb|dc9=kqrocZsU38WP>fx?Y;imd1S!$rbgnGP)uQsva&1}8V!Ko1< z&z#WTfRN4c&LxgW7|&mTknvxD5OewO77TgJe*r?ee*!}ECI$Wj5K=B9Wcm{jqJ|3q zAsX;v(O-ZNvP#!nKV81wN1j$D;iiw4A1N-eHSncY#O>a{SZNug)1vndN9*(o9|P|7 zNqykUJ$t4H|KxD1lVDhZoOf#g9lOA9UpJ_zi4C43=LOet$vs-0YXKJ?>|Qm&S&KxF zTgHn->Mc}%SYqMT(?gE2*S8UBRquCdR$JIAO0EcdtEFxp1Uhu5hVaU-R9<~5DpgHa zpQ+3^;;=Q$MO18BNy!B_-)!KW|2k>*D(QdZU8}cot^+{o+B+p#+`g+VHwAb&JeorA z@?Xb=B@3L2Q_wP!gU;Vc@X|E`Kh4Pcf!24bv{qem7G!V+GFmoQK5Z&%k;|v*61GY3 z#v~~>npU+CAj>D~tZ^o-4D>l10yC?Q*|CK)Tt+}}Rj72>G3VQ7$+)0MAyl!D` z6WMTGSu9XcW4Pf2d-nlL5ywlSfpM{dK zND9d+bRcfbPXDX8SS`nlj!eX~#oqpp2l`ope7JxKH>em!rE4@~KoLsD{vs*g$wr{t zwu)rYm)yjhu4GML-J=2-`u$x6dPI3ehuR&p-W&nDGTR(39dfIYXENJNEjP;9b3{l0 z&oyP$M9gZjLng_^T>3aVcXE+EfTA~H#EO+nI74s#Bu~s$mm!@wojb#8ByUi=v5YQo zs=Tak!zFM?y0;ugC+_H_-Pa>xB1%+yPW9QX6oFRxTozGy;YhyMbLr&#_Q!aRWEtp< z@-p@m3PeY4!^Ze(>4XWpk@{uo^{X=xu_~(%xETsBHodm|(`!nTX9SJ$_!G@jmH*+k ze@-+99{sGqVs@K8%+@}5?ydGkT!0BBsU7tXib5QMRgKJWwn*ioO|Z**%ltc)Pt;!B zRAY`80LR9GgIblwW-=XK!a!pcoaQuJp<2|26j1NvDk|hHR+{ws(kGk%kiru_@UGTG z`Djl`MV_%SxNHou7|(~-_0obvjL+WPNv`)xgh-%GAR|oEOAcR1xU5U2y^S$|2S60$ z{{>Na=XSDzh#V<;rGbGcBx4{79LozwU3xBby}|U<-o>M^ux#yUke?eExlDI}iBr_X z&^L@}d<(2g{bLyea7>4z(DRE2FF7H#&j$JMAD{(Vi z%SX?5&XSXjXAKu#cd>w2JSQ{U=h&#MJwYgo#cjvxzlu<{(rx<4Hb}U1<67Uv8zw%J z0V?j;x0*iV8_3OIC6OkMh}`vXmqq0jR~*M5ES5y1Jqe+)N3QhnUld+sT?>}ap&@WW zt+msPq_H{#wz9ktj6bmN;qGcu<~TCJ)02|*v>@^!cqlXCL#wY9Fp=l1&S;EObX7;$i?05@s3Enw!Q6fqRk8P1dl$M8bNjEci_j-Z0#hM*W^y6BEG=FwD+M3 zg7gs1Ru;9CNHc~2zk$@L$$!(McigREDAfO7t!sxh*cgG?|HyEEHa`;|UAGW%g(Fn_nWDceFOoZd5vt*#V)IB$Qyp(lllRKGnO7i4% zSN5dw(xfYe!$v+7Wlmb)4~%2IF(j426TKZv~Z8 ztzkZ=c&uSmev~pkw+kO!&3&^#E@?Sd`Q!c|uw>>78u!$}Ep}r$VZe+3f12d5**~WI ze?AE(6Q~IjA~NQd-p|GaUc)-XvLg}3tvkpvosTt~(2~tpQx@Dvnk(oCFW!&tresiB zEEo#Mr^lWr7f-Ty79XChiJ2FgIj*&^rRZo_|D_;r?<+KvFTugL^n5I|6E1llm%C-S zQHvpsIXw{D3k%EV8c~@nLAO>|UVgwcia0wY)#u&wdFf6aG9VIG6^cQSTnm9vUF4|S z$b*s8F|2#6X1-2{bp_oZ3tMR@LEq~5eRhYz*i4}$t%UmiJ=^_guKbT;6ok-8^#CV( zgNI`CCA0oTpaGK-0*1OJZGKi%;2Oam;KGLb|FpYP8+ z0pES6ZJiIZ!4Dk0Wf+Hubco{wc<19HeEO8=JZd<%)jC?kOLY2P zs%;YmMC1y!5cRJU&GiztQ;O|u5bwT^Y@Y84k7(vda>idO@T?aqkP_+V!iOy@=R9(^ z-&lOk7A`nKpIRf35O$0x)r3Eb*LS@KCy#ncj0Yr8&ELF?3v1fHiwYe4NF!eB*43_r zZw5DOSF&D{E5<1sF@Sm|739-yW5wAc7y-i zXoz8;nl(5Flo9bR-jKmJ1A*+ps_X<6*ylUF+=lNO8v1?OwI!H2#IR|D@_f(>%b0YD zfHuHKN?M*FjMv$%*Q|LtH;ST2^5)Y*l6%y+>JrpAZyE|h@OR+s#DWw0$yc$Z<_FKtEV{|X`FlYf{Zd+?^y60qM5NnnaZd0Sg8ag&I24Zv zb=kJjbsxOB&=^PL=RS^+CS`nF+Qefua@r;sj0((I9_d-r_TlU}NS${`?#wg2tw3`z z_J-l`>}pHF9ov=#v$1BQ0OKbYay3OoJR}9fa@$0ZP_FY|-nn`CBnu%*1(OsDxi?@jN^K zREwtsYVjLDExx$EN6|p=FSYpC$3NBLh3lO>5bxPBYVpbz%zr!GBm-*kZW}-?zViv^ zO`AtQ)#69^{!)t<#;CE_cr|E?AfRi2lx-&gZl z0c!DaLVSHVb#{V4E#7D@m;9IjWO>Seh2@C8M;!?G0KfltA;$WYm!?*ljSxrgm{_Z9 ztFSDN`tq04wGOsx+3_0n1WN>qPMD(I|EvM#Sa=oj48sR`vUUdu`Ao%49iZQbm zjSEY6|1XkzH|jG_y!GS6W0zz7l zzP({03S!*x_rtvvHf<6MLZr1HRlz-JA+w)*sXEX#>Cj6fbz<Cve@0+-+{oxqX+e!u}CM0-qJ zF3$;x{xp{aRrf$Cdks9R1ajI)7!6q^!xQdmdq=k~{#4_H_7*o*11)S>WUx5hrXrT0 zWZsgO<;<9jV~sf;mRlSRDRj+G)w{yR9cJRCt8I?sLRMuTYczVC8Ul>o;J`q{3+Jb0 z7reKYJC}*evGHjrer!}IDn5gyCXGBsVzLE1>?EfJNpHNWm@N>$d2? zJ%p|Za^&PKkC{!8E_;*>k*3V0Xwkzd9+!g+O3bxREIV{LFT8=l5?sy&iXMzJ#of`R zf{CG>OiF}cDkcbcAvBa$m=9&u^s*Tnojdxwhnwb%$yn&9UH|#H{afJ#YVEXjCa{T( zGTH(2z2LytUpAl2w?2~yAn{4tyR4O5M&$E;!RR3cACD>i)l?b~>CtL}~ z1$S4bU!)aV?Q9rtR^CLhF%q)*KN~YVw_%|mk}-+OGLt!e+_pfX!b~_$h#YI~kWR5$ z47w|oa?D$;Cb82JC@V$V%V>CAxWCjnD#4)-(Z9E^B#%*gKQQk4qx9|)p0!NZV!;O= z`Lv(92qn9q-Y#dxXl!zCG_XEXhRc1OZ@%1Pdh#vLk=Iq(sTBCYnSQnLoMzeLM|-u= zo_%GOnJ%t|jSs_0J3-1xlyw{B^6C|raLHPZR`dzm>BSfTu{*g_c%jWbjd*XFzmcsC zMxWYGuJh91Wb=h*x7kK-Czt0@H)>7UGj2MXMVB-pd$~WA9vn6V!#wsg2LXQa5dr{A z7r^;(*gGEj5O8zE5ib0_MuAN2Tvh?KO$|dyBbxl4`lj&Kr&n$pM!D@Jb>Fp3R>vyba1+`VY6JWc_9gsywykG&bAIF|3OD>!*H5?Tp+WBiYz=ALwhQ-; zd`Tdh@wXh7-Nyj(BR?lya|z3q6PNQ2XxGr$MaF%~iblc?HC+8-!yRW}b z4e1QR1m*)N_`jd3qvo)TAVxRhiv z*a^@>=ap9cQGBN{%i4i8he7(v*~zKJ@04*M9=c`39h-wRSJ5JmbtlknRe~1LnN!>O zBtHb^mnW7LaF0uPnEaTi`%b#&giQV0%fe+Ff%5~Mp!WlB#io}Ln2nxQI~`)Fw_ttG zteS2oJF%a(XtdCyaxEl2=KGSuPtA8J4)0X-1)4g$@%-kV z#a9{x`@5m~y!oZ*@_bJ_6SmWRGgJ5tnYTm%9l6diuw+e(4r$N7^5HcOAdJLs6kEfg zcULSWQH*~E+{50_D*A?Z+7;o*WP$`Bp@zNW5FZfpe1sMDr5GhQpX(ZW8s6Cma{T_*)&ubmNhQrRaw&WVYQT{Hn;+bkBWsYy&tkrt#b; zYe#o$W}a>bhy?>+{l_jL0Eq<$wzxcVgd{^>%`j9EapsnZJzfvM@uAIxFS@i?QdRim?2KQT+n#*7L{8{s0Qf{P=4N z%gqV^L*=X~D-xWe1h|6&R5Lw#KqqkXSIl^U8LgfHmq7ooCGr1UBlsCmGW;WWArCK% zVTA`eq6hFWCve`d=I~z%??hKZ+$5(c;ftX$NAn*dGDYCcxe16&su2eKI!OouY>9}C zlE}MnAYgcnZe41+Zp>#mjTSd~SAyClbdLg?OV9{5PdoLOnU{C=i%11TMpQhC#Zqmn zZkpWdrSP7!peIXoqr%>e@Xy4T|J(7~28SfU%{tRevXB6Eh?%{w8xqQSd=D4U`x*`J zH!d#}z0F!CNY!+SMdo$Cb6O%+L!dgd#e^Wq(Fy%aRxWfFg?F5xS=8mn4{hGwGr8&v z)~V8X2+Lg#zLPW`JmNP(E(YlCz4aX+O z<)~Yq4g(UlLrlM(A*r6SlOJ8_bDD3h z&_MCK7UcKWjlzxP1j5xK$#z}&d0I6NxcA7iIDDTLfB&@ChguP%e`K8RGxVxHN4#nt z>6d!4$oeX&Vb#Gmi9wK?+?eO?Tuuo<p%vaY81;(!<0kB5Y2x{ulwD>$FFr_9lybDt8q=p z(c-YcP#@QmMf%Bs@Wc^ct0&~{z(LnBVHO0LHgUF_#Q#Ma}nL*KQHG3E~-d+Y*b<{ z=k7l4aBmq^(^h}}6#jY)8{5|CK1+?0xY~edo=GJFvMk3NU z(L)6hp2MBxkot23)%R_ml9an35pH$F)#|Z!=%bZZ0IV+0=k?`Sio?oCw5eq)sju46 z;5eF)7a#5S^l*1U<+<-<&^P06Y@Kh;5io3%J820^Iv-Qn4E#b0o!u zmfso;DL#JDUsj3596E)4FumoGyL$|o{_Y2Z@}#`#BUjlg!~$S@o_p!+)I;R5R#PdJ zy?kGd)i_zWM)9=11bcjH+d=<0Lr%(Ldug_Fnsxy62@wW$J=%0$Bx2Vgaw4K33Bb5w zzt;8%EcCEcTe9{2S~ffRf$5@uh5Se+IFsB5_Z=F{oXO5+B0pyP6T_y_CiH=u1XT3( zm$!(c8(p1>bQ{tp#zFW!H zYxXv6Expc#uhaAEl~ja;I1BV`^oNkGt`e1Mj?& zb&w_jKQh3;MVE(%T8JCb|4#p2;s1TY#sq|e%7vp-fEd}}(Z%}0w zrC+uReO{zK+NN~Pm-&2lO0ZG9a%H#f=_RrXhTuUhzKxL)tBt#Q9Z-(C<9LUW!qDgv zmo9bsK9dwc<)a{~Lgh3o^{BHLGhY`{5lV>QeOZ@YHr-eEg4io60$%ZY%gN;+RI?2A zF^T`#*Ue#TE!QXTx2M}@@g35~?Uh|fZ+sxT324~DJMoPt*>d&%{{H(yb?o=J3*y|K zZ25DLKF0+pPk4B&c_pno)qkpMt}e$~UI1TjyKQHCcE zi^P>gksoH^zLn*G&DNeP=I+QhW80oeJhA>m%d_A08_AZ-*q~PF;cZD8K#1(j;@H<# z(7Pr+n)c9V$ZaN57hs&+cY0r>#3OfcvC8D{9NF;MGED%EN({2Pe$#pfeb~sg4(?x6 z+?LqSo`RjOU*-9GIgmC_-jq~7|0BgwW}j+Y*0j`aM35ulB=N1oLi@VY5CKKdgUXrq zGooqNgHH6(Yds3(Q)EhIhqc&TAv4$R)`fRqB;c@-}p!hANfD=&WgxxY8B z{!wF%V2;j;mC!r=?b{*h0<1Vwq&79gm;Gr|(H;Gizr@)y^he?VHEBAh>zf z{M?6*+!Nz2K3j|T-R(-AcH6H^%`{qPNdly6-NpyuYG!cR5{?4)y7z#wXJ^8Cr9Mf{ zWkNzQA>dQ3xSf24_92F#$@tpi!WE zn$LM7pHo#iGVy)1TANCUI(4A{AhS@8=sVfwVfoR zFFh4Tqeynwj}nxqcj~uvqx8?9@{q~LzC{3~(gq+Sku1dy>m;R<3)n^4f4EmtD zypLQ@{^+prOcbLva?+?)t6oI>to7H(`2ikSKY*Vr56T4GXzX{9gXVw zU%MMM^H0I@p2+TWo99+Og=MUL#cImdN0FIe<}t*IX=~J4b^9cPcPF6>1&^gj|tfOd$^>t7n*Fx2(|9JQGr%$J~US>o0(W zhR%0YAlQ^&sVetBR4|W+y?cV2h{%KnB|M?D#J^U|fFE3mD6!L3ij2%ek9ZgPJ~LDGk%D+2%pH+NGF`eKM=~LGrs_16*V{|bJ%KR4Fy^*v z|NU^y3t9yF6k%^Z9FBzp^5Z8=|2f<>^ieg{cCo6y#T6|{YlUh_>#3Ub;GRmu&Q~D+ zqeO;Soi7ZOUmqqUOgo#QW2HLaX#Q+)8LV%>sFs9@D)29Qp}+5lXoXf$yOAo-~m+ChQEE|we2%_g$2 zzs569-dF{YZ5sZ?_ zy?8BAiJ`x(?^j-AMTzB-TP>)?7Y1e#@}7ZyuP>O(-DGieV*aV#K0cSVnglY8T&Ipp zNtO#yY-4}dZcqBVc01)iwA=eI+U@#4yPZ<_F-E&R<(GDQ3?#YRrG<}(*Jl3KHLCx| z-CssU*}mbUunj5_(#?Q$i8#_jha!wfw-Ta&DBZ(DH$x+>fYbm(h?Iaxhaeq-bR#h| z46v{93H|-|`{n)cu6OOd{GbbN7tDE`_j#Rl97px-dGF#?X=R|@-uJI|JJB!gc99r$ zoOXNh-`edz|JH7|0NU*dX9J}F-+{}X%2058sCT#`LjkYld_07a?`iQ7K{glH?nS^( zFz+o@K6jWEj0*NUXVqyY`+a)S2-LS|Yt}`@hrK^vjLJzfuxn=x&bm9|S8yR^yZiXr z8c2IpZo3NDv>gHBA`0Lu-1g2k*R9s=XLh4eT7@C=oe8aqFifw>SX&uJv?ZZ#=P#xr zEx@z#t3PS^6-N6{Xjf{Q*Hn0S1K;|pj26JF2<+|D&lmNa&MFGbz2EqXzU{H@o!+uG zc?zF+;kLsNX}8{Pd#USeTYhWc3|iM+Y4l}}pEjXQKOI%c@Hd7+dfxhf&iAc7F6UXq z8i>dJF&_D-h3ofBuxo=}j{hO((Z5Zb>s4@kHOe!1r1BdYses~v3wVU zd=is(WBEEF7?YPXh8diAF%-SjFzB~%LDx6V_p!1_UocDdEmr70Q;6En(kqUaZ;1+A zh$yqX*~n#;>vhLMjn6e`rPnxv=)OcQ=ab%cPS3eK=S2M>g<=Qwzp`Dd}At&mI1Gi5%i^!EJn)}Nvvb-!0 z_T0AohNref#pl40_Ml5U180m|$*t}x1YG5jfuR<;CUV%P6k>O^kLm8JOo_43x zF+F`F@<{I=V?8=MZ z%?A4UtAaIwyp#9E|Bu15dCF2SIsE0oCPRTVM#h%ko4B*p^daz$=!E-D*u3vt0Y$OFqb|bN#X5!=xSGQtKgO z9+@E^uMvX}&$L70xF&z~diQZ8et_w3bQIA_?-jD)b#|<~NRfw|bQT!fe}!%(PmcH9 za&C)+Y^81(r2H&@mZeB{-4Kg3Attnp>5C6D;M%-|_Cywcc(rrGs9j*0nTJM{xwv{ZKkEXJoSSXIj zKaZ~6d-$;G53P5fiVXb^V8pBnler4N2&>Yg1{F*VVd;!bTEJA-s{k!XY6XTuLy(jUep zb;+iAn8R%6NPSc5mhe4AtXc!mYho|PD{T)03OLoXrz$}Cof;n5JUh%{&g=RN!DIZ1 z;|kG)z|oDdk3M~&@+~yC-+D1q*NUY9;&z~T;l)UMZ}VsRskBmsu`~~jxXWu8zupI7 zCin?pe7=gWtVp+Ygp)lfMe>)=WyagIakU%aI{M6#&>xsbobj=gp^=VV0v>D>qLafgg z0V~xFs|2CoJgCF!4?%zsowhcrf96`}iMrSFKSj8Aw?EDcSGPCs{^^Bde|zB*Fg}g* zpY8X7U!cB!LHe3^{};yD>3Ah}irO%5i!Zv4ZPFInFetH;iSC>lkds6Oc(iM3;?-Mn zTn~UlS|_PgnbYrT!^)?|US~_z9I->MAI_EF1mF9A3BDWc zskB@PO#t?WG`-yD>m&qn$sM&dj8ZUs%VmM_h4p;uW(oVkx&LPNG}h1zV9$1@u2?$kxZ zbSt%82zSdW(2Hd<P`oi|R|1yQeEfCjQfe)pB)0{FFmq4r!PXXToU%IZ;{-UFCC)6{ZML$7Y6T*Iw2L?qv=u2? zggI(TnfhbggJVQ^8+Ukbno~j=>D`lqG*ADzmLSXl;$k@42`Fp&9m|zPupvdf;un7Uv9Ut zXl!jj?JP?R#ss6X+wq=~9U!8wpV{FVkjp7D364oU?RcsfG=CUu3K7jz5A@F^6j>U0 z!cLUjy#$&;#G;Qyxgpmd>M@(wzA@u*JKGE#p8H<>&EjhkxkdWPi-C~M2QoG<`wHQ9 zJo+DbCa&zJx-5!KQk%Afy^w)f21m+=cks4)~!~{xBOH?M<#v=pm~`%r={G+yf7CdNd{<*E59VK?MysN zZqaYoQ*O&>yULzI{K}<~L}eu|05qQYCpsLBnwwre8DDDt5gnVZtZe(w>3yze{N*Ep zfU;X%*YQ=>$`J3K*vXHjUW+H7&j-ym8g-dvFTb+3*D_$QOi_V_?}YPZV4uiqi1nw57r4PXvS5@Dwsst(*ey~kp-XYeAbT> zhL=)ZW`gq;a+l&yKL?G!ZVca=WjqsJWj4ccGS<`FrVZuC5n7rg7&=`ws&HN_nY|9r zbejog3)zKMdmBKj&mGY~y-HvC7B-Ot}M<#585Eb8CsnT*Iq1N?IWe(n0->@}B?D z5V&do3GT8y5pY)gBfWDl|5ZEY=o6P#0#fG>{|Uy+jFhZ)F?J4%zf#tZOQ)*j8c^r8 zwb_g-4{Bt0pJkk;-5!9KKh}vb4;+^9YF77kp%4`rkPB+yqjjlX^>f#*E$5zK84CIAv8tVUFG0D}A$QG{LMlr#n#XcCpg}aIib1mH6a<)wNt78) zdJj=BMjl(t)pMgGy7&Tf9oc2iSOSdj9rNH}&%oA!q}zRuX!KfWxWT-Y(`fG3$LU$m zQfXF@Dp{PEt*f#{J?GiKJ~YIJn6?J0fL&EXk(6aGd2sLf&fNy22iCYLT^VWVUzxYe z%kij{8P5ydlE&wHJpTaRMmza$?pIRQ8yHCl1} z@dZ~KK((~&7`ZyztC-UoLLONn#5+#cvPuOp0lOWhhmO(7-FAL|mu}c!)H&Z_o`5Dt zLBeg<>t1@wsbq?N>4VYP)JcHlrfJvck=X3lNj7rV=^(^Qe=MR}yQYF;fs5NlFdn0WR2U0jbjosgHL(UMu=;uqO&z!6|En-qrP)%PlO<!8?rZgtLwSDa=r6H&9egwP zm1%8>!vSS6PvX?Pz;C3f?_mQ{ic1hNvBLwXkcErj&aj|mYhZE0C)&Z!fvIjhU`2Ju zf^T#%-NP-?_jz55`d94>`Zuv5YSN<)Y>c$woshfuh*9eJcbdM2MBV_aCez0Kb0k+S zxiv8*y7<;NAc9qMq^7tX>lrN)irKth%!x!K$=4iNG1zTA9roym0qCS7FrhnG;GE5U zuY++he_H?H?-l8ULhs1ST(w7c<;f1rxWut z&6off$bDNOfmp@v>czDB`S0&SZfgC(cM}1!)R)J9ar+gBR_K&#5zh5diUBgMa7vZGb>Hm>(r*I9?lZ6DN7PV+Akg&jOBKdf3UXVT z4wBCa@S_{#Iqpv=J1u>y*TiLva2oAhMpKWro99So7~b2}rW0^mAJc1!?kO@#x=1S% zVQH65bX`m$_p5F>8(4HJB0@hCgmAy>J6~E(447$>p6P?pqR8@~duD0+_X!Gqqi7qu zBvNep29WfnxN+mgDBjampxPw!FdbGqs^|2(Q*KD~3-+C8!w0ddIhmwyoW$10Jws94 zt@9~1aWNuUwv<4Ne_A46&WUbeLd-3=4U321?+F$kq#u`P2*k?FRm8t~khmqgnA|3{kxEdkgfl7H)5%@OTqP zAe7A`%)DvMB-0=$ePGTjn#F--rB?Ri#PZmcH;POb(2L1PP=J+%iUNN_+qnd2aAS5= zn|x63|DRBqi(q`ik73e=glIE50dY%q$r_Ko7|!D=2#Oz%v{dTdNi!h$GVKOq-;?Ds zQ?MiVl?{lMi`E@9^S5**BB8XVf&Yb_e~C<1!Rnj>{r>h+MZdCLSsS0ScTcnW9~u4=D|zr%4SCu*;_E)(xvE>8 znt$tdgGg_pj)SevX0UY@m331|XZpZ3NhO5!0Oxkc*bFHNd(BF8;3H+3u&jYj(WGS2 znV#5^rJ24*$u3`W>BXv2STVK=lx$1+ER13ZkAYr~4(^xjhP;=`Z{6yDB%AM&C`*t5 z`KC;3A=lU$sN&d5a+vF1ME93po5r3}D-W~8Rckv-Y4%4w`PJnXCUd5Imc)%2P8%PJ zJF|6{k%e8o58Dm$^2D2m7wm@~r#*Y?#2Xbl!c7W6Nj9*VdCMG!Ue!%T9^!WIf%x5P zpc%!(^g{Yel9;p2!^AsKAR;iN^U->AfzmnqKjRb+{yk8y{t7YMWvEnNvmZ;h%QO$> zfdVio^!taW-zQAF0ukvaq1od%%WMvGSe<&Dz4)(0c)Wz!UmS|vU?f@9;>$l!tlLOh zs{hW-ZNb^Oh?U4T7E@K+_@i*TeIbi{GR-~5511)v3E>TtXV+xbfhU(3?BgIbU5gUM>b4$3v%A?TxQ7lQv0&WjkEtz*0K~N&RG+FqE zy@P+*TL;)13NX|1J*TpQ4J+x3^pX4V)$4zgn_A3ARtcrk_rP{K9|)uQ=nlQDG8HFZ za(#>^tIsd~-^G5ZMOhF+y7v=ZnE$w#t-t>25x~))N1#N_`0#qsbw4&?R*H zP7B6Vb~rF$fQO*ncPW4a6GZ-I4&=Zn4+m==J7Jb4uKJzOH97v}CQ{UCN_%Th5ySnj zq87~^Idx;ftN`6>0!u@$yx#`x8g>_cOfm z_;*+}r2lo>Ufrj0ee`BKxo05B^IyQw-^F(p z&d&EGsgUM>7T;vQith$;KOQ4pVHhuHPMb}Id^VMC4X9(|wSBzF!hEOU*;*`VZ{R z{{N^*ThvjHKqT*L8{C<9`P>MXTzGp$0*8=0-&OS?$23BX5Mk2JZ?*Y{iuBq+2Tn!$ zZ_++f%v?LJr~wZ6|AEO(e?zegb)D9Uiq!MU2F(QR$KV?%%GQ-;d(**wWXsZ3NjO?! zTu{=$$|$CCH)E>(zjp*c-^y`Ssg-9Mg60pWcKF2xxK0X4B~+AjUq7A-Do(h>(WWz# zS)eNVCGqm4zl+lW_Z;MaxO)jh68c0jF!PIQm`8r{LlNZZ94WUUbUCzmHU|)X0D1N~ zNRm31W^~!Nn`bF0IaOy1IbbYUHakq$#F7$+N=u1rHCRa7`7x_oph0r@}t7ayrjU6@d}!z_s?^gJ@xY zBH9!xyITW_n~;3@m(9u++TxDFWo_QuK5fV%y``q!iXGF|0QkvPV+`kPFG+I=X>0e* zp4=UF`;Vrwxxv`8wN$(m&E~_?z#k-!q~xR?$w`x(=$amy@|2KdDl{_%>6kV?&uC$g zznfu#)-W}>YZ*qPAI7U-3MYFX#BoiD{{eaAnTLfdp?%MfnsLK;UgydEZ4oiSSCT!W z^80J{78=GS`RFKEaWE5fYP|g70bYxm0`;;uVwp}0{gi+Zb`c(w!}fmsanmu+7&Z9kMERrYt3g6yOJShgx*de4hm!UTAO)jO!W)4EN;oU7rFwMVs zSD{Wl|F*p3x72*iD^#BkuCzhC+7v^!`rm4MTIVw!PoqEO7oN6x=fYYq^|4!B^1@iD z7zNvvJS(CpNX%46&zTod%|HG6{s(QrZf2S_f@a0{Jfg(Nb<={6CpU0X$*E0m_AFB1 z>6c6Ock=)PQlw^YkiNuk18_LtzP1D(S?~E@Yl%XDwN`dM6lni``1YlI*e`2Q18ezu zkcm?ozLsYaYhWQ+#^<}5fJ3_yH>N}huf5iv${`L-t1{7TRA~rclu5x%1xmKEd`WIV zLY=VGtWED&0z#oIG6c273otU&(I|$4@^rjjSbSv?6^-rcCCyYu?7TY~X=+w`HK*-) z$c2}=MpMgGLu?S83-Op!KJQoVa5p=-ApkjKOPbV~?XuHUtc6h6nHw61lQtxXhvg&H zM4%VaKKG@3!r#Jo8?-3YIeglv=%!$u&tIc`nQ^UjOXV$ItHC}qBQ};cb?0Cj`8ITw zq;brt4a207O$9;S>8%(G_zUs`pXvhm>roIs_!@C~{zS~bU;6bODMxwWe1p5~x|6>j zeuA%|0<0Q0X@8%jR28GPsW?^pncn--WjuL%Nfj4p-)v_}lujFb^C4B7qDZsFQ{L3{ zXLE8$Yi=Y{0N z8%tt5*ZaG{B+n0+4mffgI#A^b*ezCeAI8IClwx7rMPmjoH$ReOJB|qGy&-&&IORj% z2CoLnR1AkuNmt2gn%t(0WC(pJ_PHX(1sT>Ll2Weo4%{#Pwi3=Hm%%MkdhKXy>?<|S zaR1m3m_!igXkQuLlw19NI6#VA5!mlg;w>2jRgb($bh+pn<%Rl748aOJGktF@_!`)Z z9ZI9L6|c`U>K)FbQ+|-yDIxjon{R6qO5T7@H873Lh1T1d1P;V?vz`*{2k>L54&Tb^ zu#^}u&G-JretaDk8l*ha`MJVd z%!dJ|_9@KWcld(1`JFaMy@w7=6|-0*eGGjfbcDGNASIG+nAZx6J@53{I10Q z#jI3~??&EKluh-5!7j>%xrlmki!V45?g+gZn5Jes@+}X>;=`Z@&xc!ka2lO9JyDbk z^Et=*q}R07IMZ^5vBy+Qq|)n1&01WsmFB4ikCh3DgTY8%vqu52)Mh3LAd|k?gs&TS zt~&0I81I9N@t03relGkD=(y;gPYvQx{xhPkG3cM6J_Hx)u?&v@W#S6UmBW7!pj7Ys zmo%^P zojLOyh+Zz6NUjA1J($x9W5^yFnW0;e-QC^HWp7a2-7@8kghs1_i}66pFQX1$S3uxe zx-feQKFdCmU!;n7C?BP#XR4SG0g>D#pxv`0vS8O?51#eR~R@Bz2s@uIPH^)j3~B^gd3SaR&9P&6Z< zR|#3~Tjy{z$EGxm%raYcp=4t$6^MLwn)84@R6sFz;EIbT@laDxF4=KR4D{Z-wvj_V zzq^6#{#%a~HOEc)4_br{D+waZv;qcm0gvP-lLSpj@6AaC-e$-9LZ`+D{^wi&aQf1< zHkruWTLLm#tmj{u|NiK2pWy7&0Mn}x_+L9&2I1^9En61<`(a?GFTd;*NJ>%~e;DL_ z>ch?a<7$n1Fr{yVND7so$T($T@3il2lUbikW`-M?9@x9Vfv5~@M<`)*>;ZJ7omD12 zoelbi8xNLGvd>rJ#;hO#qzOG|f*aEjiJ`KY?hP#lTV1^+LrXc*#Zk$0;AOQ#QQVVr z+x3e`!I&F9#OJzS93#gRO(2a9z48rp`!vYTv|pSGn=rzd{8xy#RA6qMje_V*7K^GM z=ZpsbuoB_nEDJNa>p*CbT9_L#g60w<-{2x*>dyy zFMIik)D1w04ztva&<`+AX92E8oW7Y{H}ptK(eP^djA+O^#vSk~VoX(2Omw;VMGu6( zoKL=#jA<49DyTrGe3LaKIW{7jyr(TG`?-`5zp(;NiqH0f(IJrHgEe=mA{GXi;-N5% zwzw0Y2g%w1<vRlu9I%%}R$;97>AG(8Ui$j}6-BDGCBVidu@EI#W7u=tn2efOX5I+eL8>9k zgS1tZmAcJk&mxG?M;-6+0+AqhV%$Zan#hp5wtMrJ&v>}qKH#QEcPY|Y5o}f9+wBrv zSJ{`fnP;`hnuMUX{(ljt$iVw|6clrE+2WGw^-olltOi}p4Z-cwOHAAiVo^l)J9AHN zrF(pX955f)@i4>s1hhY;2Z*c+Q^JC<8tNce8CJzn8t*owRKGUSU_2!#Ie22B3X`j9 zs#WuxZ=p=K%rX7O(iD{}yu$GVe$h)2x+Seq|2%FUMOXI5C*;DdxOC93Mql}`z&1zv z{gddy^>Zdw#PgKr=4KY;RHNxVMJuEdc-hqQ*pH;zSfbS*9q^YRS5U9)AP2ACY4;p3 z=c8%zd-SRg(n`3sT;udhR(!|jJ{Qp;Xof~2@gyK9NX*u3tKb_AFhOX`fAYC7<+sm} ziQ^pXK+#(0`TsgtI5BWAsGH7E{_lsWE)1UgQtIpkv?*FGe~VGC6&Tv5 z+`^b^oCqT=n-NLe=_ZZs|7#aAUX zrh$zxe4+H6MNyI-cc9Q^HKS$!%b6>r+!E4VvuSscRvZc^#0i@CeD`C6GP+2jTkIY5 zRuvpfOL3Y{2MU|hY_n8{OKh`82h1U+svw_4tL?V)GPU!nsYE4zBPBhK4CVgGEoq&P zX3#KpDPhYoX?vf7ps}vzFWl;Vf2xDJQU$SyT09SLvs_X94n&{0q(NN1`d0t`@5_zj zSM~P|Ic(GYhbcf^oP?|NEcZSa82)}3WLCn!-8weTgG%qjlT4h%g&p6F^MH9%^P8;z z5UgRe|EWrT{KSI(IK)Msu9YkVm7y2L>@)3aST&pWt(P<-X(f;@M3dm&tq67gQh|I# z0gGgL8>=*4&K1eQ1SEE*9K)&V83o_>h8HA+r^Q}R#R&Eglea(0rnp~daXlrn{HHbs&o@JZy)(cvJd^lg*1AI3=yVoShRF4(IU8*P-jRL2IK0?ib z1jed4kg*;-nU!gk_w*C5<~NB&Rt+`1Q`FGjI(VYkvbQ>nep;wk4h-a{=BV^2Af6bovS=wep~4p4e+kGp4mdpoI3roq{(!Z4j-wX)i=h8PzRf% zEpcw)`c)s@)92F%ErnLU*5KrnA7~c82sAXD{p#$1(&lyEhIv$Klq~#lr3OgBa47|2 zY**{=9|ZC^CSzRb$oLq5Rqk75PNhoe-3-1DhPn7om4acfAAi{EFK)R)blJ;=y`Udq zM2^X9B^2_n@=NOQP4g(o^XFi+cj!Y=V)D*Lw5x&|Bi^ce+P)}$XTdABOX3!6m0`-e zuCj)9@o*r@f9EmsEsEvi3;M;ziZ{8h1!S`x^+$2t^)nKp`OXp1(@F_*l2$t9>Syk&03o{i%IT20cdkS(V0_>Ct zmZmHW#(X;i+BT9Zo1giNcama|hxqlfTBHQCtw@X8c~36o-+`c1l81_P%NEQP%+|-N zYzHSsI3z_9JFs3po~0ae~4^^IS3k6m1sak>Fy1bk8M$% zS!-7z19mwy3q)xDsM#WkaPJEq>$brE1fVubTo?}20F}r(%ax<+HX%U|HkGETf>P#k z8X}1Jy{DsZClDEsEi6stJYUaw+8q>>>yPx9jS{wuftQzXOWH2wA#(|xu$4jZo?cs$ zP=4222bP5{7;Yg%M-N@?3X0Im?zLK=TGbm;k}3lDV!6KSW&?$(M1nFPzmB9CrL+!|!c z`O94Op*4$Y`Rs_Wko~R#Zy|M6R*VtU)P4L|2i|tA3(%Ll?r=$i6SUeycRL?%OxASe zhS3RpkvJI;G>_;Zry?y~uRlZV160I<9klk3vy;M|-BI8VlkXP|TUlORzm;Lo%T4jn zQT@~-`uOzwE4!-L`;(`w36*+|E7i@$wW}1W9`7ECa6#KP?u{ePl*gad+~6s>fe-Ib zJ1I;)YgcDIiW?f4ozFpuq`#3|D2>=x6XHWJw!Y);#NZ8Y;rRH^@3{n=@eMNgVda|ro5*uv-4kLDu7p_VHFRfo94&No>i zO^$d?{D4n-A}hI>2CWhF6M(~PqLB#wJu!YmQPo!}4Iq}ixSA+k=LK_CkYFb6{^%q< zXu=zOd<}Noi#^%@0Q7|R)Ns;4w?itM==cb%gju^BgNIodO&s5usuJAdS!jZc5Zkpd zOCY*}HB(ID(#tWOt*D!+Ynx9s6i;pGEtSmJ^MDyix$X(TSOoFkLIT4N*SN{*&A3lArWVq}T_I88~K z`6ebbG!j34grIQq;sF zI(`MHqUw(F7yWGL2-v~YMIj*cJSAp5a=YSW?|a}Okipw%Q&+PCa@#e4oTCbAHB<@s zeKa&i!?hOuNL62-9PM5|MAz==?E^lBS0D5SCAJt(H}Qr`&6O*Fs5w|!Y-Ot`OZPfM z0Ify;-CVWIaZAZL=QnF;_WPL*AOlajSts8-Y*vAc%rNNKL*^D|Ah|FrJMNs7CQoCQ4d*@8_XC{8;}|KQ_g^%rFwm$Ca{X6bm+QaFd<0B zNzw>F!|Kjdu|KYhx%cw#mhdRftq~*geg*R|lfUYxVx$zJr6Og3$g{k+euhY0mnowQ zTR~hP)k0VZ=v4&qQ`*jb(cbESBnz3(H5AcdfGE)?1xu4gxZ}xPe5!1LnrtB>?@hDVMAue=1&US^5;M#a#~e|@(&FrVd__%oC^@SIUIVj*}zt_(8P2Qve`uEwG!&U`XxsD@-!k=*_JAck}V&l zCVaaiLHJTe!X+=cEN)AVK(|2&r5?R)fsa6xNHdKJVm148GGCK>xXRw5!eRNb(2KrX z6>iWoxmcr*-)+PICxxL9(E6^hGsjNmj#q&?a6!~@WsXM3X07gM1yxKA{r)yV!EI-0 zI_d6<85nl6(ZtbexQPB^rOj|rYBJO+J6UuWb!XD}h1(tDe{<5eqQ4v={c&S_szF7+ zF~ND|I=5C8M5Wiz6D3`VEA^!K@^ps6)2F^=NAC&@(ZQ(63}4hd5_62`y<6ed>@4Cb zpdk$D+#h@rLs+CbOR;`@+4y*(jv{u%n9nrqDooIras64X<10SrVVBUfBCE6dOUKT} zpQf|L-5#h;hCj_UL`R`EHoi;Bc}*G%JBi6+aN^SHld~V+qb7>;^sAl+=vSGow>1XOU=Vi}mr%dwg=Dr?>fvt_v*bb|#3p z4ZT)>BUl=rKJ(sUz@JfIrmN|&mlJNFco-DAh@i&Y;ffILC`=kjWSN`tG4+iQ#ty~| z*`^Ao?=;;(x<}ve3SP+`&gb-OQOel8dUcLch?j{BNtCeDrJ1rIFPfporz9U_Q}DdJ zDBi|kH%{LytCG@0lc?5CFj^6KqN|iRl}WLhY=&DwNhf??Ms;B>jvvtnq>{t%>&7J! z20=qz?T!8%L;_vy4N7#Pg^9F~PTxm~kK?ZDeoYoK-pJ{487(o9?`5>-y4KpsU*9FI zHDlh%kLX3~i~>;8L@Kye2_I|lq;ZJa$CjuV(gi zj~Sa!wmJeBE&LDs|4uoiZph%;UXp7qKb>A1;)yd{SnxVf+}{lyo+Gg7Ls)2|b@eNb zj^D4>aH1)C(gD zXJ}(KG0o{V65oC-iBD)fLMXV?qOa7Qak!*MrD3o>aK2otjqbjFDBU~SyyEt6MrqF+<44Ytd@oG#_IYI_A@%X8@hiedi<%)!b^B) zT8x$-~s|S>NGV*I2TOm-!D&5qq#sT+W>SDz4`{OJksXEnDFP1)kA@ zp0)GyfS0>{hwI7Ouk5yAd`GA4x5xe{xd^=Ry~9=7^h(Ww0WHLAW{9S<-t$WYAeTO? zeFiRsl6=lI|Gf=q6;~UlbZ`QXptvpwq6flk#=A@6i@l7#?0wL5InXa5tok5R7&bB$ zeY>?K<$CR{!Wcuh@Pp71d6+P_tprv>)`Oz3mUF~JLi9+EER-HXsP=NlARig7gI)4J zPTC^qA@wEr0NgJbh?VQybZr{iLfm!amq+f1lec^ zgjs3`VD7gr(JGw6?&6;s5Jy$&g88PXwJo1R&`g`MstNJV1w~gKR2_!Y_x8<;-XWqR zaq7FXDNAIlIqx=v+3(Ge?C8a$AFJ~tl18@Fc-Qi`-cCZe*D9e1tP56!i^@CyVH?d_ zup}<)mXixOG`L;{=$E!?-k%FU0*?=uZi6;qZ;C);4`3d zO7$7J`|5|dbGOJMo6WGX-KYw zuX-sXrF_d{qjof%;bz&v%6H9w6uiM#J`H$HTZ^OXyq=Uq_mySDz(vpYo>ZqH9()i7w#qDgwgYj+| z24&sHW~^o<*GE43reVaaUMBL2FJ+&c+!T5>ZfrmH^}lH+7#d4CvYTza8w7B@29?A+ ztc!tn`{9X(8#PWpX`Cj`cKYFsgr^6wc;|hIkWQ;Zyq{*VK(1W*HWU-<bZH-;N}4s z_chQzo6uCnfCm3BEwQCaVuc;OMu9^_VK))AlgCtkB)qDrs)1th3sLgUoP3bF#JmiW z{{q_o2&0ImT4;(SZNN)*Sn6$umxL|FsUMQ%i2q<6piJZ*vIvEwjqh~jimu!j_(3Ko zk+oaOo=KxZmUs2?{R|&VIsaak1IRfRMv|b-_k?v_5QeQMTQMr;Tr(_Ep^iV<` zx&Dy}*n?blNtG2rWH7w68LZl(Tz2{BtEx0w;f*PD`AF3)&Y6;{jaLwasw;_~M&?_C zZlvxYXcj`As+>fnMGn51a6CxYiwVJ{ckf%pDIuXO*GA8WQeMKZm#W(vvpTK((lc)4 z{&RkB!kKXx|9evNHv5H?N7-mY z6qE4j@#L%OD*MIC+WjA`!;^xa{(?*$E~Y!1w!+>twfOPG(iI*6WO)rZE8)n-Q-CoJ zq~u;qb+)M_@;I2A1ZdsTV}LbZb?#hQCKTWNym|AAezlMT+kY353hqLB?>;tW7{U=j znX=nLZ_|(iuhB%{Wf5AYz4(_4z$43MR?DVFJ>A}srW}9W{s;9kh38)MS-3^GFVBD* zQr$OgoX%0{hu-PPrz@wGa#`PB^aR>&B>WfkR1!v+@ zBlP*woe@Rm$aJ<_ywEahZ1_{E40n{Mgi2Bo(rLDAmNRgv9b{W%bExxVev`Zcka)D z?{8f6irRuj?K=S+cBT7fgX6}Y%;z!wNE5(!*dfIevRn4-tDVsJYhN*dOuXprx4#9r zT!RgV#3o->OpITqGJDKyI}c3w9?PNXh&PdD(XV%)Bi z_XN+K|LR8hd((l*kfN#u8t}cu)}HO{&;G>UL4&iE(QS2r^GKbl1W0hhT?0HW*(X*~KlRmqc` zu=KBhrnVYzlMYCL6#o80@hvYr`xK3L8-mt5jqZCO9~(SblspTb=$vOO z?CCcv1ManE#oc+C0AsyMuE%yHpn0-dAXS|~iD(B@?OrjxTA>uY;=wB)=P2Jqc@ky{j}598RFUJpMc*OIC;~~PVSZ>F9L9{-4EZXP4&RMH4$@R?Y{S4-|`wAuG_tS ze)!ecP)VZ(J-i^qpFS`Cp?eQ#t;D^S9%*NzC#-KMADhm7a&&aaJ&rw-NSgjQ%Ex|` zNr1+$uG)yO>o-324DieeWe?c>vek2BSb~UqYN}@B$8(f^@cErh^B43TO9xTR(427H z=&Om@I@gmS0{5cJVxc7$$;Cp$Ydq;oI1{|?AB9V|g*Zce&F=NaeAQC8C5Es4eaC$S zYBS0GAs%c|t|0tYzb!62(Z9QOd4E1;(R^ISV|*SXLORi;Ci%7a`=1HrdB~$dd|lwK zA87ABfAoAqq5k-66 zc*?SEK2q8Adu8(qc<;>GA~T#53WRnLZRgu9K}3F*q{*g|G$&kgu00`=e7{+28#VDm?s^A7-`QiYB4h_U$9^kyou`*nk#hniCdXIL-(4me-d?AIBun>9lDOE2^ex8WHT(5kJhbGdIZZY9$;ZcZrY%c%0 zqN`aal_rmDqPaA4lDP&18c<{7SLGou^CjS|wnS2hv<#B*(k(ftgZ;rB_CP> z1Sm^}!2y?%lfrVMy0OHao1IFYa+zRzMAE}ya@pVjtjX%FT%?x?vn$Oeq;#{4OfI(z z-%5Y-;@o|(dBhO+AQI%)`Im$-T#0~_qmx$%V)cmM*$Ln_-zH#IGtFjVHsnEGI)#@XAjyGPZ0KP7-#Jl`iJ(Kj5^`=_ekvajmu zGdR5e?vQ|J*y}B($3_LX5tZ@X50ow15_?I{7$Jr|$fiFz3*27K3;sP3pt_KVuc0VI z;e77?tUslZ(vL=Ix#dArP**n}bd8KG#?OHcQu2w#V?It>hDYpDNhXovm-`RE3z>oe z_lwAA;u&~xEJk*NoR8+rE7&}X_vT{YPWB6A^wJEZ4|4U#j)R?LXAlq%HQMN}=ke&K zK29RsCse6AW!fHJh$x+HI;SL+?zyMSlo$&#Jev2l&bx68oku+X7j17D6?NDB|6fW7 zB8`9&LrF=9bPdfY2#BeTSc^3y&S%cqXP>>_@7M0o_!(H(N+jNcy7D}5WxrQ^r#jKdvs0#W{>1*#2Uo$? zsD*73*N^^R10gNjuOxI-O=qV?%b0FD!sjL|spyI#?H+ZQelOO7+xei{sJ21-K;@^m zncT7HGbCr^=oH|oqR+N`I*&M|c+qb`eRuFS4WgL4a=ZnUJMuf%NXqxm@%Un;I`$j7 zg7Zl|O@+De5%*lS3t^004WA2m-DzCGuPzs&Q~<2`(GF@=}XOM>p~c(h!N_M z&>-3gKpkH+k^<-R;!poC-oIn~2i(7pS=X@WHiAdLEr=3p3iPyO%k}8i;>6dh3P~-! z3WbUyY=wfEu#kloR^Pq$n*Q#nV-Yr=)zU0BN|R!OlN0|A#!s%zmA%=W0a(t~%aXLxS>|xm}6k7BV$7BV|Xn`xz z5t*$S%A(XY;OZ;0*vgbfp0;jkR($Hf-S$y#H?C=PSaCPTcrw_f7Uo<#d>6$Oluzjp zT|jbDK*a0{2QUkDq3;cx;}eVpqy)_WoT_V7CxkLV#<<=3;83N9+uIyd5dOH4;ko`& zuY0eP0v!!bQ><(0sVIE9J7$TTt_Aarr-$Nvc_%ESfn0%9xH?82T1mN0n;>`d87s;( z&QACKRkN!s0_9`0KHk-DpT+nf^W+S&T*Yx?pQOGTi50aST+NzNl41f|Zy%BEVA31o zK4e_a+B0M?|VFmcyg6NTCFas=Hg!6*j-zqdNQE zao!T%@+kZ<7&qnE`PGuwWgqGzktB@EXx)v)>y&aa^E&!6?uV;eK>}~rWLSseOIhtI z8DA$teLE`C#^dfaJu~4SC)i^)Ddz#N218n>%RS=0oW39Y(>t>gx=NE0-FA&_2zl5R zBA4uWIHE(Y1r;}+quoi*nFV(nNk%yYl1^6jwvdgkeZYZ3`z=fC%>(R;A04h6;zP7&h++-B1q*g#Gv|F~HT z#YQ<6 zHeZ`#SJ`AsbB+}U7W;s^;+19k252J4;4Se6K`V+2n|FSOk2?Hq+IV#8!xIs(2YXJ^ zwhvrm<%mRCHrEl!8J&QS{P2_XyFmwkcocGGh1L+SOd0!&FB%XKusR=>W<0YSE!1O} zDN9M+4$YuTr?HMCq!TV)J<@60bE=uJNC~<#zAKDnF6ZMTbTET;!A&|xdVdm>BIVTJ zb2DU-y4jYVAj!`p&R`?@JNNqV=68jg-kDN1;VPr#TGTN~>1?7jkH2-MvNinu0y9ln z&r&OG)A)AcL&AxH9P7545ptiwySxr~H7v&u<~>qj-f=MW`|-q@YJtUeV@WG{H7@H= zo5J@5!G z{$i2;RQ<*n7c-laJPwx*HeImyY3#T|(RlG&aQM{Wd61FVAs9>L@YZv0oh5gEF(cBl zNZDcCZ)!@43DT|(uFlw?tp@BGIiRP5>$TT^adyPR&(3^aiByxSuuYk{&!&W9!EElJ zdM-zN&gkxQemHjV_9R?GeItR%c8STn&Ah-xU4h@nW2fJw8z6oG6MYVsn4XsQm}0Oa zCTq~dWcuq%@}qB93M?GGwM_s-6aWSJw76y4LqKTlT?|qw>=U%?UIp;hK?94S|90ws z%hS7dP_i8p&d3Z8Q?*Nb3CR1zzW1|Hx#IUJLZgbhtJZVfw&O@@L-N^WM`7R?O-ntl zD6IZR6A)lBRa7Syd90sd<2JcpEK|_ioS5`gV5_?B2Ykl`W?)wG<7-9K8kvEx5M#kc zXjI?=o{n!5B7&w-xwgT4`ee1v5Yw?TEQa15&3droroVc!;n2yima3ctKR*heMmwk_ z%$l(N)As-xrhGgb8`;rQ`=z{Z$JI@6z?gl&kdYl^`1-3^e^wN9UF!JcnY{^&{(; zti8^Iw6kBCAr!?QSUNPCsqh{ma_heNgYp16^RKt~E!e*z_GCFuP8el{&cp}4K5q#<~E-3>fuQ?k@sJR&TfCdse3 z>6m?vnR^%=n-xqV4I2yRKF;1Pr*f+18L!rL;%HY3U?*lXM- z5r_^6>N(9tA*@Gu%PB?}gZHBK50~U5GU1EgAnIys_2cj2Jowc8P2W6_aU|RDBgtZY z5ms@%Ti7;1v~15zJ~y0t0!&ral_GS)d$efzPUWzH^C0tdSl!5`kaPs8SftyL)2MJ7 zD|N_V8e=R3FDtmFxTn-d`!TXZ=k`DW+o7LIO`eQ|SfJ=3sdHhdP7nK~R0-i$hiue? zJD^diL<|>_rPO0Em+6_maSCQiFk8+1@cKT(|l_==Hx zubk#H;{1UyLuDD2Ez_;)SN+v$4SsY2In$Dq9c|XB)Ap%iV=RO<~L%1K?Xj9o8T6`{}gPq86@dB~a2^$ot*b-XlFQk^)~3rsxi|F*k;kY5YzFM&*eT{2P#JnVN_T%tl{)!|3WyuI=6$5 zW(HpY$>Z3^)ar7an%UotbcN+@40Np(r{xQoEe&A8j1AHeUY{~VAc3swSef6VrF{0r zQd5UDi`-R-@7G*Uv)WsA}7UbwBG!seb4oB*o%S!e>EZlx6Ztg+BsSead z1XtA?PT_YGR1$dg(+|g+%Ae~~#e-WJK*!aBJ9Z$|?ejBYd-y3gH@tQwGdv8+r)d;e zxF=D5Z;VI}(4q2wm;}?cY~8r+9A>8cg8WZZ?T7>=?DB&u0i+V8G3)T42i?*97sx3F~TjF_tya4rdJMRy`y`HdPGQGIT)J4AYSo6g$3 zJ>7N+Usg%&XB1zs>entgNjZ_j=wptZ*PY_52O89L6P?ZHgw7!@DwX3LE4DfhTV9l( z_^i}bdY#{YVbS1Ika99A86$Z1wVUsV6^8b9JWID7DaUE%3jm+f*7k7EF8of28!F80 zY%+Vp&$b|I=lVq)WPKyy(dE4!;p2`LjdTY>;f<#^hD;;g|GVVjcgTS0KG(AaypB;8 z8QlG0H+Fuh^~g0OsyrN@8dWUq@RP@|RwR;J-W0_Dn`PGOp2Ec<2`6Cq2vr9p2Q)hP zNyLp^)`vMn74M~`xbR@kh7|zxDhkN+H*g+Mm}|{2i8awgHwB}_n9NZRpIl%OjN!v>SFmmtsszM zf=W)cdJ_YDW3Br`3<8}I-{=|BMc_EBd_A{NS`tpq28dF{T`jl`)kNsiJ%h$Vlayc6V8AIiD-3_e}hCQZxmw zYP|>MPTfU)UT}$3Yqp0o>`ho^)Z8tp=VZRqB<*+r!RE}a$J1N9&2RD5y8nX=gOW^A z7prBeL+u9WQ`~Dq6u=|77B%2Vh_69N!$PF^bc!A2)~D#A$hCh|TYkxyU9)#dwCawC z0M-4>g==h6Ua$4bUOercz2O)qRUVy15VLLBu)Z#6y^_##oRNYK&b&14e9sat6If^` z<<;qpLQJ$tR6;?E?rXP?35>^eSxLEQ(q%f5>VkLkrxqEb^(28#jmPD=li1Wq@sDqZ z)M#63DmCwJ?~4_`Hh4M5y6~%wN~yEMXQox9YCGfI4ie9J@;BUKCoc-ey^W0e!#>{;7K~ z7X=+rLvO|U$-e!&Ii&CoMY}2fqu+(;|JWF%>3=6;v3HcwUSAgWSF<~E?&Ir`KpA}E z-$dhdE}d?axVdbs_u*VDHA;;Vn&MIg-lAKo1PAmTQXhsEItTfIYfM&G84C*g{CDa> zPfsQmT$|2Ygawcf9VMPYpOEA0MRyJ&P0PC}sidSfDOqE+70Am+k9L}Q>Ne+9Mdq-_ zDy+xeX85KHUg8=6u<$lGBf3`xQvR04;spQh%4LJD+(IJmF~K&T#I0(kU0wOtrWXxO zh=0m*8|+)U#_k9a}fWTWrVtksK3hi^3M$3Nk21J>bE-1rO1G4b))p+2gj6I|y&k&R=AB7$N7994RX;2&| zzx!?7j(k4!No8sP23fG^OW!hrquO=}-bgr+mb<@4oz2XUR7$ibnq4vWT+5jA@|y8J z!q=z#afCqhH2e>v?G!rkz8#vV@d-WSQtqs z{>F>>7Ox&IF?5Fe=~wowc5te!pZ?mSaaNN+=^TN2lg0R}|E`r`3XIhAGR}6=M7ZjZ zm;U+{lFUZ8-&0qA19g zoBm|G_l{dlvcU4{jXFHNf^&yA3ljMp+$lRwk=AubH8STX8LG}0RYz;ip>4nvrBtKH zsuGjAj7YNkrCL}_uh_YBwRM^I04eX6nc6Y${nOpI=sVn#XSFFOr+C;EeU}m)MNh>_ zbRPgohT&Ko{XU}Nd%&yF6t|l9mz3!L>J|tPcI}ePN@QCgxduw z96S&I+2mSO54r#Hpl|9Z+)_b1<&R7X=r;nTRT#`)t&%>!<6UxtPHgyaQ}3V|+f~+7 zr$p3gnT7FieZ-0O=nbgQ-G!D%Py38>bEE*cQIE_MSs_-&yJLLO4&KoI>z%k0(bK)M z{7^QY1UHR7`DrpH6f_%;$d3=D67c^;7 z0-__$!b||BnGUp^)#pbuGbsM3cg~yU_N9Nzd?+x+oUWZYQ2qwAfK&<*rnl%QayZ3k zbQuDsH@AXk&0|El&==x6aA|*Y0)4*_6-Q`{EwyZ~NsWq8@o3;gsAsst1$9M~+- zMv9@Et4ZX+d1@%@>@mq90;j|8AtlGK&n4-%$_j|lq@!V4Dx+apyd%GcX1hb^Xc}v; zNpbUVYEC`LCZ*;K5h`N7mT0S#mHaqvFpl|Gu8b``9bYo?VoJhOKI_|H#C*w5>Ub(& zo0q`y?u%xS%!fKH$skit_d?HFKPfjF-Sk{E3YnA5Q?r?bNJ7U$<}TZZzo3H%%8u`o zA%R2s`~?7Er(ZOl`CMpTi~0OAS90o8gQ~p?nn@>*pb7_R^&QbN?PZHtF^^x+XRNw_Iuf@%-4Su zn}Eb}C@s=W<@`&0Ha@tJjqS6PA`Mzcf8ZqUp!w5|Pz$ybJ!%FG%PDoEb?KWzYp(XC zWm#0>UhjVc5&olei6-<*mhRZw8IL1Yg6@99+6JTP^!eDw+pIRnGu={iCNNrB^kv)$ z-Q@)73gDj;LPp=lK^!|6w^N;Z@jru`)~m8M%1GwOy z4l$tGn^yDLi;F%3_;GuPk1o35OXQo@d?q}-=iZbDm<_)CJ*5sH=hU)Yz^qM2Dud{A z?_)3#%Ah-edm0RSCmS?+WJ+`I+3OTAW~zhScP>vNosA4K7JTV|ytx%-K!>M?>Z4_8 zKTy@1g48`KBft3sq^}VtJ6GybWj-$mkg!nc@lkJu|L#}dU_AVLUe&;z(+Ry^9)lf8 zK$S{b&4LOsE~*gwetw@(bPhtETlz78T#g?9gw!U)F-HF)nZGMTqOc|e18?ays7YFY zO^-*?(+Q0riPTtsSw?n5kxD7@px&C+>0FZ(3rr1JzpH&HICxFS!R0F}Wkz8plU{^% zyp?p&AajtWKyTI*CsF?@_G|bOjA)w0=>YM$F#|VEabiA(+7Of>~$xqAHMHS zoMO`KL>9!ln}TzjBV*56Qx!d2ViT4V>1kGM!1T;R>j{i+u0!_5NjiUI$-@)I$3T%8 z;Oo+OiBQ<7w{z{N7^^w@`F*O4VQ2Q;0;W<&lKWUKO>D%_v9s3rR2l4dUr_e0^*KKc zV#d}}20Qhx+mMRznOe*_v>w5(CQB*kc{tfwX85&IM0?sDetAv|Cl+qwyewaKcUz2s z;Tpoy)!`dy_msWePTLcI-msI(i7oT7ZDb3h$xqUqM)1NEpJ?!6yV3{(7 zJXN4!G8lVzL)dz>c3RG(MA)K-dhD~-z%|A$*$&Q0mrKN3!~F@4YgflDQeIJ7C4!XS zJi6=n+1-}29vx$E!Jb2$*im3%DSBSB6WtaAueVnC30nSv4B7qwvm6|dcPIY=xXfkX zNG7l`hQl|*KBdK)GLZ^l?~x)88Bs?#*z_UZ9aA+zFsW&wfly6=zITy6jz&nDiK zf8@1YgLGN#XXFwc+^ySbjO$eV{n4#%{613EbAKPHmjf&Q8ZCGk*xUHLHn(c}tq+Ez z>tlJDsmS^|bEy?a7Zd0WZP*e7{WChW%F;#Q)FH+pp7BN}{aJGFG!82)hH0fv$h+fz z>8P%6JQw-{;0aMP7~&<5p@*RJGc@ekA3n%bJZ^GpsIgRKoaVB=$&_n*6~fb2en#$t zB8-;1h>oII$dxHM9oLll)oSdarGFlSrG9?uqv{RlA&X5^~l@yUKB4zda6M-oh3T#it9i z@LTpe11faqk0ur*f3L{&;r6sR`o23TZq$K-5u3xxkg%kuGw}ww>ajwmnp!1jE7-rC z1vLNZ+zg-O`a<{J=CZj&E!PsUo%;RQdzEC{gE>xl6D7vWyq1ph59EE+^&320L|h+x zMgZ|q;-zNSUsRBY5W-908F=?JxaK>mDEeFhoc+u+0-zR}BBkadJnZW=>>;&&;nyS&*GJn zUB^dWIm|8HZ39VQkc6)Us^8M8>Up7{87jE>yE#bp8 zg7}sr%|4e+{vN@ZW#lb!1@4r?(6iIEaD!l|@ac4(=dl?Uznj(i@Cxf#rWXXv=K_WJ z(=6gX$5(Lf5G69#!sO+srv~VeA5Y>vF@6#2su`T(kzOCR!iu`*Z4Vj5zwf~)dVMVA z+k17(i1#bK($?J4#W&8 z25DenIh5e^uAS^CM%x9tERU>^N95Upu3xPBKllao;F_pFXqO)}0woxZ@g_4Y(wX}y z#nx=MxOeGuHUU$SP#GcUEF9!xK_ZQs!m^Z-$hvCK1wHe7fhTGWZd@)fIu}jZ_LeG4 z^LSnz;C}C`Pii#M*3(B z?2{)1>ES%pOwnnxF(J;_iGj+gw;hy2OnM*Cx>j?e%aU~udTw?nQa}9*lO-X&}^(c;T*H^b%w&6EYay3Lh!GVDg6dQZCPw@D)#s@*{YU( zlJOcBO*FmVcIA`qVkayEsVl6%0BYUVMN9)7=E`&6x| zf(QoUS{s$e!n^mK+W!@m%wco@gkGNxQ!1Py(2+VWGt z`>@Fh;)?=w~b@})4_!c~DszPDY9t+|uKUQtxcCM{??HZ(Gm-2gl}2hwC1v!_ygu5DIAu}}Cf z+azR_fS9IxNt_>yO=&@)o2aK?r}r_O}DYW;`a_Sv0A z-pj)OF%;@Tt_lW$9yN!kY}8TIL?E%vo?q8@;TZ{%7pDhnao>xQe%m|29Hv`~S>vHc zk+ggv?=a`z@YYBH)lgweaDCN};?C(A|eE3RhOPzJli$iRmhd-QsHvitYssu?~gJK=8{UNzDw*H7ZCss zkS^jea5W#dYm>OgVxIC7j4Eeapi;y$k_$GXGV+{tKHGAuuKMYD_xK0ZpA?Cm7Lx~x z^f}7yu+T7C%Q-!*|F@3ljr1DEy2-T#|Kg4^1&;oi`V=uR|&1Z#>XJ!~s7+7fB{QVzq@w7vxVaj;TqezzMuHZny@N`o!Whi59_J zj`n2V1jh{G%4jG(@pPwJLGQI|&>Kh%wt>m{#{OP4#C5f4{d2(-sMf`9R?0iN{uQv; z8Yy{xc0_!*Yj!R3@FCQ@O;n^Zn$FKz0wUDGPFsN7Hrree1cwgXs&Gf|O}1Vmkorcy z@o5epqQ$6zS@xrR4w&86auVMNBGnu<&0k`pYusELV|UNn9#Yc2I-0aDd6>pmjx}^A z(I9pc!NObyZb8>)kZW1HrjF!gaCWf-pjIB82HIemL*OuAL*leU)g%u!8K_j#B_`5* zFHS-q!tTjN&#$m>i+zf+>^uLo1ny=I!L*JK9)Ag^5chpJt`d=Pa_oiYzX*ha3#$t) z1mUih%a-XG-q{k3!9t5OSdsdHi{p*nXKynkPjQ*?9QK#L4{=Za29-!h$YE?zl6w@4 z;g>JT{~w6A#OY5YaNWC2=y-C7GXUfn@b$#Es>u<$-wT=FU3#Lr8C^SAgUFcsxf=vw zhB)I{vy2u%4i04LHxc$g?FNKjk=~jI-irs7GQFGA*;h8 zPVjgtDRdeC`tpF>{V>0{5?gxl%%n^$_0;u(guhHw>c7dT(U0h4tTGC<2?~y#nnEU1e|7DX*U>i76WpEsh3W7vX5V635g*AXszaeW=EJ@3AM=GLKHIc0n7)x4x6sbUVB&0)c0T!z|}+t zPen%SaD4YZ+qIEVDHmEsO4U&3x1GlYt2d5!FgIkd@~va}9){7W`z$Zc%EI1mN2wpi zcNg3b`gVv<$bLm3+L`o#GsIAZZ%|^9XO&$6IX)Qa=YCT2Vk$L4SoO(Q84 z&tP6=vRiz>AAC zk#FR+V|jkHMuz0c+qSKmSVeI6euQco6GwTH0m7uz=v6&tQLP!Z0AhLe_3-GM?>WtU?!GN$((TCtquhH)*Xt#m?~aMt7fD|TM){Dm zsxI->0x)& zx@R|ikZ6~8;8XZ7h8?K;Vc1)rL)E6Y{{?%v;TQ3{AJQtM&>_|aYo_xHzZ$Fnrx9Ue z!u<%NMg{3-Qp0uSOieY3HuqwF7LY;OLZXU`C*x(;Pn_`LQ*AuGVrXXZx|s?vrAj zk zQn3O=PPiuXwxR2x{9DgJ=B!f$d9c*^eX3x^Bman+`S)37MFVO9&zOZpG5cSe+a}~- z9iL8gsk=6bL^JjoTc|Y4Eq@~_!VfwoXws$jPagLGJ4;IF%1takB6aWSx6X)%uv9z^ zM7~jR4DB8gCeOK-M@5=NeaL_oz=Ilm?mHhoN}L}kkcu$6i7sO#DOgk^L_0%#k{5OC zy7GPUrP?F8us?T^g9kwWOZ#8z|+OciM>*EVwAbqK@~ z!WUYKa!Iy)E0VyXL?O&Ur*bzvMo?wowXIR(Tasw(>Ur$?JuJ>lcvxZ@x+hVQv>YQ_pAD^{=_MEdCU$DQ5)Ir{BvS~`|O8W%tBi~T`aWw^J0LGV*Opw zsmTTv9XN#nxd_wkxd`b|*?y;Hq=~%zCx1)-kU#|qrfnd=SDbfucp9Rfx@V%HDk8WF z&ivNf4e~;JS(e`=84$6MhV`sgo|Jjrg<$Sw2-rAMgbwqlSza2SRV`z|=SQESjSo?l z>69W8i;v-x^rO_uu_8${nfS@dGhAX5!#5Tg1!43&6N_r9htl;SFa)3FqO7yrV1cls zgTt3F%kQ*|Mu+jr#6*w@O=IY~F&JUOxfhFNY}Iyh@N8Fy3yLx*8@7y$Fj#-@GL^C& zJk_N<^#CA@7BILEd~(*~oQDb+)M%LE)cPMXqVz}1?__;jTz&t~{=>)YzuesC4SzN( z*nfw=_g^3TZ|gFky7uCwQo8fmD_19l2av}F^vh`byD>qQSAlmP3h1`G3cE|X^6+f4 zVt1f48+8DX;FJ7MAXwEo-sNpv4-j>kL*zlxw@gvZy{YgJ$55}V)2;|!p%GQ&2UrNR zu*0x=eFpADq}6;tp3eYhw~nXP0!+ipasrj|O=$|#i{`-j7jT*P@|KA068*@dqIw&pF z`txG2z^?pWV2pnwHa;}XewJ1>4HPCPk4pl#YCzZ6vow#OH&**xL1Z$ud;~&t_(cp%y;wxp6VAYe z&pz@Fl4a9H7xkI9bd@kBYIN`;Kr5OR?(ohpb?2Qr(2sY^j8yeJW?ht362qX-e{va-sNms@G*<6qNF|qmsq-6SEz(kCrP!MzX7}@mGtNZg}fMRm^ zU0T8dD5ldhc6X*-Rg#V;y9%=f9~MlBN*~cl(CJKq037n z$w4KyWSP#$8T;`O_lu`0(bSBp3Q1;(dG@Ck3Xh&Z=c`{tlByTl3`aN34+)uSW*9`r zlN=Z<&N2bl;&9zM9}_B1cdI9d?sFb5@DPF|7}eY!6d8Vs=izLO0KB)NP`RkQ;(1ha zrYLrhLA`uMQBVFrnTaoyI*6#5$n6cOYS^d`;8xCloF(1~beZfcko7qjpZjz# z@v(+Se_WJc1<8^bSZ9Z_&_l=>CzZoEDX?Ji5DFa>KF@{9@;azE7q&Hop5Kg$+LjS~ zM@%E;h!84TfFDzm-{i3fp|BEr67;5jL(z<;EoPkP!72(iEZ}5|I~XIc@`aVPxQ}+= z`~2NZGS3M?GPPGDI(7icpV#LQNCxi+RYAQi%nxVJUGHuW$&*@MoPYAl2C>i`lz!T^ zm5Wb5z7%fcw8saTbL+73|Nnu_T``4$-cC`F#)GkWPNbrpY5{bR4sH8~N!{0Yt~)vJ zY6u(+-LsUJA8vs)q8`vzbmmTu$7hHf48t_9iTfBJa#vQXL)sE0$lw*)5-0IAQcISR zMu%F#f}+)Vt$7ALp|Jj!^b{8auA%dtxl`rO={U4wSKGA$=dbETv_-@!^Cd3?t36Wc za$(+6-xj&%fy3ei$ELMjLImIK{dj6bCtrqO?1FiR(#KjwYka%U##%|5JLzDPno{GL zl`#6&VDMo{a+&0|HwMXl;Go!XHBgBJERU`DJ^&Dw9~45Hno>A9 zI+X2G{`DE!kWb{q({}0ms~7vx=XuXFoRG}C5A)aA5#A^BZ`!GKhN;Jz)U(uEShvp_ zS@;I3ttr|JrAgWhvsl|D2VRgwyfC;zg)lTw$CgoOIvv?HQk~gOUrRT!Na_^rbISd! znwGQPP~}y-<6Wn8ny2Kcgl+6-T2O|t8f`b0=d=-^JSc=K7@U%d6Rn56JY0Nyqb;k5 zuOk@PbM+W-CI zg$bSrV?j{bJxKBI*Zt?^`=VD>J3en>-;$*a%x^@!cEf@#raWkmula`s;0^{A1Yc#t zk-Q_zAscsaA|&*Sfkbd=v@Rz;U(?kqzluypGsrM-;vO z5(9lb%^p9|Sh;B(9`KKJ#Ku5gDDg&`t*s@MPaCXML0;-K0#; zJR4ZZiaRwV`p;vFlrDgM1B3W3D9*6y{`J`Gv7eHFCj{oNbqBBidCHN}1k&K;@o6k_ z9j4taKB(9K9XEcJ3dc5def&w4(C(ubcZs0G97}390?G7=&>=xZ=$mrhWd#gG=V6RA zBK*e%ENtH69Cn4QA62A0ikjN}RL$Z_BC^nXY?KBxlZ&~U7rH9`Qa-eJ=Y#68o zlAe?0Ig#l?Qxxm(zCLI3UE^?h791tQF9a29EAyZrmeP;LArS?9a-04C3N1t}y!Ah-Bv$FWxZ9X2$Kh zl8-lluzKp`^m4wdWSoh4qHMMRzIrnyR-_A3Fo8dhn3aQwvUI^xd?sGDfR!ZXJuKRV zF7BEGEr78Zy@jvAcIDpDNCxi>1@pST4La#gc;c{@74f2{GBS-WZgMuO>{$tVF^*op zt#1XH`(RObm=7k?gj+D{tPWEnBeP;k&V#cHK0fJS-N_Bo~K`y$k%vd6iS92VyiR}*v-M2BNv8b?SzkRd>t>n*7>|N?nh5x%(vw81URFJ0 zvErthGrDeL}unq^B$6@=Qtm%l-Jhw#r5{(Iq3fPa)TC~V{3(GfiC@Yet~DA!9; zuFF{9EAgM<$1+I2$C)}bk)6U$&SmVYNZjJE4*i30C%KG>AUf|saw^8eJq}7w8&UwC zNR;$Ed5jEB!V@}p7)+nGxu_g!#CKE8CyZR>iBC*TVdFdE3xq|_yRIz0PBzy&1Jrw- zhn6|G$sCS1$;jmK1xfBGMm-Du>#dDELra3h_>*9FL};6;_f=^zB_eDZc#ej?S?e3X zn+T1HXs0O9^I1O6?F`rI8XbP^1c9c7Y27+0$$-Mf~r$`qYPaU z1UQpEfKzjrjCUfHoeDq}_ z@Mml2&A1n}*^OxF5Ly>iXrIn_17y{ki7#!JNm7>Mm9KvEgKqooR@LrM8DcqWMk$YnR8o7@bb$dn#x+ETh$63r}bb+|CO$Rp;WbWeTu*!h>iCE2j>jR|B zJ1`oEvM$++0}iR2JyO_0nMbBrD0(&SLmcEpfHJDy==u`5LbkiyzaiMV_@LvI ziR??)!<5RcR@pRdyjN6uOmN|?h21S3jjILrT1)@{MYu&}$jVhZUOtzSzZ1A)0oM-I zFMl~xru+i3--|wu*gdam4AW`*R`c=C4hCOvpfq6C02xq5f4)X;Y}N%>39W!GljswO z1`s~n$^Gyfv?BK~Et;2^&$Y5@Va50s|s;YpNQG^%6`R|kvO2H(sPW; z5ld2}!}mHr&)1eQKZam;8Act39yYD+2TP$DRRGy!h6tz>(8ht^Rt#|cxT~h_+cN;g zi<3L>EO+bnio0Y$y<0%f&VXbWpm%KV-`ACyKPf~N7@u<%)+{H#)bzdB&uD#nYx6?L z7e525@~7uUKj1X|#Yo^6eYlpJ@dneElmMpseaV=@+wy7ATDP8x%4%P(wtd$VVSL&_H>c5b?_j(md!QR2DR_Cdukcz#IHJc>8imS{+gcJkdKxfH85zjy?xSKBwE zN<>v=<(@`ML=0~Ze83w1Zk2RNlMXV!`c18}3-;r*&BE$#6P)ADZK{2B+QXagl(au^ z4KR=d_kve3C__OmG@5d7=war%7U-m zK~@_(M-%~IjefN&&i_5O{6^n`Ao^LnE}pDBq;~34aL{vMsrz@HZM2NpZECzL^hV~i zUjK2y<7|{=U%}m>t6^NvUw;(k)NSiF{^?a+>C`eTh^GNJu#%wko_$15x*&H?$jQ&f zovJ&XdRvpcWVN=wPj%rVujJ}*#Jjj>k5C$|E$_;7kalvXPZM3d+Ws83Ahv(NCwajo zJIaxpN;X-wQt7sJ^_DfTL|$oWMKfUG-oU$CTy1*$dcpjZ`$B{kp>;n4*aSF9G{T%$ zmx_^!DwARU;*141(|SB4;yZpb72**n7C7U?Azx=xe=p<6Bo zV0T>-Md$3_mm)7`V5M`P^)ur6X>D6Kt+*FS>j zRDeq9V0Bk6?+0xcFFlbr*~y15eDTI;`pI9?ypRL3wxOhc>$k`3Jf1d1lC?}RGU`ZL zoMzI^2VsjFELybjI`m4XWo>Hb@76UWKR=PWYtH?sRj1=>(5J)% z*^X0RNg=|9u^+-^pY_U~wfDRP}`o2=H+!2m5xaewpsyEG2NoowOUQ;+?n~i%>_aCXaOKC>fatu;xijmdUB%P zTLS*9gyiXJRx49@_V?1k(i4Mb&W|L6iTbuR-&TkyEoAyJ{MY@qm5%}+aM5KM`?pCx zjnpMDn7`~zh|U?w=kmkv4V@f+LKPeYjfpT1AQD$PL|U~IKamof*Oj8thcj(v>r5pR z)UZO&@r20qs~iMu=R>5-Ugd`?w~CaFQEO!)6D#GtzvdH=uZLwpl}^`~Biq@e3c{y@ z{MBFi^WzIXz^Q_cGu*~@DFAuk?z&uV^)TrnX?QLCFEXaM@1!XY6ZBu4ApF9YUD?6k(~7>!uzZtN3% zJP{rQMk}~!#`{+>sS+Y}EUbZ$jqjkJ@F)^Lalt|E< zMeGTDlkgU;vuQF)BiF6r^k2*5bNkgyqhpXpGBMYgdt4QBb}cR4!(2NTZHQ|vi*=EY zTu;BC6OeD73yHD|Hl_VCIexKOdhfi5&8%KfHdoN~ZGrKtxYNdz3kUa;^6!h3g)^3Y zGh|RW{J}9#EJDon2ZQtUa@EJyK|x`PnR=JU$M+*U|4&SMN%{gf_W|^w6*%CH1@eKB z2)ELB-h`#)m#hu{@L&$@m3DkR?(?3?9#mo-z5cRIvd=KcfjxWlmD)iVqH{oyhE`+w zoos&TyU6hTG!Tog2V}ICx*)wN?>+@Ynj1hj_+<1``M7B~&d&lM@k3=><`fd}RDbyP z>5dTCZWDU^framX-yHP(lCUk`U=iVqWozn-DQ%X*^5ho%!)4QaCI;UG`xkW>4bRo~ zBV|(Lpk>MO4y8Gf&w^*!WRMaaCDi3vMQB$pM9)h0cRxwfA6>>n8gaqYVRAN0iG&v+ z^Q2f_@@8Gg95udts?e(xF4Q>9_=V*DQMkVsb%6ur$?E0B(TV*}j}<}1+ffsEc(hJE12NHB`yWnUV-ejj_C5sj0Z`HZ zNpqJ->}9n@&6PF^?wIRc9sc14p@U}F8(*&<7HhgO?J6cblG}9d?0&xNgZdHNIEmop zav*3KIlA=HE!C(p-=8G(x~APNtGi@X)Jm^*I5G2xn7rh~%12Uei8&Er6_PIjY-n zuhg#k`s#;}^V;B@|BtJ)jEef(+rCPRw183rNDm?13@N3cAVV{x(h3NYgGe`$DkUv4 z#83j#9nu|A(jhH1z_aP@p63_*T0Gt|A&r_`S&jm09{=fpaWf3PuCVK?tx>hPj^v$$xcvLR!f>*Mj-;DhJ> zh85#k^skJM&gRt~o4BMXKYYPEI^$osbM&ot{85yhb<4ue2BU|nWPqWt_gl~2!tx5+Za+E~`5cktvrBGsxaGBO` zBn)98I)`S_eTirDC^58TxH1FgZn}s^h+LOny0?v;eQAp>a_L&te=i>Y0$(QNuoUfJ zKmRjEFr9>6W}`);TIkXKY6ly{UT93OcO{fza3&<217@W<*sA9C2$)R}sf5~=3sYn` zQrO9#Otso-+mgeT>5`S>VobhF@e4B0lE_n>-h5^eEA3XQoBDC-Ij(fDgTxW9|A= z7u292X6-anKRCJ*^g@QO3!G0V}p)43g4wnSm2F^h(A;$hsC zv-`>7Xz+efhH-FPODRlR?3ex3;*oDqG4nd1{=vL5dDrIo&I?xNaZx8%9_s%qdB6z5 z?-b8Zi)4PaZA}Bv%{TPF%-q)RHv4}6I%f#$coJm~df0`RuycK88P$FToyBYKM zh>=K;GJ3&EW;s*kv@oiRAi6sCz0xf)CcTtOVF0QCGX70=*s1CSkafgeftH8C#KY>3 z+YE&Vx1M$JLjayE=R!ER`R;n=l;}CKW@=w zDsJWTniadCX;Q7ggGxaa)J{+LC*pjo4ZQ9(gE{=!o;*WLvn8x4v`0Spsi|nMs|IYb>)PqIO zy0y&kp>xXdT<^gvz^apg|BQX9#TID_%i+PSTMLn>iq6x0WUMcw;|9hfolnUbJ>HJE z+)p~JPiXe5XCdc^W zcZ=BrMn%NmVs-*rgWpkF3KpTAuhcirXA{WdPb@k}CbvOJ%WEdAYXxJM)v8_jY`5Z8 z+4%VaF?K6>&Qd`Hj2`(pA%EvJ*~_Qt?`VLX9?KJ zZhMTleD{{WjAT@`YCVp8@J#@*RnkP#^vIztHjNyBvJv}swO|(B{s_XKZ}%Aexjh@L zt+xML?o~$yn%}og2if*iGF|&3zxAugvxfK2RyI!zQ*pcJh4hcIvWnuU3smp1P%Na< z`(jEcKb}0zYlUBq3_8s#&^Ey@D-o9L&iPT&mED@OzGs{X58&FVmG+}~wOr^nh+Ie0 z$;b5GoKtJmVV1(c^7)_>$5^LI=SCwe3`5;x{d))-|N2%kF{God>7V?AqsOM{!8)_2 z*y~@#_Ab9Ir)oWycKG9Irt6R@dlKCh`1C)?JU{4p2bfpNNzg`|otm~L$s{HEfsWXq z-DCfm#H}dV&FflqG*aiMnA4Cgp$Ns-ozpmHtaWaKtLh%I z&%Va&?eVp36H(*4O*d0|rqd^dUR?wzeQ;BIP>JKRsMoBYtbI6{(^a58J}Ph z8geIw=PorrUPKma=@W~NOaAYI zxV>S%8os_;R7(&MAu02|IYel+BmTP%E&0t>elq6l@5@OD+*p z_%MkZzy0NE(Qu>n7}C3HyK;I->!tp9?Pd*}$--$nG45rW2U~B;U(qGcawoOXO@F8p zNE9L4$vNin+J1)>5CR51WsD9!#p81qf8K_^z7-mv6SpN^5x@=qVxIGP3jY>qygQLR zT|CHA-uz5iVedWpR9-89(I9f<*cCTFqsPYyBHh!UL4`rs@rm|J&X*c zU=ISlUz@f3Kt+>>RUk`eW=_DViJN{e$$&j<#}Bouqv2j0G!eQ)pnv3Z5#O!D$<&jE zDAHATe^A6~sq>z5_4cjQgm$TZk?0L0Xr1SgR@qljm2^IcW~sY?bzQkR1gE@x|IP!r zPgB?Sq4RgVbY~sX*^iyT!i)8nZIC&T|GsO%Qae&OJ`pb)a7sgiQl8!{9_ziZMS6|Av z^+uw3EHZg~BYD0F(7U!}^7`6$ZdE48@kASCw#<_ z9o>nAq1GBoT?k*26t@qXG?@`b(Dw2M)ty7q#5ZIEi4LgTo5RI%iV*ZD99app=R zdN-p8Q(k?Kg9(<;`{S$H-*?Ke(|dUQovL*9z%gP94oU8MBy(sH-Vlj4wU0~Jn-~aw zsvPehD?=NMCUa55W3P4z9E zksGNU-D_Vx>#np9RYztljt-x;;Oky?YgNrPA7q84YlYnXOY3tarYaF)sM?()vk%Lc zh-b&+kVumBC|Y_M$klf+IYm$({b>I0nbsbewWEBZkEyu#$!>WKVVMc&VaPK=B(UFs z2oix>;6QJqbdSNrb!RrUs9gTGA-&p`g3Y?S*m*M{U$zeauJOxMR{?q1G?iySEHUuq z^EQ4cp<`=6$!OWj{t}?Zr;@r6{P8IPQ;%a?tD2-#d2bJ>x>G_}M(uTQoE~T6!+$O` zNwC~$@8Y8KeA?Zu4m8^CiLsP#-PekAly<>Oca;pMGOM5r5!@&%h$Fpm>)tAnS=%Sj zhVpMeZS;3^4tpJ+9^CfMg$GtCwPaR{VT_RzXu|cgbOP6Cj)X*rE~=!R#718yu$no> zmA7jC{qt3lX-oM5IYtTKYHSgTY7)DizADx%V9-M(1@@z?2O9>g?5nCQjn}#!W5cDq zXdT4I@NA~>Ec1A-&2T96P&R1fsA)qXg`~Z&TF)v$M@yoQG64UFmVr;P?gvL9k|HN6 zQBz@>J}`C<5o;aaP%%tJRs(2q+hFoM)C52=%Z+8cW6_^QYStI51%LI0q_uAE}x2H zO>vslqh6>Yd+qHkHx95}&Wg4DP)+<2=jQ!d#ma)@r!n3mF%io|PN;o$~I7F^-nY zZ|S5f0*vpHf$W;asMrq&6N}W<_>xx0N>8m=KPoBzr{jM_d4LNZ7h89 zs<2ZI)(vH4dYIzx0QM}*T2~hO>39_t7t?4W8=uOTd(iWX32`RS1mJQ?^P{A(Ece%TpZ%H=^f(Mr^UDb}FGfG( z;{AKLe4fQMX@R${dYTUy>q`h)UG`+<+ zzOz_YJ2kJotbQsZv~R}AH)AwEe%t$mt^R^ieKyfeo1*ljxj7OKN#7hiZwqtZYm4HG zm|^6q@Ge@>OQIKj05=GAxYxjO!pL)#%W*1S3aYeLl2$|>|1M4@%>p4lQ5m2PK0~PrL5%e>^w-xx7@?PuVc}f_Qm~=i zw)j5_j(L2co40y_mR@G|S^*^;@{$g83yvZd@b-D&f25{#%2Uei_ZzHSh-0{8FbXz* z*yRsPn|;)N+=^$t5&ysvh{}1kzRw{!A9KnR9K-I%Ri6Adb7KwQzIAzd+@Oi=FNJ&P z#24X^86!o&%&Cr9VB&zTF_LQUL;Ff@;gKAFcsu7KTId!>vls0%Py7rk(~t6x6Uckz z%dhI-%%nJ`ClOzY$;N|JhV|@lyk5%)##Mob82c!Z6gF+O)4sYx%8sG~HfDa?E2Ntp zSe})?8Lcp|Ju34j zmf(0$wkt8a_{5)RhZ)koy|uwC?K-CMf+G4`POuX& zdwI;i4e85+BmA?4-FN3BMuO>&3z*jBJQrxn6{XZW%~=`nAH%^_Uu@6H>E&RMtaSt~ zp{iM>#|zRV%9n!H=gvH zcJ`hZwf5n?Cxu4pi~p(mEg(-9zyZ%L{r$pDhs=+=I`ryhZ9Qpc+*Fzd`aa+9M-#S( zq3mf-bt~nmZinarCl1Xq(ulo6FvcljB)E%ZJ!0y|75>%+TBKXdHUK#Fe z1OX_KJuL~(W2pS}$rp9!iw7?Qquo!&?l`Y}dYMhq@7;Otp{c1DSUcWEIyAj1FqR6)EyS)Kx80J4ToBDEeOi%z2W-_bCpgGta`{*H|C!)cJoqF5XT@h22m zCheq^AZ+5XaCoqv8hSa|817PDU<9g`>@JnCo^)3twq6i9a5~s6?p7+xKF# zZkRdLe>&333<#2Hr^6FfBIB8UE`!3j$9IJWN9|S&b zre>%YGxpjJiM2>d?HAqM>BCXy z6vUOmn7EFP0!siQ+|cb6Ze>78S5KWc7E}&>0 zf=$Afk*7mXTHXrE6uQz?xV7WGig3xl`tGIYeBmQMjbkg5?oFlp)@QYTZggWK^}i8_ z0|vi#HcO`~yv1;AW-7z*JuLMffp?dP3O$*or__GD4`r2~2p*bAUz+{!t5Ti6x*>Pe zfiWlq`*~Ch82cCo0=IYOYS_uVzuDFV`gTIXPXaBf=2|GL$NdpGRFEVuLt%qF>Q0P_Mi{S_=JOxWb^bHOY04?N^XLTyG}TB0IuNP0)sQoJJ|Rt zY&<$AJ~) zu^^5gpxsLTVaw}5_E&Yjy7I<^m!$JuUP8Z1vGwn#y>2G3Nyw05Nc`I3k}l=v267U9 z;#cO(!kW^&u2eXkbM{wzz#R4ElD7JOOHq-X{}pV4G3C`Pf())Mu^93|E7ikV_*?eJ z1H1^mRLua2f9j%+c0QfrpqRGAz?h?b^SLWF%{014ku(XSstzk8#HUvly{>6s*q`tt zNRKIMTn=dxxi@Q7%$MdMhkb#dsFS%IUoqbHb_qb;9E6w<cp&D`PSSUM0ZK^eqA$7YWN#uQMrw&}R&OwS1$wX6d7#7SxpZT%7SR`j-qKg3$ zRa<8sn~r80AzS>a0lJwkWmXZ9m-a81r9~#<8c?QBlSvh^{IIe8?__8&KS``4C)18= z3{t2^T?VA4-r%=vkVW;d!{ba&*R_#$!F7vV-`kb%D4tHT#bCCZ5H{e-Cn!hAdM6rs(+HjZZw#t*}jGKsUqz-zU*VE|<%LOf@C;yHXc_MB(1%iP>2 zJSFqJi?H*O>$>jCjn#2qY7@N!D30S4PXlIugNx&|6dPSQV*)4v$)gci>z+n8W=o7j zY`*cmOU!+be{c7`3|=pWTnFH4od&Pb%PqF&bF@=!{Xw0|7Df0FDVbwjqhkbyle^ln zw|E{=Q>FV++Rk85R)V|Eli6`_?-K0CAy+RgOV`UcDl}4^|~zow(Y~E zAeMKa^g7y}7M+&qE9%T~=MsMP=dF%fXK8_{elrgx8<+1*UYX=*$BCQ9MZC2 zSyuP#~JQhCy80cN5) z2JILD-wl5#Ol4(C*vNK7v5~f+ZZ{5!3)r~8{yQ0wzMUhgW{q3XP`n}OQ zKS+P%K%mZYe>hqFaeIF?kCB&d9Gr1d!io!mz`ux@I-bV3Rfwds4(KzN;Oj^Fq;2bc z)m880a*ZVGsDEW^_0!{YR*4wudBvgpy1cRw{RfbqeYW6jKpZamhY7-No@BHH`-`x?C$Y%rm0Bvm zs-4;$WWM)=(K%PxAtXf={OEbZX0a+Wb1V(i*i=tMD&@Fg}k5F*z6< zc^H4l*>DD0sR4im-%1tR_#AFuqHX_X$Rb$!ecwt;aAk1}rJS{f4XAW-7F)jGgu!_H z*MIZP5@j*SJg^gWRSMu#cnQd$HnNuOSd4Hf* z7MKw$HVP7p>Vsg$5$~w6n}azVzEZ3z$4N`vD~yb(I9*A`Nt}PQyQ&~5>Q+_VY_b`T z@8u@wYfq|Pp4ofS5lKs()at|kOV(7?GEu*91laIY^605ufbxehTKcb^!Lx{i5-wgVmwbYTzkG&7)p@wh!dg*H=@7!q@a?ZtReLStD$WwBFIrP zHF;`y4k=NKbZI#04J>96ZdTJN*tt3`G0me9xUdu5qJL3)JU3F^$gCb%5q&Ri!`@Jg z-!br{S66$*ee5oDTSDxON!bgipXe(|#@NzJN(t^k!NZf$(Js@Ca9;w5jJ~(R+tjRd zf^8}TZt^O&pwRI#j6pqPiRgbLxHOc0xr~;3vNN|y23cpyx{eEq0V=wV7fp(0q>hgR z%g?FGlQO8F95xNVx#Dd^R7~6LCowmw@LWMXoJgz2@%ucG#6W1&?^a>+!~yF8$1?_$2g=MX2W*Yir;ef4!l|vrR6guk)W8J3l;7 z|J=i-iO*$2mvH2hs-LN2?Bb`_B}n{dI6UA5f&OxlC|NxBhn_wKDEl%Zc$CzYyGa@C zaUq*1w-0>duTBTW`vcVKUQj-W_B9^IMSd=B8!l4o6dyleTz+Pw`XVt#$+w~y(uOKT z{d4yiWa>D$Ok2i1Y3>L2y%3$cn%&O>qv@IJ^5)#gOgHN;Q$fa#aYdxzIJJnk!8o2X$?*?MGVOfq^2>%{ciRN)t^JaqW?Z#_4-KCHWsC-jCI9!<% zdGlo(d8xVJq#*BR-p3R2a0SRbrJ;kJy0O#UxO<;z!BC~hyc2#o$g3ui_wNXRx6x$|^ek7q#ezB#jpA6cqhC%7#hS)oW>aHM zpzpnR(E_==X9DK;@6A$xPt2r1Q%oUm?QSz_j=YqSG4x@={np!tBpcMaAc4SlaOj&q z?sgK7?gi$6?=DZV7jQt#eeL~GW<5L3VGV@@JTlv2tT82YGa_LMU;i`K0qhEMKwL_4*ruS)|T4xt%v+c4;lC z3_qq3dkq_=7!pYU-SML#fTn;QFty0!68n0~3Tx6GPEWocTczs50%$P?w~2-IaDG?y z&RZSB4>+Tet;rMRUP?ahI$cGOf=m^0;o<5Z``yr?UWt%b!4Q+OpAT_0I=fBx!~S)z zyuZFz{EY)plL$>Bh?M80(W)C^5Dqm$=8chA-GEcuXTyA!B%BI+*pr0wEe|ToGz$TkO*sm+`APReLV@sz%J4fA8|) z!9kZ&Xk= zTIPio%;wV5bXLnkKnmX!xU~<^tXzn4?js!EDDjn#>>qkMLX$dxLw7} z=9g-G{h!q|Mm$~kbIv=^6iDi7hC(o#JRA(L_eYd!&@8#m**uH!6dwv#SeXjyiv=aA z)fu^j|Biv>##o`D0aG72+WpCfPXu{0)zCd)sb53trXK3k-$zkeQoM4c&4n}(Ee58q zy}jh6Cw?%zAsPaGB9EQ!^epdlFnWGWc<)Ow(M~PG&L-*1cgA2vgm3l3HNT2ph}vDi zD!Pp)Px~iC?Qn7EOCE2AX64$5vJpI4z9ggYq*V8@{eUXCC{Ca1M(8~epKoH^Z%I_( zUk@Hhh-SUKg6I0CThnL*|KgBL;nYI-pr<1v(iEX( z`LtA!E8(#p+Cr8}@ePfbt34&Pc#MnE%2a zwQrXK{Cg%-zS$uU)#HPQVzaW@c|Dieao?LbWm6Cnw#zsV74Hq@odCT0bg13r;653F zKA}aUb2aaiXjyee%R(y1m+jInx%*<8nzejVmqW(-Kk}i8F>P9N4<1Eu)7(P12NThL zMh-T9dyXP!B?}E983VyMbFnC=!q(O>eE{=>7!h`ZIM{52UkN*gDVWY+VEkhMs*M^U zWd!&#PDp{_#c4k^)lzO#X-`ZbDg4b4au%HYF!P*5x%NDA$>iT)S4VgqH{!%Yj;!cN zN(5s~c7Rc=Wg-j276N`_^-M8)Po@g3_oA+?8KZhm$7X~imgDDgt(waE47gBlau9gL z^b*{LQ4{2)6N$SYEuwfrnv+Us9jj!1xkHsmTR!p~h4W7F|H|GRFZNy82|(Ss4U`zy zM}_;EospPO>ipJ9C@_+pj2HANz4rp*a52SGWo?AB`6|Q5$gCpevG3LCZu^=K1seLQ zY*Ax1kacX5r?_vbtl<*_+b@AH@9tDCP5lV^BROvG7kht&%l_3#d*ns)Tfv6TBlqF| z-g2SIIFwVYtxX($>4HeQzaDt>&s|_~Uhn+zNQkeIJUKP8+fPf+WJm(G^+czvvr0fF zA4~dmeSm+@tw;XHS-kP&62M$k3XbAh9bJWrzjL$H8>7{ysch})YC5S;4AF*;=(7n> zA8ILb4UD}^jIsLe_&%n!u0qWU_!IWJv72u4wHt*_9CW&Qqi&6ono$b=LC8CnLD59_ z1+q<(aFhK#%5d0VH@1QI=9tcOqRFRcsO!UO0BjA4l_f9LHe45Mzb_;U*=W_i@={Lv-{G8Hft3)VSqck7;t>n$c4uYY4LiWx0NG?Z`Nb^+m4 zvvD45Ecp&SooYoyg{GEs7TZU9(_S}Viop+q;+ZXNBH~@^kSK@hvsy+=baI!5eIcS=l^{*9E~VG1w2iPw(h z7#gBJvXI;O{nRXqL4%-`>u{*emi#m$i6rIz)WmSKin4bAl0d?H0c9Gj=XKbc(W=S6 z@3~3a8!PQ3?0CBPvTY;ZLX%s~ncsKuX?LQ`q6(zoQ*^suUAr1A^JFBn$&VP)8?ALp z3H^2(r=up|CdUoc7;o}JHI)WjrLK7=lz3^liAEdVFFgUk`-)FfDADw|C87Uf}mQD!I zljol7Brn7zsTY$1LkyhX@GNr4AI1yU2v!4XhV$4n38mJ)VX1A(NQ@F=^ zl|nAlz~^XmSY{_xf`@^z*r9e$vl#$PNspO!#x36C{S;1>T;D$!yXFOP}!-J2xmZ>IT^zKzrD{- zNo?*en^`5I43JRevE~2wS|DQts1JS5Klk^3!vcbL&iE}}kU~L#wkotT3##0?SU(Rk z(v#uZ==u?Gza8J;B)ku(w#q_daS$nG=s;NskY>yNivqMo_|EC1lY&qgRB2L2OwB=G zWxj<3CiP47cS;06*0vh1E;;A0NTi;Q0%cyuc%9erk{577rP?+zg~%GpQxP-!$(@J+ zgIu*sJ*wtm;3NL=PxUV_qUO}Brqt0|1;Mo{Ne(6MYnUN*z8ok0pSIKHL+$zHj>YJy zPCSvc)DG}>sX+#zWM5BCFP$qRH1V8y~hP^~KrNbe$*3R9fsM3v4V;kI+m zo#k3S{e={C9DzVFywkwBi*?wGpPyYb&8S?G&{J_W#uJP->{*sgU>kh809K%CeOM`} zWSg8^nfvn!k_-WsvVuQ=?`pVdX#o$s%!#p-K@xNxU6Nfou%Jhpv5mFdT6EO549te6!MUCm%MQ%{7{WtyF2>kO?;Ul zeaSO2wj$)|n&r3D=nN;01`UQ&mI)4+TRBdt+CG;rij7v~`4aHFCU2rb^Y1Bfe1cU@ zbR|~qb0tlop_9u#A^o)pNh0;liGN>LaxX=CHU|)(*M~;%%dzFha_zS1kTom3_l2^q zoZu(B2jBm7IfPRdoh++zii0!VY+F#6SfkezmVhD!cJI)aIejO2y2U07RljfRs%s&t z_klEsWT)W@Ira-&5f7rJn77H&SPQb6lkf{?Ekog8GVWHx|E#+X+zhuzAXn}N@90GM zEY}9?hWI45zC8z{C+8Wg^N71?BrW5{qTd)PMZXivoP2qs5K7CtoK45H3Gz(B3!;pT zm)PXTBzJ0Q^)7|^Kw@{5!v+%gYLO}^0pIW*??|Z~H+Iu~E8`fwM$m3w46BQFkGW}$abVLp0 zH4KI6b_0sx<;(0s=KyYejTk1<5ED|#H!uo%^h9Me-mJ={-1SBm?rKiU9pLo|WBS1; zBDz%TKFH)=1E9D-1IUj6^h)j1d0U9lDhR}B>c~tKq1E1$X7Tqr&;K zV*t*I1dVzBCwP8SG~U3g+PxrG^=U%^_C8U=4r9=~<);G?17tc;Zmnmv%rH!j&O+25 ztZnl~%Q}w$ICZzMvu#Ex04jX--mk5_w&vgG`e%PjCBVrp-Jn`OHd4&_N*Zs4t~J}f z2DEIq$v9E936#lFf1hTD9o6|VU0?QTKz4JtjuAELohXpX32n7ATaF&PRsy&!J7MPD z3?Sk@b$*M`Z#Hs=kdrkR?T-(E%%Fj-%0d(~wiCV zgE`{)8Iy*C03Z0-xLuHEe)Z%yA*>$ntttq%(QAs~@g}1ZGaW6eop90O0WH9e@hN}2 zt(_#|%$*89t@dgehnW>>yYA8p-VPeQW$orwhE4;%`V;fBId19eprZ6kO&Nfh;1rX= zLoJt;;nU`{i@8*FB*Lz)neu+D4#0oDQ&MD{nWfiLHE>DftH*i z$9#Z~c0G%$>;uUu%HhWZ8}3DGE&^?15l)oT&Ov*)pAn5E*~t?ZWb{Q%Y-6Uf-u$4$Z<$%cw}-BICv{QFa6t^{Um)6$}3@fXXCqg$?vC9k@=VIhgb96fJqKuljZ{J+7VaSl$awM*SZz7aR(+LA zYng1nAD1n;_QiiVNv>@gWI!+Cb@_}uX03Xig>8Rwt0)-(*t2(CwErB-aszP8M{P9= zHGlqh$&AB1U=+apW$`AI#NY$w?|Zi+GI-d#`6eHskS8;c5e0Q`p6ZTR;x&Z{o z%JF!W{FGK(@!x$%`<@axW7ir?+56Rnm$AZ0GZuY^Mu_9|i!YG64Bum#FDZo`3mlPx zsP$@S9&50G?@C*R0S{AnhR~8Hw_rkc5lNAlGqMSO?8#K_B$NC2Q!M=XwD&#O1b62L{>;5?Dj-P?klN)-Vw@1Lj zbc#}R1GvvUEgXSUnx@NdpXh4zHwyW=YjVA$*&NVW&Mt|_P}W41@wE1~^V@g z7gyT#5PM$MgU7e)=yb`~BCD*#>LJ-cN!f2_Wl_dLO`6}X)!~~=P zOsW~y5_=y1Nqu~P?G}>D9C`(01Gl4P&c4cvsODegJc&i&u=59?ihm2?wqg~9xU)-b z<$*GQ-W8Zax>oVoX0_mEWJhBm_N+OqC<;Eoj40c5jo!p$w-#rl>wyGc+eH5wb8FPv z*2HKr|6noyev=lUyGXp+)l-pe^2!jm{k*8C%5J?UnR}!yQ_yJV!C;kQ{)`7~Zgi|T zc~b$%_xOr9^2Po)zv!B8k+tP&9*vM)>3N-D$K%|h&%}I=cypo}oQ|)3!ilJky;s`t zNReyNnw$C2GXdX7_G|ciUoai#HsK%URRke( z2;7p3GVAX87f_dzDCv)?2LyXR?o_mQZLf0w2uQGS_r!Oy=RvfN90o*KJ`T5vBH~Kp zWphnYF_K{FyybPsVI+roe&-L?exq1}Gc`#X&jNHOT)LoC_H{`qhzQJ0B}4HdUgF&d zA&IS7;gnRNi>Y7%yD($9$2H!c*jJX$9lT783YPH&q<#it`$--A6kGt*s8?bQ)3^my zwqj0w75Qzg0q{L0d>~N^(45{vpAoiVXBT-_7#AmymUcGTQE9;)uy6j+C!v=pH`VzJ zo>%@{a3D|o1YH)63^f>wOGlxwu*7oUu4{a6@(K$aFq{`Y=YNT$z5d?yR$|>DGYB03 z4{A*sCC61gi%+$)30Y~#D^-i-eH$IQ={azZwgd9MgZg5p;+{xAj1uOo_U(dhs4Vxa zMYOc758^o;elY5;4dRE}@}sS-+U=LPGH+8nRz9sC;JM|cdDFxBcF0Lx>NjdW zlSz1%V9ybnk#e@m4B00Qb|2z&d~W5m{#!O4Aw_>WdN{VEplm{L>cDXNkl}Dbi@7u_ z3dp>`19&3V>?cFu6ZXpW8+H7>F}B;5c%1b9i7-|N+_oD+9+O)8bBK36nvGDIFU(== zzDE@465_i#k&#==nlQXd{EH>(`L$&QRl4>Fn8WfH$LT{T+g<`fVmaDa)gE?wzs!98 z!Os$fk-WW5h;(IZOcbUbSOH{+=YS^rGex>qH4oFKA07k#17#Ck%XU7qATSzptn|k0 zv9A*bL~MZRhp6*X$f1(M#t7dKU*(da4W~R6S`xz0x9}>g;>69`rYvtKpEV6a=`TPVFbNoWg~(J-V*{F(s3%cZj zqHk&{H|^1#BFYBnkQ=1;9KrjfDDo~_>kp>HdEj~uR7jV-G~cGipLj1@My-#Mq+Q>t zZDm=G-w@>|KFyv$UWC(EEj>4Z4(kLTHJn^<*$|M?0_G5zB@4%x2EBYvK2%y;*ppKu zgN)Eo#cv&i6k(k4A<2sg^YL9Rs<^_`6<(e%-H_4lYgQ zwA6#5#704bo!wo$gmpi#5O7Hp*xa){8WQW-OD}be6`plfWSs7Afjsyk6{o}CW4_r< z{p!y8q&eWDHl1qtuu;W)d zR~k!RptX|2-|r%$Ti?5xc(oie|3-$JzpJRq1L%hnW~g2R$W5aaYF=iW$ts;u(CehJvUHLT%`V@HLkxj%@hAU&kpb>bka;(u*C|A~>=Y#};CGV5bG z*(RR`q0GLv)Y)BakGuY26B$Wgqfgds1o5y97qfJcZw?E96OnrQGGws$9{Mxp-UE4~ zBeP(W(**4c&>=%%e@6~(1qa{T??28HNv#NVeIbA6ebX{~xP}i6FwG^35~JIQljax3 z#VAQNM@z8cWfG_sqshYkySmdwT(NzZb-7c;>__r2rGqEJGU{KMdHG9NlOppd{Oi2Y zXxG!&bP1o_CR z_N&yd;9K9|DTa=BornOdR6K7m-#(I)M66mg6W^VV=cwUS_m0xMqm#OjkPqWB1Up-^ zU~RY&#o(iG_T?17zCje4Qv8!sFfi(it&d;nFZ%`G2h#J$4c(>4{{ecejjpTysuRyQ z|0N^^9w#&a@rlvty|+iljIQEEyQ^P#_*q zd)n%c5#+PE-u^>sq3nHnd8#!W3t8r&vV}uSS61g6>eql+oKP0(jh;3M@ z)cQzbV?TQId7guXnSZB-xRpXa8d|w%Uf}eUoiF9y@~R(y{ltJ~s(XkzFj&TfMe_J` zryk2i&nw$wIv-r=J;Bf~x8gp#{0t9m5a1q6c+SH3b?a`7h$oS(0~-_VH1%kg$&L9Q zKaTnvj8t(H;;I*G2WXs{Ge)Ss*G2?Z1`slmZ{IqPH}=LqzH6oFxE9c{B#Ibyru-#>eY zV$O%nTVmV)5#C0uI&U9RH5P%>Ltc6h-|{1<#~!;chIUX8gtMmT0{MW@qxyLU*O9>m z5X#ci&P`6{l>+ftdiH4+jy%jtyPrWIZAe|Zvkw~E)W1Gg%Y1L65%LmjNvr9;8EZ+F z-F{8b;s{N3`0pO-hXh_<;_w!z$uS$7k)mv@w~4GhDI|L~Gf= zCI%q(;a-l2anNv`5XR22!DPP58I)y9%5ca_WW~R;$VW6-ODb%g9MLtrI|I4{tOk)8 zkJVHGy0y3RR2)_R+IXFj0h(_U)*++tU&qZa(O)(PJ2_Dx3v8MaA0inZmQ4{J|EWrP zJE%mR;C(VhzOrcXA7)5b#^BWIOjd)>4A^bRN?n^$X9kE`gsP4Vszwt@QA}zNJ&NYZ z*(fJ#)24;Eb9s2#@98u|Dy8y2T`Z`LmlC_yzSXq-Z$% z<$;O4xWco*z;-p0<-F%Ge(ML_nxQdxuqhfB6jfLRVMUH1P071hzR<6Brr+#dm+#35 zk-lnv}1-U?wG_%QJRK<5>f#Ulk}ATul7>_`rTgN<_WfZ zKqlEF!{C>)dOBCYv&`|b=@kDzai*{2*RE=~ADJxCj}3aU)~d0g?{^#1DT@y0)5&GR z#Kg<$+76} zAQ>m?=eiKjjqdzP^VTAkFlb%Lm*+_DoQ_anb-5uD>@CEAQM(POy;~pRCFGxitym>n zW@tVMBP01_sA&sJVYI!FYBI!75jheXZgQ%_1w-Sopjo>^qa@x(S1?g2&%)gRvDf|u z(;P0szpTLB27FudJn|zWi6f&cok?k(sholy$&Y2C4=Jx#YnDhh%fdmQ-zCHC{$Wq6 zFZRM)3?agQ!ff&A-qU)yNz)llYyKy}mqB2* z%Ud*d_;IFG3s4CX9ds`CxqLd4U^+8&*~xui6R4BQ;EM?b+Oke&0V+3oi8mqBtMn=D zZCc+|(qaM~i|ddHe}BB>eA?>h^BuIG*)wZ+B=uD{u->R#U0&R3msOejxK2 zM7GKU>$DBpy7|yXNjXOKCThRp_fh^5wd7l0?OeI+6krZ^&_zn5y>!x0e&_`adbkY_h>E&8c7p=#*r|$5u(X!t~$_^-vo@|9!O3D_h}oW)?ujh1VyT>mjfY&N9Y|0C}$!=muIw^0QZ6zP;2LTN;#Tgnj-hLG-(?vO^L z2Pr8fq@=q;Lb`isrE>tK1ti`*{+{Qr&vV}ET<`n!oUfxOv-jF--K*{!a0i7FtTVD2 zy<1xBYFS{yKh2M%EKl%l!iB6ds$qL(Fpzk+FMLV$S+dyfg@#TkH?`A?W_7X%8TCXc zpWdVQrrhA~j>Ll=v|?z>Qtf9+#j0OU;gi-C!%{`5H1elv*b1+I%DWmI3Me!cbir+& zK7O@_HkL&+Kk(9*qS$)@*KlUispgtBTmO{jd*V!*&l+Id9Q1Bu>ZfLG<5bmdhjBD% zd?nd!temVqvM{GYQvy8-WwLGoSFHAWqgQ~*2ET90uKufNFZhdYS}e&IE3^<*)~Gk} zAp3l8=IXXnHJP;Y65iQD2|&9>DYjvr0Ot>m=JWCw>Kh=J;9q!sp#oXqvn3dRkRs>; zZ$8w1kdoRHGoR1ptGm}Q|4-F6&6EzbY~$VMybymb?>Bohq2I*QZll0F&@y36DFoGo zd~<+v_t;SM7U@=##hcJ%RGX<5tlErvPo6pyiZc8iq>vK8LAlVr7)u4?IjPGxe}G0S z9jB7StzmTcv&Cw~Rv9HBHI*dM={BMCl$x-7B8bR^y-KcJcOL&nC^ShYWJw9i*w`r{ z96mq8LIQ-wHeyrv-i3)CR*u7b0(_DPsca5IsuILJ2E+x3B1N6sOT8^;-KI!F2}oVY z0&m&8uz0e;qcjV3Y(GXP@Yu%3P85vsbG|>4X0dF1paSLAw3dD$QQ{MK5~F>}!#jiN zx?(0IahtdO6YMg!vL}owd%qx(VB{p1Fif&;vkjt+bGV|utue5hreD3G%1C`==nz;~ z$sI{p{yJyV6nG!MPUJU_z$2eZQw_sBNZ?OVZ~C`XzIJZEmP6%nV|z5-`0*_x~`a1p} ze_}vQgW}+Q!VUUX==bn&Ynka-TIl`O=^T{{vwf^-%vv6#KcuK-LX5P)lte)3k)VZC z+uFoR?z}rZ+;ObrHOa{uBXewAdaoMdOkRwB)>3GKq|G zCH(~(@`Qfl1q^-?>=Sw(nlpuD)qGdTJJKE(u!5$EUV;7~-s?pd4uza73m^V8Q+2qw z&UG0oitA8q&a%Z)PC$qq(@iQSwb#utBBP9BbVmbuG9`K*J9{=Wh2Y_J%#-h-O*!nf z__Z@t5(WU{$PnQ13wRlIniBQk*-W(sY15Tog6#o{H1vv+djfNc&atR!;trS_G92cO zUhWLX0<)xn;c=tOfZhT{Ph5#wjvv1R%ZK&+$BCtNpe&xm6X~_^x5f7-pdxMg7+^!h zeyb1j;R&i1sA~?NJfKKIdMr)|lg`18`n@zk~mKgzvi3?6DiS>Dv z;x-Yukf-h@b_Y?C89rVD?Vr{)xkC$?ehXNP=jp2k(Bg4H9Gm6ZDU(xu$q}FKHjJ zkT)MH#T~{1QO|ZYx=2~7|3oWEKt3_g;C-JgVzWTc7H~K#eak)e&!~l<-{XVB?j39f83pGTOQA>v^mF+q(WSJa$5G zK2`k(YniTpZ5A2$p!UY&QtnB1ClZU?YL~oEcfu|xC7Th69*wgfU;A(>GlyLpxna>J zpRORI?Yf`vQ5nPaB!tU&Ia38thVAWE98EoUU|xk%cc>|x<crsIsA^ zfO&Z3&2r}9dWP<=&Gs^Ti_4_d2V5(!@F&6B?+TLiK*|m-NDCUJQAWY>vK#0$j`!O&N zYhtlfNGe^lF^b{!g1qp}m^77$%(L83^Njs;#FJI}q=v|cWYf^e`%_L&q>RejmDrpQ zr!_Y4PJ!0O3C+gMh^1jQpN=k!^mYt1V)qU8=c_fGBRza-W3@KV&vt=kvAow>4oZ?D zGTd>bgfesKj;2LN(cW^G@sH7VlK>i z^nV44e^PC<-*}a==l>6^>*u?Y?;jbW2_`V0c>U$?*5>?C=j2~SLD<^8XIMQ*x2h<@)wVxA%g9OKb?!@6^$>wKfIyhBfAQiXpIk~TnJ7_7{wXI_AS_0;`EnW z5=23#_8b9Cs^157G5b9YkR*_ZRkP{bk8k-+H%tn=x5(PZkv~X7iw_kPzn>SEj_(<^ z46?>MCyFe`JlYDwZS9Zj47P~r3V`^O>M!2Wt+(^_&~R+jXI$-q;o|qKh7Y-Uh24x~;H6oO@1Q&UOeb$nAlot)$u zE?z)6-p_7U(cPddp?jvY_y@)mp)gO?DB;$a<6jXb?Za=k@MRrS(>s%t65ov%FC8>H zzHVgUFvET1ItdKnJ~&>gtpe#q1R@f`IA9SW?*?cEyAGRYi=#V~_Rf6;+J0ujM; zJWv+d4-1w|l@i^se!fcD99%6j+=tO9wa3kHNKP*b52Mz$iY$I+qKMMBu)iVnj_y=Y zh8X&w`oz+{Eb)4pUq;(UNlqq#6^a5G6G?gqVaom}RQJ^8;c2>LX-wnH%G1(l-MJuF zpSK&%=7lF=MA8jsCBm_QfGYKjc|6DCMV1d3-#odhctvfXMlwkuc8G%&KsOGj zyCL^Bv6);xBlKow=ldXM;xbZhrelJ#jLu>ro=yTDayFUmL=EFMv=BHN-5oULPkp{V z6-}v5Kjw5@Nv9qpIelE86>tLGX%*L>rlPz)k|azo8iBbYIe$j{@yUu6D4*ORs*hi; z=G!Sj7dD)$bq_E~5>V)hANzJ;n7aw1{_j^fE`45o_5ICtMb6^|jmx20bpz z4uyxFpCJ{f@Zl?H+DK6wAjoJb!b{LqsR_$S%-})OD5; zwM=KlprL)7CDO_Ze+ENKO7X*hga?8~f6P_|1D?IFqUo+1(7_?-8 z?VX-(A2GqW0MlT%^!EEF-Ifxigym1tksY@+RU_+O{pE5K!%^@4_!J&hW&J&vcXQ2K z_Wq>J*O{5^;mMgx1M@ZQN2?A=9#UUkGj&j9uGCu5Y zEsa@kJdnC6%TIvb!CZ(NK#AR=xIL~>wpqHd!V*E8MD4iZ?|k3DpWFrWIl?RscHz%F zm~nZir0cbff7Asnd6An{Cw-iKnCXl>VX8Ihu=6$3-mii?c%IQYQnTAQW zw7!1q+PgBRkMz6NbBDiBZ~t*lJa>RWkLN~?;r_in_M{3GcK5w+xCa#a(8?u~@w3^> zpLDP_o0xV4r4mQ~rs6#b>54BtyIF#~@k%XHbR|#J^Gwk{E?9WAe9{_DukL;bsCdK4 z3o(5HD5YFGK6x4~^bd12LwFrm=oK2d=`Rkf3%W6{{fEWr zNjM77693ZZlk3i~{B{(whccBEKG{9sC=@np6`u-?R87k!~amyIcWs~k`4SC;m6*zKQd zQxvbJI;%H4VU_Y1efZT2ZDx+=)`_l{O*Y4$#iV})zrrpJgfvGHs(jF-xKXaLK9@j# zAo2QLp$327%kzsu0;j^;9G2FVzhovnen}R&e!Im&IvJ>PWy%Hl{3U*nHFSCcDnh8w zQ@4AOvmL{DX`qW!+e%(@Wvg(Rtll}*pHss0jHF;g!12zn&Odm9(hm*g>#i}`{vDsb z;OBDxeznfGX}1cZIQfO`b!oU;m>0#T=uf1y-i4E0SgCXn1}ohCO6V+-4|%Q>;#VPo zUCWGY$%ne+WhExkzc1HW3ZccNed;;>E`^vjSRaw!yrzoX@rXjyGQ%o6t@8u7P{Dm) z>g`R+#PEZH;Ffahk``FzPb2 z7)oa~qqxY3@L_F_Y(K9=&8P=jy7vgOF6X%^ zoJcIjdqcYkLJ?^hjulWCRM6Hen+lef9({hngMw6+?Tx8_FaW|C<;%)owR8b&EI)Go@cYN(PnOaFgL+9OnvO3(DcjZ zM)uC2G^p1>IcfKjsPNVj5 z#cG%+E3el<)p{9+MoMRqbLNa4)(L6RJi&*B>Rp0wnY-P86_m5Yv;77n&jnH+VNLxdM% zn5}(-t?;z|90?PnUSw@vqe-25^TtU&gLYJ$EE%1~!v9<{R}}q|fkAL-Z22@1MZbf= z`B~JilD6j&Y^Nn9I_*UmrSp;55Fa`#*Z_uOWs~8$oosedBGMRLLOK{;Pv;z$hI96| zz}QYLu=S*$`C8)p1uP!PB_{ym;m0f#aaO-Mysz8~(zt|8)HePb~j~Czjv@ z<-AurI}@M!BFcJxy*i&D8FFJsX5qiJoU}5T7ugIaLl50p#)znp9@C2`S!A8rH>)0r z42I5+PRH2nzfT2bag5V@Kky^*Z(Qlp}4%2QAm~fOYQVu zJ_E#hWt7+ODqY1dzZJm7&ulNHp@K$a!nUUrf0N2^2z@@#P3?qrh4uvRcw-+w%m5mk z*(&?iE1%*yXXNDyA*(LWW?1P`&cgyJAM1@3+C-Ie^65?gLAH&=q&SVeNQ6FD#nL2Y zJNtn$AopD&}~uTVOimd0}#C~6{N+&%NGX^1v|}C?hoF{9YKA4BZ!^!ZOw+K zB|C$XMllw+9}N!BWbQDB8z3@f^{V&8CyBZuAtWIx%bCR-HcevPTE}b*M&9<&)F%(M zD0OvzHuuA;=fsey&2E|AXZ^&op;nm_Nf@mYZA!2n9V^N1{Qg20bmqb?2aXPbwZ?-q zdCv_*vOto{g`dq~roE6x(G2gw9+tI|+c>>4x!zG?byZQM&%@3q21(A#dex3S4YiXA z4;wkk;ze*mX3vvqlz}h@BlOneNsX+IDwiSu!Z9EEFsIbU(U*<(-UwFDh~%ZFzhxKF zuAySUHF(m0rr#_mh}esvOHFHK(EY~xzTa{yy4j6~GW7(2nl9-u?d5&OC6y&2QEPjn z?r23wOK>hp6){JO>K?*yND?QRRLaMBT!Jy8DGwsV>xGPje0)wG8Nn10$FD}c_g2~W z5mbmbATi{ORsEvsF@~svOC@8%`!^X3H&f=xcwUpQmT)VNRYq7A2s|++yardLW1>-_B-Br8IKp9ar%#%9lxAi-Xl2 zj#zKxKR{D^Wa=GDsIM8)W(V|r@)J{ZY9nf%!IPW1#7SQJ zQ#X0nt7bFx$XjxAXFpCHr7fu+4V(@Y9rqCWGEKftv^q`TvR(@J3`%`-!pWrmK1(Lp zW_wGO^>ORO3|=`4mla4%3fFIU+-KDzo`+ zR#0~}6WQTvlj$9t7`p9bNCmLju6S&f|9DyA7~8D2Q$Mj4`)bM6ho;M$@|oi^(;@tr zi~p$$qY`;jR3qo{7l(vD!3{M>9f)#qr!;+_ErF@I>*%%+8*;auLzkAXY~Ns#9Pz9{ znT-|q9TK5}!|GYfQf@4Fu~H5VA*^Gm%4`cB;m`_I!QLJ%BMi&UKC>EPN#XB^>5GAs zBpw>_-k?g4a7N;V$qQ)l7~99;4M^PGJLFKsWRhdb5U07`LL)hB@u{s`o!%0O*S^c7 zUUL08?i1_|Nl|45#Z29cy*yuXXah38W-aqp#$^LTl)yB7yNbRiQualdNWDiXv@2UP zFRYky+;Av!n!<|^5F@`K|K)$(Ay3yO1WHPBNN>x{XHtaY`}IAD?o;*uZ_!<&J;&5Z ztWt*WM@8ofuh3x)j+lT*=YX4At@qxsKI(Fr8r?&`WI1J%l|Xd3kLIga!hW{F#LvlM zSsRvqd}f4&bk^B@GaG|2e@~!Lb*llq@xA@MMA}q)FstEmD@yb6cc+V9zGWQqzAQ~R zct$U1!39T%U3$CeE~dTTKUSTuQI#VllC2r|_0=LdPP=lh$uXGiDIg1~U<_1$LNcEb zC(x|q@$p29^8;)D$)Y#(<@es?|7#b05=bvhDq=59Bh*5Vzlr(qcBD@_v+Zqxjlz}1 z^@RFemF|v+Vx41qmEFyR=9N4ghxP*xDL1b6vM!i#L4dIJ%5JHdbhjbNak69`Qa?As z5`XBlV{zoXC3YOzr2t+WXYkoFAXlnT(!U@sATQjv!p?4$aMaB33sGXj#yc+Oe2?QF zNwzaa`>8L-YkQ?s-CJ!N5l@YH9+HJqaJKwHzUVb$=_eIZT1ZRrCGh$DUhUn3aM;Bv zZZ?^}zG&0!!fvh#t267`1_r$2-Zob)a#*l*vUlZlC# zon8x`Bd+1PbpPnRcShw{PaUj+tOD5Z`Y96h?~ygn%V4I97_eaN_DgFlQ7;Cb z^+We7SaVrNY6JC!Hl;@m&-YpzFPG)n%<7>Y8NQTb!8R?sdA`KCI**)Pt+rDoQd-ul zwLiA@REd_JkIN%`k~;{tKIt{KjT=!a#U0>Zb3FIjpbv z&lK$yKVbl_nr;O)LDssc)P)bF`4N`zp;o=>v^7M#f{qsYpsZ~7o!R$8I&hfPJ2`A> zBRprLN~oErQCxxB@stbi8LJv+3y~Fb0&xq>E8XV=f8fd6Gvl0~!A~EjT&NG!mYqWbw?SA#0^ z#o?BLtC^2_Kz&Dtm^wgTt(ATRuB$`7y+Pmw?_hwq)Y;sj4QfQP>hXlOFbI`x^opy8 zr*%^A8sM$s_hlxY(7LQn68HvH;A4qBQV{(HM;_Y_#V;bZB2T8(%Dwd@SpyQiu}?QBv3| z=7(L3%e^jT)L$^ji8!-T*v3m5{W$6(`b~kjwVX>y>;W`S%%!YAj0bN!pFYWcc#Ck) zO3y2Q2u`K+&~wSCnPpQ?@x;sZwj!m^)E~A|3SQyxi40VLDu`x@%3Q>; z`wwCBF=|1cFwK~E1m&VWyKYHhn?D{XYdO#M@rrIFnx}dU8E8K`(tluNqA^woms4M} z8?_KxK8hHqnc{NFI*1KY?}FgsmatKhIrVy(F8=sl%8>Gk=_oERu8x+K;*cUsc)fdQ zukr7AcnaVgD+GW3PgMZrN(!-2cMb8lO&g|;zK;bxVWWE(%7H$A>pP|^{{y^&g~DzU z1XFKYF(p6Oc4${*_fzj1%{M6O?A1afN8Pp&h7Vvo`#To4m|=T}@vprPIN}fy3c^(y zn;oZlZTT8rh-i^q&4@J`y^1C13rGsN@KpE6sm8c|)f;B@XF4&DUf&tM(PQ^U7kkf& zNi8T?=ab|okugEq`-Di4+wPZEu;4;?kIbY?=@VrxdgLLitRE@QF$Iz-(1=*8@Xp(< zRAEahB1bCz2P%?vc@gqQnsF2eKp+v0A=Wr-hYdO_hAt8$G%x(EnF0zkGU&EOv%=W* z8m2@6IqMzTk!*Pit8evH10T6&o8BKt2Re#O{gndvx%@5^2AR79^@b!HlW#blQ%Hmz z0fpD)xy$jUle+1EEIpa&^(>~%f}hH*qiWFeG4jf7OT1TFmgHycC*$*bms2Yc4W7@;%kC2ucy7b%J^uBdEwT!kKfpOEU7jgd>@3GbOq zvb&_8U0I;WaQ`0QX>*oIpP@&tCtyh18v}_z1U|DDq#U$jv5bE==RHU#8`Pd@)IVwMFUJlHnPZ*4Z|}Qd+*$Tip>*s%-vSf zqG8dWFKi^G_KrQgEz;ipG%gcY#q*3Mh&&NJh0NRSFa|I4vKPNwD=+VIB^o^xehIeL z>DuWmVLzLyUCyTKKq{q_@{_`%$b;m{ZhiYne&W4u)jV$NsyrL_lgyDy=Ru+*;rdqytMPoB zMg=?NM3aAW0kAh+yy`LgG3B}J6P?|mzV9Norhl)DZAbHiruLEW@XY1B(qc|UiOt$F zX>6@cfzLt2g!e{_Ly*8CWvZ7`#OQARd}WG@*x58$v*mQ_u2#25Tan>`)8KH{&j%Cb zUDrpBr=8Si3)f2q&f|dG$uXs-@jt`4{~C&9x`_%YXm6ALwCYjg8!UmpvoCFsec5-v z5ke!qiG!7l@669wi0K*-r@{ZAmo`Y`K7-o$mlCpRf95bHoQqM7lZS{eFq`xIfsYzS z8a$asrK}hbTn9lFMPuFR+%Q}v_S(mSguLgcW*IOoeJ-nqj=S`Q$$=jWPZ0VQw^Y<% zJRz#M=MMs2m)}1ci+#yboIc7x{x(tYHO^DY`hD(N4||&P{B+S4qCgP=I+m3H>D~&=6R#`NBT>maM7mNP+d7eyDms#q8Yz)$WV=~-@;=6k+8R@k2hUlmYAS~Q z4T-32_r5yG8z~+c7s7Jhc`q)ZgYAk!=`fOeXgN4S;}N23Oja|6A1*elXLo=s@$D5z zlM6gB`MUotEg-!u;Y#k3cCgipy%PR=49F?y?`Nh;s=In%N)K4 zeLtxXIUJV!e_Cl8re*=!=K5F;$0=`}f_K5Z7roV}p|;hiX-Iz}KvyNJqFUF(|2QCTNlhP7^;@D7~#lTOv+lP5V`r=T{bI zwdJXV)z_vRm-EeOH4eP~`^*4kR`4<*jkK}d+2YZYHgT`!!1QB7kyiZ|avQ{0{q`%F zhRv|oKRYQ6CLHv3_U{jY38T0>dxNzky0r)%-wFs8I|+N$ zy7OXt@q>Y6Frj~1oA(H{_8x~#n7Wtn3LM&&|32;IslDn8eU~!vcLdG1#Hysa?^qr# zLSIN$7|EF>=yNSXVOy*p2@Zy!4mg3ZdF{SzHvaVa*SNvH6%wT8k49`GyIM~(My;mDP& zpqfBm5ez;D(}$ z6M!l>&HtGP1OfXRDqvshkpHiMjhZ%D^#=iaPqy&-qMuwVI%)~|xV(kYk0=oL@im8S zeCHbwy3dYbMIAmy?zxPu@n;qf^my{pKep2!c0Gk4@mQ0Pw^ZKJLLi`hw6w`oGNtWh zYrP_~5qGSFb6~(2Ppm{K=-z8uQa`n@jEUhz;FX^`^J%^CM*IVoSRCf0*R&7{&mf~~ zRC;BFcu_a_J*B=BH2J8Mc=RTuo^2e`B#3ar)kS@%jquM8Nf)N#+GMF-GNd+oq~&;? z=gW8>CCFd+v&tfK#JCD>3ADcDml7Sw^xAG$mgGJAg{^r#02zzCZ^C2yb?RxdKr0aa zibijd<7l!@5qwn%1a_bPqQ!t1`PTj5Q1az$h_G9?AB$Ycrm(A~527r#(P=(e!V>zC z?6k8SnX@`o;K^k@_2}2!&+16yWDjH>ulLzo7hYvmg7U*&i4Z$JuxljfX}SpZbS>pN7`@JQR4<$ZfNjFoh#`a#89 zm4Mw>)3EGI*5H#^2A=tIXmw8upVV0FEN)Moc!AoE;Dk@ja?z1%bDwPkUDTPJ8LZj@ zH(%elip|gu44HLd0%s?pThK?Q|<^|h+a+d zRByzn+f>ZYQA>(7cp5Z}$hya+RGHGiT&A3)T&)t2>{pIK10H9OllbyZj^O19fux*K z!-CtK{aQEsY2aDqOkcko^%$>X7<~=S6F`czZjsdqSdRn`&0zTUTwHD5`R@KzPAx|% zn*IHLt$gE^`G;k#5vP^=|2O@!-#t{U;@gz?MY~UFtZ1j)7nV!u?2Q-dzi^4~(yq`i z4dya<-X9>%38Y-jqZS>10U1xjahQ6ruLKeD9DI!@=e>=L#BTQLRnhf2G{afVd-|wD z*bCF=G}mAE0&CSs#dm4s;3f_(Pi*RsNY7+bnZ$lSvUiL7xMA|5*y!%h+LVH!q8%zK zTu~fL`0g8p!XY^KKflZ*!3|aw^>hyKI#Or%wr}swxrC3LCq_0Jy&)I#GTMxr7{ick za151kS?bAZel#rl-pE=oX;9K;{DGZwEo}j3N#?Su)kD?DC&0h)vtRkUObD2DOyVLB zuiRIOw-9+1Rr9%xjl1UuuB*8Pg+P#YWPn5QjM5`_r*UX#iCxq9X=ItWKL+#o%b|}p zIk;jX#UC8dl`QYjT6wo@1{59zT07`6niT1KHP-(Igv=lnlO37bJrq1j(z?hPJU-g* zsNU||T+AWAIC*hgxH68_&gsMSCZy7XxW=+X6Le^Z?AFgbrs=es7Gk#JLaYYwikYh# zO@KtR!>6h>((3E|Teq!kZoJWG%-$)q9s4nbT$O9R_cBPG=%HTHyVYLZ$#o`m72H2< zQ9trf5VtH>x{$$tJ_N0h8B~YlG!2HSsUP^(Z_$qnO+QdyV_!~_+S$Q=`1FX?)jBF} ziuD$i5RXP)4w*G(8D`lzS_0Yha2y1YTLH7e_h(WNA#Tf`R@HV19jDwl3?$6F+%@Zd zaI1On9>Q9|!49Ec721(AcPcQ2zn?2l?Hvn2bnhs^jPREFh;GJ{NTI`76mCu%PhOjG z!tD6eWDv23_F9Kp>geXRDt^k>bo<6bCG5kiaxyOxLj?dY&=rs`R-Ik+^m2pk0>nJefbbBMXk7Yb!zWsX&h7 zGa`}4Dn8}BN?pIA{s=jP?(6+!_(4N9-ad7?>d&I>+|0=GoR40;XSf?Bc*_&nTtob0 z3{BcD^RS)S8a}-mj6D06H#eu*PJ4sEJjz@{9ZIPqx}Vnt`65Zo*XQ#6^yPm+w3j8h zt!A^0p07|8peQX|4xYwxFmlhXH8r7aXOrr+A1a^3TO{RuW>?l~kh1l>`7cT$Trad72zXd`c{&8=c&+pTLFcyC3s{3C?6EL(wTjk^mVfN z`A6YtYVxa6k)PWY_Z~xWL>@;~C(dR8*|zEGJNHvlFP&k(_Fz8mrWM^x7x9Cs3=7mY z#fk;KyOdkZREDPboNZ22Sxr7U9I5d+!FAX;1q?~EJd-+B`o6m7kV(1L{uH5CELA^% zAd?BWx~j#t;4ZRflB7EJ;w>lF{k)DVQZLxffc&n|_F^z3;w({56L8cC&7_H=WA7`o zV39to1X|P6Sc|Grr^@8CR;k{{)jk(z9lJ`I#c$V5$Et0#KO^&5GcUk@Pzn=EF>O9y zZJ8)FT+w+d^d6;aSphbZ7{8xNuv^A6068H2osXVyeN6$|uNpvD&~G4-2jJkJqJZn5 zMbjHovn?p)UEE?nP=>+$RG!fvRBqBk;JM$!hfJN`ytN9CSE->1CE0FcKB^JH{<+!Rj+T&aQHq3u& z;}K8lP>r9u^!+D)x|ygpuOq5W~bD9t#A3boOBe?Up(+sC*wVhsJ8x;&@;AVR5s9$4ESL@T7WQ^A()l@` zmSz^@9OvWfD7{d3HEhYhT5 zD&vr*-M*U}$|-0vld2)*zJcf{zSJ5|ok4pyLvYj{6cH8EsTjs6rse=LRIc3ST_c$M zs-hf^Ke@MH!g2e?h}ZVG|4dXxu9FjuiFEdx`6%My+*^6J5^5!SjdztvYV@Ru71Ty@8q&E+yV&p z%gs{-oU+R}6Q3f7HyWYXNuLTf(45tOu zK~;bvjZsY4>?-xDf&9^D;jU~hiTLHGMS?D)S8#TmRR;b?=}?Pz1jix3$Sj`KeM6N3 z{ajEp-4i0&dVlpxfA@-W*-#Z?Hph?as669erUw8#CJMkyWPM_fjOu{!EdI5=8ID0U zdd*>@K7}Q`Wk@ufcn>bDr}FG>q(_-DmKd(+_{$Q0>;8aT#xl54@$pF%H>{$&EB`Vt z{Om9z{sx6F8H2(Fab~SEK-^nVo&k7)wJH??XzZ7)s;0pmd&qFZW^c!+UZF z{;N_thCFI_;k#XMCUsE{CcV>BQAb3oR#Y6`wlHFW79w`U{rRknZZls8sg$Z(!4jbb zH&*q1+1}+J9(;-E;{4Dt#B@AUM@`B*4o2w`t^Mn8a}4is1YtS+dLFW5T)um$AsFIN zyEEz8OaK~`pA3)1-EL~r`rUB)MOCAHd9@&)$ls$NwsZJchBpwY+74`}&HC3)O(b)a z2hGDhWHaR4VExGpWX!jh+#ZMT-LRCCcx?(z`{MnCoy@(8C_{m@3fOIms6m!4<&b`O&G-?i>L@Px< zynlEeAEf?(TmWjtcOqxzdp0k)%zOxz?L!KQ{98#w^rI5L_$Ou3#5qt*0|f}K@`+ex zm2H$@Na~32toKh5>sgzcp55B3%jOyVOJ%QL@s?{PKr!9BLG$gw;SaI2c2?Y<^S-{n zzWwl_7^C*uwQ~hhN1B;W!?)wLZ3kbv@qRr%-tQ}s8YSVg1q!3pAASH~wh95KH4~eI zp_8vpS8)DnyZJ#hKb~Kg%4q8-4n4XLKLBG&bvWM~fBhH#+4}nm-2?_S3j5Zs0u6g;d;6V|8x(IK zwpgsmL_7ZEKTn8oe*}2@=sfB;o7!uW7f%>gaVb@a6lug8m+WHr{4)LH8q8QVO!yoV zl<@UD7TX5(e9q`k#y(C>8AC_iR*fg`AtaA>4Ktr2$3%;u*0+_G2_o9l(g{^4F+bxZ zo|#8{@_Ev#Ae@mtB5?N;eQ3~2n8FN%YQ!*Fj z9%R1K1KSt%7ogzQw5wGw(Q1WLr^!mJhyJS7fiXaRm6$L^dA=TTBrBkYJz1iEl{^aY zT@9eoV4br(1SBZZOL1s`ydxO09mG_;pf z!rB1zdC|&{`X8DrDawKN1lp|gn7r}V%*aa-yhPhRN5xyX)F!}g%_e0o41CU)U` zLj9S!Pr43B?a=jvyVqJ^?^A#gR7`*0-;*|JvZ&-C?#s6Pf0`Kx$h4?{+_ED6$9?`b z%YV8PEVL%<*!R#|+aT=HFWx}WhNM?Mr9BnnjH+08m&SVQ;T=KV6XsDc;H(y)V-%`n zUH=YhXM~_=M#coET!x%2Fh&HQdr?u~)*&GXrgmjgCD9{QiqFVQV|CvnLl`#oS!q6r z;3+2W<_KQXLIP8&M?SlLOWaG-P@G~0ZqjaYHmX>y-e?6%&Zv+VIhFoQPpihr5yVj& zU}NeyU*;}MOY*{B0Pff$`6BX?!220eT>g5Pf&!8r);RXHlDGb4X2NlyaCuMh$2_r= ziwTebknJZ&-2}Z~3N+d`eUbsQY++wCqg8*rO&yO3)To@>91S7N)Y8uYCB@?x75 z=D3W_H=P+NoU!Af?JlAVG}`G$Oiy+fAB3o8@#qoKhBYMF){lTZMQyh#a8lnl zg_xN5UP-~$Y>mD`(kRd+;kl~*#I1RQ%l4F9u<|`#psx+4=4llIcYhLeHI_&S2u$wF zNP~||=*JDl-QC8Q7FvQ$13qyF&DK}XSQflK=p_g!;>HnqAimmM{m5H)5yXKVgo7A=+c z%E-xues3DzZpKNg@149py=*K^)CFJp6(Sd^w1HS!Tw}lX!uO>L#F=`vkNWw@AUsMA zX2c_>SRrysr;MMeS?Y8^?6OC{Nx6~#VP-R(Jikkiiz(Q}n#P3ZP63MMp4>!|*2LjZ zvW@k^$Gw|_i|Az1D){odqOr){rx-e=%?78T@XNm9TH%IEy9%~rpp{+eG$_c}#K6H- z%os>fN^?Mi=bx>RV)=Cf_yRGAev-P@>^@%k+3}7QXi>q~qUUJhnu?<;A}CMU{el-H z0QrkVR199X4D%^7dGl#&0TEy)pbC{^zHW}PlKb>W{%)@Z1ZM~a-Ink`AN^J`$S`+98cCV*2RhI(9=f{2YStBW_;G+j} z^Nn}C>y9Ob4Pq{l&knyiQoGXJ5U{zJz4ZpDV5b!;%LjwG13Wt-9`Z2-3VH5w7wUtWfzH`lU3T9^^fA zk;NRCxX&W14oopAOA^=j&bXoPDd6T2ni=9>e*Oy}j*McCKuk@LAo{0x?SsM4$wUITiJ+*X!?B^2hGM0G zvB}59*tAy1+taRJ9l8pvtFu34o}XzdK8S@}opiaLECzSFMW9q7z_- zevefN(oA@$TmEBQqDYS3B+m6I3Q~{Q{07EosCAu$lMsVRfEB#{i+JO;e+^KVN3i1ukk33T1Vu9I(EmG548HM zB768bP2%CL)MDOaUITve70i4^pf8<6qC;_fXr_9V_LMeNnEFPub>U%qkUm#gws#w^ z`U|$nvz>?RQOK37fhxvqwh{53@$06`!>`k{1Y>coJ=zE{;*L=>+U?;;0S$8xnvM1` z{ZFi3oA-uQ<=k6{j7!&ls``!_sABH}o^^sH{OID1bn--1v#6BDLkF-SwyTnf*vN?1{05qifwOgk-A$1WPbSco!9NtFJs&UKN&C;=K_I{X&95qf0;QEDmPZtZh?>bcu{Q`4*@R6?E|rRD0$ z`=(~&l9Z>rhNW3YWqArS(4%g-qtb95jX0?MxEkzy1Cz&%=BWXFq}#wJ?-|A-MxnZm z&FB0097^-&jUK%pE0oRUC9Zd5Nn&BH61LF`)hBW_JcHitMbE<=X@S3*KOSuX^DNR& zWzA^SFG>q|SzW;B(lkaph9r)t$1_Bvh)>5R8$v3l*eEn6<+9gMI%M^{eUD})QzaNf ziOO*}uSJ%ccV`5wu0P3Dm>$N|G;rAEz^!h&ID4uw=X-@t;R@0gJZurm+zaa;snWBk zt_bPH;_PJO>J7D#TjdI%D{OOh;W-N`gel*GxJ`SBgtiJRDwuoay5DR7_3^a#T~=7` zM{_{1mGEcQx3d=^Q62Jnnb3KHgE@~a_Frv~hrKVEBlqW@b<66Hbr;-+iFr%8M`#tl zA5);PZS**Tm*lNf1&Up4!rEBTf3<&g8WflWBD=}s0?Ti?3PIApd{+Q@(4pZz&Y)OuV#CnO8f{?~ZT|2DXTS~CIW{Qx#S)(%MXVigTus@p=; z7x@wN`2aF6dzs&j}TU~;7OCl(Q zBF~oT6Zl^)o`a$vYUynt8QGr2Wq~W280dDClM39pkB_gTYzToIe-r1zWGPDo7L|~^ zd9MFPTCd@FTCdV`pNJ+yB8YM(-Vi!|Xqz&$s&rA#%1|;Es%!bq-++`qzfJE#HI*_T zjuP|5VM|FOGIgRo`)gWf-B{vDH?-6W<~^9B`6lr+REgsp>7ZRp%Q{!fG^6*_(tU!DD}ZY8z5DTiQ)>pBZ_Z$c&(aQygspTrLSS%hC{@2B zH*T&Nlz&~1#??DsgG_lEh$mDm#73!ZRQcZtSa1PxRN9ENg#8@k#LMzJC&4%(`3vsg z6^B6hYzxJe6UDCjqJ)T4>aqlHYXbKx*1BC2|2|GT|3s8&$HnJ9AgS%FJ;FN2z$Q;V zAQvY-?}7OkY1`JBHss|u)R^P@qM!glL-j6H>@3;^iC}Je%yl*KcyX{uqyGzA-tbjv z+bw7eVY#x2&hP!mw3n!gTjHL;8T0=(CjaM$EWuACx|eXXF51u&q&~5nFk|vk2M~Wg zwtpV)Ym6lqkxEv}LT9%~x_(PvD~#W(T!l0};Vh5D)d=5>{ZL)lbu}$UQXW`IxnWl} z|7y9By8O7xM`S?Ml)gzZLXRof%aV($;LMz1^@cjpK$KmAm^P33%Wf6(XZSn_8q2p- zv^dwvIzpaEv4J^`V7GP*xnwW2C%kIZ0c4J*V|o?%k{ki`2*#&eH+i-qKN6&_$o(>+ zS3gbE<+VJ>g(+q#U>|icj1rxm1Q`0K`NzD>e(2Ltw$#SpshC+zd3*?=0#dO+ZNw&q zLB4ejtmIgS1hCO;3>(r@xQxd|KX>lwAe~hZy7&U1{7b$$d;f242jTcxVNg9I4&keF z5Ai~aF^1zXeM;+8-^;p-gVd}3XChIKLAV?~x=Uc8Q_MQPNvY@DP4mOUyJ{bHnM(s{ z`;2di-LS`}z>Yvi|GV39+whMdAMw{g%pPYC#LK=}2QhBNUx8T>&06oE3qlR%ju7w*J873aJCzT^d8 zI)#r5Ep`F=NK1dRR3k3_^FmHwG-)7KQFT9u7wK*Dp8Bl}j>h}#Mi#Z`cUte(Z+Bq+ z9UUBFXAazz^0sMoci)LTR0Ds%J2)9U#ng`27>-cJR#88d>4ZPd?; zv1BSdq}eYP;aA8d$)yU6iERmv1tK<@JhBKG$;)Q9Ur%ZU=;AVB=5Fs1yE4p9#+hny z99)mm#SK7brW*5iUh+bG+;Cipq?0MU(HRNmZPW3g(T%o$W5eyULil4b*5iH-t>80mhW#oYlsqjkDRZwm+#I;;yb7|!YoN?FKbhe;VEC7VD0~hal z^6~iIwBGIpT1=~-8%0W^`O2@!thZ)JiaFfju>`ZNiynZ@*SbJ6j)4w+aUJUjtz&}sWawEeP|!P5aMD-kMR#Fh`0=7%a744J z9a({|?_zf5GH9}t7@cL5xen2`!s zt++H$hD_q(M>8n7M}gvI`RcfH9HHk}0)(WlzMzPo0Jm!L|NE^{ICV?;k>W&s9dF=P zPy};m3{oaY?F_XfYE@M`SmrZFpEcrA`hAY)`KwytGJFSU1i39!=DA2c$|**b1MQD` z0lJ5#dG~c^%?Er@7+Ty*H7fVb*i3z#1#&LbVI;TK1%4qpY9lMgS28zwmYKr-61os& z`>vjBK<+yu9~~WxxN=um`!t=$6elOw;+sa=C^brQ$($s7rjU=WVrhg<%|5C)qsK&~ z_(l7j0L5JU#R3U)x1ak4=og(i#>qsi@-eo>nbg!C-Wn;@w$V#Hnd(H2Nub$%<2|T6 zFIukoIe+t-*RL#F#UlR)lG=hq`ugNsS|%4m6%UV1%noMaK6dd7C`J{&3SZdht-1>`*_ZC`d9r`e3lwy!&Zk>d5-aU9x!@814z$oXHtx)O5(02Z9G{!$K+^-u^2vJR@_k_%@DmAzmQ zc{LOnem`%&KCN08ONR4Yy`28pMgaSiM>g*^n^?z9LHTDKzETum8a~6dU_*^NOHGPY zl*Du=FADin?`_uSvtjA_dhTLGc_ee9(lFOK49PWbkhh4FJmo=mF|-ZXlr5TR>%4;8G=1vt*lLSzCWpV)z!h@=K7?uM@tqhWTuUw%J*|Gd zRcP9g6%ed@y|2bEE-f*lxD;XvW$+lD7w-9=7j1oZW)od^9ZFOS0H{*qXfx_<94>en3K9iz8^NQ8q&(anHUUj3& zi6DwQAz*xz-(T)Do|=+G7BqnajqGB;1wI>Fv^5>-EoLhm}ydK3d`-Tvkn_7n^2k`J9}uRz;#Xz1e(mF@Yb za?E_^N7Tf8w^!+2Db#(Qda6k>N!3=HWUp#n1!Q;gELvikw+zN>4(@zZb6S%++@_zh z6DObYr~uU8T+NB@!v>K-j=$Dgv#t{I-K&=A|7(c)?}r+}G?#9)cK^61pWv7obf0)Y z5rId)jcN>n2vX*ne~;7>^jFN?$7IFLy)R`{PsQe_aL5ag3%}4-UwY`c7$FmJk(T~t;0lD#e<~|u=VjthkhC7z6_r~b-h^qdT@PngRCt{Udgj&I zyey}&Jy5sVzs@Uu_^6CgqWy8(G%k)>Do`qSac(8@IYKg9?hJM5QaEX)eRBLErkkyU z;VWEq_A*QsSd^8mcd+ST?8A^bEuT?l^$6WZ3?dHmpGr^=s0 zOS!~ZAg{gI-Tsu3dn&=co$rkJxUZ{S_q#~dq-z&OhDx(6HBL~Jwgs|%d^Fi`l9tI4 zvs>*@xh&T8xa~sX&{9Ex40&EwRx3fmS3homX|C3`V1l#H6a})W^Vb4bQYBscZG#9a z5*JhK?Q``CVhUvMe|ED;!u4-fEHMc=3b0-^eI1WGkjo&UWWj(D%ehu3zGW~wLo+9`=n|z9v(CS+wY?Nmy_;F0AyUih^DiMtuLiqqZmoH%vNnPR&69k&RuI;wD8zL| zqv1L8B{efY&Y6c~Vde$RPgTQj^6ELGFq^SFkas*MSbMV+Oy9zCeHS5jotbc%h{Y)j zuweo7elIW3A<&&T^@Ef)Y8SwnO+*Us>3O(?z_?9pn(~vblfwGmlI~z=+;({|n7D#e z;mP<=%7ggO6VGj5907^t?^wXi8VrxwdEU=f3;RpIZHJ0@k z8a>W6Di6#vxHg{PD^<^==F|3|*2Rv~F#i0P@^KuqU3q&^(GP$}E7xfs7`MwCa4V*? zNf7N=^#8v$iTcl;By6y~K}ZNc(w|7KWACEW#;lfbuh%Qk7M(^qCg0IBr`4U!3LMNjNjyE(+m>6AP5)9b0gs&>C6%$n~LgtW<1KUsa_S4ZX~qt zqKPE>VgG9-=^_yF>E@LW;1s9Ht;nNkDc>nI^*2PjbGr0250xy^WJf34K-lFy0+YXe zh1$r_e*R0-^isM+lS<}AnLfV0?7)Xg%h@d%EMUD2FcCE8c$#PNAa{$+Gio0s3PkI$ z+e0$|ToA0VdPkDsBkP=jnIYO4>+L21Ci@| zcLyO2Nn)^&VN1&4`2?iiK;q6`WV&C_ahOGF^HMPX{6AUu41qJnSFyiJXt6BQU2@_| zu8yH>@yoApu@wujQ+rtETc0WUjWUwBl&j+f(F>>lHM;)!VU|3hiKF*sd1AHBJ@7km zW(cVnVuIf0wwU>*kQ<{qo0RY)_3yYW|Eo8-NWPsGo%oPNn#t|TiYbCQ=R40RjeAgowU(LKOq00s9)zFzj

@B#j}Hv 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 R%fP>5hiwk!AH4MY{{fzLICcO4 diff --git a/docs/guide.md b/docs/guide.md deleted file mode 100644 index 0c76092f3244..000000000000 --- a/docs/guide.md +++ /dev/null @@ -1,317 +0,0 @@ - - -# Setup Guide - -- [1. Acquire a remote machine](#1-acquire-a-remote-machine) - - [Requirements](#requirements) - - [Google Cloud](#google-cloud) -- [2. Install code-server](#2-install-code-server) -- [3. Expose code-server](#3-expose-code-server) - - [SSH forwarding](#ssh-forwarding) - - [Let's Encrypt](#lets-encrypt) - - [NGINX](#nginx) - - [Self Signed Certificate](#self-signed-certificate) - - [Change the password?](#change-the-password) - - [How do I securely access development web services?](#how-do-i-securely-access-development-web-services) - - - -This guide demonstrates how to setup and use `code-server`. -To reiterate, `code-server` lets you run VS Code on a remote server and then access it via a browser. - -Further docs are at: - -- [README](../README.md) for a general overview -- [INSTALL](../docs/install.md) for installation -- [FAQ](./FAQ.md) for common questions. -- [CONTRIBUTING](../docs/CONTRIBUTING.md) for development docs - -We highly recommend reading the [FAQ](./FAQ.md) on the [Differences compared to VS Code](./FAQ.md#differences-compared-to-vs-code) before beginning. - -We'll walk you through acquiring a remote machine to run `code-server` on -and then exposing `code-server` so you can securely access it. - -## 1. Acquire a remote machine - -First, you need a machine to run `code-server` on. You can use a physical -machine you have lying around or use a VM on GCP/AWS. - -### Requirements - -For a good experience, we recommend at least: - -- 1 GB of RAM -- 2 cores - -You can use whatever linux distribution floats your boat but in this guide we assume Debian on Google Cloud. - -### Google Cloud - -For demonstration purposes, this guide assumes you're using a VM on GCP but you should be -able to easily use any machine or VM provider. - -You can sign up at https://console.cloud.google.com/getting-started. You'll get a 12 month \$300 -free trial. - -Once you've signed up and created a GCP project, create a new Compute Engine VM Instance. - -1. Navigate to `Compute Engine -> VM Instances` on the sidebar. -2. Now click `Create Instance` to create a new instance. -3. Name it whatever you want. -4. Choose the region closest to you based on [gcping.com](http://www.gcping.com). -5. Any zone is fine. -6. We'd recommend a `E2` series instance from the General-purpose family. - - Change the type to custom and set at least 2 cores and 2 GB of ram. - - Add more vCPUs and memory as you prefer, you can edit after creating the instance as well. - - https://cloud.google.com/compute/docs/machine-types#general_purpose -7. We highly recommend switching the persistent disk to an SSD of at least 32 GB. - - Click `Change` under `Boot Disk` and change the type to `SSD Persistent Disk` and the size - to `32`. - - You can always grow your disk later. -8. Navigate to `Networking -> Network interfaces` and edit the existing interface - to use a static external IP. - - Click done to save network interface changes. -9. If you do not have a [project wide SSH key](https://cloud.google.com/compute/docs/instances/adding-removing-ssh-keys#project-wide), navigate to `Security -> SSH Keys` and add your public key there. -10. Click create! - -Remember, you can shutdown your server when not in use to lower costs. - -We highly recommend learning to use the [`gcloud`](https://cloud.google.com/sdk/gcloud) cli -to avoid the slow dashboard. - -## 2. Install code-server - -We have a [script](../install.sh) to install `code-server` for Linux, macOS and FreeBSD. - -It tries to use the system package manager if possible. - -First run to print out the install process: - -```bash -curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run -``` - -Now to actually install: - -```bash -curl -fsSL https://code-server.dev/install.sh | sh -``` - -The install script will print out how to run and start using `code-server`. - -Docs on the install script, manual installation and docker image are at [./install.md](./install.md). - -## 3. Expose code-server - -**Never**, **ever** expose `code-server` directly to the internet without some form of authentication -and encryption as someone can completely takeover your machine with the terminal. - -By default, `code-server` will enable password authentication which will require you to copy the -password from the`code-server`config file to login. It will listen on`localhost` to avoid exposing -itself to the world. This is fine for testing but will not work if you want to access `code-server` -from a different machine. - -There are several approaches to securely operating and exposing `code-server`. - -**tip**: You can list the full set of `code-server` options with `code-server --help` - -### SSH forwarding - -We highly recommend this approach for not requiring any additional setup, you just need an -SSH server on your remote machine. The downside is you won't be able to access `code-server` -on any machine without an SSH client like on iPad. If that's important to you, skip to [Let's Encrypt](#lets-encrypt). - -First, ssh into your instance and edit your `code-server` config file to disable password authentication. - -```bash -# Replaces "auth: password" with "auth: none" in the code-server config. -sed -i.bak 's/auth: password/auth: none/' ~/.config/code-server/config.yaml -``` - -Restart `code-server` with (assuming you followed the guide): - -```bash -sudo systemctl restart code-server@$USER -``` - -Now forward local port 8080 to `127.0.0.1:8080` on the remote instance by running the following command on your local machine. - -Recommended reading: https://help.ubuntu.com/community/SSH/OpenSSH/PortForwarding. - -```bash -# -N disables executing a remote shell -ssh -N -L 8080:127.0.0.1:8080 [user]@ -``` - -Now if you access http://127.0.0.1:8080 locally, you should see `code-server`! - -If you want to make the SSH port forwarding persistent we recommend using -[mutagen](https://mutagen.io/documentation/introduction/installation). - -``` -# Same as the above SSH command but runs in the background continuously. -# Add `mutagen daemon start` to your ~/.bashrc to start the mutagen daemon when you open a shell. -mutagen forward create --name=code-server tcp:127.0.0.1:8080 :tcp:127.0.0.1:8080 -``` - -We also recommend adding the following lines to your `~/.ssh/config` to quickly detect bricked SSH connections: - -```bash -Host * -ServerAliveInterval 5 -ExitOnForwardFailure yes -``` - -You can also forward your SSH and GPG agent to the instance to securely access GitHub -and sign commits without copying your keys. - -1. https://developer.github.com/v3/guides/using-ssh-agent-forwarding/ -2. https://wiki.gnupg.org/AgentForwarding - -### Let's Encrypt - -[Let's Encrypt](https://letsencrypt.org) is a great option if you want to access `code-server` on an iPad -or do not want to use SSH forwarding. This does require that the remote machine be exposed to the internet. - -Assuming you have been following the guide, edit your instance and checkmark the allow HTTP/HTTPS traffic options. - -1. You'll need to buy a domain name. We recommend [Google Domains](https://domains.google.com). -2. Add an A record to your domain with your instance's IP. -3. Install caddy https://caddyserver.com/docs/download#debian-ubuntu-raspbian. - -```bash -sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https -curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/cfg/gpg/gpg.155B6D79CA56EA34.key' | sudo apt-key add - -curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/cfg/setup/config.deb.txt?distro=debian&version=any-version' | sudo tee -a /etc/apt/sources.list.d/caddy-stable.list -sudo apt update -sudo apt install caddy -``` - -4. Replace `/etc/caddy/Caddyfile` with sudo to look like this: - -``` -mydomain.com - -reverse_proxy 127.0.0.1:8080 -``` - -If you want to serve `code-server` from a sub-path, below is sample configuration for Caddy: - -``` -mydomain.com/code/* { - uri strip_prefix /code - reverse_proxy 127.0.0.1:8080 -} -``` - -Remember to replace `mydomain.com` with your domain name! - -5. Reload caddy with: - -```bash -sudo systemctl reload caddy -``` - -Visit `https://` to access `code-server`. Congratulations! - -In a future release we plan to integrate Let's Encrypt directly with `code-server` to avoid -the dependency on caddy. - -#### NGINX - -If you prefer to use NGINX instead of Caddy then please follow steps 1-2 above and then: - -3. Install `nginx`: - -```bash -sudo apt update -sudo apt install -y nginx certbot python3-certbot-nginx -``` - -4. Put the following config into `/etc/nginx/sites-available/code-server` with sudo: - -```nginx -server { - listen 80; - listen [::]:80; - server_name mydomain.com; - - location / { - proxy_pass http://localhost:8080/; - proxy_set_header Host $host; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection upgrade; - proxy_set_header Accept-Encoding gzip; - } -} -``` - -Remember to replace `mydomain.com` with your domain name! - -5. Enable the config: - -```bash -sudo ln -s ../sites-available/code-server /etc/nginx/sites-enabled/code-server -sudo certbot --non-interactive --redirect --agree-tos --nginx -d mydomain.com -m me@example.com -``` - -Make sure to substitute `me@example.com` with your actual email. - -Visit `https://` to access `code-server`. Congratulations! - -### Self Signed Certificate - -**note:** Self signed certificates do not work with iPad normally. See [./ipad.md](./ipad.md) for details. - -Recommended reading: https://security.stackexchange.com/a/8112. - -We recommend this as a last resort because self signed certificates do not work with iPads and can -cause other bizarre issues. Not to mention all the warnings when you access `code-server`. -Only use this if: - -1. You do not want to buy a domain or you cannot expose the remote machine to the internet. -2. You do not want to use SSH forwarding. - -ssh into your instance and edit your code-server config file to use a randomly generated self signed certificate: - -```bash -# Replaces "cert: false" with "cert: true" in the code-server config. -sed -i.bak 's/cert: false/cert: true/' ~/.config/code-server/config.yaml -# Replaces "bind-addr: 127.0.0.1:8080" with "bind-addr: 0.0.0.0:443" in the code-server config. -sed -i.bak 's/bind-addr: 127.0.0.1:8080/bind-addr: 0.0.0.0:443/' ~/.config/code-server/config.yaml -# Allows code-server to listen on port 443. -sudo setcap cap_net_bind_service=+ep /usr/lib/code-server/lib/node -``` - -Assuming you have been following the guide, restart `code-server` with: - -```bash -sudo systemctl restart code-server@$USER -``` - -Edit your instance and checkmark the allow HTTPS traffic option. - -Visit `https://` to access `code-server`. -You'll get a warning when accessing but if you click through you should be good. - -To avoid the warnings, you can use [mkcert](https://mkcert.dev) to create a self signed certificate -trusted by your OS and then pass it into `code-server` via the `cert` and `cert-key` config -fields. - -### Change the password? - -Edit the `password` field in the `code-server` config file at `~/.config/code-server/config.yaml` -and then restart `code-server` with: - -```bash -sudo systemctl restart code-server@$USER -``` - -Alternatively, you can specify the SHA-256 of your password at the `hashed-password` field in the config file. -The `hashed-password` field takes precedence over `password`. - -### How do I securely access development web services? - -If you're working on a web service and want to access it locally, `code-server` can proxy it for you. - -See the [FAQ](./FAQ.md#how-do-i-securely-access-web-services). diff --git a/docs/install.md b/docs/install.md deleted file mode 100644 index f9e77616ce1a..000000000000 --- a/docs/install.md +++ /dev/null @@ -1,225 +0,0 @@ - - -# Install - -- [Upgrading](#upgrading) -- [install.sh](#installsh) - - [Flags](#flags) - - [Detection Reference](#detection-reference) -- [Debian, Ubuntu](#debian-ubuntu) -- [Fedora, CentOS, RHEL, SUSE](#fedora-centos-rhel-suse) -- [Arch Linux](#arch-linux) -- [Termux](#termux) -- [yarn, npm](#yarn-npm) -- [macOS](#macos) -- [Standalone Releases](#standalone-releases) -- [Docker](#docker) -- [helm](#helm) -- [Cloud Providers](#cloud-providers) - - - -This document demonstrates how to install `code-server` on -various distros and operating systems. - -## Upgrading - -When upgrading you can just install the new version over the old one. code-server -maintains all user data in `~/.local/share/code-server` so that it is preserved in between -installations. - -## install.sh - -We have a [script](../install.sh) to install code-server for Linux, macOS and FreeBSD. - -It tries to use the system package manager if possible. - -First run to print out the install process: - -```bash -curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run -``` - -Now to actually install: - -```bash -curl -fsSL https://code-server.dev/install.sh | sh -``` - -The script will print out how to run and start using code-server. - -If you believe an install script used with `curl | sh` is insecure, please give -[this wonderful blogpost](https://sandstorm.io/news/2015-09-24-is-curl-bash-insecure-pgp-verified-install) by -[sandstorm.io](https://sandstorm.io) a read. - -If you'd still prefer manual installation despite the below [detection reference](#detection-reference) and `--dry-run` -then continue on for docs on manual installation. The [`install.sh`](../install.sh) script runs the _exact_ same -commands presented in the rest of this document. - -### Flags - -- `--dry-run` to echo the commands for the install process without running them. -- `--method` to choose the installation method. - - `--method=detect` to detect the package manager but fallback to `--method=standalone`. - - `--method=standalone` to install a standalone release archive into `~/.local`. -- `--prefix=/usr/local` to install a standalone release archive system wide. -- `--version=X.X.X` to install version `X.X.X` instead of latest. -- `--help` to see full usage docs. - -### Detection Reference - -- For Debian, Ubuntu and Raspbian it will install the latest deb package. -- For Fedora, CentOS, RHEL and openSUSE it will install the latest rpm package. -- For Arch Linux it will install the AUR package. -- For any unrecognized Linux operating system it will install the latest standalone release into `~/.local`. - - - Add `~/.local/bin` to your `$PATH` to run code-server. - -- For macOS it will install the Homebrew package. - - - If Homebrew is not installed it will install the latest standalone release into `~/.local`. - - Add `~/.local/bin` to your `$PATH` to run code-server. - -- For FreeBSD, it will install the [npm package](#yarn-npm) with `yarn` or `npm`. - -- If ran on an architecture with no releases, it will install the [npm package](#yarn-npm) with `yarn` or `npm`. - - We only have releases for amd64 and arm64 presently. - - The [npm package](#yarn-npm) builds the native modules on postinstall. - -## Debian, Ubuntu - -NOTE: The standalone arm64 .deb does not support Ubuntu <16.04. -Please upgrade or [build with yarn](#yarn-npm). - -```bash -curl -fOL https://github.com/cdr/code-server/releases/download/v3.9.3/code-server_3.9.3_amd64.deb -sudo dpkg -i code-server_3.9.3_amd64.deb -sudo systemctl enable --now code-server@$USER -# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml -``` - -## Fedora, CentOS, RHEL, SUSE - -NOTE: The standalone arm64 .rpm does not support CentOS 7. -Please upgrade or [build with yarn](#yarn-npm). - -```bash -curl -fOL https://github.com/cdr/code-server/releases/download/v3.9.3/code-server-3.9.3-amd64.rpm -sudo rpm -i code-server-3.9.3-amd64.rpm -sudo systemctl enable --now code-server@$USER -# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml -``` - -## Arch Linux - -```bash -# Installs code-server from the AUR using yay. -yay -S code-server -sudo systemctl enable --now code-server@$USER -# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml -``` - -```bash -# Installs code-server from the AUR with plain makepkg. -git clone https://aur.archlinux.org/code-server.git -cd code-server -makepkg -si -sudo systemctl enable --now code-server@$USER -# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml -``` - -## Termux - -Please see "Installation" in the [Termux docs](./termux.md#installation) - -## yarn, npm - -We recommend installing with `yarn` or `npm` when: - -1. You aren't on `amd64` or `arm64`. -2. If you're on Linux with glibc < v2.17 or glibcxx < v3.4.18 on amd64, or glibc < v2.23 or glibcxx < v3.4.21 on arm64. -3. You're running Alpine Linux, or are using a non-glibc libc. See [#1430](https://github.com/cdr/code-server/issues/1430#issuecomment-629883198) - -**note:** Installing via `yarn` or `npm` builds native modules on install and so requires C dependencies. -See [./npm.md](./npm.md) for installing these dependencies. - -You will need at least node v12 installed. See [#1633](https://github.com/cdr/code-server/issues/1633). - -```bash -yarn global add code-server -# Or: npm install -g code-server -code-server -# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml -``` - -## macOS - -```bash -brew install code-server -brew services start code-server -# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml -``` - -## Standalone Releases - -We publish self contained `.tar.gz` archives for every release on [github](https://github.com/cdr/code-server/releases). -They bundle the node binary and `node_modules`. - -These are created from the [npm package](#yarn-npm) and the rest of the releases are created from these. -Only requirement is glibc >= 2.17 && glibcxx >= v3.4.18 on Linux and for macOS there is no minimum system requirement. - -1. Download the latest release archive for your system from [github](https://github.com/cdr/code-server/releases). -2. Unpack the release. -3. You can run code-server by executing `./bin/code-server`. - -You can add the code-server `bin` directory to your `$PATH` to easily execute `code-server` -without the full path every time. - -Here is an example script for installing and using a standalone `code-server` release on Linux: - -```bash -mkdir -p ~/.local/lib ~/.local/bin -curl -fL https://github.com/cdr/code-server/releases/download/v3.9.3/code-server-3.9.3-linux-amd64.tar.gz \ - | tar -C ~/.local/lib -xz -mv ~/.local/lib/code-server-3.9.3-linux-amd64 ~/.local/lib/code-server-3.9.3 -ln -s ~/.local/lib/code-server-3.9.3/bin/code-server ~/.local/bin/code-server -PATH="~/.local/bin:$PATH" -code-server -# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml -``` - -## Docker - -```bash -# This will start a code-server container and expose it at http://127.0.0.1:8080. -# It will also mount your current directory into the container as `/home/coder/project` -# and forward your UID/GID so that all file system operations occur as your user outside -# the container. -# -# Your $HOME/.config is mounted at $HOME/.config within the container to ensure you can -# easily access/modify your code-server config in $HOME/.config/code-server/config.json -# outside the container. -mkdir -p ~/.config -docker run -it --name code-server -p 127.0.0.1:8080:8080 \ - -v "$HOME/.config:/home/coder/.config" \ - -v "$PWD:/home/coder/project" \ - -u "$(id -u):$(id -g)" \ - -e "DOCKER_USER=$USER" \ - codercom/code-server:latest -``` - -Our official image supports `amd64` and `arm64`. - -For `arm32` support there is a popular community maintained alternative: - -https://hub.docker.com/r/linuxserver/code-server - -## helm - -See [the chart](../ci/helm-chart). - -## Cloud Providers - -We maintain one-click apps and install scripts for different cloud providers such as DigitalOcean, Railway, Heroku, Azure, etc. Check out the repository: - -https://github.com/cdr/deploy-code-server diff --git a/docs/ipad.md b/docs/ipad.md deleted file mode 100644 index 5ffaa50d0c4b..000000000000 --- a/docs/ipad.md +++ /dev/null @@ -1,163 +0,0 @@ - - -# iPad - -- [Known Issues](#known-issues) -- [How to install PWA](#how-to-install-pwa) -- [How to access code-server with a self signed certificate on iPad?](#how-to-access-code-server-with-a-self-signed-certificate-on-ipad) - - [Servediter iPad App](#servediter-ipad-app) -- [Raspberry Pi USB-C Network](#raspberry-pi-usb-c-network) -- [Ctrl C Workaround](#ctrl-c-workaround) -- [Recommendations](#recommendations) -- [By 2022 iPad coding more desirable on Arm Macs](#by-2022-ipad-coding-more-desirable-on-arm-macs) - - - -## Known Issues - -- Getting self signed certificates certificates to work is involved, see below. -- Keyboard issues - - May disappear sometimes [#1313](https://github.com/cdr/code-server/issues/1313), [#979](https://github.com/cdr/code-server/issues/979) - - Some short cuts expectations may not be met - - `command + n` opens new browser window instead of new file and difficult to even set to another quick key - - In general it's just note worthy you most likely will need to edit keyboard shortcuts - - No escape key by default on Magic Keyboard but everyone sets the globe key to be an escape key - - Opinion: It's actually an awesome joy having the escape key at bottom of keyboard -- Trackpad scrolling does not work [#1455](https://github.com/cdr/code-server/issues/1455) - - [Bug tracking of a WebKit fix here](https://bugs.webkit.org/show_bug.cgi?id=210071#c13) - - [tracking of WebKit patch](https://trac.webkit.org/changeset/270712/webkit) - - Alternative: Install line-jump extension and use keyboard to nav by jumping large amount of lines - - Alternative: Just use touch scrolling -- See [issues tagged with the iPad label](https://github.com/cdr/code-server/issues?q=is%3Aopen+is%3Aissue+label%3AiPad) for more. -- `ctrl+c` does not stop a long-running process in the browser - - Tracking upstream issue here: [#114009](https://github.com/microsoft/vscode/issues/114009) - - See [workaround](#ctrl-c-workaround) - -## How to install PWA - -To install the code-server PWA, follow these steps: - -1. Open code-server in Safari -2. Click the Share icon -3. Click "Add to Home Screen" - -Now when you open code-server from the home screen, you will be using the PWA. -The advantages of this are more screen real estate and access to top-level keyboard shortcuts because it's running like an app. -An example shortcut is the `cmd+w` to close an active file in the workbench. You can add this to your `keybindings.json` by doing the following: - -1. Open up code-serer -2. `Command Palette > Open Keyboard Shortcuts (JSON)` -3. Add the following to your `keybindings.json` - -```json -{ - "key": "cmd+w", - "command": "workbench.action.closeActiveEditor" -} -``` - -Test out command by hitting `cmd+w` to close an active file - -## How to access code-server with a self signed certificate on iPad? - -Accessing a self signed certificate on iPad isn't as easy as accepting through all -the security warnings. Safari will prevent WebSocket connections unless the certificate -is installed as a profile on the device. - -The below assumes you are using the self signed certificate that code-server -generates for you. If not, that's fine but you'll have to make sure your certificate -abides by the following guidelines from Apple: https://support.apple.com/en-us/HT210176 - -**note**: Another undocumented requirement we noticed is that the certificate has to have `basicConstraints=CA:true`. - -The following instructions assume you have code-server installed and running -with a self signed certificate. If not, please first go through [./guide.md](./guide.md)! - -**warning**: Your iPad must access code-server via a domain name. It could be local -DNS like `mymacbookpro.local` but it must be a domain name. Otherwise Safari will -refuse to allow WebSockets to connect. - -1. Your certificate **must** have a subject alt name that matches the hostname - at which you will access code-server from your iPad. You can pass this to code-server - so that it generates the certificate correctly with `--cert-host`. -2. Share your self signed certificate with the iPad. - - code-server will print the location of the certificate it has generated in the logs. - -``` -[2020-10-30T08:55:45.139Z] info - Using generated certificate and key for HTTPS: ~/.local/share/code-server/mymbp_local.crt -``` - -- You can mail it to yourself or if you have a Mac, it's easiest to just Airdrop to the iPad. - -3. When opening the `*.crt` file, you'll be prompted to go into settings to install. -4. Go to `Settings -> General -> Profile`, select the profile and then hit `Install`. - - It should say the profile is verified. -5. Go to `Settings -> About -> Certificate Trust Settings` and enable full trust for - the certificate. [more apple support here](https://support.apple.com/en-us/HT204477) -6. Now you can access code-server! 🍻 - -### Servediter iPad App - -If you are unable to get the self signed certificate working or you do not have a domain -name to use, you can use the Servediter iPad App instead! - -**note**: This is not an officially supported app by the code-server team! - -Download [Serveediter](https://apps.apple.com/us/app/servediter-for-code-server/id1504491325) from the -App Store and then input your server information. If you are running a local server or mabye a usb-c -connected Raspberry Pi, you will input your settings into "Self Hosted Server". - -## Raspberry Pi USB-C Network - -It is a bit out of scope for this project, however, great success is being reported using iPad on the go with just a single USB-C cable connected to a Raspberry Pi both powering and supplying direct network access. Many support articles already exist but the key steps boil down to turning on Network over USB-C on the Raspberry Pi itself and the rest of the steps are just like getting Code Server running any where else. - -Resources worthy of review: - -- [General intro to Pi as an iPad accessory](https://www.youtube.com/watch?v=IR6sDcKo3V8) -- [iPad with Pi FAQ](https://www.youtube.com/watch?v=SPSlyqo5Q2Q) -- [Technical guide to perform the steps](https://www.geeky-gadgets.com/connect-a-raspberry-pi-4-to-an-ipad-pro-21-01-2020/) - -> Here are my keys to success. I bought a 4" touch screen with fan included that attaches as a case to the Pi. I use the touch screen for anytime I have connection issues, otherwise I turn off the Pi screen. I gave my Pi a network name so I can easily connect at home on wifi or when on go with 1 usb-c cable that supplys both power and network connectivity. Lastly, not all usb-c cables are equal and not all will work so try different usb-c cables if you are going mad (confirm over wifi first then move to cable). -> -> -- [Acker Apple](http://github.com/ackerapple/) - -## Ctrl C Workaround - -There is currently an issue with `ctrl+c` not stopping a running process in the integrated terminal. We have filed an issue upstream and are tracking [here](https://github.com/microsoft/vscode/issues/114009). As a temporary workaround, it works if you manually define the shortcut like so: - -1. Open Command Palette -2. Look for "Preferences: Open Keyboard Shortcuts (JSON)" -3. Add this: - -```json -{ - "key": "ctrl+c", - "command": "workbench.action.terminal.sendSequence", - "args": { - "text": "\u0003" - }, - "when": "terminalFocus" -} -``` - -Source: [StackOverflow](https://stackoverflow.com/a/52735954/3015595) - -## Recommendations - -Once you have code-server accessible to your iPad a few things could help save you time: - -- Use multi task mode to make code changes and see browser at the same time - - Prevents iOs background dropping an App's state if you are full screen switching between code-server and browser -- Be sure you are using the debug/terminal that is built into VS Code so that you don’t need another terminal app running - - Again, prevents switching between full screen app and losing your view to iOs background app memory management -- You should be of a mindset willing to deal and adapt with differences in having an imperfect experience, for the perceived joyful benefits of interacting with your computer in more intuitive ways - -## By 2022 iPad coding more desirable on Arm Macs - -> This section is generalized opinions intended to inform fellow Apple product consumers of perceived over time changes coming down the line - -The general feeling from overall Apple movements recently, is that the Mac arm processors are in fact helping support the direction of having Macs with touch screens. Many great YouTube videos of interest call out highly suggestive evidence. In the past Apple has hard declared reasons of body fatigue and such as why not to encourage nor further developments on the iPad touch experience mixed with a keyboard/mouse/trackpad. Regardless, products and software have been released further supporting just that very experience. - -The iPad coding experience has been a joy for some of us that are willing to trade an imperfect experience for a uniquely effective focus driven experience. Note worthy, some of us think it's a trashy waste of time. This experience is undoubtably going to get better just by the work that can be seen by all parties, even in our own code-server attempt to make it better. - -Lastly, it is note worthy that if you have decided to incorporate a Raspberry Pi into you iPad coding experience, they are Arm processors. You are perfectly lined up with the future of Macs as well. diff --git a/docs/npm.md b/docs/npm.md deleted file mode 100644 index 4ef945fe954d..000000000000 --- a/docs/npm.md +++ /dev/null @@ -1,60 +0,0 @@ - - -# npm Install Requirements - -- [Ubuntu, Debian](#ubuntu-debian) -- [Fedora, CentOS, RHEL](#fedora-centos-rhel) -- [Alpine](#alpine) -- [macOS](#macos) -- [FreeBSD](#freebsd) - - - -If you're installing the npm module you'll need certain dependencies to build the native modules used by VS Code. - -- Node.js: version `>= 12`, `<= 14` - -_Note: the Node.js version requirements are based on the VS Code Node.js requirements. See [here](https://github.com/microsoft/vscode/wiki/How-to-Contribute#prerequisites)._ - -Related: - -- [#1633](https://github.com/cdr/code-server/issues/1633) - -## Ubuntu, Debian - -```bash -sudo apt-get install -y \ - build-essential \ - pkg-config \ - python3 -npm config set python python3 -``` - -## Fedora, CentOS, RHEL - -```bash -sudo yum groupinstall -y 'Development Tools' -sudo yum config-manager --set-enabled PowerTools # unnecessary on CentOS 7 -sudo yum install -y python2 -npm config set python python2 -``` - -## Alpine - -```bash -apk add alpine-sdk bash libstdc++ libc6-compat -npm config set python python3 -``` - -## macOS - -```bash -xcode-select --install -``` - -## FreeBSD - -```sh -pkg install -y git python npm-node12 yarn-node12 pkgconf -pkg install -y libinotify -``` diff --git a/docs/termux.md b/docs/termux.md deleted file mode 100644 index ff5f6ff8181f..000000000000 --- a/docs/termux.md +++ /dev/null @@ -1,61 +0,0 @@ - - -# Termux - -- [Termux](#termux) - - [Installation](#installation) - - [Upgrading](#upgrading) - - [Known Issues](#known-issues) - - [Search issue](#search-issue) - - [Backspace not working](#backspace-not-working) - - - -# Termux - -Termux is an Android terminal application and Linux environment, which can also run code-server from your phone. - -## Installation - -1. Install Termux from the [Google Play Store](https://play.google.com/store/apps/details?id=com.termux) -2. Make sure it's up-to-date by running `apt update && apt upgrade` -3. Install required packages: `apt install build-essential python git nodejs yarn` -4. Install code-server: `yarn global add code-server` -5. Run code-server: `code-server` and navigate to localhost:8080 in your browser - -## Upgrading - -To upgrade run: `yarn global upgrade code-server --latest` - -## Known Issues - -### Search issue - -There is a known issue with search not working on Android because it's missing `bin/rg`. To fix: - -1. Install `ripgrep` with `pkg` - ```sh - pkg install ripgrep - ``` -2. Make a soft link using `ln -s` - -```sh -# run this command inside the code-server directory -ln -s $PREFIX/bin/rg ./lib/vscode/node_modules/vscode-ripgrep/bin/rg -``` - -For more context, see [comment](https://github.com/cdr/code-server/issues/1730#issuecomment-721515979). - -### Backspace not working - -There is a known issue with the backspace key not working correctly when using the on-screen keyboard on Android. This is due to an upstream issue. Read more: - -- [Issues with Backspace in Codespaces on Android (Surface Duo)](https://github.com/microsoft/vscode/issues/107602) -- [Support mobile platforms](https://github.com/xtermjs/xterm.js/issues/1101) - -Workaround: use a Bluetooth keyboard. - -For more context, see issues: - -- [500 error: 3.9.2 not working on Android + Termux](https://github.com/cdr/code-server/issues/3036) -- [Document Android backspace issue](https://github.com/cdr/code-server/issues/3079) diff --git a/docs/triage.md b/docs/triage.md deleted file mode 100644 index e508df414c5e..000000000000 --- a/docs/triage.md +++ /dev/null @@ -1,37 +0,0 @@ -# Triage - -## Filter - -Triaging code-server issues is done with the following issue filter: - -``` -is:issue is:open no:project sort:created-asc -label:blocked -label:upstream -label:waiting-for-info -label:extension-request -``` - -This will show issues that: - -1. Are open. -2. Have no assigned project. -3. Are not `blocked` or tagged for work by `upstream` (VS Code core team) - - If an upstream issue is detrimental to the code-server experience we may fix it in - our patch instead of waiting for the VS Code team to fix it. - - Someone should periodically go through these issues to see if they can be unblocked - though! -4. Are not in `waiting-for-info`. -5. Are not extension requests. - -## Process - -1. If an issue is a question/discussion it should be converted into a GitHub discussion. -2. Next, give the issue the appropriate labels and feel free to create new ones if - necessary. - - There are no hard and set rules for labels. We don't have many so look through and - see how they've been used throughout the repository. They all also have descriptions. -3. If more information is required, please ask the submitter and tag as - `waiting-for-info` and wait. -4. Finally, the issue should be moved into the - [code-server](https://github.com/cdr/code-server/projects/1) project where we pick - out issues to fix and track their progress. - -We also use [milestones](https://github.com/cdr/code-server/milestones) to track what -issues are planned/or were closed for what release. diff --git a/lib/vscode/extensions/bat/.vscodeignore b/extensions/bat/.vscodeignore similarity index 100% rename from lib/vscode/extensions/bat/.vscodeignore rename to extensions/bat/.vscodeignore diff --git a/lib/vscode/extensions/bat/cgmanifest.json b/extensions/bat/cgmanifest.json similarity index 74% rename from lib/vscode/extensions/bat/cgmanifest.json rename to extensions/bat/cgmanifest.json index 5bc3e285f0c1..7e0426c1387f 100644 --- a/lib/vscode/extensions/bat/cgmanifest.json +++ b/extensions/bat/cgmanifest.json @@ -6,11 +6,11 @@ "git": { "name": "mmims/language-batchfile", "repositoryUrl": "https://github.com/mmims/language-batchfile", - "commitHash": "95ea8c699f7a8296b15767069868532d52631c46" + "commitHash": "6154ae25a24e01ac9329e7bcf958e093cd8733a9" } }, "license": "MIT", - "version": "0.7.5" + "version": "0.7.6" } ], "version": 1 diff --git a/lib/vscode/extensions/bat/language-configuration.json b/extensions/bat/language-configuration.json similarity index 100% rename from lib/vscode/extensions/bat/language-configuration.json rename to extensions/bat/language-configuration.json diff --git a/lib/vscode/extensions/bat/package.json b/extensions/bat/package.json similarity index 100% rename from lib/vscode/extensions/bat/package.json rename to extensions/bat/package.json diff --git a/lib/vscode/extensions/bat/package.nls.json b/extensions/bat/package.nls.json similarity index 100% rename from lib/vscode/extensions/bat/package.nls.json rename to extensions/bat/package.nls.json diff --git a/lib/vscode/extensions/bat/snippets/batchfile.code-snippets b/extensions/bat/snippets/batchfile.code-snippets similarity index 100% rename from lib/vscode/extensions/bat/snippets/batchfile.code-snippets rename to extensions/bat/snippets/batchfile.code-snippets diff --git a/lib/vscode/extensions/bat/syntaxes/batchfile.tmLanguage.json b/extensions/bat/syntaxes/batchfile.tmLanguage.json similarity index 89% rename from lib/vscode/extensions/bat/syntaxes/batchfile.tmLanguage.json rename to extensions/bat/syntaxes/batchfile.tmLanguage.json index 9eff3c9de2ba..85e03dbc85b0 100644 --- a/lib/vscode/extensions/bat/syntaxes/batchfile.tmLanguage.json +++ b/extensions/bat/syntaxes/batchfile.tmLanguage.json @@ -4,9 +4,18 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/mmims/language-batchfile/commit/95ea8c699f7a8296b15767069868532d52631c46", + "version": "https://github.com/mmims/language-batchfile/commit/6154ae25a24e01ac9329e7bcf958e093cd8733a9", "name": "Batch File", "scopeName": "source.batchfile", + "injections": { + "L:meta.block.repeat.batchfile": { + "patterns": [ + { + "include": "#repeatParameter" + } + ] + } + }, "patterns": [ { "include": "#commands" @@ -46,7 +55,7 @@ "commands": { "patterns": [ { - "match": "(?<=^|[\\s@])(?i:adprep|append|arp|assoc|at|atmadm|attrib|auditpol|autochk|autoconv|autofmt|bcdboot|bcdedit|bdehdcfg|bitsadmin|bootcfg|brea|cacls|cd|certreq|certutil|change|chcp|chdir|chglogon|chgport|chgusr|chkdsk|chkntfs|choice|cipher|clip|cls|clscluadmin|cluster|cmd|cmdkey|cmstp|color|comp|compact|convert|copy|cprofile|cscript|csvde|date|dcdiag|dcgpofix|dcpromo|defra|del|dfscmd|dfsdiag|dfsrmig|diantz|dir|dirquota|diskcomp|diskcopy|diskpart|diskperf|diskraid|diskshadow|dispdiag|doin|dnscmd|doskey|driverquery|dsacls|dsadd|dsamain|dsdbutil|dsget|dsmgmt|dsmod|dsmove|dsquery|dsrm|edit|endlocal|eraseesentutl|eventcreate|eventquery|eventtriggers|evntcmd|expand|extract|fc|filescrn|find|findstr|finger|flattemp|fonde|forfiles|format|freedisk|fsutil|ftp|ftype|fveupdate|getmac|gettype|gpfixup|gpresult|gpupdate|graftabl|hashgen|hep|helpctr|hostname|icacls|iisreset|inuse|ipconfig|ipxroute|irftp|ismserv|jetpack|klist|ksetup|ktmutil|ktpass|label|ldifd|ldp|lodctr|logman|logoff|lpq|lpr|macfile|makecab|manage-bde|mapadmin|md|mkdir|mklink|mmc|mode|more|mount|mountvol|move|mqbup|mqsvc|mqtgsvc|msdt|msg|msiexec|msinfo32|mstsc|nbtstat|net computer|net group|net localgroup|net print|net session|net share|net start|net stop|net use|net user|net view|net|netcfg|netdiag|netdom|netsh|netstat|nfsadmin|nfsshare|nfsstat|nlb|nlbmgr|nltest|nslookup|ntackup|ntcmdprompt|ntdsutil|ntfrsutl|openfiles|pagefileconfig|path|pathping|pause|pbadmin|pentnt|perfmon|ping|pnpunatten|pnputil|popd|powercfg|powershell|powershell_ise|print|prncnfg|prndrvr|prnjobs|prnmngr|prnport|prnqctl|prompt|pubprn|pushd|pushprinterconnections|pwlauncher|qappsrv|qprocess|query|quser|qwinsta|rasdial|rcp|rd|rdpsign|regentc|recover|redircmp|redirusr|reg|regini|regsvr32|relog|ren|rename|rendom|repadmin|repair-bde|replace|reset session|rxec|risetup|rmdir|robocopy|route|rpcinfo|rpcping|rsh|runas|rundll32|rwinsta|scp|sc|schtasks|scwcmd|secedit|serverceipoptin|servrmanagercmd|serverweroptin|setspn|setx|sfc|shadow|shift|showmount|shutdown|sort|ssh|start|storrept|subst|sxstrace|ysocmgr|systeminfo|takeown|tapicfg|taskkill|tasklist|tcmsetup|telnet|tftp|time|timeout|title|tlntadmn|tpmvscmgr|tpmvscmgr|tacerpt|tracert|tree|tscon|tsdiscon|tsecimp|tskill|tsprof|type|typeperf|tzutil|uddiconfig|umount|unlodctr|ver|verifier|verif|vol|vssadmin|w32tm|waitfor|wbadmin|wdsutil|wecutil|wevtutil|where|whoami|winnt|winnt32|winpop|winrm|winrs|winsat|wlbs|mic|wscript|xcopy)(?=$|\\s)", + "match": "(?<=^|[\\s@])(?i:adprep|append|arp|assoc|at|atmadm|attrib|auditpol|autochk|autoconv|autofmt|bcdboot|bcdedit|bdehdcfg|bitsadmin|bootcfg|brea|cacls|cd|certreq|certutil|change|chcp|chdir|chglogon|chgport|chgusr|chkdsk|chkntfs|choice|cipher|clip|cls|clscluadmin|cluster|cmd|cmdkey|cmstp|color|comp|compact|convert|copy|cprofile|cscript|csvde|date|dcdiag|dcgpofix|dcpromo|defra|del|dfscmd|dfsdiag|dfsrmig|diantz|dir|dirquota|diskcomp|diskcopy|diskpart|diskperf|diskraid|diskshadow|dispdiag|doin|dnscmd|doskey|driverquery|dsacls|dsadd|dsamain|dsdbutil|dsget|dsmgmt|dsmod|dsmove|dsquery|dsrm|edit|endlocal|eraseesentutl|eventcreate|eventquery|eventtriggers|evntcmd|expand|extract|fc|filescrn|find|findstr|finger|flattemp|fonde|forfiles|format|freedisk|fsutil|ftp|ftype|fveupdate|getmac|gettype|gpfixup|gpresult|gpupdate|graftabl|hashgen|hep|helpctr|hostname|icacls|iisreset|inuse|ipconfig|ipxroute|irftp|ismserv|jetpack|klist|ksetup|ktmutil|ktpass|label|ldifd|ldp|lodctr|logman|logoff|lpq|lpr|macfile|makecab|manage-bde|mapadmin|md|mkdir|mklink|mmc|mode|more|mount|mountvol|move|mqbup|mqsvc|mqtgsvc|msdt|msg|msiexec|msinfo32|mstsc|nbtstat|net computer|net group|net localgroup|net print|net session|net share|net start|net stop|net use|net user|net view|net|netcfg|netdiag|netdom|netsh|netstat|nfsadmin|nfsshare|nfsstat|nlb|nlbmgr|nltest|nslookup|ntackup|ntcmdprompt|ntdsutil|ntfrsutl|openfiles|pagefileconfig|path|pathping|pause|pbadmin|pentnt|perfmon|ping|pnpunatten|pnputil|popd|powercfg|powershell|powershell_ise|print|prncnfg|prndrvr|prnjobs|prnmngr|prnport|prnqctl|prompt|pubprn|pushd|pushprinterconnections|pwlauncher|qappsrv|qprocess|query|quser|qwinsta|rasdial|rcp|rd|rdpsign|regentc|recover|redircmp|redirusr|reg|regini|regsvr32|relog|ren|rename|rendom|repadmin|repair-bde|replace|reset session|rxec|risetup|rmdir|robocopy|route|rpcinfo|rpcping|rsh|runas|rundll32|rwinsta|sc|schtasks|scp|scwcmd|secedit|serverceipoptin|servrmanagercmd|serverweroptin|setspn|setx|sfc|sftp|shadow|shift|showmount|shutdown|sort|ssh|ssh-add|ssh-agent|ssh-keygen|ssh-keyscan|start|storrept|subst|sxstrace|ysocmgr|systeminfo|takeown|tapicfg|taskkill|tasklist|tcmsetup|telnet|tftp|time|timeout|title|tlntadmn|tpmvscmgr|tpmvscmgr|tacerpt|tracert|tree|tscon|tsdiscon|tsecimp|tskill|tsprof|type|typeperf|tzutil|uddiconfig|umount|unlodctr|ver|verifier|verif|vol|vssadmin|w32tm|waitfor|wbadmin|wdsutil|wecutil|wevtutil|where|whoami|winnt|winnt32|winpop|winrm|winrs|winsat|wlbs|wmic|wscript|wsl|xcopy)(?=$|\\s)", "name": "keyword.command.batchfile" }, { @@ -285,7 +294,7 @@ "name": "keyword.operator.logical.batchfile" }, { - "match": "([^ ][^=]*)(=)", + "match": "([^ =]*)(=)", "captures": { "1": { "name": "variable.other.readwrite.batchfile" @@ -420,8 +429,38 @@ "name": "keyword.control.conditional.batchfile" }, { - "match": "(?<=^|\\s)(?i)for(?=\\s)", - "name": "keyword.control.repeat.batchfile" + "begin": "(?<=^|[\\s(&^])(?i)for(?=\\s)", + "beginCaptures": { + "0": { + "name": "keyword.control.repeat.batchfile" + } + }, + "name": "meta.block.repeat.batchfile", + "end": "\\n", + "patterns": [ + { + "begin": "(?<=[\\s^])(?i)in(?=\\s)", + "beginCaptures": { + "0": { + "name": "keyword.control.repeat.in.batchfile" + } + }, + "end": "(?<=[\\s)^])(?i)do(?=\\s)|\\n", + "endCaptures": { + "0": { + "name": "keyword.control.repeat.do.batchfile" + } + }, + "patterns": [ + { + "include": "$self" + } + ] + }, + { + "include": "$self" + } + ] } ] }, @@ -436,7 +475,7 @@ "labels": { "patterns": [ { - "match": "(?i)(?:^\\s*|(?<=goto)\\s*)(:)([^+=,;:\\s].*)$", + "match": "(?i)(?:^\\s*|(?<=call|goto)\\s*)(:)([^+=,;:\\s]\\S*)", "captures": { "1": { "name": "punctuation.separator.batchfile" @@ -512,6 +551,19 @@ } ] }, + "repeatParameter": { + "patterns": [ + { + "match": "(%%)(?:(?i:~[fdpnxsatz]*(?:\\$PATH:)?)?[a-zA-Z])", + "captures": { + "1": { + "name": "punctuation.definition.variable.batchfile" + } + }, + "name": "variable.parameter.repeat.batchfile" + } + ] + }, "strings": { "patterns": [ { @@ -546,15 +598,13 @@ "variables": { "patterns": [ { - "match": "(%)((~([fdpnxsatz]|\\$PATH:)*)?\\d|\\*)", + "match": "(%)(?:(?i:~[fdpnxsatz]*(?:\\$PATH:)?)?\\d|\\*)", "captures": { "1": { "name": "punctuation.definition.variable.batchfile" - }, - "2": { - "name": "variable.parameter.batchfile" } - } + }, + "name": "variable.parameter.batchfile" }, { "include": "#variable" diff --git a/lib/vscode/extensions/bat/yarn.lock b/extensions/bat/yarn.lock similarity index 100% rename from lib/vscode/extensions/bat/yarn.lock rename to extensions/bat/yarn.lock diff --git a/lib/vscode/extensions/cgmanifest.json b/extensions/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/cgmanifest.json rename to extensions/cgmanifest.json diff --git a/lib/vscode/extensions/clojure/.vscodeignore b/extensions/clojure/.vscodeignore similarity index 100% rename from lib/vscode/extensions/clojure/.vscodeignore rename to extensions/clojure/.vscodeignore diff --git a/lib/vscode/extensions/clojure/cgmanifest.json b/extensions/clojure/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/clojure/cgmanifest.json rename to extensions/clojure/cgmanifest.json diff --git a/lib/vscode/extensions/clojure/language-configuration.json b/extensions/clojure/language-configuration.json similarity index 100% rename from lib/vscode/extensions/clojure/language-configuration.json rename to extensions/clojure/language-configuration.json diff --git a/lib/vscode/extensions/clojure/package.json b/extensions/clojure/package.json similarity index 100% rename from lib/vscode/extensions/clojure/package.json rename to extensions/clojure/package.json diff --git a/lib/vscode/extensions/clojure/package.nls.json b/extensions/clojure/package.nls.json similarity index 100% rename from lib/vscode/extensions/clojure/package.nls.json rename to extensions/clojure/package.nls.json diff --git a/lib/vscode/extensions/clojure/syntaxes/clojure.tmLanguage.json b/extensions/clojure/syntaxes/clojure.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/clojure/syntaxes/clojure.tmLanguage.json rename to extensions/clojure/syntaxes/clojure.tmLanguage.json diff --git a/lib/vscode/extensions/clojure/yarn.lock b/extensions/clojure/yarn.lock similarity index 100% rename from lib/vscode/extensions/clojure/yarn.lock rename to extensions/clojure/yarn.lock diff --git a/lib/vscode/extensions/coffeescript/.vscodeignore b/extensions/coffeescript/.vscodeignore similarity index 100% rename from lib/vscode/extensions/coffeescript/.vscodeignore rename to extensions/coffeescript/.vscodeignore diff --git a/lib/vscode/extensions/coffeescript/cgmanifest.json b/extensions/coffeescript/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/coffeescript/cgmanifest.json rename to extensions/coffeescript/cgmanifest.json diff --git a/lib/vscode/extensions/coffeescript/language-configuration.json b/extensions/coffeescript/language-configuration.json similarity index 100% rename from lib/vscode/extensions/coffeescript/language-configuration.json rename to extensions/coffeescript/language-configuration.json diff --git a/lib/vscode/extensions/coffeescript/package.json b/extensions/coffeescript/package.json similarity index 100% rename from lib/vscode/extensions/coffeescript/package.json rename to extensions/coffeescript/package.json diff --git a/lib/vscode/extensions/coffeescript/package.nls.json b/extensions/coffeescript/package.nls.json similarity index 100% rename from lib/vscode/extensions/coffeescript/package.nls.json rename to extensions/coffeescript/package.nls.json diff --git a/lib/vscode/extensions/coffeescript/snippets/coffeescript.code-snippets b/extensions/coffeescript/snippets/coffeescript.code-snippets similarity index 100% rename from lib/vscode/extensions/coffeescript/snippets/coffeescript.code-snippets rename to extensions/coffeescript/snippets/coffeescript.code-snippets diff --git a/lib/vscode/extensions/coffeescript/syntaxes/coffeescript.tmLanguage.json b/extensions/coffeescript/syntaxes/coffeescript.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/coffeescript/syntaxes/coffeescript.tmLanguage.json rename to extensions/coffeescript/syntaxes/coffeescript.tmLanguage.json diff --git a/lib/vscode/extensions/coffeescript/yarn.lock b/extensions/coffeescript/yarn.lock similarity index 100% rename from lib/vscode/extensions/coffeescript/yarn.lock rename to extensions/coffeescript/yarn.lock diff --git a/lib/vscode/extensions/configuration-editing/.vscodeignore b/extensions/configuration-editing/.vscodeignore similarity index 100% rename from lib/vscode/extensions/configuration-editing/.vscodeignore rename to extensions/configuration-editing/.vscodeignore diff --git a/lib/vscode/extensions/configuration-editing/build/inline-allOf.ts b/extensions/configuration-editing/build/inline-allOf.ts similarity index 100% rename from lib/vscode/extensions/configuration-editing/build/inline-allOf.ts rename to extensions/configuration-editing/build/inline-allOf.ts diff --git a/lib/vscode/extensions/configuration-editing/build/tsconfig.json b/extensions/configuration-editing/build/tsconfig.json similarity index 100% rename from lib/vscode/extensions/configuration-editing/build/tsconfig.json rename to extensions/configuration-editing/build/tsconfig.json diff --git a/lib/vscode/extensions/configuration-editing/extension-browser.webpack.config.js b/extensions/configuration-editing/extension-browser.webpack.config.js similarity index 100% rename from lib/vscode/extensions/configuration-editing/extension-browser.webpack.config.js rename to extensions/configuration-editing/extension-browser.webpack.config.js diff --git a/lib/vscode/extensions/configuration-editing/extension.webpack.config.js b/extensions/configuration-editing/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/configuration-editing/extension.webpack.config.js rename to extensions/configuration-editing/extension.webpack.config.js diff --git a/lib/vscode/extensions/configuration-editing/images/icon.png b/extensions/configuration-editing/images/icon.png similarity index 100% rename from lib/vscode/extensions/configuration-editing/images/icon.png rename to extensions/configuration-editing/images/icon.png diff --git a/lib/vscode/extensions/configuration-editing/package.json b/extensions/configuration-editing/package.json similarity index 99% rename from lib/vscode/extensions/configuration-editing/package.json rename to extensions/configuration-editing/package.json index 324e0c80607d..80e627e5f939 100644 --- a/lib/vscode/extensions/configuration-editing/package.json +++ b/extensions/configuration-editing/package.json @@ -139,7 +139,7 @@ ] }, "devDependencies": { - "@types/node": "^12.19.9" + "@types/node": "14.x" }, "repository": { "type": "git", diff --git a/lib/vscode/extensions/configuration-editing/package.nls.json b/extensions/configuration-editing/package.nls.json similarity index 100% rename from lib/vscode/extensions/configuration-editing/package.nls.json rename to extensions/configuration-editing/package.nls.json diff --git a/lib/vscode/extensions/configuration-editing/schemas/attachContainer.schema.json b/extensions/configuration-editing/schemas/attachContainer.schema.json similarity index 85% rename from lib/vscode/extensions/configuration-editing/schemas/attachContainer.schema.json rename to extensions/configuration-editing/schemas/attachContainer.schema.json index ec765b8fc24b..9cdd3a5f6d36 100644 --- a/lib/vscode/extensions/configuration-editing/schemas/attachContainer.schema.json +++ b/extensions/configuration-editing/schemas/attachContainer.schema.json @@ -54,6 +54,19 @@ "type": "string", "description": "Label that will be shown in the UI for this port.", "default": "Application" + }, + "requireLocalPort": { + "type": "boolean", + "markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.", + "default": false + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "https" + ], + "description": "The protocol to use when forwarding this port." } }, "default": { @@ -80,7 +93,13 @@ "properties": { "onAutoForward": { "type": "string", - "enum": ["notify", "openBrowser", "openPreview", "silent", "ignore"], + "enum": [ + "notify", + "openBrowser", + "openPreview", + "silent", + "ignore" + ], "enumDescriptions": [ "Shows a notification when a port is automatically forwarded.", "Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.", @@ -100,9 +119,28 @@ "type": "string", "description": "Label that will be shown in the UI for this port.", "default": "Application" + }, + "requireLocalPort": { + "type": "boolean", + "markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.", + "default": false + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "https" + ], + "description": "The protocol to use when forwarding this port." } }, - "defaultSnippets": [{ "body": { "onAutoForward": "ignore" } }], + "defaultSnippets": [ + { + "body": { + "onAutoForward": "ignore" + } + } + ], "markdownDescription": "Set default properties that are applied to all ports that don't get properties from the setting `remote.portsAttributes`. For example:\n\n```\n{\n \"onAutoForward\": \"ignore\"\n}\n```", "additionalProperties": false }, diff --git a/lib/vscode/extensions/configuration-editing/schemas/devContainer.schema.generated.json b/extensions/configuration-editing/schemas/devContainer.schema.generated.json similarity index 74% rename from lib/vscode/extensions/configuration-editing/schemas/devContainer.schema.generated.json rename to extensions/configuration-editing/schemas/devContainer.schema.generated.json index 90e70c0125ac..095a0e355f13 100644 --- a/lib/vscode/extensions/configuration-editing/schemas/devContainer.schema.generated.json +++ b/extensions/configuration-editing/schemas/devContainer.schema.generated.json @@ -162,6 +162,19 @@ "type": "string", "description": "Label that will be shown in the UI for this port.", "default": "Application" + }, + "requireLocalPort": { + "type": "boolean", + "markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.", + "default": false + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "https" + ], + "description": "The protocol to use when forwarding this port." } }, "default": { @@ -215,6 +228,19 @@ "type": "string", "description": "Label that will be shown in the UI for this port.", "default": "Application" + }, + "requireLocalPort": { + "type": "boolean", + "markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.", + "default": false + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "https" + ], + "description": "The protocol to use when forwarding this port." } }, "defaultSnippets": [ @@ -246,7 +272,27 @@ "string", "array" ], - "description": "A command to run locally before anything else. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run locally before anything else. This command is run before \"onCreateCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "items": { + "type": "string" + } + }, + "onCreateCommand": { + "type": [ + "string", + "array" + ], + "description": "A command to run when creating the container. This command is run after \"initializeCommand\" and before \"updateContentCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "items": { + "type": "string" + } + }, + "updateContentCommand": { + "type": [ + "string", + "array" + ], + "description": "A command to run when creating the container and rerun when the workspace content was updated while creating the container. This command is run after \"onCreateCommand\" and before \"postCreateCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -256,7 +302,7 @@ "string", "array" ], - "description": "A command to run after creating the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run after creating the container. This command is run after \"updateContentCommand\" and before \"postStartCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -266,7 +312,7 @@ "string", "array" ], - "description": "A command to run after starting the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run after starting the container. This command is run after \"postCreateCommand\" and before \"postAttachCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -276,11 +322,23 @@ "string", "array" ], - "description": "A command to run after attaching to the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run when attaching to the container. This command is run after \"postStartCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } }, + "waitFor": { + "type": "string", + "enum": [ + "initializeCommand", + "onCreateCommand", + "updateContentCommand", + "postCreateCommand", + "postStartCommand", + "postAttachCommand" + ], + "description": "The user command to wait for before continuing execution in the background while the UI is starting up. The default is \"updateContentCommand\"." + }, "devPort": { "type": "integer", "description": "The port VS Code can use to connect to its backend." @@ -461,6 +519,19 @@ "type": "string", "description": "Label that will be shown in the UI for this port.", "default": "Application" + }, + "requireLocalPort": { + "type": "boolean", + "markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.", + "default": false + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "https" + ], + "description": "The protocol to use when forwarding this port." } }, "default": { @@ -514,6 +585,19 @@ "type": "string", "description": "Label that will be shown in the UI for this port.", "default": "Application" + }, + "requireLocalPort": { + "type": "boolean", + "markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.", + "default": false + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "https" + ], + "description": "The protocol to use when forwarding this port." } }, "defaultSnippets": [ @@ -545,7 +629,27 @@ "string", "array" ], - "description": "A command to run locally before anything else. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run locally before anything else. This command is run before \"onCreateCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "items": { + "type": "string" + } + }, + "onCreateCommand": { + "type": [ + "string", + "array" + ], + "description": "A command to run when creating the container. This command is run after \"initializeCommand\" and before \"updateContentCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "items": { + "type": "string" + } + }, + "updateContentCommand": { + "type": [ + "string", + "array" + ], + "description": "A command to run when creating the container and rerun when the workspace content was updated while creating the container. This command is run after \"onCreateCommand\" and before \"postCreateCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -555,7 +659,7 @@ "string", "array" ], - "description": "A command to run after creating the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run after creating the container. This command is run after \"updateContentCommand\" and before \"postStartCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -565,7 +669,7 @@ "string", "array" ], - "description": "A command to run after starting the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run after starting the container. This command is run after \"postCreateCommand\" and before \"postAttachCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -575,11 +679,23 @@ "string", "array" ], - "description": "A command to run after attaching to the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run when attaching to the container. This command is run after \"postStartCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } }, + "waitFor": { + "type": "string", + "enum": [ + "initializeCommand", + "onCreateCommand", + "updateContentCommand", + "postCreateCommand", + "postStartCommand", + "postAttachCommand" + ], + "description": "The user command to wait for before continuing execution in the background while the UI is starting up. The default is \"updateContentCommand\"." + }, "devPort": { "type": "integer", "description": "The port VS Code can use to connect to its backend." @@ -736,6 +852,19 @@ "type": "string", "description": "Label that will be shown in the UI for this port.", "default": "Application" + }, + "requireLocalPort": { + "type": "boolean", + "markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.", + "default": false + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "https" + ], + "description": "The protocol to use when forwarding this port." } }, "default": { @@ -789,6 +918,19 @@ "type": "string", "description": "Label that will be shown in the UI for this port.", "default": "Application" + }, + "requireLocalPort": { + "type": "boolean", + "markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.", + "default": false + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "https" + ], + "description": "The protocol to use when forwarding this port." } }, "defaultSnippets": [ @@ -820,7 +962,27 @@ "string", "array" ], - "description": "A command to run locally before anything else. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run locally before anything else. This command is run before \"onCreateCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "items": { + "type": "string" + } + }, + "onCreateCommand": { + "type": [ + "string", + "array" + ], + "description": "A command to run when creating the container. This command is run after \"initializeCommand\" and before \"updateContentCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "items": { + "type": "string" + } + }, + "updateContentCommand": { + "type": [ + "string", + "array" + ], + "description": "A command to run when creating the container and rerun when the workspace content was updated while creating the container. This command is run after \"onCreateCommand\" and before \"postCreateCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -830,7 +992,7 @@ "string", "array" ], - "description": "A command to run after creating the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run after creating the container. This command is run after \"updateContentCommand\" and before \"postStartCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -840,7 +1002,7 @@ "string", "array" ], - "description": "A command to run after starting the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run after starting the container. This command is run after \"postCreateCommand\" and before \"postAttachCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -850,11 +1012,23 @@ "string", "array" ], - "description": "A command to run after attaching to the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run when attaching to the container. This command is run after \"postStartCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } }, + "waitFor": { + "type": "string", + "enum": [ + "initializeCommand", + "onCreateCommand", + "updateContentCommand", + "postCreateCommand", + "postStartCommand", + "postAttachCommand" + ], + "description": "The user command to wait for before continuing execution in the background while the UI is starting up. The default is \"updateContentCommand\"." + }, "devPort": { "type": "integer", "description": "The port VS Code can use to connect to its backend." @@ -977,6 +1151,19 @@ "type": "string", "description": "Label that will be shown in the UI for this port.", "default": "Application" + }, + "requireLocalPort": { + "type": "boolean", + "markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.", + "default": false + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "https" + ], + "description": "The protocol to use when forwarding this port." } }, "default": { @@ -1030,6 +1217,19 @@ "type": "string", "description": "Label that will be shown in the UI for this port.", "default": "Application" + }, + "requireLocalPort": { + "type": "boolean", + "markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.", + "default": false + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "https" + ], + "description": "The protocol to use when forwarding this port." } }, "defaultSnippets": [ @@ -1061,7 +1261,27 @@ "string", "array" ], - "description": "A command to run locally before anything else. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run locally before anything else. This command is run before \"onCreateCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "items": { + "type": "string" + } + }, + "onCreateCommand": { + "type": [ + "string", + "array" + ], + "description": "A command to run when creating the container. This command is run after \"initializeCommand\" and before \"updateContentCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "items": { + "type": "string" + } + }, + "updateContentCommand": { + "type": [ + "string", + "array" + ], + "description": "A command to run when creating the container and rerun when the workspace content was updated while creating the container. This command is run after \"onCreateCommand\" and before \"postCreateCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -1071,7 +1291,7 @@ "string", "array" ], - "description": "A command to run after creating the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run after creating the container. This command is run after \"updateContentCommand\" and before \"postStartCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -1081,7 +1301,7 @@ "string", "array" ], - "description": "A command to run after starting the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run after starting the container. This command is run after \"postCreateCommand\" and before \"postAttachCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -1091,11 +1311,23 @@ "string", "array" ], - "description": "A command to run after attaching to the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run when attaching to the container. This command is run after \"postStartCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } }, + "waitFor": { + "type": "string", + "enum": [ + "initializeCommand", + "onCreateCommand", + "updateContentCommand", + "postCreateCommand", + "postStartCommand", + "postAttachCommand" + ], + "description": "The user command to wait for before continuing execution in the background while the UI is starting up. The default is \"updateContentCommand\"." + }, "devPort": { "type": "integer", "description": "The port VS Code can use to connect to its backend." @@ -1187,6 +1419,19 @@ "type": "string", "description": "Label that will be shown in the UI for this port.", "default": "Application" + }, + "requireLocalPort": { + "type": "boolean", + "markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.", + "default": false + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "https" + ], + "description": "The protocol to use when forwarding this port." } }, "default": { @@ -1240,6 +1485,19 @@ "type": "string", "description": "Label that will be shown in the UI for this port.", "default": "Application" + }, + "requireLocalPort": { + "type": "boolean", + "markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.", + "default": false + }, + "protocol": { + "type": "string", + "enum": [ + "http", + "https" + ], + "description": "The protocol to use when forwarding this port." } }, "defaultSnippets": [ @@ -1271,7 +1529,27 @@ "string", "array" ], - "description": "A command to run locally before anything else. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run locally before anything else. This command is run before \"onCreateCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "items": { + "type": "string" + } + }, + "onCreateCommand": { + "type": [ + "string", + "array" + ], + "description": "A command to run when creating the container. This command is run after \"initializeCommand\" and before \"updateContentCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "items": { + "type": "string" + } + }, + "updateContentCommand": { + "type": [ + "string", + "array" + ], + "description": "A command to run when creating the container and rerun when the workspace content was updated while creating the container. This command is run after \"onCreateCommand\" and before \"postCreateCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -1281,7 +1559,7 @@ "string", "array" ], - "description": "A command to run after creating the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run after creating the container. This command is run after \"updateContentCommand\" and before \"postStartCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -1291,7 +1569,7 @@ "string", "array" ], - "description": "A command to run after starting the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run after starting the container. This command is run after \"postCreateCommand\" and before \"postAttachCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -1301,11 +1579,23 @@ "string", "array" ], - "description": "A command to run after attaching to the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run when attaching to the container. This command is run after \"postStartCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } }, + "waitFor": { + "type": "string", + "enum": [ + "initializeCommand", + "onCreateCommand", + "updateContentCommand", + "postCreateCommand", + "postStartCommand", + "postAttachCommand" + ], + "description": "The user command to wait for before continuing execution in the background while the UI is starting up. The default is \"updateContentCommand\"." + }, "devPort": { "type": "integer", "description": "The port VS Code can use to connect to its backend." diff --git a/lib/vscode/extensions/configuration-editing/schemas/devContainer.schema.src.json b/extensions/configuration-editing/schemas/devContainer.schema.src.json similarity index 82% rename from lib/vscode/extensions/configuration-editing/schemas/devContainer.schema.src.json rename to extensions/configuration-editing/schemas/devContainer.schema.src.json index 2987aad16c5a..3d1536fa7437 100644 --- a/lib/vscode/extensions/configuration-editing/schemas/devContainer.schema.src.json +++ b/extensions/configuration-editing/schemas/devContainer.schema.src.json @@ -68,6 +68,16 @@ "type": "string", "description": "Label that will be shown in the UI for this port.", "default": "Application" + }, + "requireLocalPort": { + "type": "boolean", + "markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.", + "default": false + }, + "protocol": { + "type": "string", + "enum": ["http", "https"], + "description": "The protocol to use when forwarding this port." } }, "default": { @@ -120,6 +130,16 @@ "type": "string", "description": "Label that will be shown in the UI for this port.", "default": "Application" + }, + "requireLocalPort": { + "type": "boolean", + "markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.", + "default": false + }, + "protocol": { + "type": "string", + "enum": ["http", "https"], + "description": "The protocol to use when forwarding this port." } }, "defaultSnippets": [ @@ -151,7 +171,27 @@ "string", "array" ], - "description": "A command to run locally before anything else. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run locally before anything else. This command is run before \"onCreateCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "items": { + "type": "string" + } + }, + "onCreateCommand": { + "type": [ + "string", + "array" + ], + "description": "A command to run when creating the container. This command is run after \"initializeCommand\" and before \"updateContentCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "items": { + "type": "string" + } + }, + "updateContentCommand": { + "type": [ + "string", + "array" + ], + "description": "A command to run when creating the container and rerun when the workspace content was updated while creating the container. This command is run after \"onCreateCommand\" and before \"postCreateCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -161,7 +201,7 @@ "string", "array" ], - "description": "A command to run after creating the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run after creating the container. This command is run after \"updateContentCommand\" and before \"postStartCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -171,7 +211,7 @@ "string", "array" ], - "description": "A command to run after starting the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run after starting the container. This command is run after \"postCreateCommand\" and before \"postAttachCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } @@ -181,11 +221,23 @@ "string", "array" ], - "description": "A command to run after attaching to the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "description": "A command to run when attaching to the container. This command is run after \"postStartCommand\". If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" } }, + "waitFor": { + "type": "string", + "enum": [ + "initializeCommand", + "onCreateCommand", + "updateContentCommand", + "postCreateCommand", + "postStartCommand", + "postAttachCommand" + ], + "description": "The user command to wait for before continuing execution in the background while the UI is starting up. The default is \"updateContentCommand\"." + }, "devPort": { "type": "integer", "description": "The port VS Code can use to connect to its backend." diff --git a/lib/vscode/extensions/configuration-editing/src/configurationEditingMain.ts b/extensions/configuration-editing/src/configurationEditingMain.ts similarity index 100% rename from lib/vscode/extensions/configuration-editing/src/configurationEditingMain.ts rename to extensions/configuration-editing/src/configurationEditingMain.ts diff --git a/lib/vscode/extensions/configuration-editing/src/extensionsProposals.ts b/extensions/configuration-editing/src/extensionsProposals.ts similarity index 100% rename from lib/vscode/extensions/configuration-editing/src/extensionsProposals.ts rename to extensions/configuration-editing/src/extensionsProposals.ts diff --git a/lib/vscode/extensions/configuration-editing/src/settingsDocumentHelper.ts b/extensions/configuration-editing/src/settingsDocumentHelper.ts similarity index 92% rename from lib/vscode/extensions/configuration-editing/src/settingsDocumentHelper.ts rename to extensions/configuration-editing/src/settingsDocumentHelper.ts index a21ec18e3103..3a469148da61 100644 --- a/lib/vscode/extensions/configuration-editing/src/settingsDocumentHelper.ts +++ b/extensions/configuration-editing/src/settingsDocumentHelper.ts @@ -6,7 +6,7 @@ import * as vscode from 'vscode'; import { getLocation, Location, parse } from 'jsonc-parser'; import * as nls from 'vscode-nls'; -import { provideInstalledExtensionProposals, provideWorkspaceTrustExtensionProposals } from './extensionsProposals'; +import { provideInstalledExtensionProposals } from './extensionsProposals'; const localize = nls.loadMessageBundle(); @@ -60,13 +60,9 @@ export class SettingsDocument { return provideInstalledExtensionProposals(alreadyConfigured, `: [\n\t"ui"\n]`, range, true); } - // extensions.supportUntrustedWorkspaces - if (location.path[0] === 'extensions.supportUntrustedWorkspaces' && location.path.length === 2 && location.isAtPropertyKey) { - let alreadyConfigured: string[] = []; - try { - alreadyConfigured = Object.keys(parse(this.document.getText())['extensions.supportUntrustedWorkspaces']); - } catch (e) {/* ignore error */ } - return provideWorkspaceTrustExtensionProposals(alreadyConfigured, range); + // remote.portsAttributes + if (location.path[0] === 'remote.portsAttributes' && location.path.length === 2 && location.isAtPropertyKey) { + return this.providePortsAttributesCompletionItem(range); } return this.provideLanguageOverridesCompletionItems(location, position); @@ -247,6 +243,31 @@ export class SettingsDocument { return Promise.resolve([]); } + private providePortsAttributesCompletionItem(range: vscode.Range): vscode.CompletionItem[] { + return [this.newSnippetCompletionItem( + { + label: '\"3000\"', + documentation: 'Single Port Attribute', + range, + snippet: '\n \"${1:3000}\": {\n \"label\": \"${2:Application}\",\n \"onAutoForward\": \"${3:openPreview}\"\n }\n' + }), + this.newSnippetCompletionItem( + { + label: '\"5000-6000\"', + documentation: 'Ranged Port Attribute', + range, + snippet: '\n \"${1:40000-55000}\": {\n \"onAutoForward\": \"${2:ignore}\"\n }\n' + }), + this.newSnippetCompletionItem( + { + label: '\".+\\\\/server.js\"', + documentation: 'Command Match Port Attribute', + range, + snippet: '\n \"${1:.+\\\\/server.js\}\": {\n \"label\": \"${2:Application}\",\n \"onAutoForward\": \"${3:openPreview}\"\n }\n' + }) + ]; + } + private newSimpleCompletionItem(text: string, range: vscode.Range, description?: string, insertText?: string): vscode.CompletionItem { const item = new vscode.CompletionItem(text); item.kind = vscode.CompletionItemKind.Value; diff --git a/lib/vscode/extensions/configuration-editing/src/typings/ref.d.ts b/extensions/configuration-editing/src/typings/ref.d.ts similarity index 100% rename from lib/vscode/extensions/configuration-editing/src/typings/ref.d.ts rename to extensions/configuration-editing/src/typings/ref.d.ts diff --git a/lib/vscode/extensions/configuration-editing/tsconfig.json b/extensions/configuration-editing/tsconfig.json similarity index 100% rename from lib/vscode/extensions/configuration-editing/tsconfig.json rename to extensions/configuration-editing/tsconfig.json diff --git a/lib/vscode/extensions/configuration-editing/yarn.lock b/extensions/configuration-editing/yarn.lock similarity index 69% rename from lib/vscode/extensions/configuration-editing/yarn.lock rename to extensions/configuration-editing/yarn.lock index ebfaa046da41..d7215349a938 100644 --- a/lib/vscode/extensions/configuration-editing/yarn.lock +++ b/extensions/configuration-editing/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== jsonc-parser@^2.2.1: version "2.2.1" diff --git a/lib/vscode/extensions/cpp/.vscodeignore b/extensions/cpp/.vscodeignore similarity index 100% rename from lib/vscode/extensions/cpp/.vscodeignore rename to extensions/cpp/.vscodeignore diff --git a/lib/vscode/extensions/cpp/build/update-grammars.js b/extensions/cpp/build/update-grammars.js similarity index 100% rename from lib/vscode/extensions/cpp/build/update-grammars.js rename to extensions/cpp/build/update-grammars.js diff --git a/lib/vscode/extensions/cpp/cgmanifest.json b/extensions/cpp/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/cpp/cgmanifest.json rename to extensions/cpp/cgmanifest.json diff --git a/lib/vscode/extensions/cpp/language-configuration.json b/extensions/cpp/language-configuration.json similarity index 100% rename from lib/vscode/extensions/cpp/language-configuration.json rename to extensions/cpp/language-configuration.json diff --git a/lib/vscode/extensions/cpp/package.json b/extensions/cpp/package.json similarity index 100% rename from lib/vscode/extensions/cpp/package.json rename to extensions/cpp/package.json diff --git a/lib/vscode/extensions/cpp/package.nls.json b/extensions/cpp/package.nls.json similarity index 100% rename from lib/vscode/extensions/cpp/package.nls.json rename to extensions/cpp/package.nls.json diff --git a/lib/vscode/extensions/cpp/snippets/c.code-snippets b/extensions/cpp/snippets/c.code-snippets similarity index 100% rename from lib/vscode/extensions/cpp/snippets/c.code-snippets rename to extensions/cpp/snippets/c.code-snippets diff --git a/lib/vscode/extensions/cpp/snippets/cpp.code-snippets b/extensions/cpp/snippets/cpp.code-snippets similarity index 100% rename from lib/vscode/extensions/cpp/snippets/cpp.code-snippets rename to extensions/cpp/snippets/cpp.code-snippets diff --git a/lib/vscode/extensions/cpp/syntaxes/c.tmLanguage.json b/extensions/cpp/syntaxes/c.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/cpp/syntaxes/c.tmLanguage.json rename to extensions/cpp/syntaxes/c.tmLanguage.json diff --git a/lib/vscode/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json b/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json rename to extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json diff --git a/lib/vscode/extensions/cpp/syntaxes/cpp.tmLanguage.json b/extensions/cpp/syntaxes/cpp.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/cpp/syntaxes/cpp.tmLanguage.json rename to extensions/cpp/syntaxes/cpp.tmLanguage.json diff --git a/lib/vscode/extensions/cpp/syntaxes/cuda-cpp.tmLanguage.json b/extensions/cpp/syntaxes/cuda-cpp.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/cpp/syntaxes/cuda-cpp.tmLanguage.json rename to extensions/cpp/syntaxes/cuda-cpp.tmLanguage.json diff --git a/lib/vscode/extensions/cpp/syntaxes/platform.tmLanguage.json b/extensions/cpp/syntaxes/platform.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/cpp/syntaxes/platform.tmLanguage.json rename to extensions/cpp/syntaxes/platform.tmLanguage.json diff --git a/lib/vscode/extensions/cpp/yarn.lock b/extensions/cpp/yarn.lock similarity index 100% rename from lib/vscode/extensions/cpp/yarn.lock rename to extensions/cpp/yarn.lock diff --git a/lib/vscode/extensions/csharp/.vscodeignore b/extensions/csharp/.vscodeignore similarity index 100% rename from lib/vscode/extensions/csharp/.vscodeignore rename to extensions/csharp/.vscodeignore diff --git a/lib/vscode/extensions/csharp/cgmanifest.json b/extensions/csharp/cgmanifest.json similarity index 86% rename from lib/vscode/extensions/csharp/cgmanifest.json rename to extensions/csharp/cgmanifest.json index 0b192d30ec47..6156bbb50828 100644 --- a/lib/vscode/extensions/csharp/cgmanifest.json +++ b/extensions/csharp/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "dotnet/csharp-tmLanguage", "repositoryUrl": "https://github.com/dotnet/csharp-tmLanguage", - "commitHash": "4d14854c9bfc9d84cce625d2bfebaac9741b9db8" + "commitHash": "572697a2c2267430010b3534281f73337144e94f" } }, "license": "MIT", diff --git a/lib/vscode/extensions/csharp/language-configuration.json b/extensions/csharp/language-configuration.json similarity index 100% rename from lib/vscode/extensions/csharp/language-configuration.json rename to extensions/csharp/language-configuration.json diff --git a/lib/vscode/extensions/csharp/package.json b/extensions/csharp/package.json similarity index 100% rename from lib/vscode/extensions/csharp/package.json rename to extensions/csharp/package.json diff --git a/lib/vscode/extensions/csharp/package.nls.json b/extensions/csharp/package.nls.json similarity index 100% rename from lib/vscode/extensions/csharp/package.nls.json rename to extensions/csharp/package.nls.json diff --git a/lib/vscode/extensions/csharp/snippets/csharp.code-snippets b/extensions/csharp/snippets/csharp.code-snippets similarity index 100% rename from lib/vscode/extensions/csharp/snippets/csharp.code-snippets rename to extensions/csharp/snippets/csharp.code-snippets diff --git a/lib/vscode/extensions/csharp/syntaxes/csharp.tmLanguage.json b/extensions/csharp/syntaxes/csharp.tmLanguage.json similarity index 80% rename from lib/vscode/extensions/csharp/syntaxes/csharp.tmLanguage.json rename to extensions/csharp/syntaxes/csharp.tmLanguage.json index f67a94ba101d..8e26aaefa775 100644 --- a/lib/vscode/extensions/csharp/syntaxes/csharp.tmLanguage.json +++ b/extensions/csharp/syntaxes/csharp.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/dotnet/csharp-tmLanguage/commit/4d14854c9bfc9d84cce625d2bfebaac9741b9db8", + "version": "https://github.com/dotnet/csharp-tmLanguage/commit/572697a2c2267430010b3534281f73337144e94f", "name": "C#", "scopeName": "source.cs", "patterns": [ @@ -286,9 +286,6 @@ { "include": "#this-or-base-expression" }, - { - "include": "#switch-expression" - }, { "include": "#conditional-operator" }, @@ -619,7 +616,7 @@ ] }, "delegate-declaration": { - "begin": "(?x)\n(?:\\b(delegate)\\b)\\s+\n(?\n (?:\n (?:ref\\s+(?:readonly\\s+)?)? # ref return\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)\\s+\n(\\g)\\s*\n(<([^<>]+)>)?\\s*\n(?=\\()", + "begin": "(?x)\n(?:\\b(delegate)\\b)\\s+\n(?\n (?:\n (?:ref\\s+(?:readonly\\s+)?)? # ref return\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)\\s+\n(\\g)\\s*\n(<([^<>]+)>)?\\s*\n(?=\\()", "beginCaptures": { "1": { "name": "keyword.other.delegate.cs" @@ -970,7 +967,7 @@ ] }, "field-declaration": { - "begin": "(?x)\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)\\s+\n(\\g)\\s* # first field name\n(?!=>|==)(?=,|;|=|$)", + "begin": "(?x)\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)\\s+\n(\\g)\\s* # first field name\n(?!=>|==)(?=,|;|=|$)", "beginCaptures": { "1": { "patterns": [ @@ -1004,7 +1001,7 @@ ] }, "property-declaration": { - "begin": "(?x)\n\n# The negative lookahead below ensures that we don't match nested types\n# or other declarations as properties.\n(?![[:word:][:space:]]*\\b(?:class|interface|struct|enum|event)\\b)\n\n(?\n (?\n (?:\n (?:ref\\s+(?:readonly\\s+)?)? # ref return\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n )\\s+\n)\n(?\\g\\s*\\.\\s*)?\n(?\\g)\\s*\n(?=\\{|=>|$)", + "begin": "(?x)\n\n# The negative lookahead below ensures that we don't match nested types\n# or other declarations as properties.\n(?![[:word:][:space:]]*\\b(?:class|interface|struct|enum|event)\\b)\n\n(?\n (?\n (?:\n (?:ref\\s+(?:readonly\\s+)?)? # ref return\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n )\\s+\n)\n(?\\g\\s*\\.\\s*)?\n(?\\g)\\s*\n(?=\\{|=>|$)", "beginCaptures": { "1": { "patterns": [ @@ -1047,7 +1044,7 @@ ] }, "indexer-declaration": { - "begin": "(?x)\n(?\n (?\n (?:\n (?:ref\\s+(?:readonly\\s+)?)? # ref return\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n )\\s+\n)\n(?\\g\\s*\\.\\s*)?\n(?this)\\s*\n(?=\\[)", + "begin": "(?x)\n(?\n (?\n (?:\n (?:ref\\s+(?:readonly\\s+)?)? # ref return\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n )\\s+\n)\n(?\\g\\s*\\.\\s*)?\n(?this)\\s*\n(?=\\[)", "beginCaptures": { "1": { "patterns": [ @@ -1090,7 +1087,7 @@ ] }, "event-declaration": { - "begin": "(?x)\n\\b(event)\\b\\s*\n(?\n (?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n )\\s+\n)\n(?\\g\\s*\\.\\s*)?\n(?\\g(?:\\s*,\\s*\\g)*)\\s*\n(?=\\{|;|$)", + "begin": "(?x)\n\\b(event)\\b\\s*\n(?\n (?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n )\\s+\n)\n(?\\g\\s*\\.\\s*)?\n(?\\g(?:\\s*,\\s*\\g)*)\\s*\n(?=\\{|;|$)", "beginCaptures": { "1": { "name": "keyword.other.event.cs" @@ -1220,7 +1217,7 @@ ] }, "method-declaration": { - "begin": "(?x)\n(?\n (?\n (?:\n (?:ref\\s+(?:readonly\\s+)?)? # ref return\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n )\\s+\n)\n(?\\g\\s*\\.\\s*)?\n(\\g)\\s*\n(<([^<>]+)>)?\\s*\n(?=\\()", + "begin": "(?x)\n(?\n (?\n (?:\n (?:ref\\s+(?:readonly\\s+)?)? # ref return\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n )\\s+\n)\n(?\\g\\s*\\.\\s*)?\n(\\g)\\s*\n(<([^<>]+)>)?\\s*\n(?=\\()", "beginCaptures": { "1": { "patterns": [ @@ -1356,7 +1353,7 @@ ] }, "operator-declaration": { - "begin": "(?x)\n(?\n (?:\n (?:ref\\s+(?:readonly\\s+)?)? # ref return\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)\\s*\n(?(?:\\b(?:operator)))\\s*\n(?(?:\\+|-|\\*|/|%|&|\\||\\^|\\<\\<|\\>\\>|==|!=|\\>|\\<|\\>=|\\<=|!|~|\\+\\+|--|true|false))\\s*\n(?=\\()", + "begin": "(?x)\n(?\n (?:\n (?:ref\\s+(?:readonly\\s+)?)? # ref return\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)\\s*\n(?(?:\\b(?:operator)))\\s*\n(?(?:\\+|-|\\*|/|%|&|\\||\\^|\\<\\<|\\>\\>|==|!=|\\>|\\<|\\>=|\\<=|!|~|\\+\\+|--|true|false))\\s*\n(?=\\()", "beginCaptures": { "1": { "patterns": [ @@ -1389,7 +1386,7 @@ ] }, "conversion-operator-declaration": { - "begin": "(?x)\n(?(?:\\b(?:explicit|implicit)))\\s*\n(?(?:\\b(?:operator)))\\s*\n(?\n (?:\n (?:ref\\s+(?:readonly\\s+)?)? # ref return\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)\\s*\n(?=\\()", + "begin": "(?x)\n(?(?:\\b(?:explicit|implicit)))\\s*\n(?(?:\\b(?:operator)))\\s*\n(?\n (?:\n (?:ref\\s+(?:readonly\\s+)?)? # ref return\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)\\s*\n(?=\\()", "beginCaptures": { "1": { "patterns": [ @@ -1618,7 +1615,7 @@ "end": "(?=;)", "patterns": [ { - "include": "#statement" + "include": "#expression" } ] }, @@ -1721,178 +1718,6 @@ } ] }, - "switch-expression": { - "begin": "(?x) (?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)\\s+\n(\\g)\\b\\s*", - "beginCaptures": { - "1": { - "patterns": [ - { - "include": "#type" - } - ] - }, - "2": { - "name": "entity.name.variable.local.cs" - } - }, - "end": "(?==>)", - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#switch-when-clause" - } - ] - }, - "switch-property-expression": { - "begin": "(?x) # e.g. int x OR var x\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)?\\s*\n(\\{)", - "beginCaptures": { - "1": { - "patterns": [ - { - "include": "#type" - } - ] - }, - "6": { - "name": "punctuation.curlybrace.open.cs" - } - }, - "end": "\\}", - "endCaptures": { - "0": { - "name": "punctuation.curlybrace.close.cs" - } - }, - "patterns": [ - { - "include": "#expression" - }, - { - "include": "#punctuation-comma" - } - ] - }, - "switch-var-pattern": { - "begin": "(?x) # match foreach (var (x, y) in ...)\n(?:\\b(var)\\b\\s*)\n(?\\((?:[^\\(\\)]|\\g)+\\))\\s*", - "beginCaptures": { - "1": { - "name": "keyword.other.var.cs" - }, - "2": { - "patterns": [ - { - "include": "#tuple-declaration-deconstruction-element-list" - } - ] - } - }, - "end": "(?==>)", - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#switch-when-clause" - } - ] - }, - "switch-when-clause": { - "begin": "(?)", - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#expression" - }, - { - "include": "#punctuation-comma" - }, - { - "match": "\\(", - "captures": { - "0": { - "name": "punctuation.parenthesis.open.cs" - } - } - }, - { - "match": "\\)", - "captures": { - "0": { - "name": "punctuation.parenthesis.close.cs" - } - } - } - ] - }, "switch-label": { "patterns": [ { @@ -2040,7 +1865,7 @@ }, "patterns": [ { - "match": "(?x)\n(?:\n (\\bvar\\b)|\n (?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n )\n)\\s+\n(\\g)\\s+\n\\b(in)\\b", + "match": "(?x)\n(?:\n (\\bvar\\b)|\n (?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n )\n)\\s+\n(\\g)\\s+\n\\b(in)\\b", "captures": { "1": { "name": "keyword.other.var.cs" @@ -2159,7 +1984,7 @@ }, "patterns": [ { - "match": "(?x)\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)\\s*\n(?:(\\g)\\b)?", + "match": "(?x)\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)\\s*\n(?:(\\g)\\b)?", "captures": { "1": { "patterns": [ @@ -2319,37 +2144,31 @@ { "include": "#local-variable-declaration" }, - { - "include": "#local-function-declaration" - }, { "include": "#local-tuple-var-deconstruction" } ] }, "local-variable-declaration": { - "begin": "(?x)\n(?:\n (?:(\\busing)\\s+)?\n (?:(\\bref)\\s+(?:(\\breadonly)\\s+)?)?(\\bvar\\b)| # ref local\n (?\n (?:\n (?:ref\\s+(?:readonly\\s+)?)? # ref local\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n )\n)\\s+\n(\\g)\\s*\n(?!=>)\n(?=,|;|=|\\))", + "begin": "(?x)\n(?:\n (?:(\\bref)\\s+(?:(\\breadonly)\\s+)?)?(\\bvar\\b)| # ref local\n (?\n (?:\n (?:ref\\s+(?:readonly\\s+)?)? # ref local\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n )\n)\\s+\n(\\g)\\s*\n(?!=>)\n(?=,|;|=|\\))", "beginCaptures": { "1": { - "name": "keyword.other.using.cs" + "name": "storage.modifier.cs" }, "2": { "name": "storage.modifier.cs" }, "3": { - "name": "storage.modifier.cs" - }, - "4": { "name": "keyword.other.var.cs" }, - "5": { + "4": { "patterns": [ { "include": "#type" } ] }, - "10": { + "9": { "name": "entity.name.variable.local.cs" } }, @@ -2371,7 +2190,7 @@ ] }, "local-constant-declaration": { - "begin": "(?x)\n(?\\b(?:const)\\b)\\s*\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)\\s+\n(\\g)\\s*\n(?=,|;|=)", + "begin": "(?x)\n(?\\b(?:const)\\b)\\s*\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)\\s+\n(\\g)\\s*\n(?=,|;|=)", "beginCaptures": { "1": { "name": "storage.modifier.cs" @@ -2404,13 +2223,6 @@ } ] }, - "local-function-declaration": { - "patterns": [ - { - "include": "#method-declaration" - } - ] - }, "local-tuple-var-deconstruction": { "begin": "(?x) # e.g. var (x, y) = GetPoint();\n(?:\\b(var)\\b\\s*)\n(?\\((?:[^\\(\\)]|\\g)+\\))\\s*\n(?=;|=|\\))", "beginCaptures": { @@ -2520,7 +2332,7 @@ ] }, "declaration-expression-local": { - "match": "(?x) # e.g. int x OR var x\n(?:\n \\b(var)\\b|\n (?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n )\n)\\s+\n(\\g)\\b\\s*\n(?=[,)\\]])", + "match": "(?x) # e.g. int x OR var x\n(?:\n \\b(var)\\b|\n (?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n )\n)\\s+\n(\\g)\\b\\s*\n(?=[,)\\]])", "captures": { "1": { "name": "keyword.other.var.cs" @@ -2538,7 +2350,7 @@ } }, "declaration-expression-tuple": { - "match": "(?x) # e.g. int x OR var x\n(?:\n \\b(var)\\b|\n (?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n )\n)\\s+\n(\\g)\\b\\s*\n(?=[,)])", + "match": "(?x) # e.g. int x OR var x\n(?:\n \\b(var)\\b|\n (?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n )\n)\\s+\n(\\g)\\b\\s*\n(?=[,)])", "captures": { "1": { "name": "keyword.other.var.cs" @@ -2663,7 +2475,7 @@ }, "verbatim-interpolated-string": { "name": "string.quoted.double.cs", - "begin": "(?:\\$@|@\\$)\"", + "begin": "\\$@\"", "beginCaptures": { "0": { "name": "punctuation.definition.string.begin.cs" @@ -2900,7 +2712,7 @@ "patterns": [ { "name": "keyword.operator.assignment.compound.cs", - "match": "\\*=|/=|%=|\\+=|-=|\\?\\?=" + "match": "\\*=|/=|%=|\\+=|-=" }, { "name": "keyword.operator.assignment.compound.bitwise.cs", @@ -2948,26 +2760,6 @@ } ] }, - "switch-literal": { - "name": "constant.language.null.cs", - "match": "(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)\\s*\n(\\))(?=\\s*@?[_[:alnum:]\\(])", + "match": "(?x)\n(\\()\\s*\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)\\s*\n(\\))(?=\\s*@?[_[:alnum:]\\(])", "captures": { "1": { "name": "punctuation.parenthesis.open.cs" @@ -3055,7 +2847,7 @@ } }, "as-expression": { - "match": "(?x)\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)?", + "match": "(?x)\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)?", "captures": { "1": { "name": "keyword.other.as.cs" @@ -3070,7 +2862,7 @@ } }, "is-expression": { - "match": "(?x)\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)?", + "match": "(?x)\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)?", "captures": { "1": { "name": "keyword.other.is.cs" @@ -3096,7 +2888,7 @@ } }, "invocation-expression": { - "begin": "(?x)\n(?:(\\?)\\s*)? # preceding null-conditional operator?\n(?:(\\.)\\s*)? # preceding dot?\n(@?[_[:alpha:]][_[:alnum:]]*)\\s* # method name\n(?\\s*<([^<>]|\\g)+>\\s*)?\\s* # type arguments\n(?=\\() # open paren of argument list", + "begin": "(?x)\n(?:(\\?)\\s*)? # preceding null-conditional operator?\n(?:(\\.)\\s*)? # preceding dot?\n(@?[_[:alpha:]][_[:alnum:]]*)\\s* # method name\n(?\\s*<([^<>]|\\g)+>\\s*)?\\s* # type arguments\n(?=\\() # open paren of argument list", "beginCaptures": { "1": { "name": "keyword.operator.null-conditional.cs" @@ -3162,7 +2954,7 @@ } }, { - "match": "(?x)\n(\\.)?\\s*\n(@?[_[:alpha:]][_[:alnum:]]*)\n(?\\s*<([^<>]|\\g)+>\\s*)\n(?=\n (\\s*\\?)?\n \\s*\\.\\s*@?[_[:alpha:]][_[:alnum:]]*\n)", + "match": "(?x)\n(\\.)?\\s*\n(@?[_[:alpha:]][_[:alnum:]]*)\n(?\\s*<([^<>]|\\g)+>\\s*)\n(?=\n (\\s*\\?)?\n \\s*\\.\\s*@?[_[:alpha:]][_[:alnum:]]*\n)", "captures": { "1": { "name": "punctuation.accessor.cs" @@ -3200,7 +2992,7 @@ ] }, "object-creation-expression-with-parameters": { - "begin": "(?x)\n(new)\\s+\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)\\s*\n(?=\\()", + "begin": "(?x)\n(new)\\s+\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)\\s*\n(?=\\()", "beginCaptures": { "1": { "name": "keyword.other.new.cs" @@ -3221,7 +3013,7 @@ ] }, "object-creation-expression-with-no-parameters": { - "match": "(?x)\n(new)\\s+\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)\\s*\n(?=\\{|$)", + "match": "(?x)\n(new)\\s+\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)\\s*\n(?=\\{|$)", "captures": { "1": { "name": "keyword.other.new.cs" @@ -3236,7 +3028,7 @@ } }, "array-creation-expression": { - "begin": "(?x)\n\\b(new|stackalloc)\\b\\s*\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)?\\s*\n(?=\\[)", + "begin": "(?x)\n\\b(new|stackalloc)\\b\\s*\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)?\\s*\n(?=\\[)", "beginCaptures": { "1": { "name": "keyword.other.new.cs" @@ -3339,7 +3131,7 @@ ] }, "parameter": { - "match": "(?x)\n(?:(?:\\b(ref|params|out|in|this)\\b)\\s+)?\n(?\n (?:\n (?:ref\\s+)? # ref return\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)\\s+\n(\\g)", + "match": "(?x)\n(?:(?:\\b(ref|params|out|in|this)\\b)\\s+)?\n(?\n (?:\n (?:ref\\s+)? # ref return\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)\\s+\n(\\g)", "captures": { "1": { "name": "storage.modifier.cs" @@ -3438,7 +3230,7 @@ ] }, "query-expression": { - "begin": "(?x)\n\\b(from)\\b\\s*\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)?\n\\s+(\\g)\\b\\s*\n\\b(in)\\b\\s*", + "begin": "(?x)\n\\b(from)\\b\\s*\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)?\n\\s+(\\g)\\b\\s*\n\\b(in)\\b\\s*", "beginCaptures": { "1": { "name": "keyword.query.from.cs" @@ -3530,7 +3322,7 @@ ] }, "join-clause": { - "begin": "(?x)\n\\b(join)\\b\\s*\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)?\n\\s+(\\g)\\b\\s*\n\\b(in)\\b\\s*", + "begin": "(?x)\n\\b(join)\\b\\s*\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)?\n\\s+(\\g)\\b\\s*\n\\b(in)\\b\\s*", "beginCaptures": { "1": { "name": "keyword.query.join.cs" @@ -3800,7 +3592,7 @@ ] }, "lambda-parameter": { - "match": "(?x)\n(?:\\b(ref|out|in)\\b)?\\s*\n(?:(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)\\s+)?\n(\\g)\\b\\s*\n(?=[,)])", + "match": "(?x)\n(?:\\b(ref|out|in)\\b)?\\s*\n(?:(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)\\s+)?\n(\\g)\\b\\s*\n(?=[,)])", "captures": { "1": { "name": "storage.modifier.cs" @@ -3880,7 +3672,7 @@ ] }, "tuple-element": { - "match": "(?x)\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)\n(?:(?\\g)\\b)?", + "match": "(?x)\n(?\n (?:\n (?:\n (?:(?@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (? # identifier + type arguments (if any)\n \\g\\s*\n (?\\s*<(?:[^<>]|\\g)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g)* | # Are there any more names being dotted into?\n (?\\s*\\((?:[^\\(\\)]|\\g)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s*\\[(?:\\s*,\\s*)*\\]\\s*)* # array suffix?\n )\n)\n(?:(?\\g)\\b)?", "captures": { "1": { "patterns": [ diff --git a/lib/vscode/extensions/csharp/yarn.lock b/extensions/csharp/yarn.lock similarity index 100% rename from lib/vscode/extensions/csharp/yarn.lock rename to extensions/csharp/yarn.lock diff --git a/lib/vscode/extensions/css-language-features/.vscode/launch.json b/extensions/css-language-features/.vscode/launch.json similarity index 100% rename from lib/vscode/extensions/css-language-features/.vscode/launch.json rename to extensions/css-language-features/.vscode/launch.json diff --git a/lib/vscode/extensions/css-language-features/.vscode/settings.json b/extensions/css-language-features/.vscode/settings.json similarity index 100% rename from lib/vscode/extensions/css-language-features/.vscode/settings.json rename to extensions/css-language-features/.vscode/settings.json diff --git a/lib/vscode/extensions/css-language-features/.vscode/tasks.json b/extensions/css-language-features/.vscode/tasks.json similarity index 100% rename from lib/vscode/extensions/css-language-features/.vscode/tasks.json rename to extensions/css-language-features/.vscode/tasks.json diff --git a/lib/vscode/extensions/css-language-features/.vscodeignore b/extensions/css-language-features/.vscodeignore similarity index 100% rename from lib/vscode/extensions/css-language-features/.vscodeignore rename to extensions/css-language-features/.vscodeignore diff --git a/lib/vscode/extensions/css-language-features/CONTRIBUTING.md b/extensions/css-language-features/CONTRIBUTING.md similarity index 100% rename from lib/vscode/extensions/css-language-features/CONTRIBUTING.md rename to extensions/css-language-features/CONTRIBUTING.md diff --git a/lib/vscode/extensions/css-language-features/README.md b/extensions/css-language-features/README.md similarity index 100% rename from lib/vscode/extensions/css-language-features/README.md rename to extensions/css-language-features/README.md diff --git a/lib/vscode/extensions/css-language-features/client/src/browser/cssClientMain.ts b/extensions/css-language-features/client/src/browser/cssClientMain.ts similarity index 100% rename from lib/vscode/extensions/css-language-features/client/src/browser/cssClientMain.ts rename to extensions/css-language-features/client/src/browser/cssClientMain.ts diff --git a/lib/vscode/extensions/css-language-features/client/src/cssClient.ts b/extensions/css-language-features/client/src/cssClient.ts similarity index 100% rename from lib/vscode/extensions/css-language-features/client/src/cssClient.ts rename to extensions/css-language-features/client/src/cssClient.ts diff --git a/lib/vscode/extensions/css-language-features/client/src/customData.ts b/extensions/css-language-features/client/src/customData.ts similarity index 100% rename from lib/vscode/extensions/css-language-features/client/src/customData.ts rename to extensions/css-language-features/client/src/customData.ts diff --git a/lib/vscode/extensions/css-language-features/client/src/node/cssClientMain.ts b/extensions/css-language-features/client/src/node/cssClientMain.ts similarity index 100% rename from lib/vscode/extensions/css-language-features/client/src/node/cssClientMain.ts rename to extensions/css-language-features/client/src/node/cssClientMain.ts diff --git a/lib/vscode/extensions/css-language-features/client/src/node/nodeFs.ts b/extensions/css-language-features/client/src/node/nodeFs.ts similarity index 100% rename from lib/vscode/extensions/css-language-features/client/src/node/nodeFs.ts rename to extensions/css-language-features/client/src/node/nodeFs.ts diff --git a/lib/vscode/extensions/css-language-features/client/src/requests.ts b/extensions/css-language-features/client/src/requests.ts similarity index 100% rename from lib/vscode/extensions/css-language-features/client/src/requests.ts rename to extensions/css-language-features/client/src/requests.ts diff --git a/lib/vscode/extensions/css-language-features/client/src/typings/ref.d.ts b/extensions/css-language-features/client/src/typings/ref.d.ts similarity index 100% rename from lib/vscode/extensions/css-language-features/client/src/typings/ref.d.ts rename to extensions/css-language-features/client/src/typings/ref.d.ts diff --git a/lib/vscode/extensions/css-language-features/client/tsconfig.json b/extensions/css-language-features/client/tsconfig.json similarity index 100% rename from lib/vscode/extensions/css-language-features/client/tsconfig.json rename to extensions/css-language-features/client/tsconfig.json diff --git a/lib/vscode/extensions/css-language-features/extension-browser.webpack.config.js b/extensions/css-language-features/extension-browser.webpack.config.js similarity index 100% rename from lib/vscode/extensions/css-language-features/extension-browser.webpack.config.js rename to extensions/css-language-features/extension-browser.webpack.config.js diff --git a/lib/vscode/extensions/css-language-features/extension.webpack.config.js b/extensions/css-language-features/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/css-language-features/extension.webpack.config.js rename to extensions/css-language-features/extension.webpack.config.js diff --git a/lib/vscode/extensions/css-language-features/icons/css.png b/extensions/css-language-features/icons/css.png similarity index 100% rename from lib/vscode/extensions/css-language-features/icons/css.png rename to extensions/css-language-features/icons/css.png diff --git a/lib/vscode/extensions/css-language-features/package.json b/extensions/css-language-features/package.json similarity index 99% rename from lib/vscode/extensions/css-language-features/package.json rename to extensions/css-language-features/package.json index 7d80d7512237..207041a60943 100644 --- a/lib/vscode/extensions/css-language-features/package.json +++ b/extensions/css-language-features/package.json @@ -853,7 +853,7 @@ "vscode-uri": "^3.0.2" }, "devDependencies": { - "@types/node": "^12.19.9" + "@types/node": "14.x" }, "repository": { "type": "git", diff --git a/lib/vscode/extensions/css-language-features/package.nls.json b/extensions/css-language-features/package.nls.json similarity index 100% rename from lib/vscode/extensions/css-language-features/package.nls.json rename to extensions/css-language-features/package.nls.json diff --git a/lib/vscode/extensions/css-language-features/schemas/package.schema.json b/extensions/css-language-features/schemas/package.schema.json similarity index 100% rename from lib/vscode/extensions/css-language-features/schemas/package.schema.json rename to extensions/css-language-features/schemas/package.schema.json diff --git a/lib/vscode/extensions/css-language-features/server/.vscode/launch.json b/extensions/css-language-features/server/.vscode/launch.json similarity index 100% rename from lib/vscode/extensions/css-language-features/server/.vscode/launch.json rename to extensions/css-language-features/server/.vscode/launch.json diff --git a/lib/vscode/extensions/css-language-features/server/.vscode/tasks.json b/extensions/css-language-features/server/.vscode/tasks.json similarity index 100% rename from lib/vscode/extensions/css-language-features/server/.vscode/tasks.json rename to extensions/css-language-features/server/.vscode/tasks.json diff --git a/lib/vscode/extensions/css-language-features/server/extension-browser.webpack.config.js b/extensions/css-language-features/server/extension-browser.webpack.config.js similarity index 100% rename from lib/vscode/extensions/css-language-features/server/extension-browser.webpack.config.js rename to extensions/css-language-features/server/extension-browser.webpack.config.js diff --git a/lib/vscode/extensions/css-language-features/server/extension.webpack.config.js b/extensions/css-language-features/server/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/css-language-features/server/extension.webpack.config.js rename to extensions/css-language-features/server/extension.webpack.config.js diff --git a/lib/vscode/extensions/css-language-features/server/package.json b/extensions/css-language-features/server/package.json similarity index 92% rename from lib/vscode/extensions/css-language-features/server/package.json rename to extensions/css-language-features/server/package.json index ce3020c21a4e..62238cf5c40c 100644 --- a/lib/vscode/extensions/css-language-features/server/package.json +++ b/extensions/css-language-features/server/package.json @@ -10,13 +10,13 @@ "main": "./out/node/cssServerMain", "browser": "./dist/browser/cssServerMain", "dependencies": { - "vscode-css-languageservice": "^5.1.1", + "vscode-css-languageservice": "^5.1.3", "vscode-languageserver": "^7.0.0", "vscode-uri": "^3.0.2" }, "devDependencies": { "@types/mocha": "^8.2.0", - "@types/node": "^12.19.9" + "@types/node": "14.x" }, "scripts": { "compile": "gulp compile-extension:css-language-features-server", diff --git a/lib/vscode/extensions/css-language-features/server/src/browser/cssServerMain.ts b/extensions/css-language-features/server/src/browser/cssServerMain.ts similarity index 100% rename from lib/vscode/extensions/css-language-features/server/src/browser/cssServerMain.ts rename to extensions/css-language-features/server/src/browser/cssServerMain.ts diff --git a/lib/vscode/extensions/css-language-features/server/src/cssServer.ts b/extensions/css-language-features/server/src/cssServer.ts similarity index 100% rename from lib/vscode/extensions/css-language-features/server/src/cssServer.ts rename to extensions/css-language-features/server/src/cssServer.ts diff --git a/lib/vscode/extensions/css-language-features/server/src/customData.ts b/extensions/css-language-features/server/src/customData.ts similarity index 100% rename from lib/vscode/extensions/css-language-features/server/src/customData.ts rename to extensions/css-language-features/server/src/customData.ts diff --git a/lib/vscode/extensions/css-language-features/server/src/languageModelCache.ts b/extensions/css-language-features/server/src/languageModelCache.ts similarity index 100% rename from lib/vscode/extensions/css-language-features/server/src/languageModelCache.ts rename to extensions/css-language-features/server/src/languageModelCache.ts diff --git a/lib/vscode/extensions/css-language-features/server/src/node/cssServerMain.ts b/extensions/css-language-features/server/src/node/cssServerMain.ts similarity index 100% rename from lib/vscode/extensions/css-language-features/server/src/node/cssServerMain.ts rename to extensions/css-language-features/server/src/node/cssServerMain.ts diff --git a/lib/vscode/extensions/css-language-features/server/src/node/nodeFs.ts b/extensions/css-language-features/server/src/node/nodeFs.ts similarity index 100% rename from lib/vscode/extensions/css-language-features/server/src/node/nodeFs.ts rename to extensions/css-language-features/server/src/node/nodeFs.ts diff --git a/lib/vscode/extensions/css-language-features/server/src/requests.ts b/extensions/css-language-features/server/src/requests.ts similarity index 100% rename from lib/vscode/extensions/css-language-features/server/src/requests.ts rename to extensions/css-language-features/server/src/requests.ts diff --git a/lib/vscode/extensions/css-language-features/server/src/test/completion.test.ts b/extensions/css-language-features/server/src/test/completion.test.ts similarity index 96% rename from lib/vscode/extensions/css-language-features/server/src/test/completion.test.ts rename to extensions/css-language-features/server/src/test/completion.test.ts index 55eb64d9789c..ec336448a504 100644 --- a/lib/vscode/extensions/css-language-features/server/src/test/completion.test.ts +++ b/extensions/css-language-features/server/src/test/completion.test.ts @@ -24,10 +24,10 @@ suite('Completions', () => { return completion.label === expected.label; }); - assert.equal(matches.length, 1, `${expected.label} should only existing once: Actual: ${completions.items.map(c => c.label).join(', ')}`); + assert.strictEqual(matches.length, 1, `${expected.label} should only existing once: Actual: ${completions.items.map(c => c.label).join(', ')}`); let match = matches[0]; if (expected.resultText && TextEdit.is(match.textEdit)) { - assert.equal(TextDocument.applyEdits(document, [match.textEdit]), expected.resultText); + assert.strictEqual(TextDocument.applyEdits(document, [match.textEdit]), expected.resultText); } }; @@ -50,7 +50,7 @@ suite('Completions', () => { let list = await cssLanguageService.doComplete2(document, position, stylesheet, context); if (expected.count) { - assert.equal(list.items.length, expected.count); + assert.strictEqual(list.items.length, expected.count); } if (expected.items) { for (let item of expected.items) { diff --git a/lib/vscode/extensions/css-language-features/server/src/test/links.test.ts b/extensions/css-language-features/server/src/test/links.test.ts similarity index 89% rename from lib/vscode/extensions/css-language-features/server/src/test/links.test.ts rename to extensions/css-language-features/server/src/test/links.test.ts index f67b5e92f25c..bc4c6db6477a 100644 --- a/lib/vscode/extensions/css-language-features/server/src/test/links.test.ts +++ b/extensions/css-language-features/server/src/test/links.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'mocha'; import * as assert from 'assert'; -import { URI } from 'vscode-uri'; +import { URI } from 'vscode-uri'; import { resolve } from 'path'; import { TextDocument, DocumentLink } from 'vscode-languageserver-types'; import { WorkspaceFolder } from 'vscode-languageserver-protocol'; @@ -26,10 +26,10 @@ suite('Links', () => { return document.offsetAt(link.range.start) === expected.offset; }); - assert.equal(matches.length, 1, `${expected.offset} should only existing once: Actual: ${links.map(l => document.offsetAt(l.range.start)).join(', ')}`); + assert.strictEqual(matches.length, 1, `${expected.offset} should only existing once: Actual: ${links.map(l => document.offsetAt(l.range.start)).join(', ')}`); let match = matches[0]; - assert.equal(document.getText(match.range), expected.value); - assert.equal(match.target, expected.target); + assert.strictEqual(document.getText(match.range), expected.value); + assert.strictEqual(match.target, expected.target); }; async function assertLinks(value: string, expected: ItemDescription[], testUri: string, workspaceFolders?: WorkspaceFolder[], lang: string = 'css'): Promise { @@ -47,7 +47,7 @@ suite('Links', () => { const stylesheet = cssLanguageService.parseStylesheet(document); let links = await cssLanguageService.findDocumentLinks2(document, stylesheet, context)!; - assert.equal(links.length, expected.length); + assert.strictEqual(links.length, expected.length); for (let item of expected) { assertLink(links, item, document); diff --git a/lib/vscode/extensions/css-language-features/server/src/utils/documentContext.ts b/extensions/css-language-features/server/src/utils/documentContext.ts similarity index 100% rename from lib/vscode/extensions/css-language-features/server/src/utils/documentContext.ts rename to extensions/css-language-features/server/src/utils/documentContext.ts diff --git a/lib/vscode/extensions/css-language-features/server/src/utils/runner.ts b/extensions/css-language-features/server/src/utils/runner.ts similarity index 100% rename from lib/vscode/extensions/css-language-features/server/src/utils/runner.ts rename to extensions/css-language-features/server/src/utils/runner.ts diff --git a/lib/vscode/extensions/css-language-features/server/src/utils/strings.ts b/extensions/css-language-features/server/src/utils/strings.ts similarity index 100% rename from lib/vscode/extensions/css-language-features/server/src/utils/strings.ts rename to extensions/css-language-features/server/src/utils/strings.ts diff --git a/lib/vscode/extensions/css-language-features/server/test/index.js b/extensions/css-language-features/server/test/index.js similarity index 100% rename from lib/vscode/extensions/css-language-features/server/test/index.js rename to extensions/css-language-features/server/test/index.js diff --git a/lib/vscode/extensions/css-language-features/server/test/linksTestFixtures/.gitignore b/extensions/css-language-features/server/test/linksTestFixtures/.gitignore similarity index 100% rename from lib/vscode/extensions/css-language-features/server/test/linksTestFixtures/.gitignore rename to extensions/css-language-features/server/test/linksTestFixtures/.gitignore diff --git a/lib/vscode/extensions/css-language-features/server/test/linksTestFixtures/node_modules/foo/package.json b/extensions/css-language-features/server/test/linksTestFixtures/node_modules/foo/package.json similarity index 100% rename from lib/vscode/extensions/css-language-features/server/test/linksTestFixtures/node_modules/foo/package.json rename to extensions/css-language-features/server/test/linksTestFixtures/node_modules/foo/package.json diff --git a/lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/.foo.js b/extensions/css-language-features/server/test/pathCompletionFixtures/.foo.js similarity index 100% rename from lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/.foo.js rename to extensions/css-language-features/server/test/pathCompletionFixtures/.foo.js diff --git a/lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/about/about.css b/extensions/css-language-features/server/test/pathCompletionFixtures/about/about.css similarity index 100% rename from lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/about/about.css rename to extensions/css-language-features/server/test/pathCompletionFixtures/about/about.css diff --git a/lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/about/about.html b/extensions/css-language-features/server/test/pathCompletionFixtures/about/about.html similarity index 100% rename from lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/about/about.html rename to extensions/css-language-features/server/test/pathCompletionFixtures/about/about.html diff --git a/lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/index.html b/extensions/css-language-features/server/test/pathCompletionFixtures/index.html similarity index 100% rename from lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/index.html rename to extensions/css-language-features/server/test/pathCompletionFixtures/index.html diff --git a/lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/scss/_foo.scss b/extensions/css-language-features/server/test/pathCompletionFixtures/scss/_foo.scss similarity index 100% rename from lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/scss/_foo.scss rename to extensions/css-language-features/server/test/pathCompletionFixtures/scss/_foo.scss diff --git a/lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/scss/main.scss b/extensions/css-language-features/server/test/pathCompletionFixtures/scss/main.scss similarity index 100% rename from lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/scss/main.scss rename to extensions/css-language-features/server/test/pathCompletionFixtures/scss/main.scss diff --git a/lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/src/data/foo.asar b/extensions/css-language-features/server/test/pathCompletionFixtures/src/data/foo.asar similarity index 100% rename from lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/src/data/foo.asar rename to extensions/css-language-features/server/test/pathCompletionFixtures/src/data/foo.asar diff --git a/lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/src/feature.js b/extensions/css-language-features/server/test/pathCompletionFixtures/src/feature.js similarity index 100% rename from lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/src/feature.js rename to extensions/css-language-features/server/test/pathCompletionFixtures/src/feature.js diff --git a/lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/src/test.js b/extensions/css-language-features/server/test/pathCompletionFixtures/src/test.js similarity index 100% rename from lib/vscode/extensions/css-language-features/server/test/pathCompletionFixtures/src/test.js rename to extensions/css-language-features/server/test/pathCompletionFixtures/src/test.js diff --git a/lib/vscode/extensions/css-language-features/server/tsconfig.json b/extensions/css-language-features/server/tsconfig.json similarity index 100% rename from lib/vscode/extensions/css-language-features/server/tsconfig.json rename to extensions/css-language-features/server/tsconfig.json diff --git a/lib/vscode/extensions/css-language-features/server/yarn.lock b/extensions/css-language-features/server/yarn.lock similarity index 84% rename from lib/vscode/extensions/css-language-features/server/yarn.lock rename to extensions/css-language-features/server/yarn.lock index 3ff39d282f66..c734be9d5baa 100644 --- a/lib/vscode/extensions/css-language-features/server/yarn.lock +++ b/extensions/css-language-features/server/yarn.lock @@ -7,15 +7,15 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.0.tgz#3eb56d13a1de1d347ecb1957c6860c911704bc44" integrity sha512-/Sge3BymXo4lKc31C8OINJgXLaw+7vL1/L1pGiBNpGrBiT8FQiaFpSYV0uhTaG4y78vcMBTMFsWaHDvuD+xGzQ== -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== - -vscode-css-languageservice@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-5.1.1.tgz#d68a22ea0b34a8356c169cafc7d32564c2ff6e87" - integrity sha512-QW0oe/g2y5E2AbVqY7FJNr2Q8uHiAHNSFpptI6xB8Y0KgzVKppOcIVrgmBNzXhFp9IswAwptkdqr8ExSJbqPkQ== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== + +vscode-css-languageservice@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-5.1.3.tgz#a7b2f21ed48842af5d9a98223bcae09e33d707d5" + integrity sha512-c8xiUhrDBNG6iS92FEE+K3IWOHAqVvzsqjjLSaXHyF5Qdn/6VhUweGNjtZ2CBSfs+Vkmz7pJzLQ7Io1x5deumA== dependencies: vscode-languageserver-textdocument "^1.0.1" vscode-languageserver-types "^3.16.0" diff --git a/lib/vscode/extensions/css-language-features/test/mocha.opts b/extensions/css-language-features/test/mocha.opts similarity index 100% rename from lib/vscode/extensions/css-language-features/test/mocha.opts rename to extensions/css-language-features/test/mocha.opts diff --git a/lib/vscode/extensions/css-language-features/yarn.lock b/extensions/css-language-features/yarn.lock similarity index 93% rename from lib/vscode/extensions/css-language-features/yarn.lock rename to extensions/css-language-features/yarn.lock index eec3195c3f72..2e524319229d 100644 --- a/lib/vscode/extensions/css-language-features/yarn.lock +++ b/extensions/css-language-features/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== balanced-match@^1.0.0: version "1.0.0" diff --git a/lib/vscode/extensions/css/.vscode/launch.json b/extensions/css/.vscode/launch.json similarity index 100% rename from lib/vscode/extensions/css/.vscode/launch.json rename to extensions/css/.vscode/launch.json diff --git a/lib/vscode/extensions/css/.vscodeignore b/extensions/css/.vscodeignore similarity index 100% rename from lib/vscode/extensions/css/.vscodeignore rename to extensions/css/.vscodeignore diff --git a/lib/vscode/extensions/css/cgmanifest.json b/extensions/css/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/css/cgmanifest.json rename to extensions/css/cgmanifest.json diff --git a/lib/vscode/extensions/css/language-configuration.json b/extensions/css/language-configuration.json similarity index 100% rename from lib/vscode/extensions/css/language-configuration.json rename to extensions/css/language-configuration.json diff --git a/lib/vscode/extensions/css/package.json b/extensions/css/package.json similarity index 100% rename from lib/vscode/extensions/css/package.json rename to extensions/css/package.json diff --git a/lib/vscode/extensions/css/package.nls.json b/extensions/css/package.nls.json similarity index 100% rename from lib/vscode/extensions/css/package.nls.json rename to extensions/css/package.nls.json diff --git a/lib/vscode/extensions/css/syntaxes/css.tmLanguage.json b/extensions/css/syntaxes/css.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/css/syntaxes/css.tmLanguage.json rename to extensions/css/syntaxes/css.tmLanguage.json diff --git a/lib/vscode/extensions/css/yarn.lock b/extensions/css/yarn.lock similarity index 100% rename from lib/vscode/extensions/css/yarn.lock rename to extensions/css/yarn.lock diff --git a/lib/vscode/extensions/julia/.vscodeignore b/extensions/dart/.vscodeignore similarity index 100% rename from lib/vscode/extensions/julia/.vscodeignore rename to extensions/dart/.vscodeignore diff --git a/extensions/dart/cgmanifest.json b/extensions/dart/cgmanifest.json new file mode 100644 index 000000000000..52c4a994d19d --- /dev/null +++ b/extensions/dart/cgmanifest.json @@ -0,0 +1,46 @@ +{ + "registrations": [ + { + "component": { + "type": "git", + "git": { + "name": "dart-lang/dart-syntax-highlight", + "repositoryUrl": "https://github.com/dart-lang/dart-syntax-highlight", + "commitHash": "65f211722c85e9fdf0aa658d5663e6ccaf2ebe25" + } + }, + "licenseDetail": [ + "Copyright 2020, the Dart project authors.", + "", + "Redistribution and use in source and binary forms, with or without", + "modification, are permitted provided that the following conditions are", + "met:", + "", + " * Redistributions of source code must retain the above copyright", + " notice, this list of conditions and the following disclaimer.", + " * Redistributions in binary form must reproduce the above", + " copyright notice, this list of conditions and the following", + " disclaimer in the documentation and/or other materials provided", + " with the distribution.", + " * Neither the name of Google LLC nor the names of its", + " contributors may be used to endorse or promote products derived", + " from this software without specific prior written permission.", + "", + "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS", + "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT", + "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR", + "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT", + "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,", + "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT", + "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,", + "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY", + "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT", + "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE", + "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + ], + "license": "BSD", + "version": "0.0.0" + } + ], + "version": 1 +} diff --git a/extensions/dart/language-configuration.json b/extensions/dart/language-configuration.json new file mode 100644 index 000000000000..9d44a40ee84b --- /dev/null +++ b/extensions/dart/language-configuration.json @@ -0,0 +1,29 @@ +{ + "comments": { + "lineComment": "//", + "blockComment": [ "/*", "*/" ] + }, + "brackets": [ + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], + "autoClosingPairs": [ + { "open": "{", "close": "}" }, + { "open": "[", "close": "]" }, + { "open": "(", "close": ")" }, + { "open": "'", "close": "'", "notIn": ["string", "comment"] }, + { "open": "\"", "close": "\"", "notIn": ["string"] }, + { "open": "`", "close": "`", "notIn": ["string", "comment"] }, + { "open": "/**", "close": " */", "notIn": ["string"] } + ], + "surroundingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["<", ">"], + ["'", "'"], + ["\"", "\""], + ["`", "`"] + ] +} diff --git a/extensions/dart/package.json b/extensions/dart/package.json new file mode 100644 index 000000000000..92863ffb2b7f --- /dev/null +++ b/extensions/dart/package.json @@ -0,0 +1,35 @@ +{ + "name": "dart", + "displayName": "%displayName%", + "description": "%description%", + "version": "1.0.0", + "publisher": "vscode", + "license": "MIT", + "engines": { + "vscode": "0.10.x" + }, + "scripts": { + "update-grammar": "node ../node_modules/vscode-grammar-updater/bin dart-lang/dart-syntax-highlight grammars/dart.json ./syntaxes/dart.tmLanguage.json" + }, + "contributes": { + "languages": [ + { + "id": "dart", + "extensions": [ + ".dart" + ], + "aliases": [ + "Dart" + ], + "configuration": "./language-configuration.json" + } + ], + "grammars": [ + { + "language": "dart", + "scopeName": "source.dart", + "path": "./syntaxes/dart.tmLanguage.json" + } + ] + } +} diff --git a/extensions/dart/package.nls.json b/extensions/dart/package.nls.json new file mode 100644 index 000000000000..71e6b91e93ae --- /dev/null +++ b/extensions/dart/package.nls.json @@ -0,0 +1,4 @@ +{ + "displayName": "Dart Language Basics", + "description": "Provides syntax highlighting & bracket matching in Dart files." +} diff --git a/extensions/dart/syntaxes/dart.tmLanguage.json b/extensions/dart/syntaxes/dart.tmLanguage.json new file mode 100644 index 000000000000..fc2fae5bc4c3 --- /dev/null +++ b/extensions/dart/syntaxes/dart.tmLanguage.json @@ -0,0 +1,439 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/dart-lang/dart-syntax-highlight/blob/master/grammars/dart.json", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": "https://github.com/dart-lang/dart-syntax-highlight/commit/65f211722c85e9fdf0aa658d5663e6ccaf2ebe25", + "name": "Dart", + "scopeName": "source.dart", + "patterns": [ + { + "name": "meta.preprocessor.script.dart", + "match": "^(#!.*)$" + }, + { + "name": "meta.declaration.dart", + "begin": "^\\w*\\b(library|import|part of|part|export)\\b", + "beginCaptures": { + "0": { + "name": "keyword.other.import.dart" + } + }, + "end": ";", + "endCaptures": { + "0": { + "name": "punctuation.terminator.dart" + } + }, + "patterns": [ + { + "include": "#strings" + }, + { + "include": "#comments" + }, + { + "name": "keyword.other.import.dart", + "match": "\\b(as|show|hide)\\b" + } + ] + }, + { + "include": "#comments" + }, + { + "include": "#punctuation" + }, + { + "include": "#annotations" + }, + { + "include": "#keywords" + }, + { + "include": "#constants-and-special-vars" + }, + { + "include": "#strings" + } + ], + "repository": { + "dartdoc": { + "patterns": [ + { + "match": "(\\[.*?\\])", + "captures": { + "0": { + "name": "variable.name.source.dart" + } + } + }, + { + "match": "^ {4,}(?![ \\*]).*", + "captures": { + "0": { + "name": "variable.name.source.dart" + } + } + }, + { + "contentName": "variable.other.source.dart", + "begin": "```.*?$", + "end": "```" + }, + { + "match": "(`.*?`)", + "captures": { + "0": { + "name": "variable.other.source.dart" + } + } + }, + { + "match": "(`.*?`)", + "captures": { + "0": { + "name": "variable.other.source.dart" + } + } + }, + { + "match": "(\\* (( ).*))$", + "captures": { + "2": { + "name": "variable.other.source.dart" + } + } + }, + { + "match": "(\\* .*)$" + } + ] + }, + "comments": { + "patterns": [ + { + "name": "comment.block.empty.dart", + "match": "/\\*\\*/", + "captures": { + "0": { + "name": "punctuation.definition.comment.dart" + } + } + }, + { + "include": "#comments-doc-oldschool" + }, + { + "include": "#comments-doc" + }, + { + "include": "#comments-inline" + } + ] + }, + "comments-doc-oldschool": { + "patterns": [ + { + "name": "comment.block.documentation.dart", + "begin": "/\\*\\*", + "end": "\\*/", + "patterns": [ + { + "include": "#comments-doc-oldschool" + }, + { + "include": "#comments-block" + }, + { + "include": "#dartdoc" + } + ] + } + ] + }, + "comments-doc": { + "patterns": [ + { + "name": "comment.block.documentation.dart", + "begin": "///", + "while": "^\\s*///", + "patterns": [ + { + "include": "#dartdoc" + } + ] + } + ] + }, + "comments-inline": { + "patterns": [ + { + "include": "#comments-block" + }, + { + "match": "((//).*)$", + "captures": { + "1": { + "name": "comment.line.double-slash.dart" + } + } + } + ] + }, + "comments-block": { + "patterns": [ + { + "name": "comment.block.dart", + "begin": "/\\*", + "end": "\\*/", + "patterns": [ + { + "include": "#comments-block" + } + ] + } + ] + }, + "annotations": { + "patterns": [ + { + "name": "storage.type.annotation.dart", + "match": "@[a-zA-Z]+" + } + ] + }, + "constants-and-special-vars": { + "patterns": [ + { + "name": "constant.language.dart", + "match": "(?)", + "captures": { + "1": { + "name": "entity.name.function.dart" + } + } + } + ] + }, + "keywords": { + "patterns": [ + { + "name": "keyword.cast.dart", + "match": "(?>>?|~|\\^|\\||&)" + }, + { + "name": "keyword.operator.assignment.bitwise.dart", + "match": "((&|\\^|\\||<<|>>>?)=)" + }, + { + "name": "keyword.operator.closure.dart", + "match": "(=>)" + }, + { + "name": "keyword.operator.comparison.dart", + "match": "(==|!=|<=?|>=?)" + }, + { + "name": "keyword.operator.assignment.arithmetic.dart", + "match": "(([+*/%-]|\\~)=)" + }, + { + "name": "keyword.operator.assignment.dart", + "match": "(=)" + }, + { + "name": "keyword.operator.increment-decrement.dart", + "match": "(\\-\\-|\\+\\+)" + }, + { + "name": "keyword.operator.arithmetic.dart", + "match": "(\\-|\\+|\\*|\\/|\\~\\/|%)" + }, + { + "name": "keyword.operator.logical.dart", + "match": "(!|&&|\\|\\|)" + }, + { + "name": "storage.modifier.dart", + "match": "(? { let { start, end } = rangeToReplace; const startOffset = document.offsetAt(start); - const startNode = getFlatNode(rootNode, startOffset, true); + const documentText = document.getText(); + const startNode = getHtmlFlatNode(documentText, rootNode, startOffset, true); if (startNode && isOffsetInsideOpenOrCloseTag(startNode, startOffset)) { start = document.positionAt(startNode.start); const nodeEndPosition = document.positionAt(startNode.end); @@ -64,7 +65,7 @@ export async function wrapWithAbbreviation(args: any): Promise { } const endOffset = document.offsetAt(end); - const endNode = getFlatNode(rootNode, endOffset, true); + const endNode = getHtmlFlatNode(documentText, rootNode, endOffset, true); if (endNode && isOffsetInsideOpenOrCloseTag(endNode, endOffset)) { const nodeStartPosition = document.positionAt(endNode.start); start = nodeStartPosition.isBefore(start) ? nodeStartPosition : start; @@ -665,6 +666,8 @@ function expandAbbr(input: ExpandAbbreviationInput): string | undefined { const expandOptions = helper.getExpandOptions(input.syntax, getEmmetConfiguration(input.syntax), input.filter); if (input.textToWrap) { + // escape ${ sections, fixes #122231 + input.textToWrap = input.textToWrap.map(e => e.replace(/\$\{/g, '\\\$\{')); if (input.filter && input.filter.includes('t')) { input.textToWrap = input.textToWrap.map(line => { return line.replace(trimRegex, '').trim(); diff --git a/lib/vscode/extensions/emmet/src/balance.ts b/extensions/emmet/src/balance.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/balance.ts rename to extensions/emmet/src/balance.ts diff --git a/lib/vscode/extensions/emmet/src/browser/emmetBrowserMain.ts b/extensions/emmet/src/browser/emmetBrowserMain.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/browser/emmetBrowserMain.ts rename to extensions/emmet/src/browser/emmetBrowserMain.ts diff --git a/lib/vscode/extensions/emmet/src/bufferStream.ts b/extensions/emmet/src/bufferStream.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/bufferStream.ts rename to extensions/emmet/src/bufferStream.ts diff --git a/lib/vscode/extensions/emmet/src/defaultCompletionProvider.ts b/extensions/emmet/src/defaultCompletionProvider.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/defaultCompletionProvider.ts rename to extensions/emmet/src/defaultCompletionProvider.ts diff --git a/lib/vscode/extensions/emmet/src/editPoint.ts b/extensions/emmet/src/editPoint.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/editPoint.ts rename to extensions/emmet/src/editPoint.ts diff --git a/lib/vscode/extensions/emmet/src/emmetCommon.ts b/extensions/emmet/src/emmetCommon.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/emmetCommon.ts rename to extensions/emmet/src/emmetCommon.ts diff --git a/lib/vscode/extensions/emmet/src/evaluateMathExpression.ts b/extensions/emmet/src/evaluateMathExpression.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/evaluateMathExpression.ts rename to extensions/emmet/src/evaluateMathExpression.ts diff --git a/lib/vscode/extensions/emmet/src/imageSizeHelper.ts b/extensions/emmet/src/imageSizeHelper.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/imageSizeHelper.ts rename to extensions/emmet/src/imageSizeHelper.ts diff --git a/lib/vscode/extensions/emmet/src/incrementDecrement.ts b/extensions/emmet/src/incrementDecrement.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/incrementDecrement.ts rename to extensions/emmet/src/incrementDecrement.ts diff --git a/lib/vscode/extensions/emmet/src/locateFile.ts b/extensions/emmet/src/locateFile.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/locateFile.ts rename to extensions/emmet/src/locateFile.ts diff --git a/lib/vscode/extensions/emmet/src/matchTag.ts b/extensions/emmet/src/matchTag.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/matchTag.ts rename to extensions/emmet/src/matchTag.ts diff --git a/lib/vscode/extensions/emmet/src/mergeLines.ts b/extensions/emmet/src/mergeLines.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/mergeLines.ts rename to extensions/emmet/src/mergeLines.ts diff --git a/lib/vscode/extensions/emmet/src/node/emmetNodeMain.ts b/extensions/emmet/src/node/emmetNodeMain.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/node/emmetNodeMain.ts rename to extensions/emmet/src/node/emmetNodeMain.ts diff --git a/lib/vscode/extensions/emmet/src/parseDocument.ts b/extensions/emmet/src/parseDocument.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/parseDocument.ts rename to extensions/emmet/src/parseDocument.ts diff --git a/lib/vscode/extensions/emmet/src/reflectCssValue.ts b/extensions/emmet/src/reflectCssValue.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/reflectCssValue.ts rename to extensions/emmet/src/reflectCssValue.ts diff --git a/lib/vscode/extensions/emmet/src/removeTag.ts b/extensions/emmet/src/removeTag.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/removeTag.ts rename to extensions/emmet/src/removeTag.ts diff --git a/lib/vscode/extensions/emmet/src/selectItem.ts b/extensions/emmet/src/selectItem.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/selectItem.ts rename to extensions/emmet/src/selectItem.ts diff --git a/lib/vscode/extensions/emmet/src/selectItemHTML.ts b/extensions/emmet/src/selectItemHTML.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/selectItemHTML.ts rename to extensions/emmet/src/selectItemHTML.ts diff --git a/lib/vscode/extensions/emmet/src/selectItemStylesheet.ts b/extensions/emmet/src/selectItemStylesheet.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/selectItemStylesheet.ts rename to extensions/emmet/src/selectItemStylesheet.ts diff --git a/lib/vscode/extensions/emmet/src/splitJoinTag.ts b/extensions/emmet/src/splitJoinTag.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/splitJoinTag.ts rename to extensions/emmet/src/splitJoinTag.ts diff --git a/lib/vscode/extensions/emmet/src/test/abbreviationAction.test.ts b/extensions/emmet/src/test/abbreviationAction.test.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/test/abbreviationAction.test.ts rename to extensions/emmet/src/test/abbreviationAction.test.ts diff --git a/lib/vscode/extensions/emmet/src/test/completion.test.ts b/extensions/emmet/src/test/completion.test.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/test/completion.test.ts rename to extensions/emmet/src/test/completion.test.ts diff --git a/lib/vscode/extensions/emmet/src/test/cssAbbreviationAction.test.ts b/extensions/emmet/src/test/cssAbbreviationAction.test.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/test/cssAbbreviationAction.test.ts rename to extensions/emmet/src/test/cssAbbreviationAction.test.ts diff --git a/lib/vscode/extensions/emmet/src/test/editPointSelectItemBalance.test.ts b/extensions/emmet/src/test/editPointSelectItemBalance.test.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/test/editPointSelectItemBalance.test.ts rename to extensions/emmet/src/test/editPointSelectItemBalance.test.ts diff --git a/lib/vscode/extensions/emmet/src/test/evaluateMathExpression.test.ts b/extensions/emmet/src/test/evaluateMathExpression.test.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/test/evaluateMathExpression.test.ts rename to extensions/emmet/src/test/evaluateMathExpression.test.ts diff --git a/lib/vscode/extensions/emmet/src/test/incrementDecrement.test.ts b/extensions/emmet/src/test/incrementDecrement.test.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/test/incrementDecrement.test.ts rename to extensions/emmet/src/test/incrementDecrement.test.ts diff --git a/lib/vscode/extensions/emmet/src/test/index.ts b/extensions/emmet/src/test/index.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/test/index.ts rename to extensions/emmet/src/test/index.ts diff --git a/lib/vscode/extensions/emmet/src/test/partialParsingStylesheet.test.ts b/extensions/emmet/src/test/partialParsingStylesheet.test.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/test/partialParsingStylesheet.test.ts rename to extensions/emmet/src/test/partialParsingStylesheet.test.ts diff --git a/lib/vscode/extensions/emmet/src/test/reflectCssValue.test.ts b/extensions/emmet/src/test/reflectCssValue.test.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/test/reflectCssValue.test.ts rename to extensions/emmet/src/test/reflectCssValue.test.ts diff --git a/lib/vscode/extensions/emmet/src/test/tagActions.test.ts b/extensions/emmet/src/test/tagActions.test.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/test/tagActions.test.ts rename to extensions/emmet/src/test/tagActions.test.ts diff --git a/lib/vscode/extensions/emmet/src/test/testUtils.ts b/extensions/emmet/src/test/testUtils.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/test/testUtils.ts rename to extensions/emmet/src/test/testUtils.ts diff --git a/lib/vscode/extensions/emmet/src/test/toggleComment.test.ts b/extensions/emmet/src/test/toggleComment.test.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/test/toggleComment.test.ts rename to extensions/emmet/src/test/toggleComment.test.ts diff --git a/lib/vscode/extensions/emmet/src/test/updateImageSize.test.ts b/extensions/emmet/src/test/updateImageSize.test.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/test/updateImageSize.test.ts rename to extensions/emmet/src/test/updateImageSize.test.ts diff --git a/lib/vscode/extensions/emmet/src/test/wrapWithAbbreviation.test.ts b/extensions/emmet/src/test/wrapWithAbbreviation.test.ts similarity index 84% rename from lib/vscode/extensions/emmet/src/test/wrapWithAbbreviation.test.ts rename to extensions/emmet/src/test/wrapWithAbbreviation.test.ts index 020f01912913..978d154ae97f 100644 --- a/lib/vscode/extensions/emmet/src/test/wrapWithAbbreviation.test.ts +++ b/extensions/emmet/src/test/wrapWithAbbreviation.test.ts @@ -13,6 +13,7 @@ const htmlContentsForBlockWrapTests = ` `; @@ -20,6 +21,7 @@ const htmlContentsForInlineWrapTests = ` `; @@ -31,6 +33,9 @@ const wrapBlockElementExpected = `
  • $hithere
  • +
    +
  • \${hithere}
  • +
    `; @@ -38,6 +43,7 @@ const wrapInlineElementExpected = ` `; @@ -49,6 +55,9 @@ const wrapSnippetExpected = `
  • $hithere
  • + +
  • \${hithere}
  • +
    `; @@ -64,6 +73,11 @@ const wrapMultiLineAbbrExpected = `
  • $hithere
  • +
      +
    • +
    • \${hithere}
    • + +
    `; @@ -77,15 +91,18 @@ const wrapInlineElementExpectedFormatFalse = `

  • $hithere
  • +

    +
  • \${hithere}
  • +

    `; suite('Tests for Wrap with Abbreviations', () => { teardown(closeAllEditors); - const multiCursors = [new Selection(2, 6, 2, 6), new Selection(3, 6, 3, 6)]; - const multiCursorsWithSelection = [new Selection(2, 2, 2, 28), new Selection(3, 2, 3, 33)]; - const multiCursorsWithFullLineSelection = [new Selection(2, 0, 2, 28), new Selection(3, 0, 4, 0)]; + const multiCursors = [new Selection(2, 6, 2, 6), new Selection(3, 6, 3, 6), new Selection(4, 6, 4, 6)]; + const multiCursorsWithSelection = [new Selection(2, 2, 2, 28), new Selection(3, 2, 3, 33), new Selection(4, 6, 4, 36)]; + const multiCursorsWithFullLineSelection = [new Selection(2, 0, 2, 28), new Selection(3, 0, 3, 33), new Selection(4, 0, 4, 36)]; const oldValueForSyntaxProfiles = workspace.getConfiguration('emmet').inspect('syntaxProfile'); @@ -202,6 +219,79 @@ suite('Tests for Wrap with Abbreviations', () => { return testWrapWithAbbreviation([new Selection(3, 2, 3, 2)], 'div', expectedContents, contents); }); + test('Wrap with abbreviation inner node in cdata', () => { + const contents = ` + +

    Test 2

    + ]]> + hello + + `; + const expectedContents = ` + +
    +

    Test 2

    +
    + ]]> + hello + + `; + return testWrapWithAbbreviation([new Selection(6, 5, 6, 5)], 'div', expectedContents, contents); + }); + + test('Wrap with abbreviation inner node in script in cdata', () => { + const contents = ` + + `; + const expectedContents = ` + + `; + return testWrapWithAbbreviation([new Selection(4, 10, 4, 10)], 'div', expectedContents, contents); + }); + + test('Wrap with abbreviation inner node in cdata one-liner', () => { + const contents = ` + + `; + // this result occurs because no selection on the open/close p tag was given + const expectedContents = ` + + `; + return testWrapWithAbbreviation([new Selection(2, 15, 2, 15)], 'div', expectedContents, contents); + }); + test('Wrap with multiline abbreviation doesnt add extra spaces', () => { // Issue #29898 const contents = ` @@ -343,11 +433,12 @@ suite('Tests for Wrap with Abbreviations', () => {
  • img
  • $hithere
  • +
  • \${hithere}
  • `; - return testWrapWithAbbreviation([new Selection(2, 2, 3, 33)], '.hello', wrapMultiLineJsxExpected, htmlContentsForBlockWrapTests, 'jsx'); + return testWrapWithAbbreviation([new Selection(2, 2, 4, 36)], '.hello', wrapMultiLineJsxExpected, htmlContentsForBlockWrapTests, 'jsx'); }); test('Wrap individual line with abbreviation uses className for jsx files', () => { @@ -359,10 +450,13 @@ suite('Tests for Wrap with Abbreviations', () => {
  • $hithere
  • +
    +
  • \${hithere}
  • +
    `; - return testWrapIndividualLinesWithAbbreviation([new Selection(2, 2, 3, 33)], '.hello$*', wrapIndividualLinesJsxExpected, htmlContentsForBlockWrapTests, 'jsx'); + return testWrapIndividualLinesWithAbbreviation([new Selection(2, 2, 4, 36)], '.hello$*', wrapIndividualLinesJsxExpected, htmlContentsForBlockWrapTests, 'jsx'); }); test('Wrap with abbreviation merge overlapping computed ranges', () => { diff --git a/lib/vscode/extensions/emmet/src/toggleComment.ts b/extensions/emmet/src/toggleComment.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/toggleComment.ts rename to extensions/emmet/src/toggleComment.ts diff --git a/lib/vscode/extensions/emmet/src/typings/EmmetFlatNode.d.ts b/extensions/emmet/src/typings/EmmetFlatNode.d.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/typings/EmmetFlatNode.d.ts rename to extensions/emmet/src/typings/EmmetFlatNode.d.ts diff --git a/lib/vscode/extensions/emmet/src/typings/EmmetNode.d.ts b/extensions/emmet/src/typings/EmmetNode.d.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/typings/EmmetNode.d.ts rename to extensions/emmet/src/typings/EmmetNode.d.ts diff --git a/lib/vscode/extensions/emmet/src/typings/emmetio__css-parser.d.ts b/extensions/emmet/src/typings/emmetio__css-parser.d.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/typings/emmetio__css-parser.d.ts rename to extensions/emmet/src/typings/emmetio__css-parser.d.ts diff --git a/lib/vscode/extensions/emmet/src/typings/emmetio__html-matcher.d.ts b/extensions/emmet/src/typings/emmetio__html-matcher.d.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/typings/emmetio__html-matcher.d.ts rename to extensions/emmet/src/typings/emmetio__html-matcher.d.ts diff --git a/lib/vscode/extensions/emmet/src/typings/image-size.d.ts b/extensions/emmet/src/typings/image-size.d.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/typings/image-size.d.ts rename to extensions/emmet/src/typings/image-size.d.ts diff --git a/lib/vscode/extensions/emmet/src/typings/refs.d.ts b/extensions/emmet/src/typings/refs.d.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/typings/refs.d.ts rename to extensions/emmet/src/typings/refs.d.ts diff --git a/lib/vscode/extensions/emmet/src/updateImageSize.ts b/extensions/emmet/src/updateImageSize.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/updateImageSize.ts rename to extensions/emmet/src/updateImageSize.ts diff --git a/lib/vscode/extensions/emmet/src/updateTag.ts b/extensions/emmet/src/updateTag.ts similarity index 100% rename from lib/vscode/extensions/emmet/src/updateTag.ts rename to extensions/emmet/src/updateTag.ts diff --git a/lib/vscode/extensions/emmet/src/util.ts b/extensions/emmet/src/util.ts similarity index 95% rename from lib/vscode/extensions/emmet/src/util.ts rename to extensions/emmet/src/util.ts index cb63f504d5d0..cb4a876bdcb3 100644 --- a/lib/vscode/extensions/emmet/src/util.ts +++ b/extensions/emmet/src/util.ts @@ -381,13 +381,19 @@ export function getHtmlFlatNode(documentText: string, root: FlatNode | undefined // If the currentNode is a script one, first set up its subtree and then find HTML node. if (currentNode.name === 'script' && currentNode.children.length === 0) { - setUpScriptNodeSubtree(documentText, currentNode); - currentNode = getFlatNode(currentNode, offset, includeNodeBoundary) ?? currentNode; + const scriptNodeBody = setupScriptNodeSubtree(documentText, currentNode); + if (scriptNodeBody) { + currentNode = getHtmlFlatNode(scriptNodeBody, currentNode, offset, includeNodeBoundary) ?? currentNode; + } + } + else if (currentNode.type === 'cdata') { + const cdataBody = setupCdataNodeSubtree(documentText, currentNode); + currentNode = getHtmlFlatNode(cdataBody, currentNode, offset, includeNodeBoundary) ?? currentNode; } return currentNode; } -export function setUpScriptNodeSubtree(documentText: string, scriptNode: HtmlFlatNode): void { +export function setupScriptNodeSubtree(documentText: string, scriptNode: HtmlFlatNode): string { const isTemplateScript = scriptNode.name === 'script' && (scriptNode.attributes && scriptNode.attributes.some(x => x.name.toString() === 'type' @@ -403,7 +409,25 @@ export function setUpScriptNodeSubtree(documentText: string, scriptNode: HtmlFla scriptNode.children.push(child); child.parent = scriptNode; }); + return scriptBodyText; } + return ''; +} + +export function setupCdataNodeSubtree(documentText: string, cdataNode: HtmlFlatNode): string { + // blank out the rest of the document and generate the subtree. + const cdataStart = ''; + const startToUse = cdataNode.start + cdataStart.length; + const endToUse = cdataNode.end - cdataEnd.length; + const beforePadding = ' '.repeat(startToUse); + const cdataBody = beforePadding + documentText.substring(startToUse, endToUse); + const innerRoot: HtmlFlatNode = parse(cdataBody); + innerRoot.children.forEach(child => { + cdataNode.children.push(child); + child.parent = cdataNode; + }); + return cdataBody; } export function isOffsetInsideOpenOrCloseTag(node: FlatNode, offset: number): boolean { diff --git a/lib/vscode/extensions/emmet/test-workspace/.vscode/settings.json b/extensions/emmet/test-workspace/.vscode/settings.json similarity index 100% rename from lib/vscode/extensions/emmet/test-workspace/.vscode/settings.json rename to extensions/emmet/test-workspace/.vscode/settings.json diff --git a/lib/vscode/extensions/emmet/tsconfig.json b/extensions/emmet/tsconfig.json similarity index 100% rename from lib/vscode/extensions/emmet/tsconfig.json rename to extensions/emmet/tsconfig.json diff --git a/lib/vscode/extensions/emmet/yarn.lock b/extensions/emmet/yarn.lock similarity index 91% rename from lib/vscode/extensions/emmet/yarn.lock rename to extensions/emmet/yarn.lock index 3578363bdc5b..2d35a2c78aba 100644 --- a/lib/vscode/extensions/emmet/yarn.lock +++ b/extensions/emmet/yarn.lock @@ -53,10 +53,10 @@ resolved "https://registry.yarnpkg.com/@emmetio/stream-reader/-/stream-reader-2.2.0.tgz#46cffea119a0a003312a21c2d9b5628cb5fcd442" integrity sha1-Rs/+oRmgoAMxKiHC2bVijLX81EI= -"@types/node@^12.19.9": - version "12.20.7" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.7.tgz#1cb61fd0c85cb87e728c43107b5fd82b69bc9ef8" - integrity sha512-gWL8VUkg8VRaCAUgG9WmhefMqHmMblxe2rVpMF86nZY/+ZysU+BkAp+3cz03AixWDSSz0ks5WX59yAhv/cDwFA== +"@types/node@14.x": + version "14.17.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.1.tgz#5e07e0cb2ff793aa7a1b41deae76221e6166049f" + integrity sha512-/tpUyFD7meeooTRwl3sYlihx2BrJE7q9XF71EguPFIySj9B7qgnRtHsHTho+0AUm4m1SvWGm6uSncrR94q6Vtw== emmet@^2.3.0: version "2.3.4" @@ -77,9 +77,9 @@ jsonc-parser@^2.3.0: integrity sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg== vscode-emmet-helper@^2.3.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-2.6.2.tgz#777b471a7851ba0ca8e4151533be7f92511f39b0" - integrity sha512-SkL1WjZZsA+bfTo52QH4PgqXCQAJSqzOmJtAY3rOl17MKbY6iJhVv2T26PshjmUnHoXnXMNa7PcLMCS75RsQDQ== + version "2.6.4" + resolved "https://registry.yarnpkg.com/vscode-emmet-helper/-/vscode-emmet-helper-2.6.4.tgz#bea47f17649bba26b412f3d1fac18aaee43eba25" + integrity sha512-fP0nunW1RUWEKGf4gqiYLOVNFFGXSRHjCl0pikxtwCFlty8WwimM+RBJ5o0aIiwerrYD30HqeaVyvDW027Sseg== dependencies: emmet "^2.3.0" jsonc-parser "^2.3.0" diff --git a/lib/vscode/extensions/extension-editing/.vscodeignore b/extensions/extension-editing/.vscodeignore similarity index 100% rename from lib/vscode/extensions/extension-editing/.vscodeignore rename to extensions/extension-editing/.vscodeignore diff --git a/lib/vscode/extensions/extension-editing/extension-browser.webpack.config.js b/extensions/extension-editing/extension-browser.webpack.config.js similarity index 100% rename from lib/vscode/extensions/extension-editing/extension-browser.webpack.config.js rename to extensions/extension-editing/extension-browser.webpack.config.js diff --git a/lib/vscode/extensions/extension-editing/extension.webpack.config.js b/extensions/extension-editing/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/extension-editing/extension.webpack.config.js rename to extensions/extension-editing/extension.webpack.config.js diff --git a/lib/vscode/extensions/extension-editing/images/icon.png b/extensions/extension-editing/images/icon.png similarity index 100% rename from lib/vscode/extensions/extension-editing/images/icon.png rename to extensions/extension-editing/images/icon.png diff --git a/lib/vscode/extensions/extension-editing/package.json b/extensions/extension-editing/package.json similarity index 98% rename from lib/vscode/extensions/extension-editing/package.json rename to extensions/extension-editing/package.json index d60c8420514f..710f3d7be706 100644 --- a/lib/vscode/extensions/extension-editing/package.json +++ b/extensions/extension-editing/package.json @@ -69,7 +69,7 @@ }, "devDependencies": { "@types/markdown-it": "0.0.2", - "@types/node": "^12.19.9" + "@types/node": "14.x" }, "repository": { "type": "git", diff --git a/lib/vscode/extensions/extension-editing/package.nls.json b/extensions/extension-editing/package.nls.json similarity index 100% rename from lib/vscode/extensions/extension-editing/package.nls.json rename to extensions/extension-editing/package.nls.json diff --git a/lib/vscode/extensions/extension-editing/src/extensionEditingBrowserMain.ts b/extensions/extension-editing/src/extensionEditingBrowserMain.ts similarity index 100% rename from lib/vscode/extensions/extension-editing/src/extensionEditingBrowserMain.ts rename to extensions/extension-editing/src/extensionEditingBrowserMain.ts diff --git a/lib/vscode/extensions/extension-editing/src/extensionEditingMain.ts b/extensions/extension-editing/src/extensionEditingMain.ts similarity index 100% rename from lib/vscode/extensions/extension-editing/src/extensionEditingMain.ts rename to extensions/extension-editing/src/extensionEditingMain.ts diff --git a/lib/vscode/extensions/extension-editing/src/extensionLinter.ts b/extensions/extension-editing/src/extensionLinter.ts similarity index 100% rename from lib/vscode/extensions/extension-editing/src/extensionLinter.ts rename to extensions/extension-editing/src/extensionLinter.ts diff --git a/lib/vscode/extensions/extension-editing/src/packageDocumentHelper.ts b/extensions/extension-editing/src/packageDocumentHelper.ts similarity index 100% rename from lib/vscode/extensions/extension-editing/src/packageDocumentHelper.ts rename to extensions/extension-editing/src/packageDocumentHelper.ts diff --git a/lib/vscode/extensions/extension-editing/src/typings/ref.d.ts b/extensions/extension-editing/src/typings/ref.d.ts similarity index 100% rename from lib/vscode/extensions/extension-editing/src/typings/ref.d.ts rename to extensions/extension-editing/src/typings/ref.d.ts diff --git a/lib/vscode/extensions/extension-editing/tsconfig.json b/extensions/extension-editing/tsconfig.json similarity index 100% rename from lib/vscode/extensions/extension-editing/tsconfig.json rename to extensions/extension-editing/tsconfig.json diff --git a/lib/vscode/extensions/extension-editing/yarn.lock b/extensions/extension-editing/yarn.lock similarity index 92% rename from lib/vscode/extensions/extension-editing/yarn.lock rename to extensions/extension-editing/yarn.lock index 3275b1f2ad6b..01c08624126a 100644 --- a/lib/vscode/extensions/extension-editing/yarn.lock +++ b/extensions/extension-editing/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-0.0.2.tgz#5d9ad19e6e6508cdd2f2596df86fd0aade598660" integrity sha1-XZrRnm5lCM3S8llt+G/Qqt5ZhmA= -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== "@types/node@^6.0.46": version "6.0.78" diff --git a/lib/vscode/extensions/fsharp/.vscodeignore b/extensions/fsharp/.vscodeignore similarity index 100% rename from lib/vscode/extensions/fsharp/.vscodeignore rename to extensions/fsharp/.vscodeignore diff --git a/lib/vscode/extensions/fsharp/cgmanifest.json b/extensions/fsharp/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/fsharp/cgmanifest.json rename to extensions/fsharp/cgmanifest.json diff --git a/lib/vscode/extensions/fsharp/language-configuration.json b/extensions/fsharp/language-configuration.json similarity index 100% rename from lib/vscode/extensions/fsharp/language-configuration.json rename to extensions/fsharp/language-configuration.json diff --git a/lib/vscode/extensions/fsharp/package.json b/extensions/fsharp/package.json similarity index 100% rename from lib/vscode/extensions/fsharp/package.json rename to extensions/fsharp/package.json diff --git a/lib/vscode/extensions/fsharp/package.nls.json b/extensions/fsharp/package.nls.json similarity index 100% rename from lib/vscode/extensions/fsharp/package.nls.json rename to extensions/fsharp/package.nls.json diff --git a/lib/vscode/extensions/fsharp/snippets/fsharp.code-snippets b/extensions/fsharp/snippets/fsharp.code-snippets similarity index 100% rename from lib/vscode/extensions/fsharp/snippets/fsharp.code-snippets rename to extensions/fsharp/snippets/fsharp.code-snippets diff --git a/lib/vscode/extensions/fsharp/syntaxes/fsharp.tmLanguage.json b/extensions/fsharp/syntaxes/fsharp.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/fsharp/syntaxes/fsharp.tmLanguage.json rename to extensions/fsharp/syntaxes/fsharp.tmLanguage.json diff --git a/lib/vscode/extensions/fsharp/yarn.lock b/extensions/fsharp/yarn.lock similarity index 100% rename from lib/vscode/extensions/fsharp/yarn.lock rename to extensions/fsharp/yarn.lock diff --git a/lib/vscode/extensions/git/.vscodeignore b/extensions/git/.vscodeignore similarity index 100% rename from lib/vscode/extensions/git/.vscodeignore rename to extensions/git/.vscodeignore diff --git a/lib/vscode/extensions/git/README.md b/extensions/git/README.md similarity index 100% rename from lib/vscode/extensions/git/README.md rename to extensions/git/README.md diff --git a/lib/vscode/extensions/git/build/update-emoji.js b/extensions/git/build/update-emoji.js similarity index 100% rename from lib/vscode/extensions/git/build/update-emoji.js rename to extensions/git/build/update-emoji.js diff --git a/lib/vscode/extensions/git/build/update-grammars.js b/extensions/git/build/update-grammars.js similarity index 100% rename from lib/vscode/extensions/git/build/update-grammars.js rename to extensions/git/build/update-grammars.js diff --git a/lib/vscode/extensions/git/cgmanifest.json b/extensions/git/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/git/cgmanifest.json rename to extensions/git/cgmanifest.json diff --git a/lib/vscode/extensions/git/extension.webpack.config.js b/extensions/git/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/git/extension.webpack.config.js rename to extensions/git/extension.webpack.config.js diff --git a/lib/vscode/extensions/git/languages/diff.language-configuration.json b/extensions/git/languages/diff.language-configuration.json similarity index 100% rename from lib/vscode/extensions/git/languages/diff.language-configuration.json rename to extensions/git/languages/diff.language-configuration.json diff --git a/lib/vscode/extensions/git/languages/git-commit.language-configuration.json b/extensions/git/languages/git-commit.language-configuration.json similarity index 100% rename from lib/vscode/extensions/git/languages/git-commit.language-configuration.json rename to extensions/git/languages/git-commit.language-configuration.json diff --git a/lib/vscode/extensions/git/languages/git-rebase.language-configuration.json b/extensions/git/languages/git-rebase.language-configuration.json similarity index 100% rename from lib/vscode/extensions/git/languages/git-rebase.language-configuration.json rename to extensions/git/languages/git-rebase.language-configuration.json diff --git a/lib/vscode/extensions/git/languages/ignore.language-configuration.json b/extensions/git/languages/ignore.language-configuration.json similarity index 100% rename from lib/vscode/extensions/git/languages/ignore.language-configuration.json rename to extensions/git/languages/ignore.language-configuration.json diff --git a/lib/vscode/extensions/git/package.json b/extensions/git/package.json similarity index 99% rename from lib/vscode/extensions/git/package.json rename to extensions/git/package.json index 7d5e81b25510..55f83ea6a896 100644 --- a/lib/vscode/extensions/git/package.json +++ b/extensions/git/package.json @@ -2385,7 +2385,7 @@ "@types/byline": "4.2.31", "@types/file-type": "^5.2.1", "@types/mocha": "^8.2.0", - "@types/node": "^12.19.9", + "@types/node": "14.x", "@types/which": "^1.0.28" }, "repository": { diff --git a/lib/vscode/extensions/git/package.nls.json b/extensions/git/package.nls.json similarity index 100% rename from lib/vscode/extensions/git/package.nls.json rename to extensions/git/package.nls.json diff --git a/lib/vscode/extensions/git/resources/emojis.json b/extensions/git/resources/emojis.json similarity index 100% rename from lib/vscode/extensions/git/resources/emojis.json rename to extensions/git/resources/emojis.json diff --git a/lib/vscode/extensions/git/resources/icons/dark/status-added.svg b/extensions/git/resources/icons/dark/status-added.svg similarity index 100% rename from lib/vscode/extensions/git/resources/icons/dark/status-added.svg rename to extensions/git/resources/icons/dark/status-added.svg diff --git a/lib/vscode/extensions/git/resources/icons/dark/status-conflict.svg b/extensions/git/resources/icons/dark/status-conflict.svg similarity index 100% rename from lib/vscode/extensions/git/resources/icons/dark/status-conflict.svg rename to extensions/git/resources/icons/dark/status-conflict.svg diff --git a/lib/vscode/extensions/git/resources/icons/dark/status-copied.svg b/extensions/git/resources/icons/dark/status-copied.svg similarity index 100% rename from lib/vscode/extensions/git/resources/icons/dark/status-copied.svg rename to extensions/git/resources/icons/dark/status-copied.svg diff --git a/lib/vscode/extensions/git/resources/icons/dark/status-deleted.svg b/extensions/git/resources/icons/dark/status-deleted.svg similarity index 100% rename from lib/vscode/extensions/git/resources/icons/dark/status-deleted.svg rename to extensions/git/resources/icons/dark/status-deleted.svg diff --git a/lib/vscode/extensions/git/resources/icons/dark/status-ignored.svg b/extensions/git/resources/icons/dark/status-ignored.svg similarity index 100% rename from lib/vscode/extensions/git/resources/icons/dark/status-ignored.svg rename to extensions/git/resources/icons/dark/status-ignored.svg diff --git a/lib/vscode/extensions/git/resources/icons/dark/status-modified.svg b/extensions/git/resources/icons/dark/status-modified.svg similarity index 100% rename from lib/vscode/extensions/git/resources/icons/dark/status-modified.svg rename to extensions/git/resources/icons/dark/status-modified.svg diff --git a/lib/vscode/extensions/git/resources/icons/dark/status-renamed.svg b/extensions/git/resources/icons/dark/status-renamed.svg similarity index 100% rename from lib/vscode/extensions/git/resources/icons/dark/status-renamed.svg rename to extensions/git/resources/icons/dark/status-renamed.svg diff --git a/lib/vscode/extensions/git/resources/icons/dark/status-untracked.svg b/extensions/git/resources/icons/dark/status-untracked.svg similarity index 100% rename from lib/vscode/extensions/git/resources/icons/dark/status-untracked.svg rename to extensions/git/resources/icons/dark/status-untracked.svg diff --git a/lib/vscode/extensions/git/resources/icons/git.png b/extensions/git/resources/icons/git.png similarity index 100% rename from lib/vscode/extensions/git/resources/icons/git.png rename to extensions/git/resources/icons/git.png diff --git a/lib/vscode/extensions/git/resources/icons/light/status-added.svg b/extensions/git/resources/icons/light/status-added.svg similarity index 100% rename from lib/vscode/extensions/git/resources/icons/light/status-added.svg rename to extensions/git/resources/icons/light/status-added.svg diff --git a/lib/vscode/extensions/git/resources/icons/light/status-conflict.svg b/extensions/git/resources/icons/light/status-conflict.svg similarity index 100% rename from lib/vscode/extensions/git/resources/icons/light/status-conflict.svg rename to extensions/git/resources/icons/light/status-conflict.svg diff --git a/lib/vscode/extensions/git/resources/icons/light/status-copied.svg b/extensions/git/resources/icons/light/status-copied.svg similarity index 100% rename from lib/vscode/extensions/git/resources/icons/light/status-copied.svg rename to extensions/git/resources/icons/light/status-copied.svg diff --git a/lib/vscode/extensions/git/resources/icons/light/status-deleted.svg b/extensions/git/resources/icons/light/status-deleted.svg similarity index 100% rename from lib/vscode/extensions/git/resources/icons/light/status-deleted.svg rename to extensions/git/resources/icons/light/status-deleted.svg diff --git a/lib/vscode/extensions/git/resources/icons/light/status-ignored.svg b/extensions/git/resources/icons/light/status-ignored.svg similarity index 100% rename from lib/vscode/extensions/git/resources/icons/light/status-ignored.svg rename to extensions/git/resources/icons/light/status-ignored.svg diff --git a/lib/vscode/extensions/git/resources/icons/light/status-modified.svg b/extensions/git/resources/icons/light/status-modified.svg similarity index 100% rename from lib/vscode/extensions/git/resources/icons/light/status-modified.svg rename to extensions/git/resources/icons/light/status-modified.svg diff --git a/lib/vscode/extensions/git/resources/icons/light/status-renamed.svg b/extensions/git/resources/icons/light/status-renamed.svg similarity index 100% rename from lib/vscode/extensions/git/resources/icons/light/status-renamed.svg rename to extensions/git/resources/icons/light/status-renamed.svg diff --git a/lib/vscode/extensions/git/resources/icons/light/status-untracked.svg b/extensions/git/resources/icons/light/status-untracked.svg similarity index 100% rename from lib/vscode/extensions/git/resources/icons/light/status-untracked.svg rename to extensions/git/resources/icons/light/status-untracked.svg diff --git a/lib/vscode/extensions/git/src/api/api1.ts b/extensions/git/src/api/api1.ts similarity index 100% rename from lib/vscode/extensions/git/src/api/api1.ts rename to extensions/git/src/api/api1.ts diff --git a/lib/vscode/extensions/git/src/api/extension.ts b/extensions/git/src/api/extension.ts similarity index 100% rename from lib/vscode/extensions/git/src/api/extension.ts rename to extensions/git/src/api/extension.ts diff --git a/lib/vscode/extensions/git/src/api/git.d.ts b/extensions/git/src/api/git.d.ts similarity index 100% rename from lib/vscode/extensions/git/src/api/git.d.ts rename to extensions/git/src/api/git.d.ts diff --git a/lib/vscode/extensions/git/src/askpass-empty.sh b/extensions/git/src/askpass-empty.sh similarity index 100% rename from lib/vscode/extensions/git/src/askpass-empty.sh rename to extensions/git/src/askpass-empty.sh diff --git a/lib/vscode/extensions/git/src/askpass-main.ts b/extensions/git/src/askpass-main.ts similarity index 100% rename from lib/vscode/extensions/git/src/askpass-main.ts rename to extensions/git/src/askpass-main.ts diff --git a/lib/vscode/extensions/git/src/askpass.sh b/extensions/git/src/askpass.sh similarity index 100% rename from lib/vscode/extensions/git/src/askpass.sh rename to extensions/git/src/askpass.sh diff --git a/lib/vscode/extensions/git/src/askpass.ts b/extensions/git/src/askpass.ts similarity index 100% rename from lib/vscode/extensions/git/src/askpass.ts rename to extensions/git/src/askpass.ts diff --git a/lib/vscode/extensions/git/src/autofetch.ts b/extensions/git/src/autofetch.ts similarity index 100% rename from lib/vscode/extensions/git/src/autofetch.ts rename to extensions/git/src/autofetch.ts diff --git a/lib/vscode/extensions/git/src/commands.ts b/extensions/git/src/commands.ts similarity index 100% rename from lib/vscode/extensions/git/src/commands.ts rename to extensions/git/src/commands.ts diff --git a/lib/vscode/extensions/git/src/decorationProvider.ts b/extensions/git/src/decorationProvider.ts similarity index 100% rename from lib/vscode/extensions/git/src/decorationProvider.ts rename to extensions/git/src/decorationProvider.ts diff --git a/lib/vscode/extensions/git/src/decorators.ts b/extensions/git/src/decorators.ts similarity index 100% rename from lib/vscode/extensions/git/src/decorators.ts rename to extensions/git/src/decorators.ts diff --git a/lib/vscode/extensions/git/src/emoji.ts b/extensions/git/src/emoji.ts similarity index 100% rename from lib/vscode/extensions/git/src/emoji.ts rename to extensions/git/src/emoji.ts diff --git a/lib/vscode/extensions/git/src/encoding.ts b/extensions/git/src/encoding.ts similarity index 100% rename from lib/vscode/extensions/git/src/encoding.ts rename to extensions/git/src/encoding.ts diff --git a/lib/vscode/extensions/git/src/fileSystemProvider.ts b/extensions/git/src/fileSystemProvider.ts similarity index 100% rename from lib/vscode/extensions/git/src/fileSystemProvider.ts rename to extensions/git/src/fileSystemProvider.ts diff --git a/lib/vscode/extensions/git/src/git.ts b/extensions/git/src/git.ts similarity index 100% rename from lib/vscode/extensions/git/src/git.ts rename to extensions/git/src/git.ts diff --git a/lib/vscode/extensions/git/src/ipc/ipcClient.ts b/extensions/git/src/ipc/ipcClient.ts similarity index 100% rename from lib/vscode/extensions/git/src/ipc/ipcClient.ts rename to extensions/git/src/ipc/ipcClient.ts diff --git a/lib/vscode/extensions/git/src/ipc/ipcServer.ts b/extensions/git/src/ipc/ipcServer.ts similarity index 100% rename from lib/vscode/extensions/git/src/ipc/ipcServer.ts rename to extensions/git/src/ipc/ipcServer.ts diff --git a/lib/vscode/extensions/git/src/log.ts b/extensions/git/src/log.ts similarity index 100% rename from lib/vscode/extensions/git/src/log.ts rename to extensions/git/src/log.ts diff --git a/lib/vscode/extensions/git/src/main.ts b/extensions/git/src/main.ts similarity index 100% rename from lib/vscode/extensions/git/src/main.ts rename to extensions/git/src/main.ts diff --git a/lib/vscode/extensions/git/src/model.ts b/extensions/git/src/model.ts similarity index 100% rename from lib/vscode/extensions/git/src/model.ts rename to extensions/git/src/model.ts diff --git a/lib/vscode/extensions/git/src/protocolHandler.ts b/extensions/git/src/protocolHandler.ts similarity index 100% rename from lib/vscode/extensions/git/src/protocolHandler.ts rename to extensions/git/src/protocolHandler.ts diff --git a/lib/vscode/extensions/git/src/pushError.ts b/extensions/git/src/pushError.ts similarity index 100% rename from lib/vscode/extensions/git/src/pushError.ts rename to extensions/git/src/pushError.ts diff --git a/lib/vscode/extensions/git/src/remoteProvider.ts b/extensions/git/src/remoteProvider.ts similarity index 100% rename from lib/vscode/extensions/git/src/remoteProvider.ts rename to extensions/git/src/remoteProvider.ts diff --git a/lib/vscode/extensions/git/src/remoteSource.ts b/extensions/git/src/remoteSource.ts similarity index 100% rename from lib/vscode/extensions/git/src/remoteSource.ts rename to extensions/git/src/remoteSource.ts diff --git a/lib/vscode/extensions/git/src/repository.ts b/extensions/git/src/repository.ts similarity index 100% rename from lib/vscode/extensions/git/src/repository.ts rename to extensions/git/src/repository.ts diff --git a/lib/vscode/extensions/git/src/staging.ts b/extensions/git/src/staging.ts similarity index 100% rename from lib/vscode/extensions/git/src/staging.ts rename to extensions/git/src/staging.ts diff --git a/lib/vscode/extensions/git/src/statusbar.ts b/extensions/git/src/statusbar.ts similarity index 100% rename from lib/vscode/extensions/git/src/statusbar.ts rename to extensions/git/src/statusbar.ts diff --git a/lib/vscode/extensions/git/src/terminal.ts b/extensions/git/src/terminal.ts similarity index 100% rename from lib/vscode/extensions/git/src/terminal.ts rename to extensions/git/src/terminal.ts diff --git a/lib/vscode/extensions/git/src/test/git.test.ts b/extensions/git/src/test/git.test.ts similarity index 90% rename from lib/vscode/extensions/git/src/test/git.test.ts rename to extensions/git/src/test/git.test.ts index 4c74e26321b9..c0d0d2003c96 100644 --- a/lib/vscode/extensions/git/src/test/git.test.ts +++ b/extensions/git/src/test/git.test.ts @@ -12,19 +12,19 @@ suite('git', () => { suite('GitStatusParser', () => { test('empty parser', () => { const parser = new GitStatusParser(); - assert.deepEqual(parser.status, []); + assert.deepStrictEqual(parser.status, []); }); test('empty parser 2', () => { const parser = new GitStatusParser(); parser.update(''); - assert.deepEqual(parser.status, []); + assert.deepStrictEqual(parser.status, []); }); test('simple', () => { const parser = new GitStatusParser(); parser.update('?? file.txt\0'); - assert.deepEqual(parser.status, [ + assert.deepStrictEqual(parser.status, [ { path: 'file.txt', rename: undefined, x: '?', y: '?' } ]); }); @@ -34,7 +34,7 @@ suite('git', () => { parser.update('?? file.txt\0'); parser.update('?? file2.txt\0'); parser.update('?? file3.txt\0'); - assert.deepEqual(parser.status, [ + assert.deepStrictEqual(parser.status, [ { path: 'file.txt', rename: undefined, x: '?', y: '?' }, { path: 'file2.txt', rename: undefined, x: '?', y: '?' }, { path: 'file3.txt', rename: undefined, x: '?', y: '?' } @@ -51,7 +51,7 @@ suite('git', () => { parser.update(''); parser.update('?? file3.txt\0'); parser.update(''); - assert.deepEqual(parser.status, [ + assert.deepStrictEqual(parser.status, [ { path: 'file.txt', rename: undefined, x: '?', y: '?' }, { path: 'file2.txt', rename: undefined, x: '?', y: '?' }, { path: 'file3.txt', rename: undefined, x: '?', y: '?' } @@ -61,7 +61,7 @@ suite('git', () => { test('combined', () => { const parser = new GitStatusParser(); parser.update('?? file.txt\0?? file2.txt\0?? file3.txt\0'); - assert.deepEqual(parser.status, [ + assert.deepStrictEqual(parser.status, [ { path: 'file.txt', rename: undefined, x: '?', y: '?' }, { path: 'file2.txt', rename: undefined, x: '?', y: '?' }, { path: 'file3.txt', rename: undefined, x: '?', y: '?' } @@ -72,7 +72,7 @@ suite('git', () => { const parser = new GitStatusParser(); parser.update('?? file.txt\0?? file2'); parser.update('.txt\0?? file3.txt\0'); - assert.deepEqual(parser.status, [ + assert.deepStrictEqual(parser.status, [ { path: 'file.txt', rename: undefined, x: '?', y: '?' }, { path: 'file2.txt', rename: undefined, x: '?', y: '?' }, { path: 'file3.txt', rename: undefined, x: '?', y: '?' } @@ -83,7 +83,7 @@ suite('git', () => { const parser = new GitStatusParser(); parser.update('?? file.txt'); parser.update('\0?? file2.txt\0?? file3.txt\0'); - assert.deepEqual(parser.status, [ + assert.deepStrictEqual(parser.status, [ { path: 'file.txt', rename: undefined, x: '?', y: '?' }, { path: 'file2.txt', rename: undefined, x: '?', y: '?' }, { path: 'file3.txt', rename: undefined, x: '?', y: '?' } @@ -94,7 +94,7 @@ suite('git', () => { const parser = new GitStatusParser(); parser.update('?? file.txt\0?? file2.txt\0?? file3.txt'); parser.update('\0'); - assert.deepEqual(parser.status, [ + assert.deepStrictEqual(parser.status, [ { path: 'file.txt', rename: undefined, x: '?', y: '?' }, { path: 'file2.txt', rename: undefined, x: '?', y: '?' }, { path: 'file3.txt', rename: undefined, x: '?', y: '?' } @@ -104,7 +104,7 @@ suite('git', () => { test('rename', () => { const parser = new GitStatusParser(); parser.update('R newfile.txt\0file.txt\0?? file2.txt\0?? file3.txt\0'); - assert.deepEqual(parser.status, [ + assert.deepStrictEqual(parser.status, [ { path: 'file.txt', rename: 'newfile.txt', x: 'R', y: ' ' }, { path: 'file2.txt', rename: undefined, x: '?', y: '?' }, { path: 'file3.txt', rename: undefined, x: '?', y: '?' } @@ -115,7 +115,7 @@ suite('git', () => { const parser = new GitStatusParser(); parser.update('R newfile.txt\0fil'); parser.update('e.txt\0?? file2.txt\0?? file3.txt\0'); - assert.deepEqual(parser.status, [ + assert.deepStrictEqual(parser.status, [ { path: 'file.txt', rename: 'newfile.txt', x: 'R', y: ' ' }, { path: 'file2.txt', rename: undefined, x: '?', y: '?' }, { path: 'file3.txt', rename: undefined, x: '?', y: '?' } @@ -127,7 +127,7 @@ suite('git', () => { parser.update('?? file2.txt\0R new'); parser.update('file.txt\0fil'); parser.update('e.txt\0?? file3.txt\0'); - assert.deepEqual(parser.status, [ + assert.deepStrictEqual(parser.status, [ { path: 'file2.txt', rename: undefined, x: '?', y: '?' }, { path: 'file.txt', rename: 'newfile.txt', x: 'R', y: ' ' }, { path: 'file3.txt', rename: undefined, x: '?', y: '?' } @@ -137,7 +137,7 @@ suite('git', () => { suite('parseGitmodules', () => { test('empty', () => { - assert.deepEqual(parseGitmodules(''), []); + assert.deepStrictEqual(parseGitmodules(''), []); }); test('sample', () => { @@ -146,7 +146,7 @@ suite('git', () => { url = https://github.com/gabime/spdlog.git `; - assert.deepEqual(parseGitmodules(sample), [ + assert.deepStrictEqual(parseGitmodules(sample), [ { name: 'deps/spdlog', path: 'deps/spdlog', url: 'https://github.com/gabime/spdlog.git' } ]); }); @@ -166,7 +166,7 @@ suite('git', () => { url = https://github.com/gabime/spdlog4.git `; - assert.deepEqual(parseGitmodules(sample), [ + assert.deepStrictEqual(parseGitmodules(sample), [ { name: 'deps/spdlog', path: 'deps/spdlog', url: 'https://github.com/gabime/spdlog.git' }, { name: 'deps/spdlog2', path: 'deps/spdlog2', url: 'https://github.com/gabime/spdlog.git' }, { name: 'deps/spdlog3', path: 'deps/spdlog3', url: 'https://github.com/gabime/spdlog.git' }, @@ -180,7 +180,7 @@ suite('git', () => { url = https://github.com/gabime/spdlog.git `; - assert.deepEqual(parseGitmodules(sample), [ + assert.deepStrictEqual(parseGitmodules(sample), [ { name: 'deps/spdlog', path: 'deps/spdlog', url: 'https://github.com/gabime/spdlog.git' } ]); }); @@ -191,7 +191,7 @@ suite('git', () => { url=https://github.com/gabime/spdlog.git `; - assert.deepEqual(parseGitmodules(sample), [ + assert.deepStrictEqual(parseGitmodules(sample), [ { name: 'deps/spdlog', path: 'deps/spdlog', url: 'https://github.com/gabime/spdlog.git' } ]); }); @@ -207,7 +207,7 @@ john.doe@mail.com 8e5a374372b8393906c7e380dbb09349c5385554 This is a commit message.\x00`; - assert.deepEqual(parseGitCommits(GIT_OUTPUT_SINGLE_PARENT), [{ + assert.deepStrictEqual(parseGitCommits(GIT_OUTPUT_SINGLE_PARENT), [{ hash: '52c293a05038d865604c2284aa8698bd087915a1', message: 'This is a commit message.', parents: ['8e5a374372b8393906c7e380dbb09349c5385554'], @@ -227,7 +227,7 @@ john.doe@mail.com 8e5a374372b8393906c7e380dbb09349c5385554 df27d8c75b129ab9b178b386077da2822101b217 This is a commit message.\x00`; - assert.deepEqual(parseGitCommits(GIT_OUTPUT_MULTIPLE_PARENTS), [{ + assert.deepStrictEqual(parseGitCommits(GIT_OUTPUT_MULTIPLE_PARENTS), [{ hash: '52c293a05038d865604c2284aa8698bd087915a1', message: 'This is a commit message.', parents: ['8e5a374372b8393906c7e380dbb09349c5385554', 'df27d8c75b129ab9b178b386077da2822101b217'], @@ -247,7 +247,7 @@ john.doe@mail.com This is a commit message.\x00`; - assert.deepEqual(parseGitCommits(GIT_OUTPUT_NO_PARENTS), [{ + assert.deepStrictEqual(parseGitCommits(GIT_OUTPUT_NO_PARENTS), [{ hash: '52c293a05038d865604c2284aa8698bd087915a1', message: 'This is a commit message.', parents: [], @@ -275,7 +275,7 @@ This is a commit message.\x00`; const output = parseLsTree(input); - assert.deepEqual(output, [ + assert.deepStrictEqual(output, [ { mode: '040000', type: 'tree', object: '0274a81f8ee9ca3669295dc40f510bd2021d0043', size: '-', file: '.vscode' }, { mode: '100644', type: 'blob', object: '1d487c1817262e4f20efbfa1d04c18f51b0046f6', size: '491570', file: 'Screen Shot 2018-06-01 at 14.48.05.png' }, { mode: '100644', type: 'blob', object: '686c16e4f019b734655a2576ce8b98749a9ffdb9', size: '764420', file: 'Screen Shot 2018-06-07 at 20.04.59.png' }, @@ -307,7 +307,7 @@ This is a commit message.\x00`; const output = parseLsFiles(input); - assert.deepEqual(output, [ + assert.deepStrictEqual(output, [ { mode: '100644', object: '7a73a41bfdf76d6f793007240d80983a52f15f97', stage: '0', file: '.vscode/settings.json' }, { mode: '100644', object: '1d487c1817262e4f20efbfa1d04c18f51b0046f6', stage: '0', file: 'Screen Shot 2018-06-01 at 14.48.05.png' }, { mode: '100644', object: '686c16e4f019b734655a2576ce8b98749a9ffdb9', stage: '0', file: 'Screen Shot 2018-06-07 at 20.04.59.png' }, @@ -325,72 +325,72 @@ This is a commit message.\x00`; suite('splitInChunks', () => { test('unit tests', function () { - assert.deepEqual( + assert.deepStrictEqual( [...splitInChunks(['hello', 'there', 'cool', 'stuff'], 6)], [['hello'], ['there'], ['cool'], ['stuff']] ); - assert.deepEqual( + assert.deepStrictEqual( [...splitInChunks(['hello', 'there', 'cool', 'stuff'], 10)], [['hello', 'there'], ['cool', 'stuff']] ); - assert.deepEqual( + assert.deepStrictEqual( [...splitInChunks(['hello', 'there', 'cool', 'stuff'], 12)], [['hello', 'there'], ['cool', 'stuff']] ); - assert.deepEqual( + assert.deepStrictEqual( [...splitInChunks(['hello', 'there', 'cool', 'stuff'], 14)], [['hello', 'there', 'cool'], ['stuff']] ); - assert.deepEqual( + assert.deepStrictEqual( [...splitInChunks(['hello', 'there', 'cool', 'stuff'], 2000)], [['hello', 'there', 'cool', 'stuff']] ); - assert.deepEqual( + assert.deepStrictEqual( [...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 1)], [['0'], ['01'], ['012'], ['0'], ['01'], ['012'], ['0'], ['01'], ['012']] ); - assert.deepEqual( + assert.deepStrictEqual( [...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 2)], [['0'], ['01'], ['012'], ['0'], ['01'], ['012'], ['0'], ['01'], ['012']] ); - assert.deepEqual( + assert.deepStrictEqual( [...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 3)], [['0', '01'], ['012'], ['0', '01'], ['012'], ['0', '01'], ['012']] ); - assert.deepEqual( + assert.deepStrictEqual( [...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 4)], [['0', '01'], ['012', '0'], ['01'], ['012', '0'], ['01'], ['012']] ); - assert.deepEqual( + assert.deepStrictEqual( [...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 5)], [['0', '01'], ['012', '0'], ['01', '012'], ['0', '01'], ['012']] ); - assert.deepEqual( + assert.deepStrictEqual( [...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 6)], [['0', '01', '012'], ['0', '01', '012'], ['0', '01', '012']] ); - assert.deepEqual( + assert.deepStrictEqual( [...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 7)], [['0', '01', '012', '0'], ['01', '012', '0'], ['01', '012']] ); - assert.deepEqual( + assert.deepStrictEqual( [...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 8)], [['0', '01', '012', '0'], ['01', '012', '0', '01'], ['012']] ); - assert.deepEqual( + assert.deepStrictEqual( [...splitInChunks(['0', '01', '012', '0', '01', '012', '0', '01', '012'], 9)], [['0', '01', '012', '0', '01'], ['012', '0', '01', '012']] ); diff --git a/lib/vscode/extensions/git/src/test/index.ts b/extensions/git/src/test/index.ts similarity index 100% rename from lib/vscode/extensions/git/src/test/index.ts rename to extensions/git/src/test/index.ts diff --git a/lib/vscode/extensions/git/src/test/smoke.test.ts b/extensions/git/src/test/smoke.test.ts similarity index 86% rename from lib/vscode/extensions/git/src/test/smoke.test.ts rename to extensions/git/src/test/smoke.test.ts index ed6a5d504a6f..2ba3da99aa67 100644 --- a/lib/vscode/extensions/git/src/test/smoke.test.ts +++ b/extensions/git/src/test/smoke.test.ts @@ -59,8 +59,8 @@ suite('git smoke test', function () { await eventToPromise(git.onDidOpenRepository); } - assert.equal(git.repositories.length, 1); - assert.equal(fs.realpathSync(git.repositories[0].rootUri.fsPath), cwd); + assert.strictEqual(git.repositories.length, 1); + assert.strictEqual(fs.realpathSync(git.repositories[0].rootUri.fsPath), cwd); repository = git.repositories[0]; }); @@ -72,7 +72,7 @@ suite('git smoke test', function () { await type(appjs, ' world'); await appjs.save(); await repository.status(); - assert.equal(repository.state.workingTreeChanges.length, 1); + assert.strictEqual(repository.state.workingTreeChanges.length, 1); repository.state.workingTreeChanges.some(r => r.uri.path === appjs.uri.path && r.status === Status.MODIFIED); fs.writeFileSync(file('newfile.txt'), ''); @@ -80,7 +80,7 @@ suite('git smoke test', function () { await type(newfile, 'hey there'); await newfile.save(); await repository.status(); - assert.equal(repository.state.workingTreeChanges.length, 2); + assert.strictEqual(repository.state.workingTreeChanges.length, 2); repository.state.workingTreeChanges.some(r => r.uri.path === appjs.uri.path && r.status === Status.MODIFIED); repository.state.workingTreeChanges.some(r => r.uri.path === newfile.uri.path && r.status === Status.UNTRACKED); }); @@ -90,7 +90,7 @@ suite('git smoke test', function () { await commands.executeCommand('git.openChange', appjs); assert(window.activeTextEditor); - assert.equal(window.activeTextEditor!.document.uri.path, appjs.path); + assert.strictEqual(window.activeTextEditor!.document.uri.path, appjs.path); // TODO: how do we really know this is a diff editor? }); @@ -100,13 +100,13 @@ suite('git smoke test', function () { const newfile = uri('newfile.txt'); await commands.executeCommand('git.stage', appjs); - assert.equal(repository.state.workingTreeChanges.length, 1); + assert.strictEqual(repository.state.workingTreeChanges.length, 1); repository.state.workingTreeChanges.some(r => r.uri.path === newfile.path && r.status === Status.UNTRACKED); - assert.equal(repository.state.indexChanges.length, 1); + assert.strictEqual(repository.state.indexChanges.length, 1); repository.state.indexChanges.some(r => r.uri.path === appjs.path && r.status === Status.INDEX_MODIFIED); await commands.executeCommand('git.unstage', appjs); - assert.equal(repository.state.workingTreeChanges.length, 2); + assert.strictEqual(repository.state.workingTreeChanges.length, 2); repository.state.workingTreeChanges.some(r => r.uri.path === appjs.path && r.status === Status.MODIFIED); repository.state.workingTreeChanges.some(r => r.uri.path === newfile.path && r.status === Status.UNTRACKED); }); @@ -117,14 +117,14 @@ suite('git smoke test', function () { await commands.executeCommand('git.stage', appjs); await repository.commit('second commit'); - assert.equal(repository.state.workingTreeChanges.length, 1); + assert.strictEqual(repository.state.workingTreeChanges.length, 1); repository.state.workingTreeChanges.some(r => r.uri.path === newfile.path && r.status === Status.UNTRACKED); - assert.equal(repository.state.indexChanges.length, 0); + assert.strictEqual(repository.state.indexChanges.length, 0); await commands.executeCommand('git.stageAll', appjs); await repository.commit('third commit'); - assert.equal(repository.state.workingTreeChanges.length, 0); - assert.equal(repository.state.indexChanges.length, 0); + assert.strictEqual(repository.state.workingTreeChanges.length, 0); + assert.strictEqual(repository.state.indexChanges.length, 0); }); test('rename/delete conflict', async function () { diff --git a/lib/vscode/extensions/git/src/timelineProvider.ts b/extensions/git/src/timelineProvider.ts similarity index 100% rename from lib/vscode/extensions/git/src/timelineProvider.ts rename to extensions/git/src/timelineProvider.ts diff --git a/lib/vscode/extensions/git/src/typings/refs.d.ts b/extensions/git/src/typings/refs.d.ts similarity index 100% rename from lib/vscode/extensions/git/src/typings/refs.d.ts rename to extensions/git/src/typings/refs.d.ts diff --git a/lib/vscode/extensions/git/src/uri.ts b/extensions/git/src/uri.ts similarity index 100% rename from lib/vscode/extensions/git/src/uri.ts rename to extensions/git/src/uri.ts diff --git a/lib/vscode/extensions/git/src/util.ts b/extensions/git/src/util.ts similarity index 100% rename from lib/vscode/extensions/git/src/util.ts rename to extensions/git/src/util.ts diff --git a/lib/vscode/extensions/git/src/watch.ts b/extensions/git/src/watch.ts similarity index 100% rename from lib/vscode/extensions/git/src/watch.ts rename to extensions/git/src/watch.ts diff --git a/lib/vscode/extensions/git/syntaxes/diff.tmLanguage.json b/extensions/git/syntaxes/diff.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/git/syntaxes/diff.tmLanguage.json rename to extensions/git/syntaxes/diff.tmLanguage.json diff --git a/lib/vscode/extensions/git/syntaxes/git-commit.tmLanguage.json b/extensions/git/syntaxes/git-commit.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/git/syntaxes/git-commit.tmLanguage.json rename to extensions/git/syntaxes/git-commit.tmLanguage.json diff --git a/lib/vscode/extensions/git/syntaxes/git-rebase.tmLanguage.json b/extensions/git/syntaxes/git-rebase.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/git/syntaxes/git-rebase.tmLanguage.json rename to extensions/git/syntaxes/git-rebase.tmLanguage.json diff --git a/lib/vscode/extensions/git/syntaxes/ignore.tmLanguage.json b/extensions/git/syntaxes/ignore.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/git/syntaxes/ignore.tmLanguage.json rename to extensions/git/syntaxes/ignore.tmLanguage.json diff --git a/lib/vscode/extensions/git/test/colorize-fixtures/COMMIT_EDITMSG b/extensions/git/test/colorize-fixtures/COMMIT_EDITMSG similarity index 100% rename from lib/vscode/extensions/git/test/colorize-fixtures/COMMIT_EDITMSG rename to extensions/git/test/colorize-fixtures/COMMIT_EDITMSG diff --git a/lib/vscode/extensions/git/test/colorize-fixtures/example.diff b/extensions/git/test/colorize-fixtures/example.diff similarity index 100% rename from lib/vscode/extensions/git/test/colorize-fixtures/example.diff rename to extensions/git/test/colorize-fixtures/example.diff diff --git a/lib/vscode/extensions/git/test/colorize-fixtures/git-rebase-todo b/extensions/git/test/colorize-fixtures/git-rebase-todo similarity index 100% rename from lib/vscode/extensions/git/test/colorize-fixtures/git-rebase-todo rename to extensions/git/test/colorize-fixtures/git-rebase-todo diff --git a/lib/vscode/extensions/git/test/colorize-results/COMMIT_EDITMSG.json b/extensions/git/test/colorize-results/COMMIT_EDITMSG.json similarity index 100% rename from lib/vscode/extensions/git/test/colorize-results/COMMIT_EDITMSG.json rename to extensions/git/test/colorize-results/COMMIT_EDITMSG.json diff --git a/lib/vscode/extensions/git/test/colorize-results/example_diff.json b/extensions/git/test/colorize-results/example_diff.json similarity index 100% rename from lib/vscode/extensions/git/test/colorize-results/example_diff.json rename to extensions/git/test/colorize-results/example_diff.json diff --git a/lib/vscode/extensions/git/test/colorize-results/git-rebase-todo.json b/extensions/git/test/colorize-results/git-rebase-todo.json similarity index 100% rename from lib/vscode/extensions/git/test/colorize-results/git-rebase-todo.json rename to extensions/git/test/colorize-results/git-rebase-todo.json diff --git a/lib/vscode/extensions/git/test/mocha.opts b/extensions/git/test/mocha.opts similarity index 100% rename from lib/vscode/extensions/git/test/mocha.opts rename to extensions/git/test/mocha.opts diff --git a/lib/vscode/extensions/git/tsconfig.json b/extensions/git/tsconfig.json similarity index 100% rename from lib/vscode/extensions/git/tsconfig.json rename to extensions/git/tsconfig.json diff --git a/lib/vscode/extensions/git/yarn.lock b/extensions/git/yarn.lock similarity index 96% rename from lib/vscode/extensions/git/yarn.lock rename to extensions/git/yarn.lock index c964f284a3af..3853a2d2c046 100644 --- a/lib/vscode/extensions/git/yarn.lock +++ b/extensions/git/yarn.lock @@ -26,10 +26,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.51.tgz#b31d716fb8d58eeb95c068a039b9b6292817d5fb" integrity sha512-El3+WJk2D/ppWNd2X05aiP5l2k4EwF7KwheknQZls+I26eSICoWRhRIJ56jGgw2dqNGQ5LtNajmBU2ajS28EvQ== -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== "@types/which@^1.0.28": version "1.0.28" diff --git a/lib/vscode/extensions/github-authentication/.gitignore b/extensions/github-authentication/.gitignore similarity index 100% rename from lib/vscode/extensions/github-authentication/.gitignore rename to extensions/github-authentication/.gitignore diff --git a/lib/vscode/extensions/github-authentication/.vscodeignore b/extensions/github-authentication/.vscodeignore similarity index 100% rename from lib/vscode/extensions/github-authentication/.vscodeignore rename to extensions/github-authentication/.vscodeignore diff --git a/lib/vscode/extensions/github-authentication/README.md b/extensions/github-authentication/README.md similarity index 100% rename from lib/vscode/extensions/github-authentication/README.md rename to extensions/github-authentication/README.md diff --git a/lib/vscode/extensions/github-authentication/extension-browser.webpack.config.js b/extensions/github-authentication/extension-browser.webpack.config.js similarity index 100% rename from lib/vscode/extensions/github-authentication/extension-browser.webpack.config.js rename to extensions/github-authentication/extension-browser.webpack.config.js diff --git a/lib/vscode/extensions/github-authentication/extension.webpack.config.js b/extensions/github-authentication/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/github-authentication/extension.webpack.config.js rename to extensions/github-authentication/extension.webpack.config.js diff --git a/lib/vscode/extensions/github-authentication/images/icon.png b/extensions/github-authentication/images/icon.png similarity index 100% rename from lib/vscode/extensions/github-authentication/images/icon.png rename to extensions/github-authentication/images/icon.png diff --git a/lib/vscode/extensions/github-authentication/package.json b/extensions/github-authentication/package.json similarity index 67% rename from lib/vscode/extensions/github-authentication/package.json rename to extensions/github-authentication/package.json index 4a18a5bd0a85..2064e28dedc8 100644 --- a/lib/vscode/extensions/github-authentication/package.json +++ b/extensions/github-authentication/package.json @@ -4,7 +4,7 @@ "description": "%description%", "publisher": "vscode", "license": "MIT", - "version": "0.0.1", + "version": "0.0.2", "engines": { "vscode": "^1.41.0" }, @@ -19,7 +19,8 @@ "web" ], "activationEvents": [ - "onAuthenticationRequest:github" + "onAuthenticationRequest:github", + "onAuthenticationRequest:github-enterprise" ], "capabilities": { "virtualWorkspaces": true, @@ -31,7 +32,14 @@ "commands": [ { "command": "github.provide-token", - "title": "Manually Provide Token" + "title": "Manually Provide Token", + "category": "GitHub" + }, + { + "command": "github-enterprise.provide-token", + "title": "Manually Provide Token", + "category": "GitHub Enterprise" + } ], "menus": { @@ -39,6 +47,10 @@ { "command": "github.provide-token", "when": "false" + }, + { + "command": "github-enterprise.provide-token", + "when": "false" } ] }, @@ -46,8 +58,21 @@ { "label": "GitHub", "id": "github" + }, + { + "label": "GitHub Enterprise", + "id": "github-enterprise" } - ] + ], + "configuration": { + "title": "GitHub Enterprise Authentication Provider", + "properties": { + "github-enterprise.uri" : { + "type": "string", + "description": "URI of your GitHub Enterprise Instanace" + } + } + } }, "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", "main": "./out/extension.js", @@ -67,7 +92,7 @@ "vscode-tas-client": "^0.1.22" }, "devDependencies": { - "@types/node": "^12.19.9", + "@types/node": "14.x", "@types/node-fetch": "^2.5.7", "@types/uuid": "8.0.0" }, diff --git a/lib/vscode/extensions/github-authentication/package.nls.json b/extensions/github-authentication/package.nls.json similarity index 100% rename from lib/vscode/extensions/github-authentication/package.nls.json rename to extensions/github-authentication/package.nls.json diff --git a/lib/vscode/extensions/github-authentication/src/common/keychain.ts b/extensions/github-authentication/src/common/keychain.ts similarity index 89% rename from lib/vscode/extensions/github-authentication/src/common/keychain.ts rename to extensions/github-authentication/src/common/keychain.ts index d1dc0a32a640..04d64682c989 100644 --- a/lib/vscode/extensions/github-authentication/src/common/keychain.ts +++ b/extensions/github-authentication/src/common/keychain.ts @@ -28,13 +28,11 @@ export type Keytar = { deletePassword: typeof keytarType['deletePassword']; }; -const SERVICE_ID = `github.auth`; - export class Keychain { - constructor(private context: vscode.ExtensionContext) { } + constructor(private context: vscode.ExtensionContext, private serviceId: string) { } async setToken(token: string): Promise { try { - return await this.context.secrets.store(SERVICE_ID, token); + return await this.context.secrets.store(this.serviceId, token); } catch (e) { // Ignore Logger.error(`Setting token failed: ${e}`); @@ -48,7 +46,7 @@ export class Keychain { async getToken(): Promise { try { - return await this.context.secrets.get(SERVICE_ID); + return await this.context.secrets.get(this.serviceId); } catch (e) { // Ignore Logger.error(`Getting token failed: ${e}`); @@ -58,7 +56,7 @@ export class Keychain { async deleteToken(): Promise { try { - return await this.context.secrets.delete(SERVICE_ID); + return await this.context.secrets.delete(this.serviceId); } catch (e) { // Ignore Logger.error(`Deleting token failed: ${e}`); diff --git a/lib/vscode/extensions/github-authentication/src/common/logger.ts b/extensions/github-authentication/src/common/logger.ts similarity index 100% rename from lib/vscode/extensions/github-authentication/src/common/logger.ts rename to extensions/github-authentication/src/common/logger.ts diff --git a/lib/vscode/extensions/github-authentication/src/common/utils.ts b/extensions/github-authentication/src/common/utils.ts similarity index 100% rename from lib/vscode/extensions/github-authentication/src/common/utils.ts rename to extensions/github-authentication/src/common/utils.ts diff --git a/lib/vscode/extensions/github-authentication/src/experimentationService.ts b/extensions/github-authentication/src/experimentationService.ts similarity index 100% rename from lib/vscode/extensions/github-authentication/src/experimentationService.ts rename to extensions/github-authentication/src/experimentationService.ts diff --git a/extensions/github-authentication/src/extension.ts b/extensions/github-authentication/src/extension.ts new file mode 100644 index 000000000000..bc7a086f6927 --- /dev/null +++ b/extensions/github-authentication/src/extension.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 vscode from 'vscode'; +import { GitHubAuthenticationProvider, AuthProviderType } from './github'; +import TelemetryReporter from 'vscode-extension-telemetry'; +import { createExperimentationService, ExperimentationTelemetry } from './experimentationService'; + +export async function activate(context: vscode.ExtensionContext) { + const { name, version, aiKey } = require('../package.json') as { name: string, version: string, aiKey: string }; + const telemetryReporter = new ExperimentationTelemetry(new TelemetryReporter(name, version, aiKey)); + + const experimentationService = await createExperimentationService(context, telemetryReporter); + await experimentationService.initialFetch; + + [ + AuthProviderType.github, + AuthProviderType['github-enterprise'] + ].forEach(async type => { + const loginService = new GitHubAuthenticationProvider(context, type, telemetryReporter); + await loginService.initialize(); + }); +} + +// this method is called when your extension is deactivated +export function deactivate() { } diff --git a/lib/vscode/extensions/github-authentication/src/github.ts b/extensions/github-authentication/src/github.ts similarity index 59% rename from lib/vscode/extensions/github-authentication/src/github.ts rename to extensions/github-authentication/src/github.ts index 4d3573a7e643..fa676744079c 100644 --- a/lib/vscode/extensions/github-authentication/src/github.ts +++ b/extensions/github-authentication/src/github.ts @@ -6,13 +6,11 @@ import * as vscode from 'vscode'; import { v4 as uuid } from 'uuid'; import { Keychain } from './common/keychain'; -import { GitHubServer, NETWORK_ERROR } from './githubServer'; +import { GitHubServer, uriHandler, NETWORK_ERROR } from './githubServer'; import Logger from './common/logger'; import { arrayEquals } from './common/utils'; import { ExperimentationTelemetry } from './experimentationService'; -export const onDidChangeSessions = new vscode.EventEmitter(); - interface SessionData { id: string; account?: { @@ -24,18 +22,29 @@ interface SessionData { accessToken: string; } -export class GitHubAuthenticationProvider { +export enum AuthProviderType { + github = 'github', + 'github-enterprise' = 'github-enterprise' +} + + +export class GitHubAuthenticationProvider implements vscode.AuthenticationProvider { private _sessions: vscode.AuthenticationSession[] = []; + private _sessionChangeEmitter = new vscode.EventEmitter(); private _githubServer: GitHubServer; private _keychain: Keychain; - constructor(context: vscode.ExtensionContext, telemetryReporter: ExperimentationTelemetry) { - this._keychain = new Keychain(context); - this._githubServer = new GitHubServer(telemetryReporter); + constructor(private context: vscode.ExtensionContext, private type: AuthProviderType, private telemetryReporter: ExperimentationTelemetry) { + this._keychain = new Keychain(context, `${type}.auth`); + this._githubServer = new GitHubServer(type, telemetryReporter); } - public async initialize(context: vscode.ExtensionContext): Promise { + get onDidChangeSessions() { + return this._sessionChangeEmitter.event; + } + + public async initialize(): Promise { try { this._sessions = await this.readSessions(); await this.verifySessions(); @@ -43,7 +52,17 @@ export class GitHubAuthenticationProvider { // Ignore, network request failed } - context.subscriptions.push(context.secrets.onDidChange(() => this.checkForUpdates())); + let friendlyName = 'GitHub'; + if (this.type === AuthProviderType.github) { + this.context.subscriptions.push(vscode.window.registerUriHandler(uriHandler)); + } + if (this.type === AuthProviderType['github-enterprise']) { + friendlyName = 'GitHub Enterprise'; + } + + this.context.subscriptions.push(vscode.commands.registerCommand(`${this.type}.provide-token`, () => this.manuallyProvideToken())); + this.context.subscriptions.push(vscode.authentication.registerAuthenticationProvider(this.type, friendlyName, this, { supportsMultipleAccounts: false })); + this.context.subscriptions.push(this.context.secrets.onDidChange(() => this.checkForUpdates())); } async getSessions(scopes?: string[]): Promise { @@ -52,12 +71,21 @@ export class GitHubAuthenticationProvider { : this._sessions; } + private async afterTokenLoad(token: string): Promise { + if (this.type === AuthProviderType.github) { + this._githubServer.checkIsEdu(token); + } + if (this.type === AuthProviderType['github-enterprise']) { + this._githubServer.checkEnterpriseVersion(token); + } + } + private async verifySessions(): Promise { const verifiedSessions: vscode.AuthenticationSession[] = []; const verificationPromises = this._sessions.map(async session => { try { await this._githubServer.getUserInfo(session.accessToken); - this._githubServer.checkIsEdu(session.accessToken); + this.afterTokenLoad(session.accessToken); verifiedSessions.push(session); } catch (e) { // Remove sessions that return unauthorized response @@ -112,7 +140,7 @@ export class GitHubAuthenticationProvider { }); if (added.length || removed.length) { - onDidChangeSessions.fire({ added, removed, changed: [] }); + this._sessionChangeEmitter.fire({ added, removed, changed: [] }); } } @@ -163,12 +191,41 @@ export class GitHubAuthenticationProvider { return this._sessions; } - public async createSession(scopes: string): Promise { - const token = await this._githubServer.login(scopes); - const session = await this.tokenToSession(token, scopes.split(' ')); - this._githubServer.checkIsEdu(token); - await this.setToken(session); - return session; + public async createSession(scopes: string[]): Promise { + try { + /* __GDPR__ + "login" : { } + */ + this.telemetryReporter?.sendTelemetryEvent('login'); + + const token = await this._githubServer.login(scopes.join(' ')); + this.afterTokenLoad(token); + const session = await this.tokenToSession(token, scopes); + await this.setToken(session); + this._sessionChangeEmitter.fire({ added: [session], removed: [], changed: [] }); + + Logger.info('Login success!'); + + return session; + } catch (e) { + // If login was cancelled, do not notify user. + if (e.message === 'Cancelled') { + /* __GDPR__ + "loginCancelled" : { } + */ + this.telemetryReporter?.sendTelemetryEvent('loginCancelled'); + throw e; + } + + /* __GDPR__ + "loginFailed" : { } + */ + this.telemetryReporter?.sendTelemetryEvent('loginFailed'); + + vscode.window.showErrorMessage(`Sign in failed: ${e}`); + Logger.error(e); + throw e; + } } public async manuallyProvideToken(): Promise { @@ -196,18 +253,33 @@ export class GitHubAuthenticationProvider { await this.storeSessions(); } - public async removeSession(id: string): Promise { - Logger.info(`Logging out of ${id}`); - const sessionIndex = this._sessions.findIndex(session => session.id === id); - let session: vscode.AuthenticationSession | undefined; - if (sessionIndex > -1) { - session = this._sessions[sessionIndex]; - this._sessions.splice(sessionIndex, 1); - } else { - Logger.error('Session not found'); - } + public async removeSession(id: string) { + try { + /* __GDPR__ + "logout" : { } + */ + this.telemetryReporter?.sendTelemetryEvent('logout'); - await this.storeSessions(); - return session; + Logger.info(`Logging out of ${id}`); + const sessionIndex = this._sessions.findIndex(session => session.id === id); + if (sessionIndex > -1) { + const session = this._sessions[sessionIndex]; + this._sessions.splice(sessionIndex, 1); + this._sessionChangeEmitter.fire({ added: [], removed: [session], changed: [] }); + } else { + Logger.error('Session not found'); + } + + await this.storeSessions(); + } catch (e) { + /* __GDPR__ + "logoutFailed" : { } + */ + this.telemetryReporter?.sendTelemetryEvent('logoutFailed'); + + vscode.window.showErrorMessage(`Sign out failed: ${e}`); + Logger.error(e); + throw e; + } } } diff --git a/lib/vscode/extensions/github-authentication/src/githubServer.ts b/extensions/github-authentication/src/githubServer.ts similarity index 74% rename from lib/vscode/extensions/github-authentication/src/githubServer.ts rename to extensions/github-authentication/src/githubServer.ts index 4fdafe0ccb12..f675507c4dd3 100644 --- a/lib/vscode/extensions/github-authentication/src/githubServer.ts +++ b/extensions/github-authentication/src/githubServer.ts @@ -10,12 +10,12 @@ import { v4 as uuid } from 'uuid'; import { PromiseAdapter, promiseFromEvent } from './common/utils'; import Logger from './common/logger'; import { ExperimentationTelemetry } from './experimentationService'; +import { AuthProviderType } from './github'; const localize = nls.loadMessageBundle(); export const NETWORK_ERROR = 'network error'; -// NOTE@coder: use our own auth relay (the commented one is microsoft's, not ours) -const AUTH_RELAY_SERVER = 'auth.code-server.dev'; +const AUTH_RELAY_SERVER = 'vscode-auth.github.com'; // const AUTH_RELAY_STAGING_SERVER = 'client-auth-staging-14a768b.herokuapp.com'; class UriEventHandler extends vscode.EventEmitter implements vscode.UriHandler { @@ -26,10 +26,6 @@ class UriEventHandler extends vscode.EventEmitter implements vscode. export const uriHandler = new UriEventHandler; -const onDidManuallyProvideToken = new vscode.EventEmitter(); - - - function parseQuery(uri: vscode.Uri) { return uri.query.split('&').reduce((prev: any, current) => { const queryString = current.split('='); @@ -40,20 +36,21 @@ function parseQuery(uri: vscode.Uri) { export class GitHubServer { private _statusBarItem: vscode.StatusBarItem | undefined; + private _onDidManuallyProvideToken = new vscode.EventEmitter(); private _pendingStates = new Map(); private _codeExchangePromises = new Map, cancel: vscode.EventEmitter }>(); - constructor(private readonly telemetryReporter: ExperimentationTelemetry) { } + constructor(private type: AuthProviderType, private readonly telemetryReporter: ExperimentationTelemetry) { } private isTestEnvironment(url: vscode.Uri): boolean { - return /\.azurewebsites\.net$/.test(url.authority) || url.authority.startsWith('localhost:'); + return this.type === AuthProviderType['github-enterprise'] || /\.azurewebsites\.net$/.test(url.authority) || url.authority.startsWith('localhost:'); } // TODO@joaomoreno TODO@RMacfarlane private async isNoCorsEnvironment(): Promise { - const uri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/did-authenticate`)); - return uri.scheme === 'https' && /^vscode\./.test(uri.authority); + const uri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/dummy`)); + return (uri.scheme === 'https' && /^vscode\./.test(uri.authority)) || (uri.scheme === 'http' && /^localhost/.test(uri.authority)); } public async login(scopes: string): Promise { @@ -105,7 +102,7 @@ export class GitHubServer { return Promise.race([ codeExchangePromise.promise, - promiseFromEvent(onDidManuallyProvideToken.event, (token: string | undefined, resolve, reject): void => { + promiseFromEvent(this._onDidManuallyProvideToken.event, (token: string | undefined, resolve, reject): void => { if (!token) { reject('Cancelled'); } else { @@ -165,11 +162,31 @@ export class GitHubServer { } }; + private getServerUri(path?: string) { + const apiUri = this.type === AuthProviderType['github-enterprise'] + ? vscode.Uri.parse(vscode.workspace.getConfiguration('github-enterprise').get('uri') || '', true) + : vscode.Uri.parse('https://api.github.com'); + + if (!path) { + path = ''; + } + if (this.type === AuthProviderType['github-enterprise']) { + path = '/api/v3' + path; + } + + return vscode.Uri.parse(`${apiUri.scheme}://${apiUri.authority}${path}`); + } + private updateStatusBarItem(isStart?: boolean) { if (isStart && !this._statusBarItem) { - this._statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); - this._statusBarItem.text = localize('signingIn', "$(mark-github) Signing in to github.com..."); - this._statusBarItem.command = 'github.provide-token'; + this._statusBarItem = vscode.window.createStatusBarItem('status.git.signIn', vscode.StatusBarAlignment.Left); + this._statusBarItem.name = localize('status.git.signIn.name', "GitHub Sign-in"); + this._statusBarItem.text = this.type === AuthProviderType.github + ? localize('signingIn', "$(mark-github) Signing in to github.com...") + : localize('signingInEnterprise', "$(mark-github) Signing in to {0}...", this.getServerUri().authority); + this._statusBarItem.command = this.type === AuthProviderType.github + ? 'github.provide-token' + : 'github-enterprise.provide-token'; this._statusBarItem.show(); } @@ -182,7 +199,7 @@ export class GitHubServer { public async manuallyProvideToken() { const uriOrToken = await vscode.window.showInputBox({ prompt: 'Token', ignoreFocusOut: true }); if (!uriOrToken) { - onDidManuallyProvideToken.fire(undefined); + this._onDidManuallyProvideToken.fire(undefined); return; } @@ -193,14 +210,14 @@ export class GitHubServer { } catch (e) { // If it doesn't look like a URI, treat it as a token. Logger.info('Treating input as token'); - onDidManuallyProvideToken.fire(uriOrToken); + this._onDidManuallyProvideToken.fire(uriOrToken); } } private async getScopes(token: string): Promise { try { Logger.info('Getting token scopes...'); - const result = await fetch('https://api.github.com', { + const result = await fetch(this.getServerUri('/').toString(), { headers: { Authorization: `token ${token}`, 'User-Agent': 'Visual-Studio-Code' @@ -224,7 +241,7 @@ export class GitHubServer { let result: Response; try { Logger.info('Getting user info...'); - result = await fetch('https://api.github.com/user', { + result = await fetch(this.getServerUri('/user').toString(), { headers: { Authorization: `token ${token}`, 'User-Agent': 'Visual-Studio-Code' @@ -280,6 +297,34 @@ export class GitHubServer { } catch (e) { // No-op } + } + + public async checkEnterpriseVersion(token: string): Promise { + try { + + const result = await fetch(this.getServerUri('/meta').toString(), { + headers: { + Authorization: `token ${token}`, + 'User-Agent': 'Visual-Studio-Code' + } + }); + if (!result.ok) { + return; + } + + const json: { verifiable_password_authentication: boolean, installed_version: string } = await result.json(); + + /* __GDPR__ + "ghe-session" : { + "version": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + this.telemetryReporter.sendTelemetryEvent('ghe-session', { + version: json.installed_version + }); + } catch { + // No-op + } } } diff --git a/lib/vscode/extensions/simple-browser/src/typings/ref.d.ts b/extensions/github-authentication/src/typings/ref.d.ts similarity index 100% rename from lib/vscode/extensions/simple-browser/src/typings/ref.d.ts rename to extensions/github-authentication/src/typings/ref.d.ts diff --git a/lib/vscode/extensions/github-authentication/tsconfig.json b/extensions/github-authentication/tsconfig.json similarity index 100% rename from lib/vscode/extensions/github-authentication/tsconfig.json rename to extensions/github-authentication/tsconfig.json diff --git a/lib/vscode/extensions/github-authentication/yarn.lock b/extensions/github-authentication/yarn.lock similarity index 96% rename from lib/vscode/extensions/github-authentication/yarn.lock rename to extensions/github-authentication/yarn.lock index 8095e5745237..090dc94dcb76 100644 --- a/lib/vscode/extensions/github-authentication/yarn.lock +++ b/extensions/github-authentication/yarn.lock @@ -15,10 +15,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.5.tgz#3d03acd3b3414cf67faf999aed11682ed121f22b" integrity sha512-90hiq6/VqtQgX8Sp0EzeIsv3r+ellbGj4URKj5j30tLlZvRUpnAe9YbYnjl3pJM93GyXU0tghHhvXHq+5rnCKA== -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== "@types/uuid@8.0.0": version "8.0.0" diff --git a/lib/vscode/extensions/github/.vscodeignore b/extensions/github/.vscodeignore similarity index 100% rename from lib/vscode/extensions/github/.vscodeignore rename to extensions/github/.vscodeignore diff --git a/lib/vscode/extensions/github/README.md b/extensions/github/README.md similarity index 100% rename from lib/vscode/extensions/github/README.md rename to extensions/github/README.md diff --git a/lib/vscode/extensions/github/extension.webpack.config.js b/extensions/github/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/github/extension.webpack.config.js rename to extensions/github/extension.webpack.config.js diff --git a/lib/vscode/extensions/github/images/icon.png b/extensions/github/images/icon.png similarity index 100% rename from lib/vscode/extensions/github/images/icon.png rename to extensions/github/images/icon.png diff --git a/lib/vscode/extensions/github/package.json b/extensions/github/package.json similarity index 98% rename from lib/vscode/extensions/github/package.json rename to extensions/github/package.json index 8f67314b459d..f21080ab6f17 100644 --- a/lib/vscode/extensions/github/package.json +++ b/extensions/github/package.json @@ -70,7 +70,7 @@ "vscode-nls": "^4.1.2" }, "devDependencies": { - "@types/node": "^12.19.9" + "@types/node": "14.x" }, "repository": { "type": "git", diff --git a/lib/vscode/extensions/github/package.nls.json b/extensions/github/package.nls.json similarity index 100% rename from lib/vscode/extensions/github/package.nls.json rename to extensions/github/package.nls.json diff --git a/lib/vscode/extensions/github/src/auth.ts b/extensions/github/src/auth.ts similarity index 100% rename from lib/vscode/extensions/github/src/auth.ts rename to extensions/github/src/auth.ts diff --git a/lib/vscode/extensions/github/src/commands.ts b/extensions/github/src/commands.ts similarity index 100% rename from lib/vscode/extensions/github/src/commands.ts rename to extensions/github/src/commands.ts diff --git a/lib/vscode/extensions/github/src/credentialProvider.ts b/extensions/github/src/credentialProvider.ts similarity index 100% rename from lib/vscode/extensions/github/src/credentialProvider.ts rename to extensions/github/src/credentialProvider.ts diff --git a/lib/vscode/extensions/github/src/extension.ts b/extensions/github/src/extension.ts similarity index 100% rename from lib/vscode/extensions/github/src/extension.ts rename to extensions/github/src/extension.ts diff --git a/lib/vscode/extensions/github/src/publish.ts b/extensions/github/src/publish.ts similarity index 100% rename from lib/vscode/extensions/github/src/publish.ts rename to extensions/github/src/publish.ts diff --git a/lib/vscode/extensions/github/src/pushErrorHandler.ts b/extensions/github/src/pushErrorHandler.ts similarity index 100% rename from lib/vscode/extensions/github/src/pushErrorHandler.ts rename to extensions/github/src/pushErrorHandler.ts diff --git a/lib/vscode/extensions/github/src/remoteSourceProvider.ts b/extensions/github/src/remoteSourceProvider.ts similarity index 100% rename from lib/vscode/extensions/github/src/remoteSourceProvider.ts rename to extensions/github/src/remoteSourceProvider.ts diff --git a/lib/vscode/extensions/github/src/typings/git.d.ts b/extensions/github/src/typings/git.d.ts similarity index 100% rename from lib/vscode/extensions/github/src/typings/git.d.ts rename to extensions/github/src/typings/git.d.ts diff --git a/lib/vscode/extensions/github/src/typings/ref.d.ts b/extensions/github/src/typings/ref.d.ts similarity index 100% rename from lib/vscode/extensions/github/src/typings/ref.d.ts rename to extensions/github/src/typings/ref.d.ts diff --git a/lib/vscode/extensions/github/src/util.ts b/extensions/github/src/util.ts similarity index 100% rename from lib/vscode/extensions/github/src/util.ts rename to extensions/github/src/util.ts diff --git a/lib/vscode/extensions/github/tsconfig.json b/extensions/github/tsconfig.json similarity index 100% rename from lib/vscode/extensions/github/tsconfig.json rename to extensions/github/tsconfig.json diff --git a/lib/vscode/extensions/github/yarn.lock b/extensions/github/yarn.lock similarity index 96% rename from lib/vscode/extensions/github/yarn.lock rename to extensions/github/yarn.lock index 05a0b4cf6f9f..94f7a26da9d9 100644 --- a/lib/vscode/extensions/github/yarn.lock +++ b/extensions/github/yarn.lock @@ -99,16 +99,16 @@ dependencies: "@types/node" ">= 8" +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== + "@types/node@>= 8": version "14.0.23" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.23.tgz#676fa0883450ed9da0bb24156213636290892806" integrity sha512-Z4U8yDAl5TFkmYsZdFPdjeMa57NOvnaf1tljHzhouaPEp7LCj2JKkejpI1ODviIAQuW4CcQmxkQ77rnLsOOoKw== -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== - before-after-hook@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635" diff --git a/lib/vscode/extensions/go/.vscodeignore b/extensions/go/.vscodeignore similarity index 100% rename from lib/vscode/extensions/go/.vscodeignore rename to extensions/go/.vscodeignore diff --git a/lib/vscode/extensions/go/cgmanifest.json b/extensions/go/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/go/cgmanifest.json rename to extensions/go/cgmanifest.json diff --git a/lib/vscode/extensions/go/language-configuration.json b/extensions/go/language-configuration.json similarity index 100% rename from lib/vscode/extensions/go/language-configuration.json rename to extensions/go/language-configuration.json diff --git a/lib/vscode/extensions/go/package.json b/extensions/go/package.json similarity index 100% rename from lib/vscode/extensions/go/package.json rename to extensions/go/package.json diff --git a/lib/vscode/extensions/go/package.nls.json b/extensions/go/package.nls.json similarity index 100% rename from lib/vscode/extensions/go/package.nls.json rename to extensions/go/package.nls.json diff --git a/lib/vscode/extensions/go/syntaxes/go.tmLanguage.json b/extensions/go/syntaxes/go.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/go/syntaxes/go.tmLanguage.json rename to extensions/go/syntaxes/go.tmLanguage.json diff --git a/lib/vscode/extensions/go/yarn.lock b/extensions/go/yarn.lock similarity index 100% rename from lib/vscode/extensions/go/yarn.lock rename to extensions/go/yarn.lock diff --git a/lib/vscode/extensions/groovy/.vscodeignore b/extensions/groovy/.vscodeignore similarity index 100% rename from lib/vscode/extensions/groovy/.vscodeignore rename to extensions/groovy/.vscodeignore diff --git a/lib/vscode/extensions/groovy/cgmanifest.json b/extensions/groovy/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/groovy/cgmanifest.json rename to extensions/groovy/cgmanifest.json diff --git a/lib/vscode/extensions/groovy/language-configuration.json b/extensions/groovy/language-configuration.json similarity index 100% rename from lib/vscode/extensions/groovy/language-configuration.json rename to extensions/groovy/language-configuration.json diff --git a/lib/vscode/extensions/groovy/package.json b/extensions/groovy/package.json similarity index 100% rename from lib/vscode/extensions/groovy/package.json rename to extensions/groovy/package.json diff --git a/lib/vscode/extensions/groovy/package.nls.json b/extensions/groovy/package.nls.json similarity index 100% rename from lib/vscode/extensions/groovy/package.nls.json rename to extensions/groovy/package.nls.json diff --git a/lib/vscode/extensions/groovy/snippets/groovy.code-snippets b/extensions/groovy/snippets/groovy.code-snippets similarity index 100% rename from lib/vscode/extensions/groovy/snippets/groovy.code-snippets rename to extensions/groovy/snippets/groovy.code-snippets diff --git a/lib/vscode/extensions/groovy/syntaxes/groovy.tmLanguage.json b/extensions/groovy/syntaxes/groovy.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/groovy/syntaxes/groovy.tmLanguage.json rename to extensions/groovy/syntaxes/groovy.tmLanguage.json diff --git a/lib/vscode/extensions/groovy/yarn.lock b/extensions/groovy/yarn.lock similarity index 100% rename from lib/vscode/extensions/groovy/yarn.lock rename to extensions/groovy/yarn.lock diff --git a/lib/vscode/extensions/grunt/.vscodeignore b/extensions/grunt/.vscodeignore similarity index 100% rename from lib/vscode/extensions/grunt/.vscodeignore rename to extensions/grunt/.vscodeignore diff --git a/lib/vscode/extensions/grunt/README.md b/extensions/grunt/README.md similarity index 100% rename from lib/vscode/extensions/grunt/README.md rename to extensions/grunt/README.md diff --git a/lib/vscode/extensions/grunt/extension.webpack.config.js b/extensions/grunt/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/grunt/extension.webpack.config.js rename to extensions/grunt/extension.webpack.config.js diff --git a/lib/vscode/extensions/grunt/images/grunt.png b/extensions/grunt/images/grunt.png similarity index 100% rename from lib/vscode/extensions/grunt/images/grunt.png rename to extensions/grunt/images/grunt.png diff --git a/lib/vscode/extensions/grunt/package.json b/extensions/grunt/package.json similarity index 95% rename from lib/vscode/extensions/grunt/package.json rename to extensions/grunt/package.json index d7fbd50e57ac..c784b1ed83a1 100644 --- a/lib/vscode/extensions/grunt/package.json +++ b/extensions/grunt/package.json @@ -20,7 +20,7 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "^12.19.9" + "@types/node": "14.x" }, "main": "./out/main", "activationEvents": [ @@ -39,13 +39,13 @@ "title": "Grunt", "properties": { "grunt.autoDetect": { - "scope": "resource", + "scope": "application", "type": "string", "enum": [ "off", "on" ], - "default": "on", + "default": "off", "description": "%config.grunt.autoDetect%" } } diff --git a/lib/vscode/extensions/grunt/package.nls.json b/extensions/grunt/package.nls.json similarity index 71% rename from lib/vscode/extensions/grunt/package.nls.json rename to extensions/grunt/package.nls.json index 873de038882f..789a579cc545 100644 --- a/lib/vscode/extensions/grunt/package.nls.json +++ b/extensions/grunt/package.nls.json @@ -1,7 +1,7 @@ { "description": "Extension to add Grunt capabilities to VS Code.", "displayName": "Grunt support for VS Code", - "config.grunt.autoDetect": "Controls whether auto detection of Grunt tasks is on or off. Default is on.", + "config.grunt.autoDetect": "Controls enablement of Grunt task detection. Grunt task detection can cause files in any open workspace to be executed.", "grunt.taskDefinition.type.description": "The Grunt task to customize.", "grunt.taskDefinition.args.description": "Command line arguments to pass to the grunt task", "grunt.taskDefinition.file.description": "The Grunt file that provides the task. Can be omitted." diff --git a/lib/vscode/extensions/grunt/src/main.ts b/extensions/grunt/src/main.ts similarity index 100% rename from lib/vscode/extensions/grunt/src/main.ts rename to extensions/grunt/src/main.ts diff --git a/lib/vscode/extensions/grunt/src/typings/refs.d.ts b/extensions/grunt/src/typings/refs.d.ts similarity index 100% rename from lib/vscode/extensions/grunt/src/typings/refs.d.ts rename to extensions/grunt/src/typings/refs.d.ts diff --git a/lib/vscode/extensions/grunt/tsconfig.json b/extensions/grunt/tsconfig.json similarity index 100% rename from lib/vscode/extensions/grunt/tsconfig.json rename to extensions/grunt/tsconfig.json diff --git a/lib/vscode/extensions/debug-server-ready/yarn.lock b/extensions/grunt/yarn.lock similarity index 56% rename from lib/vscode/extensions/debug-server-ready/yarn.lock rename to extensions/grunt/yarn.lock index 687f15f481e5..f7a30098ef45 100644 --- a/lib/vscode/extensions/debug-server-ready/yarn.lock +++ b/extensions/grunt/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== vscode-nls@^4.0.0: version "4.0.0" diff --git a/lib/vscode/extensions/gulp/.vscodeignore b/extensions/gulp/.vscodeignore similarity index 100% rename from lib/vscode/extensions/gulp/.vscodeignore rename to extensions/gulp/.vscodeignore diff --git a/lib/vscode/extensions/gulp/README.md b/extensions/gulp/README.md similarity index 100% rename from lib/vscode/extensions/gulp/README.md rename to extensions/gulp/README.md diff --git a/lib/vscode/extensions/gulp/extension.webpack.config.js b/extensions/gulp/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/gulp/extension.webpack.config.js rename to extensions/gulp/extension.webpack.config.js diff --git a/lib/vscode/extensions/gulp/images/gulp.png b/extensions/gulp/images/gulp.png similarity index 100% rename from lib/vscode/extensions/gulp/images/gulp.png rename to extensions/gulp/images/gulp.png diff --git a/lib/vscode/extensions/gulp/package.json b/extensions/gulp/package.json similarity index 94% rename from lib/vscode/extensions/gulp/package.json rename to extensions/gulp/package.json index 2fb8d5831234..21800e96cfb6 100644 --- a/lib/vscode/extensions/gulp/package.json +++ b/extensions/gulp/package.json @@ -20,7 +20,7 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "^12.19.9" + "@types/node": "14.x" }, "main": "./out/main", "activationEvents": [ @@ -39,13 +39,13 @@ "title": "Gulp", "properties": { "gulp.autoDetect": { - "scope": "resource", + "scope": "application", "type": "string", "enum": [ "off", "on" ], - "default": "on", + "default": "off", "description": "%config.gulp.autoDetect%" } } diff --git a/lib/vscode/extensions/gulp/package.nls.json b/extensions/gulp/package.nls.json similarity index 65% rename from lib/vscode/extensions/gulp/package.nls.json rename to extensions/gulp/package.nls.json index a87dbe1dc85b..222ad3a87ec3 100644 --- a/lib/vscode/extensions/gulp/package.nls.json +++ b/extensions/gulp/package.nls.json @@ -1,7 +1,7 @@ { "description": "Extension to add Gulp capabilities to VSCode.", "displayName": "Gulp support for VSCode", - "config.gulp.autoDetect": "Controls whether auto detection of Gulp tasks is on or off. Default is on.", + "config.gulp.autoDetect": "Controls enablement of Gulp task detection. Gulp task detection can cause files in any open workspace to be executed.", "gulp.taskDefinition.type.description": "The Gulp task to customize.", "gulp.taskDefinition.file.description": "The Gulp file that provides the task. Can be omitted." } diff --git a/lib/vscode/extensions/gulp/src/main.ts b/extensions/gulp/src/main.ts similarity index 100% rename from lib/vscode/extensions/gulp/src/main.ts rename to extensions/gulp/src/main.ts diff --git a/lib/vscode/extensions/gulp/src/typings/refs.d.ts b/extensions/gulp/src/typings/refs.d.ts similarity index 100% rename from lib/vscode/extensions/gulp/src/typings/refs.d.ts rename to extensions/gulp/src/typings/refs.d.ts diff --git a/lib/vscode/extensions/gulp/tsconfig.json b/extensions/gulp/tsconfig.json similarity index 100% rename from lib/vscode/extensions/gulp/tsconfig.json rename to extensions/gulp/tsconfig.json diff --git a/lib/vscode/extensions/grunt/yarn.lock b/extensions/gulp/yarn.lock similarity index 56% rename from lib/vscode/extensions/grunt/yarn.lock rename to extensions/gulp/yarn.lock index 687f15f481e5..f7a30098ef45 100644 --- a/lib/vscode/extensions/grunt/yarn.lock +++ b/extensions/gulp/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== vscode-nls@^4.0.0: version "4.0.0" diff --git a/lib/vscode/extensions/handlebars/.vscodeignore b/extensions/handlebars/.vscodeignore similarity index 100% rename from lib/vscode/extensions/handlebars/.vscodeignore rename to extensions/handlebars/.vscodeignore diff --git a/lib/vscode/extensions/handlebars/cgmanifest.json b/extensions/handlebars/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/handlebars/cgmanifest.json rename to extensions/handlebars/cgmanifest.json diff --git a/lib/vscode/extensions/handlebars/language-configuration.json b/extensions/handlebars/language-configuration.json similarity index 100% rename from lib/vscode/extensions/handlebars/language-configuration.json rename to extensions/handlebars/language-configuration.json diff --git a/lib/vscode/extensions/handlebars/package.json b/extensions/handlebars/package.json similarity index 100% rename from lib/vscode/extensions/handlebars/package.json rename to extensions/handlebars/package.json diff --git a/lib/vscode/extensions/handlebars/package.nls.json b/extensions/handlebars/package.nls.json similarity index 100% rename from lib/vscode/extensions/handlebars/package.nls.json rename to extensions/handlebars/package.nls.json diff --git a/lib/vscode/extensions/handlebars/syntaxes/Handlebars.tmLanguage.json b/extensions/handlebars/syntaxes/Handlebars.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/handlebars/syntaxes/Handlebars.tmLanguage.json rename to extensions/handlebars/syntaxes/Handlebars.tmLanguage.json diff --git a/lib/vscode/extensions/handlebars/yarn.lock b/extensions/handlebars/yarn.lock similarity index 100% rename from lib/vscode/extensions/handlebars/yarn.lock rename to extensions/handlebars/yarn.lock diff --git a/lib/vscode/extensions/hlsl/.vscodeignore b/extensions/hlsl/.vscodeignore similarity index 100% rename from lib/vscode/extensions/hlsl/.vscodeignore rename to extensions/hlsl/.vscodeignore diff --git a/lib/vscode/extensions/hlsl/cgmanifest.json b/extensions/hlsl/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/hlsl/cgmanifest.json rename to extensions/hlsl/cgmanifest.json diff --git a/lib/vscode/extensions/hlsl/language-configuration.json b/extensions/hlsl/language-configuration.json similarity index 100% rename from lib/vscode/extensions/hlsl/language-configuration.json rename to extensions/hlsl/language-configuration.json diff --git a/lib/vscode/extensions/hlsl/package.json b/extensions/hlsl/package.json similarity index 100% rename from lib/vscode/extensions/hlsl/package.json rename to extensions/hlsl/package.json diff --git a/lib/vscode/extensions/hlsl/package.nls.json b/extensions/hlsl/package.nls.json similarity index 100% rename from lib/vscode/extensions/hlsl/package.nls.json rename to extensions/hlsl/package.nls.json diff --git a/lib/vscode/extensions/hlsl/syntaxes/hlsl.tmLanguage.json b/extensions/hlsl/syntaxes/hlsl.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/hlsl/syntaxes/hlsl.tmLanguage.json rename to extensions/hlsl/syntaxes/hlsl.tmLanguage.json diff --git a/lib/vscode/extensions/hlsl/yarn.lock b/extensions/hlsl/yarn.lock similarity index 100% rename from lib/vscode/extensions/hlsl/yarn.lock rename to extensions/hlsl/yarn.lock diff --git a/lib/vscode/extensions/html-language-features/.vscode/launch.json b/extensions/html-language-features/.vscode/launch.json similarity index 100% rename from lib/vscode/extensions/html-language-features/.vscode/launch.json rename to extensions/html-language-features/.vscode/launch.json diff --git a/lib/vscode/extensions/html-language-features/.vscode/settings.json b/extensions/html-language-features/.vscode/settings.json similarity index 100% rename from lib/vscode/extensions/html-language-features/.vscode/settings.json rename to extensions/html-language-features/.vscode/settings.json diff --git a/lib/vscode/extensions/html-language-features/.vscode/tasks.json b/extensions/html-language-features/.vscode/tasks.json similarity index 100% rename from lib/vscode/extensions/html-language-features/.vscode/tasks.json rename to extensions/html-language-features/.vscode/tasks.json diff --git a/lib/vscode/extensions/html-language-features/.vscodeignore b/extensions/html-language-features/.vscodeignore similarity index 100% rename from lib/vscode/extensions/html-language-features/.vscodeignore rename to extensions/html-language-features/.vscodeignore diff --git a/lib/vscode/extensions/html-language-features/CONTRIBUTING.md b/extensions/html-language-features/CONTRIBUTING.md similarity index 100% rename from lib/vscode/extensions/html-language-features/CONTRIBUTING.md rename to extensions/html-language-features/CONTRIBUTING.md diff --git a/lib/vscode/extensions/html-language-features/README.md b/extensions/html-language-features/README.md similarity index 100% rename from lib/vscode/extensions/html-language-features/README.md rename to extensions/html-language-features/README.md diff --git a/lib/vscode/extensions/html-language-features/build/bundleTypeScriptLibraries.js b/extensions/html-language-features/build/bundleTypeScriptLibraries.js similarity index 100% rename from lib/vscode/extensions/html-language-features/build/bundleTypeScriptLibraries.js rename to extensions/html-language-features/build/bundleTypeScriptLibraries.js diff --git a/lib/vscode/extensions/html-language-features/cgmanifest.json b/extensions/html-language-features/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/html-language-features/cgmanifest.json rename to extensions/html-language-features/cgmanifest.json diff --git a/lib/vscode/extensions/html-language-features/client/src/browser/htmlClientMain.ts b/extensions/html-language-features/client/src/browser/htmlClientMain.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/client/src/browser/htmlClientMain.ts rename to extensions/html-language-features/client/src/browser/htmlClientMain.ts diff --git a/lib/vscode/extensions/html-language-features/client/src/customData.ts b/extensions/html-language-features/client/src/customData.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/client/src/customData.ts rename to extensions/html-language-features/client/src/customData.ts diff --git a/lib/vscode/extensions/html-language-features/client/src/htmlClient.ts b/extensions/html-language-features/client/src/htmlClient.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/client/src/htmlClient.ts rename to extensions/html-language-features/client/src/htmlClient.ts diff --git a/lib/vscode/extensions/html-language-features/client/src/htmlEmptyTagsShared.ts b/extensions/html-language-features/client/src/htmlEmptyTagsShared.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/client/src/htmlEmptyTagsShared.ts rename to extensions/html-language-features/client/src/htmlEmptyTagsShared.ts diff --git a/lib/vscode/extensions/html-language-features/client/src/node/htmlClientMain.ts b/extensions/html-language-features/client/src/node/htmlClientMain.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/client/src/node/htmlClientMain.ts rename to extensions/html-language-features/client/src/node/htmlClientMain.ts diff --git a/lib/vscode/extensions/html-language-features/client/src/node/nodeFs.ts b/extensions/html-language-features/client/src/node/nodeFs.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/client/src/node/nodeFs.ts rename to extensions/html-language-features/client/src/node/nodeFs.ts diff --git a/lib/vscode/extensions/html-language-features/client/src/requests.ts b/extensions/html-language-features/client/src/requests.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/client/src/requests.ts rename to extensions/html-language-features/client/src/requests.ts diff --git a/lib/vscode/extensions/html-language-features/client/src/tagClosing.ts b/extensions/html-language-features/client/src/tagClosing.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/client/src/tagClosing.ts rename to extensions/html-language-features/client/src/tagClosing.ts diff --git a/lib/vscode/extensions/html-language-features/client/src/typings/ref.d.ts b/extensions/html-language-features/client/src/typings/ref.d.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/client/src/typings/ref.d.ts rename to extensions/html-language-features/client/src/typings/ref.d.ts diff --git a/lib/vscode/extensions/html-language-features/client/tsconfig.json b/extensions/html-language-features/client/tsconfig.json similarity index 100% rename from lib/vscode/extensions/html-language-features/client/tsconfig.json rename to extensions/html-language-features/client/tsconfig.json diff --git a/lib/vscode/extensions/html-language-features/extension-browser.webpack.config.js b/extensions/html-language-features/extension-browser.webpack.config.js similarity index 100% rename from lib/vscode/extensions/html-language-features/extension-browser.webpack.config.js rename to extensions/html-language-features/extension-browser.webpack.config.js diff --git a/lib/vscode/extensions/html-language-features/extension.webpack.config.js b/extensions/html-language-features/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/html-language-features/extension.webpack.config.js rename to extensions/html-language-features/extension.webpack.config.js diff --git a/lib/vscode/extensions/html-language-features/icons/html.png b/extensions/html-language-features/icons/html.png similarity index 100% rename from lib/vscode/extensions/html-language-features/icons/html.png rename to extensions/html-language-features/icons/html.png diff --git a/lib/vscode/extensions/html-language-features/package.json b/extensions/html-language-features/package.json similarity index 99% rename from lib/vscode/extensions/html-language-features/package.json rename to extensions/html-language-features/package.json index 9fa6bc314e52..3c6a539c0797 100644 --- a/lib/vscode/extensions/html-language-features/package.json +++ b/extensions/html-language-features/package.json @@ -245,7 +245,7 @@ "vscode-nls": "^5.0.0" }, "devDependencies": { - "@types/node": "^12.19.9" + "@types/node": "14.x" }, "repository": { "type": "git", diff --git a/lib/vscode/extensions/html-language-features/package.nls.json b/extensions/html-language-features/package.nls.json similarity index 100% rename from lib/vscode/extensions/html-language-features/package.nls.json rename to extensions/html-language-features/package.nls.json diff --git a/lib/vscode/extensions/html-language-features/schemas/package.schema.json b/extensions/html-language-features/schemas/package.schema.json similarity index 100% rename from lib/vscode/extensions/html-language-features/schemas/package.schema.json rename to extensions/html-language-features/schemas/package.schema.json diff --git a/lib/vscode/extensions/html-language-features/server/.vscode/launch.json b/extensions/html-language-features/server/.vscode/launch.json similarity index 100% rename from lib/vscode/extensions/html-language-features/server/.vscode/launch.json rename to extensions/html-language-features/server/.vscode/launch.json diff --git a/lib/vscode/extensions/html-language-features/server/.vscode/tasks.json b/extensions/html-language-features/server/.vscode/tasks.json similarity index 100% rename from lib/vscode/extensions/html-language-features/server/.vscode/tasks.json rename to extensions/html-language-features/server/.vscode/tasks.json diff --git a/lib/vscode/extensions/html-language-features/server/build/javaScriptLibraryLoader.js b/extensions/html-language-features/server/build/javaScriptLibraryLoader.js similarity index 100% rename from lib/vscode/extensions/html-language-features/server/build/javaScriptLibraryLoader.js rename to extensions/html-language-features/server/build/javaScriptLibraryLoader.js diff --git a/lib/vscode/extensions/html-language-features/server/extension-browser.webpack.config.js b/extensions/html-language-features/server/extension-browser.webpack.config.js similarity index 100% rename from lib/vscode/extensions/html-language-features/server/extension-browser.webpack.config.js rename to extensions/html-language-features/server/extension-browser.webpack.config.js diff --git a/lib/vscode/extensions/html-language-features/server/extension.webpack.config.js b/extensions/html-language-features/server/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/html-language-features/server/extension.webpack.config.js rename to extensions/html-language-features/server/extension.webpack.config.js diff --git a/lib/vscode/extensions/html-language-features/server/lib/cgmanifest.json b/extensions/html-language-features/server/lib/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/html-language-features/server/lib/cgmanifest.json rename to extensions/html-language-features/server/lib/cgmanifest.json diff --git a/lib/vscode/extensions/html-language-features/server/lib/jquery.d.ts b/extensions/html-language-features/server/lib/jquery.d.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/lib/jquery.d.ts rename to extensions/html-language-features/server/lib/jquery.d.ts diff --git a/lib/vscode/extensions/html-language-features/server/package.json b/extensions/html-language-features/server/package.json similarity index 89% rename from lib/vscode/extensions/html-language-features/server/package.json rename to extensions/html-language-features/server/package.json index fdb292853138..ab5b93df5c76 100644 --- a/lib/vscode/extensions/html-language-features/server/package.json +++ b/extensions/html-language-features/server/package.json @@ -9,8 +9,8 @@ }, "main": "./out/node/htmlServerMain", "dependencies": { - "vscode-css-languageservice": "^5.1.1", - "vscode-html-languageservice": "^4.0.3", + "vscode-css-languageservice": "^5.1.3", + "vscode-html-languageservice": "^4.0.4", "vscode-languageserver": "^7.0.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-nls": "^5.0.0", @@ -18,7 +18,7 @@ }, "devDependencies": { "@types/mocha": "^8.2.0", - "@types/node": "^12.19.9" + "@types/node": "14.x" }, "scripts": { "compile": "npx gulp compile-extension:html-language-features-server", diff --git a/lib/vscode/extensions/html-language-features/server/src/browser/htmlServerMain.ts b/extensions/html-language-features/server/src/browser/htmlServerMain.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/browser/htmlServerMain.ts rename to extensions/html-language-features/server/src/browser/htmlServerMain.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/customData.ts b/extensions/html-language-features/server/src/customData.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/customData.ts rename to extensions/html-language-features/server/src/customData.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/htmlServer.ts b/extensions/html-language-features/server/src/htmlServer.ts similarity index 90% rename from lib/vscode/extensions/html-language-features/server/src/htmlServer.ts rename to extensions/html-language-features/server/src/htmlServer.ts index 7bc6a444bea7..e153cf7fa91f 100644 --- a/lib/vscode/extensions/html-language-features/server/src/htmlServer.ts +++ b/extensions/html-language-features/server/src/htmlServer.ts @@ -5,9 +5,9 @@ import { Connection, TextDocuments, InitializeParams, InitializeResult, RequestType, - DocumentRangeFormattingRequest, Disposable, DocumentSelector, TextDocumentPositionParams, ServerCapabilities, + DocumentRangeFormattingRequest, Disposable, TextDocumentPositionParams, ServerCapabilities, ConfigurationRequest, ConfigurationParams, DidChangeWorkspaceFoldersNotification, - DocumentColorRequest, ColorPresentationRequest, TextDocumentSyncKind, NotificationType, RequestType0 + DocumentColorRequest, ColorPresentationRequest, TextDocumentSyncKind, NotificationType, RequestType0, DocumentFormattingRequest, FormattingOptions, TextEdit } from 'vscode-languageserver'; import { getLanguageModes, LanguageModes, Settings, TextDocument, Position, Diagnostic, WorkspaceFolder, ColorInformation, @@ -152,7 +152,8 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) completionProvider: clientSnippetSupport ? { resolveProvider: true, triggerCharacters: ['.', ':', '<', '"', '=', '/'] } : undefined, hoverProvider: true, documentHighlightProvider: true, - documentRangeFormattingProvider: initializationOptions?.provideFormatter === true, + documentRangeFormattingProvider: params.initializationOptions?.provideFormatter === true, + documentFormattingProvider: params.initializationOptions?.provideFormatter === true, documentLinkProvider: { resolveProvider: false }, documentSymbolProvider: true, definitionProvider: true, @@ -188,7 +189,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) } }); - let formatterRegistration: Thenable | null = null; + let formatterRegistrations: Thenable[] | null = null; // The settings have changed. Is send on server activation as well. connection.onDidChangeConfiguration((change) => { @@ -200,13 +201,16 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) if (dynamicFormatterRegistration) { const enableFormatter = globalSettings && globalSettings.html && globalSettings.html.format && globalSettings.html.format.enable; if (enableFormatter) { - if (!formatterRegistration) { - const documentSelector: DocumentSelector = [{ language: 'html' }, { language: 'handlebars' }]; - formatterRegistration = connection.client.register(DocumentRangeFormattingRequest.type, { documentSelector }); + if (!formatterRegistrations) { + const documentSelector = [{ language: 'html' }, { language: 'handlebars' }]; + formatterRegistrations = [ + connection.client.register(DocumentRangeFormattingRequest.type, { documentSelector }), + connection.client.register(DocumentFormattingRequest.type, { documentSelector }) + ]; } - } else if (formatterRegistration) { - formatterRegistration.then(r => r.dispose()); - formatterRegistration = null; + } else if (formatterRegistrations) { + formatterRegistrations.forEach(p => p.then(r => r.dispose())); + formatterRegistrations = null; } } }); @@ -381,21 +385,27 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) }, null, `Error while computing signature help for ${signatureHelpParms.textDocument.uri}`, token); }); - connection.onDocumentRangeFormatting(async (formatParams, token) => { - return runSafe(async () => { - const document = documents.get(formatParams.textDocument.uri); - if (document) { - let settings = await getDocumentSettings(document, () => true); - if (!settings) { - settings = globalSettings; - } - const unformattedTags: string = settings && settings.html && settings.html.format && settings.html.format.unformatted || ''; - const enabledModes = { css: !unformattedTags.match(/\bstyle\b/), javascript: !unformattedTags.match(/\bscript\b/) }; - - return format(languageModes, document, formatParams.range, formatParams.options, settings, enabledModes); + async function onFormat(textDocument: TextDocumentIdentifier, range: Range | undefined, options: FormattingOptions): Promise { + const document = documents.get(textDocument.uri); + if (document) { + let settings = await getDocumentSettings(document, () => true); + if (!settings) { + settings = globalSettings; } - return []; - }, [], `Error while formatting range for ${formatParams.textDocument.uri}`, token); + const unformattedTags: string = settings && settings.html && settings.html.format && settings.html.format.unformatted || ''; + const enabledModes = { css: !unformattedTags.match(/\bstyle\b/), javascript: !unformattedTags.match(/\bscript\b/) }; + + return format(languageModes, document, range ?? getFullRange(document), options, settings, enabledModes); + } + return []; + } + + connection.onDocumentRangeFormatting((formatParams, token) => { + return runSafe(() => onFormat(formatParams.textDocument, formatParams.range, formatParams.options), [], `Error while formatting range for ${formatParams.textDocument.uri}`, token); + }); + + connection.onDocumentFormatting((formatParams, token) => { + return runSafe(() => onFormat(formatParams.textDocument, undefined, formatParams.options), [], `Error while formatting ${formatParams.textDocument.uri}`, token); }); connection.onDocumentLinks((documentLinkParam, token) => { @@ -561,3 +571,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) // Listen on the connection connection.listen(); } + +function getFullRange(document: TextDocument): Range { + return Range.create(Position.create(0, 0), document.positionAt(document.getText().length)); +} diff --git a/lib/vscode/extensions/html-language-features/server/src/languageModelCache.ts b/extensions/html-language-features/server/src/languageModelCache.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/languageModelCache.ts rename to extensions/html-language-features/server/src/languageModelCache.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/modes/cssMode.ts b/extensions/html-language-features/server/src/modes/cssMode.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/modes/cssMode.ts rename to extensions/html-language-features/server/src/modes/cssMode.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/modes/embeddedSupport.ts b/extensions/html-language-features/server/src/modes/embeddedSupport.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/modes/embeddedSupport.ts rename to extensions/html-language-features/server/src/modes/embeddedSupport.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/modes/formatting.ts b/extensions/html-language-features/server/src/modes/formatting.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/modes/formatting.ts rename to extensions/html-language-features/server/src/modes/formatting.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/modes/htmlFolding.ts b/extensions/html-language-features/server/src/modes/htmlFolding.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/modes/htmlFolding.ts rename to extensions/html-language-features/server/src/modes/htmlFolding.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/modes/htmlMode.ts b/extensions/html-language-features/server/src/modes/htmlMode.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/modes/htmlMode.ts rename to extensions/html-language-features/server/src/modes/htmlMode.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/modes/javascriptLibs.ts b/extensions/html-language-features/server/src/modes/javascriptLibs.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/modes/javascriptLibs.ts rename to extensions/html-language-features/server/src/modes/javascriptLibs.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/modes/javascriptMode.ts b/extensions/html-language-features/server/src/modes/javascriptMode.ts similarity index 99% rename from lib/vscode/extensions/html-language-features/server/src/modes/javascriptMode.ts rename to extensions/html-language-features/server/src/modes/javascriptMode.ts index 01e0b381d112..e6571c5bac0a 100644 --- a/lib/vscode/extensions/html-language-features/server/src/modes/javascriptMode.ts +++ b/extensions/html-language-features/server/src/modes/javascriptMode.ts @@ -127,7 +127,6 @@ export function getJavaScriptMode(documentRegions: LanguageModelCache { const jsDocument = jsDocuments.get(document); const jsLanguageService = await host.getLanguageService(jsDocument); - // @ts-expect-error until 4.3 protocol update let details = jsLanguageService.getCompletionEntryDetails(jsDocument.uri, item.data.offset, item.label, undefined, undefined, undefined, undefined); if (details) { item.detail = ts.displayPartsToString(details.displayParts); diff --git a/lib/vscode/extensions/html-language-features/server/src/modes/javascriptSemanticTokens.ts b/extensions/html-language-features/server/src/modes/javascriptSemanticTokens.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/modes/javascriptSemanticTokens.ts rename to extensions/html-language-features/server/src/modes/javascriptSemanticTokens.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/modes/languageModes.ts b/extensions/html-language-features/server/src/modes/languageModes.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/modes/languageModes.ts rename to extensions/html-language-features/server/src/modes/languageModes.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/modes/selectionRanges.ts b/extensions/html-language-features/server/src/modes/selectionRanges.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/modes/selectionRanges.ts rename to extensions/html-language-features/server/src/modes/selectionRanges.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/modes/semanticTokens.ts b/extensions/html-language-features/server/src/modes/semanticTokens.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/modes/semanticTokens.ts rename to extensions/html-language-features/server/src/modes/semanticTokens.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/node/htmlServerMain.ts b/extensions/html-language-features/server/src/node/htmlServerMain.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/node/htmlServerMain.ts rename to extensions/html-language-features/server/src/node/htmlServerMain.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/node/nodeFs.ts b/extensions/html-language-features/server/src/node/nodeFs.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/node/nodeFs.ts rename to extensions/html-language-features/server/src/node/nodeFs.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/requests.ts b/extensions/html-language-features/server/src/requests.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/requests.ts rename to extensions/html-language-features/server/src/requests.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/test/completions.test.ts b/extensions/html-language-features/server/src/test/completions.test.ts similarity index 95% rename from lib/vscode/extensions/html-language-features/server/src/test/completions.test.ts rename to extensions/html-language-features/server/src/test/completions.test.ts index 0371a2f74cd0..aaf3cb5ec6b8 100644 --- a/lib/vscode/extensions/html-language-features/server/src/test/completions.test.ts +++ b/extensions/html-language-features/server/src/test/completions.test.ts @@ -23,24 +23,24 @@ export function assertCompletion(completions: CompletionList, expected: ItemDesc return completion.label === expected.label; }); if (expected.notAvailable) { - assert.equal(matches.length, 0, `${expected.label} should not existing is results`); + assert.strictEqual(matches.length, 0, `${expected.label} should not existing is results`); return; } - assert.equal(matches.length, 1, `${expected.label} should only existing once: Actual: ${completions.items.map(c => c.label).join(', ')}`); + assert.strictEqual(matches.length, 1, `${expected.label} should only existing once: Actual: ${completions.items.map(c => c.label).join(', ')}`); let match = matches[0]; if (expected.documentation) { - assert.equal(match.documentation, expected.documentation); + assert.strictEqual(match.documentation, expected.documentation); } if (expected.kind) { - assert.equal(match.kind, expected.kind); + assert.strictEqual(match.kind, expected.kind); } if (expected.resultText && match.textEdit) { const edit = TextEdit.is(match.textEdit) ? match.textEdit : TextEdit.replace(match.textEdit.replace, match.textEdit.newText); - assert.equal(TextDocument.applyEdits(document, [edit]), expected.resultText); + assert.strictEqual(TextDocument.applyEdits(document, [edit]), expected.resultText); } if (expected.command) { - assert.deepEqual(match.command, expected.command); + assert.deepStrictEqual(match.command, expected.command); } } @@ -65,7 +65,7 @@ export async function testCompletionFor(value: string, expected: { count?: numbe let list = await mode.doComplete!(document, position, context); if (expected.count) { - assert.equal(list.items.length, expected.count); + assert.strictEqual(list.items.length, expected.count); } if (expected.items) { for (let item of expected.items) { diff --git a/lib/vscode/extensions/html-language-features/server/src/test/documentContext.test.ts b/extensions/html-language-features/server/src/test/documentContext.test.ts similarity index 62% rename from lib/vscode/extensions/html-language-features/server/src/test/documentContext.test.ts rename to extensions/html-language-features/server/src/test/documentContext.test.ts index 612c0063c058..29ba68809723 100644 --- a/lib/vscode/extensions/html-language-features/server/src/test/documentContext.test.ts +++ b/extensions/html-language-features/server/src/test/documentContext.test.ts @@ -12,9 +12,9 @@ suite('HTML Document Context', () => { const rootFolders = [{ name: '', uri: 'file:///users/test/' }]; let context = getDocumentContext(docURI, rootFolders); - assert.equal(context.resolveReference('/', docURI), 'file:///users/test/'); - assert.equal(context.resolveReference('/message.html', docURI), 'file:///users/test/message.html'); - assert.equal(context.resolveReference('message.html', docURI), 'file:///users/test/folder/message.html'); - assert.equal(context.resolveReference('message.html', 'file:///users/test/'), 'file:///users/test/message.html'); + assert.strictEqual(context.resolveReference('/', docURI), 'file:///users/test/'); + assert.strictEqual(context.resolveReference('/message.html', docURI), 'file:///users/test/message.html'); + assert.strictEqual(context.resolveReference('message.html', docURI), 'file:///users/test/folder/message.html'); + assert.strictEqual(context.resolveReference('message.html', 'file:///users/test/'), 'file:///users/test/message.html'); }); -}); \ No newline at end of file +}); diff --git a/lib/vscode/extensions/html-language-features/server/src/test/embedded.test.ts b/extensions/html-language-features/server/src/test/embedded.test.ts similarity index 98% rename from lib/vscode/extensions/html-language-features/server/src/test/embedded.test.ts rename to extensions/html-language-features/server/src/test/embedded.test.ts index 525d5a59c112..005ecf0864c3 100644 --- a/lib/vscode/extensions/html-language-features/server/src/test/embedded.test.ts +++ b/extensions/html-language-features/server/src/test/embedded.test.ts @@ -23,7 +23,7 @@ suite('HTML Embedded Support', () => { const docRegions = embeddedSupport.getDocumentRegions(htmlLanguageService, document); const languageId = docRegions.getLanguageAtPosition(position); - assert.equal(languageId, expectedLanguageId); + assert.strictEqual(languageId, expectedLanguageId); } function assertEmbeddedLanguageContent(value: string, languageId: string, expectedContent: string): void { @@ -31,7 +31,7 @@ suite('HTML Embedded Support', () => { const docRegions = embeddedSupport.getDocumentRegions(htmlLanguageService, document); const content = docRegions.getEmbeddedDocument(languageId); - assert.equal(content.getText(), expectedContent); + assert.strictEqual(content.getText(), expectedContent); } test('Styles', function (): any { diff --git a/lib/vscode/extensions/html-language-features/server/src/test/fixtures/expected/19813-4spaces.html b/extensions/html-language-features/server/src/test/fixtures/expected/19813-4spaces.html similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/test/fixtures/expected/19813-4spaces.html rename to extensions/html-language-features/server/src/test/fixtures/expected/19813-4spaces.html diff --git a/lib/vscode/extensions/html-language-features/server/src/test/fixtures/expected/19813-tab.html b/extensions/html-language-features/server/src/test/fixtures/expected/19813-tab.html similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/test/fixtures/expected/19813-tab.html rename to extensions/html-language-features/server/src/test/fixtures/expected/19813-tab.html diff --git a/lib/vscode/extensions/html-language-features/server/src/test/fixtures/expected/19813.html b/extensions/html-language-features/server/src/test/fixtures/expected/19813.html similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/test/fixtures/expected/19813.html rename to extensions/html-language-features/server/src/test/fixtures/expected/19813.html diff --git a/lib/vscode/extensions/html-language-features/server/src/test/fixtures/expected/21634.html b/extensions/html-language-features/server/src/test/fixtures/expected/21634.html similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/test/fixtures/expected/21634.html rename to extensions/html-language-features/server/src/test/fixtures/expected/21634.html diff --git a/lib/vscode/extensions/html-language-features/server/src/test/fixtures/inputs/19813.html b/extensions/html-language-features/server/src/test/fixtures/inputs/19813.html similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/test/fixtures/inputs/19813.html rename to extensions/html-language-features/server/src/test/fixtures/inputs/19813.html diff --git a/lib/vscode/extensions/html-language-features/server/src/test/fixtures/inputs/21634.html b/extensions/html-language-features/server/src/test/fixtures/inputs/21634.html similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/test/fixtures/inputs/21634.html rename to extensions/html-language-features/server/src/test/fixtures/inputs/21634.html diff --git a/lib/vscode/extensions/html-language-features/server/src/test/folding.test.ts b/extensions/html-language-features/server/src/test/folding.test.ts similarity index 99% rename from lib/vscode/extensions/html-language-features/server/src/test/folding.test.ts rename to extensions/html-language-features/server/src/test/folding.test.ts index 693a74420f08..7bf90bb10d54 100644 --- a/lib/vscode/extensions/html-language-features/server/src/test/folding.test.ts +++ b/extensions/html-language-features/server/src/test/folding.test.ts @@ -30,7 +30,7 @@ async function assertRanges(lines: string[], expected: ExpectedIndentRange[], me actualRanges[i] = r(actual[i].startLine, actual[i].endLine, actual[i].kind); } actualRanges = actualRanges.sort((r1, r2) => r1.startLine - r2.startLine); - assert.deepEqual(actualRanges, expected, message); + assert.deepStrictEqual(actualRanges, expected, message); } function r(startLine: number, endLine: number, kind?: string): ExpectedIndentRange { diff --git a/lib/vscode/extensions/html-language-features/server/src/test/formatting.test.ts b/extensions/html-language-features/server/src/test/formatting.test.ts similarity index 99% rename from lib/vscode/extensions/html-language-features/server/src/test/formatting.test.ts rename to extensions/html-language-features/server/src/test/formatting.test.ts index d7c922c736a6..107001c7c007 100644 --- a/lib/vscode/extensions/html-language-features/server/src/test/formatting.test.ts +++ b/extensions/html-language-features/server/src/test/formatting.test.ts @@ -41,7 +41,7 @@ suite('HTML Embedded Formatting', () => { let result = await format(languageModes, document, range, formatOptions, undefined, { css: true, javascript: true }); let actual = TextDocument.applyEdits(document, result); - assert.equal(actual, expected, message); + assert.strictEqual(actual, expected, message); } async function assertFormatWithFixture(fixtureName: string, expectedPath: string, options?: any, formatOptions?: FormattingOptions): Promise { diff --git a/lib/vscode/extensions/html-language-features/server/src/test/pathCompletionFixtures/.foo.js b/extensions/html-language-features/server/src/test/pathCompletionFixtures/.foo.js similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/test/pathCompletionFixtures/.foo.js rename to extensions/html-language-features/server/src/test/pathCompletionFixtures/.foo.js diff --git a/lib/vscode/extensions/html-language-features/server/src/test/pathCompletionFixtures/about/about.css b/extensions/html-language-features/server/src/test/pathCompletionFixtures/about/about.css similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/test/pathCompletionFixtures/about/about.css rename to extensions/html-language-features/server/src/test/pathCompletionFixtures/about/about.css diff --git a/lib/vscode/extensions/html-language-features/server/src/test/pathCompletionFixtures/about/about.html b/extensions/html-language-features/server/src/test/pathCompletionFixtures/about/about.html similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/test/pathCompletionFixtures/about/about.html rename to extensions/html-language-features/server/src/test/pathCompletionFixtures/about/about.html diff --git a/lib/vscode/extensions/html-language-features/server/src/test/pathCompletionFixtures/about/media/icon.pic b/extensions/html-language-features/server/src/test/pathCompletionFixtures/about/media/icon.pic similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/test/pathCompletionFixtures/about/media/icon.pic rename to extensions/html-language-features/server/src/test/pathCompletionFixtures/about/media/icon.pic diff --git a/lib/vscode/extensions/html-language-features/server/src/test/pathCompletionFixtures/index.html b/extensions/html-language-features/server/src/test/pathCompletionFixtures/index.html similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/test/pathCompletionFixtures/index.html rename to extensions/html-language-features/server/src/test/pathCompletionFixtures/index.html diff --git a/lib/vscode/extensions/html-language-features/server/src/test/pathCompletionFixtures/src/feature.js b/extensions/html-language-features/server/src/test/pathCompletionFixtures/src/feature.js similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/test/pathCompletionFixtures/src/feature.js rename to extensions/html-language-features/server/src/test/pathCompletionFixtures/src/feature.js diff --git a/lib/vscode/extensions/html-language-features/server/src/test/pathCompletionFixtures/src/test.js b/extensions/html-language-features/server/src/test/pathCompletionFixtures/src/test.js similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/test/pathCompletionFixtures/src/test.js rename to extensions/html-language-features/server/src/test/pathCompletionFixtures/src/test.js diff --git a/lib/vscode/extensions/html-language-features/server/src/test/rename.test.ts b/extensions/html-language-features/server/src/test/rename.test.ts similarity index 97% rename from lib/vscode/extensions/html-language-features/server/src/test/rename.test.ts rename to extensions/html-language-features/server/src/test/rename.test.ts index 2705b56fdf87..edebe68d7b26 100644 --- a/lib/vscode/extensions/html-language-features/server/src/test/rename.test.ts +++ b/extensions/html-language-features/server/src/test/rename.test.ts @@ -34,7 +34,7 @@ async function testRename(value: string, newName: string, expectedDocContent: st } const newDocContent = TextDocument.applyEdits(document, edits); - assert.equal(newDocContent, expectedDocContent, `Expected: ${expectedDocContent}\nActual: ${newDocContent}`); + assert.strictEqual(newDocContent, expectedDocContent, `Expected: ${expectedDocContent}\nActual: ${newDocContent}`); } else { assert.fail('should have javascriptMode but no') } diff --git a/lib/vscode/extensions/html-language-features/server/src/test/selectionRanges.test.ts b/extensions/html-language-features/server/src/test/selectionRanges.test.ts similarity index 95% rename from lib/vscode/extensions/html-language-features/server/src/test/selectionRanges.test.ts rename to extensions/html-language-features/server/src/test/selectionRanges.test.ts index 9f9937bcaf73..c5166c7bb453 100644 --- a/lib/vscode/extensions/html-language-features/server/src/test/selectionRanges.test.ts +++ b/extensions/html-language-features/server/src/test/selectionRanges.test.ts @@ -5,7 +5,7 @@ import 'mocha'; import * as assert from 'assert'; -import { getLanguageModes, ClientCapabilities, TextDocument, SelectionRange} from '../modes/languageModes'; +import { getLanguageModes, ClientCapabilities, TextDocument, SelectionRange } from '../modes/languageModes'; import { getSelectionRanges } from '../modes/selectionRanges'; import { getNodeFSRequestService } from '../node/nodeFs'; @@ -23,7 +23,7 @@ async function assertRanges(content: string, expected: (number | string)[][]): P const document = TextDocument.create('test://foo.html', 'html', 1, content); const actualRanges = await getSelectionRanges(languageModes, document, [document.positionAt(offset)]); - assert.equal(actualRanges.length, 1); + assert.strictEqual(actualRanges.length, 1); const offsetPairs: [number, string][] = []; let curr: SelectionRange | undefined = actualRanges[0]; while (curr) { @@ -32,7 +32,7 @@ async function assertRanges(content: string, expected: (number | string)[][]): P } message += `${JSON.stringify(offsetPairs)}\n but should give:\n${JSON.stringify(expected)}\n`; - assert.deepEqual(offsetPairs, expected, message); + assert.deepStrictEqual(offsetPairs, expected, message); } suite('HTML SelectionRange', () => { diff --git a/lib/vscode/extensions/html-language-features/server/src/test/semanticTokens.test.ts b/extensions/html-language-features/server/src/test/semanticTokens.test.ts similarity index 99% rename from lib/vscode/extensions/html-language-features/server/src/test/semanticTokens.test.ts rename to extensions/html-language-features/server/src/test/semanticTokens.test.ts index 548ce7d84586..3cf242df18f1 100644 --- a/lib/vscode/extensions/html-language-features/server/src/test/semanticTokens.test.ts +++ b/extensions/html-language-features/server/src/test/semanticTokens.test.ts @@ -40,7 +40,7 @@ async function assertTokens(lines: string[], expected: ExpectedToken[], ranges?: lastLine = line; lastCharacter = character; } - assert.deepEqual(actualRanges, expected, message); + assert.deepStrictEqual(actualRanges, expected, message); } function t(startLine: number, character: number, length: number, tokenClassifiction: string): ExpectedToken { diff --git a/lib/vscode/extensions/html-language-features/server/src/test/words.test.ts b/extensions/html-language-features/server/src/test/words.test.ts similarity index 95% rename from lib/vscode/extensions/html-language-features/server/src/test/words.test.ts rename to extensions/html-language-features/server/src/test/words.test.ts index e094bfb4251b..f86ae969c666 100644 --- a/lib/vscode/extensions/html-language-features/server/src/test/words.test.ts +++ b/extensions/html-language-features/server/src/test/words.test.ts @@ -16,7 +16,7 @@ suite('HTML Words', () => { let actualRange = words.getWordAtText(value, offset, wordRegex); assert(actualRange.start <= offset); assert(actualRange.start + actualRange.length >= offset); - assert.equal(value.substr(actualRange.start, actualRange.length), expected); + assert.strictEqual(value.substr(actualRange.start, actualRange.length), expected); } @@ -41,4 +41,4 @@ suite('HTML Words', () => { assertWord('console.log("hello");\n\r |var x1 = new F(a, b);', 'var'); }); -}); \ No newline at end of file +}); diff --git a/lib/vscode/extensions/html-language-features/server/src/utils/arrays.ts b/extensions/html-language-features/server/src/utils/arrays.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/utils/arrays.ts rename to extensions/html-language-features/server/src/utils/arrays.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/utils/documentContext.ts b/extensions/html-language-features/server/src/utils/documentContext.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/utils/documentContext.ts rename to extensions/html-language-features/server/src/utils/documentContext.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/utils/positions.ts b/extensions/html-language-features/server/src/utils/positions.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/utils/positions.ts rename to extensions/html-language-features/server/src/utils/positions.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/utils/runner.ts b/extensions/html-language-features/server/src/utils/runner.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/utils/runner.ts rename to extensions/html-language-features/server/src/utils/runner.ts diff --git a/lib/vscode/extensions/html-language-features/server/src/utils/strings.ts b/extensions/html-language-features/server/src/utils/strings.ts similarity index 100% rename from lib/vscode/extensions/html-language-features/server/src/utils/strings.ts rename to extensions/html-language-features/server/src/utils/strings.ts diff --git a/lib/vscode/extensions/html-language-features/server/test/index.js b/extensions/html-language-features/server/test/index.js similarity index 100% rename from lib/vscode/extensions/html-language-features/server/test/index.js rename to extensions/html-language-features/server/test/index.js diff --git a/lib/vscode/extensions/html-language-features/server/tsconfig.json b/extensions/html-language-features/server/tsconfig.json similarity index 100% rename from lib/vscode/extensions/html-language-features/server/tsconfig.json rename to extensions/html-language-features/server/tsconfig.json diff --git a/lib/vscode/extensions/html-language-features/server/yarn.lock b/extensions/html-language-features/server/yarn.lock similarity index 79% rename from lib/vscode/extensions/html-language-features/server/yarn.lock rename to extensions/html-language-features/server/yarn.lock index ca035d1c79b3..5a578b7ea202 100644 --- a/lib/vscode/extensions/html-language-features/server/yarn.lock +++ b/extensions/html-language-features/server/yarn.lock @@ -7,25 +7,25 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.0.tgz#3eb56d13a1de1d347ecb1957c6860c911704bc44" integrity sha512-/Sge3BymXo4lKc31C8OINJgXLaw+7vL1/L1pGiBNpGrBiT8FQiaFpSYV0uhTaG4y78vcMBTMFsWaHDvuD+xGzQ== -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== -vscode-css-languageservice@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-5.1.1.tgz#d68a22ea0b34a8356c169cafc7d32564c2ff6e87" - integrity sha512-QW0oe/g2y5E2AbVqY7FJNr2Q8uHiAHNSFpptI6xB8Y0KgzVKppOcIVrgmBNzXhFp9IswAwptkdqr8ExSJbqPkQ== +vscode-css-languageservice@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-5.1.3.tgz#a7b2f21ed48842af5d9a98223bcae09e33d707d5" + integrity sha512-c8xiUhrDBNG6iS92FEE+K3IWOHAqVvzsqjjLSaXHyF5Qdn/6VhUweGNjtZ2CBSfs+Vkmz7pJzLQ7Io1x5deumA== dependencies: vscode-languageserver-textdocument "^1.0.1" vscode-languageserver-types "^3.16.0" vscode-nls "^5.0.0" vscode-uri "^3.0.2" -vscode-html-languageservice@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-4.0.3.tgz#3b7e7d3cfee75d47da0181dd638b5f459456a913" - integrity sha512-34KPIgRHVInT+TiFNmfiPFDrUAOOLuySNP2h0pMxBu1ObAbSixSqB3BMQFxIHz9hrGd3X0DEvi5YkobDxs4rWw== +vscode-html-languageservice@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-4.0.4.tgz#f171f663e83037c8a5c5f4552a6b4771c1a9f017" + integrity sha512-WHXpLfj5NlCAgppDa6n5gQjW1YTTt72MVs0lkkuGQwTb5Sfdq8UhMjLDT82MuzqwV0QvmSBWlUbreGodzXleLg== dependencies: vscode-languageserver-textdocument "^1.0.1" vscode-languageserver-types "^3.16.0" diff --git a/lib/vscode/extensions/html-language-features/yarn.lock b/extensions/html-language-features/yarn.lock similarity index 96% rename from lib/vscode/extensions/html-language-features/yarn.lock rename to extensions/html-language-features/yarn.lock index f538d16e7d46..d14954d241fd 100644 --- a/lib/vscode/extensions/html-language-features/yarn.lock +++ b/extensions/html-language-features/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== applicationinsights@1.7.4: version "1.7.4" diff --git a/lib/vscode/extensions/html/.vscodeignore b/extensions/html/.vscodeignore similarity index 100% rename from lib/vscode/extensions/html/.vscodeignore rename to extensions/html/.vscodeignore diff --git a/lib/vscode/extensions/html/build/update-grammar.js b/extensions/html/build/update-grammar.js similarity index 100% rename from lib/vscode/extensions/html/build/update-grammar.js rename to extensions/html/build/update-grammar.js diff --git a/lib/vscode/extensions/html/cgmanifest.json b/extensions/html/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/html/cgmanifest.json rename to extensions/html/cgmanifest.json diff --git a/lib/vscode/extensions/html/language-configuration.json b/extensions/html/language-configuration.json similarity index 100% rename from lib/vscode/extensions/html/language-configuration.json rename to extensions/html/language-configuration.json diff --git a/lib/vscode/extensions/html/package.json b/extensions/html/package.json similarity index 100% rename from lib/vscode/extensions/html/package.json rename to extensions/html/package.json diff --git a/lib/vscode/extensions/html/package.nls.json b/extensions/html/package.nls.json similarity index 100% rename from lib/vscode/extensions/html/package.nls.json rename to extensions/html/package.nls.json diff --git a/lib/vscode/extensions/html/syntaxes/html-derivative.tmLanguage.json b/extensions/html/syntaxes/html-derivative.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/html/syntaxes/html-derivative.tmLanguage.json rename to extensions/html/syntaxes/html-derivative.tmLanguage.json diff --git a/lib/vscode/extensions/html/syntaxes/html.tmLanguage.json b/extensions/html/syntaxes/html.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/html/syntaxes/html.tmLanguage.json rename to extensions/html/syntaxes/html.tmLanguage.json diff --git a/lib/vscode/extensions/html/yarn.lock b/extensions/html/yarn.lock similarity index 100% rename from lib/vscode/extensions/html/yarn.lock rename to extensions/html/yarn.lock diff --git a/lib/vscode/extensions/image-preview/.vscodeignore b/extensions/image-preview/.vscodeignore similarity index 100% rename from lib/vscode/extensions/image-preview/.vscodeignore rename to extensions/image-preview/.vscodeignore diff --git a/lib/vscode/extensions/image-preview/README.md b/extensions/image-preview/README.md similarity index 100% rename from lib/vscode/extensions/image-preview/README.md rename to extensions/image-preview/README.md diff --git a/lib/vscode/extensions/image-preview/extension-browser.webpack.config.js b/extensions/image-preview/extension-browser.webpack.config.js similarity index 100% rename from lib/vscode/extensions/image-preview/extension-browser.webpack.config.js rename to extensions/image-preview/extension-browser.webpack.config.js diff --git a/lib/vscode/extensions/image-preview/extension.webpack.config.js b/extensions/image-preview/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/image-preview/extension.webpack.config.js rename to extensions/image-preview/extension.webpack.config.js diff --git a/lib/vscode/extensions/image-preview/icon.png b/extensions/image-preview/icon.png similarity index 100% rename from lib/vscode/extensions/image-preview/icon.png rename to extensions/image-preview/icon.png diff --git a/lib/vscode/extensions/image-preview/icon.svg b/extensions/image-preview/icon.svg similarity index 100% rename from lib/vscode/extensions/image-preview/icon.svg rename to extensions/image-preview/icon.svg diff --git a/lib/vscode/extensions/image-preview/media/loading-dark.svg b/extensions/image-preview/media/loading-dark.svg similarity index 100% rename from lib/vscode/extensions/image-preview/media/loading-dark.svg rename to extensions/image-preview/media/loading-dark.svg diff --git a/lib/vscode/extensions/image-preview/media/loading-hc.svg b/extensions/image-preview/media/loading-hc.svg similarity index 100% rename from lib/vscode/extensions/image-preview/media/loading-hc.svg rename to extensions/image-preview/media/loading-hc.svg diff --git a/lib/vscode/extensions/image-preview/media/loading.svg b/extensions/image-preview/media/loading.svg similarity index 100% rename from lib/vscode/extensions/image-preview/media/loading.svg rename to extensions/image-preview/media/loading.svg diff --git a/lib/vscode/extensions/image-preview/media/main.css b/extensions/image-preview/media/main.css similarity index 100% rename from lib/vscode/extensions/image-preview/media/main.css rename to extensions/image-preview/media/main.css diff --git a/lib/vscode/extensions/image-preview/media/main.js b/extensions/image-preview/media/main.js similarity index 100% rename from lib/vscode/extensions/image-preview/media/main.js rename to extensions/image-preview/media/main.js diff --git a/lib/vscode/extensions/image-preview/package.json b/extensions/image-preview/package.json similarity index 100% rename from lib/vscode/extensions/image-preview/package.json rename to extensions/image-preview/package.json diff --git a/lib/vscode/extensions/image-preview/package.nls.json b/extensions/image-preview/package.nls.json similarity index 100% rename from lib/vscode/extensions/image-preview/package.nls.json rename to extensions/image-preview/package.nls.json diff --git a/lib/vscode/extensions/image-preview/src/binarySizeStatusBarEntry.ts b/extensions/image-preview/src/binarySizeStatusBarEntry.ts similarity index 89% rename from lib/vscode/extensions/image-preview/src/binarySizeStatusBarEntry.ts rename to extensions/image-preview/src/binarySizeStatusBarEntry.ts index 0c983d37cd21..ce375fc19b80 100644 --- a/lib/vscode/extensions/image-preview/src/binarySizeStatusBarEntry.ts +++ b/extensions/image-preview/src/binarySizeStatusBarEntry.ts @@ -39,12 +39,7 @@ class BinarySize { export class BinarySizeStatusBarEntry extends PreviewStatusBarEntry { constructor() { - super({ - id: 'imagePreview.binarySize', - name: localize('sizeStatusBar.name', "Image Binary Size"), - alignment: vscode.StatusBarAlignment.Right, - priority: 100, - }); + super('status.imagePreview.binarySize', localize('sizeStatusBar.name', "Image Binary Size"), vscode.StatusBarAlignment.Right, 100); } public show(owner: string, size: number | undefined) { diff --git a/lib/vscode/extensions/image-preview/src/dispose.ts b/extensions/image-preview/src/dispose.ts similarity index 100% rename from lib/vscode/extensions/image-preview/src/dispose.ts rename to extensions/image-preview/src/dispose.ts diff --git a/lib/vscode/extensions/image-preview/src/extension.ts b/extensions/image-preview/src/extension.ts similarity index 100% rename from lib/vscode/extensions/image-preview/src/extension.ts rename to extensions/image-preview/src/extension.ts diff --git a/lib/vscode/extensions/image-preview/src/ownedStatusBarEntry.ts b/extensions/image-preview/src/ownedStatusBarEntry.ts similarity index 85% rename from lib/vscode/extensions/image-preview/src/ownedStatusBarEntry.ts rename to extensions/image-preview/src/ownedStatusBarEntry.ts index 51c9e25503cf..31165f67d69d 100644 --- a/lib/vscode/extensions/image-preview/src/ownedStatusBarEntry.ts +++ b/extensions/image-preview/src/ownedStatusBarEntry.ts @@ -11,9 +11,10 @@ export abstract class PreviewStatusBarEntry extends Disposable { protected readonly entry: vscode.StatusBarItem; - constructor(options: vscode.StatusBarItemOptions) { + constructor(id: string, name: string, alignment: vscode.StatusBarAlignment, priority: number) { super(); - this.entry = this._register(vscode.window.createStatusBarItem(options)); + this.entry = this._register(vscode.window.createStatusBarItem(id, alignment, priority)); + this.entry.name = name; } protected showItem(owner: string, text: string) { diff --git a/lib/vscode/extensions/image-preview/src/preview.ts b/extensions/image-preview/src/preview.ts similarity index 100% rename from lib/vscode/extensions/image-preview/src/preview.ts rename to extensions/image-preview/src/preview.ts diff --git a/lib/vscode/extensions/image-preview/src/sizeStatusBarEntry.ts b/extensions/image-preview/src/sizeStatusBarEntry.ts similarity index 77% rename from lib/vscode/extensions/image-preview/src/sizeStatusBarEntry.ts rename to extensions/image-preview/src/sizeStatusBarEntry.ts index e74eea0fe603..68e5c34d2325 100644 --- a/lib/vscode/extensions/image-preview/src/sizeStatusBarEntry.ts +++ b/extensions/image-preview/src/sizeStatusBarEntry.ts @@ -12,12 +12,7 @@ const localize = nls.loadMessageBundle(); export class SizeStatusBarEntry extends PreviewStatusBarEntry { constructor() { - super({ - id: 'imagePreview.size', - name: localize('sizeStatusBar.name', "Image Size"), - alignment: vscode.StatusBarAlignment.Right, - priority: 101 /* to the left of editor status (100) */, - }); + super('status.imagePreview.size', localize('sizeStatusBar.name', "Image Size"), vscode.StatusBarAlignment.Right, 101 /* to the left of editor status (100) */); } public show(owner: string, text: string) { diff --git a/lib/vscode/extensions/image-preview/src/typings/ref.d.ts b/extensions/image-preview/src/typings/ref.d.ts similarity index 100% rename from lib/vscode/extensions/image-preview/src/typings/ref.d.ts rename to extensions/image-preview/src/typings/ref.d.ts diff --git a/lib/vscode/extensions/image-preview/src/zoomStatusBarEntry.ts b/extensions/image-preview/src/zoomStatusBarEntry.ts similarity index 89% rename from lib/vscode/extensions/image-preview/src/zoomStatusBarEntry.ts rename to extensions/image-preview/src/zoomStatusBarEntry.ts index 18adc19d6d2b..a4fcdc2b604c 100644 --- a/lib/vscode/extensions/image-preview/src/zoomStatusBarEntry.ts +++ b/extensions/image-preview/src/zoomStatusBarEntry.ts @@ -19,12 +19,7 @@ export class ZoomStatusBarEntry extends OwnedStatusBarEntry { public readonly onDidChangeScale = this._onDidChangeScale.event; constructor() { - super({ - id: 'imagePreview.zoom', - name: localize('zoomStatusBar.name', "Image Zoom"), - alignment: vscode.StatusBarAlignment.Right, - priority: 102 /* to the left of editor size entry (101) */, - }); + super('status.imagePreview.zoom', localize('zoomStatusBar.name', "Image Zoom"), vscode.StatusBarAlignment.Right, 102 /* to the left of editor size entry (101) */); this._register(vscode.commands.registerCommand(selectZoomLevelCommandId, async () => { type MyPickItem = vscode.QuickPickItem & { scale: Scale }; diff --git a/lib/vscode/extensions/image-preview/tsconfig.json b/extensions/image-preview/tsconfig.json similarity index 100% rename from lib/vscode/extensions/image-preview/tsconfig.json rename to extensions/image-preview/tsconfig.json diff --git a/lib/vscode/extensions/image-preview/yarn.lock b/extensions/image-preview/yarn.lock similarity index 100% rename from lib/vscode/extensions/image-preview/yarn.lock rename to extensions/image-preview/yarn.lock diff --git a/lib/vscode/extensions/ini/.vscodeignore b/extensions/ini/.vscodeignore similarity index 100% rename from lib/vscode/extensions/ini/.vscodeignore rename to extensions/ini/.vscodeignore diff --git a/lib/vscode/extensions/ini/cgmanifest.json b/extensions/ini/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/ini/cgmanifest.json rename to extensions/ini/cgmanifest.json diff --git a/lib/vscode/extensions/ini/ini.language-configuration.json b/extensions/ini/ini.language-configuration.json similarity index 100% rename from lib/vscode/extensions/ini/ini.language-configuration.json rename to extensions/ini/ini.language-configuration.json diff --git a/lib/vscode/extensions/ini/package.json b/extensions/ini/package.json similarity index 100% rename from lib/vscode/extensions/ini/package.json rename to extensions/ini/package.json diff --git a/lib/vscode/extensions/ini/package.nls.json b/extensions/ini/package.nls.json similarity index 100% rename from lib/vscode/extensions/ini/package.nls.json rename to extensions/ini/package.nls.json diff --git a/lib/vscode/extensions/ini/properties.language-configuration.json b/extensions/ini/properties.language-configuration.json similarity index 100% rename from lib/vscode/extensions/ini/properties.language-configuration.json rename to extensions/ini/properties.language-configuration.json diff --git a/lib/vscode/extensions/ini/syntaxes/ini.tmLanguage.json b/extensions/ini/syntaxes/ini.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/ini/syntaxes/ini.tmLanguage.json rename to extensions/ini/syntaxes/ini.tmLanguage.json diff --git a/lib/vscode/extensions/ini/yarn.lock b/extensions/ini/yarn.lock similarity index 100% rename from lib/vscode/extensions/ini/yarn.lock rename to extensions/ini/yarn.lock diff --git a/lib/vscode/extensions/jake/.vscodeignore b/extensions/jake/.vscodeignore similarity index 100% rename from lib/vscode/extensions/jake/.vscodeignore rename to extensions/jake/.vscodeignore diff --git a/lib/vscode/extensions/jake/README.md b/extensions/jake/README.md similarity index 100% rename from lib/vscode/extensions/jake/README.md rename to extensions/jake/README.md diff --git a/lib/vscode/extensions/jake/extension.webpack.config.js b/extensions/jake/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/jake/extension.webpack.config.js rename to extensions/jake/extension.webpack.config.js diff --git a/lib/vscode/extensions/jake/images/cowboy_hat.png b/extensions/jake/images/cowboy_hat.png similarity index 100% rename from lib/vscode/extensions/jake/images/cowboy_hat.png rename to extensions/jake/images/cowboy_hat.png diff --git a/lib/vscode/extensions/jake/package.json b/extensions/jake/package.json similarity index 94% rename from lib/vscode/extensions/jake/package.json rename to extensions/jake/package.json index ce19974e1057..244d12d96e56 100644 --- a/lib/vscode/extensions/jake/package.json +++ b/extensions/jake/package.json @@ -20,7 +20,7 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "^12.19.9" + "@types/node": "14.x" }, "main": "./out/main", "activationEvents": [ @@ -39,13 +39,13 @@ "title": "Jake", "properties": { "jake.autoDetect": { - "scope": "resource", + "scope": "application", "type": "string", "enum": [ "off", "on" ], - "default": "on", + "default": "off", "description": "%config.jake.autoDetect%" } } diff --git a/lib/vscode/extensions/jake/package.nls.json b/extensions/jake/package.nls.json similarity index 65% rename from lib/vscode/extensions/jake/package.nls.json rename to extensions/jake/package.nls.json index c2dfb3c3818b..e82030efcb81 100644 --- a/lib/vscode/extensions/jake/package.nls.json +++ b/extensions/jake/package.nls.json @@ -3,5 +3,5 @@ "displayName": "Jake support for VS Code", "jake.taskDefinition.type.description": "The Jake task to customize.", "jake.taskDefinition.file.description": "The Jake file that provides the task. Can be omitted.", - "config.jake.autoDetect": "Controls whether auto detection of Jake tasks is on or off. Default is on." + "config.jake.autoDetect": "Controls enablement of Jake task detection. Jake task detection can cause files in any open workspace to be executed." } diff --git a/lib/vscode/extensions/jake/src/main.ts b/extensions/jake/src/main.ts similarity index 100% rename from lib/vscode/extensions/jake/src/main.ts rename to extensions/jake/src/main.ts diff --git a/lib/vscode/extensions/jake/src/typings/refs.d.ts b/extensions/jake/src/typings/refs.d.ts similarity index 100% rename from lib/vscode/extensions/jake/src/typings/refs.d.ts rename to extensions/jake/src/typings/refs.d.ts diff --git a/lib/vscode/extensions/jake/tsconfig.json b/extensions/jake/tsconfig.json similarity index 100% rename from lib/vscode/extensions/jake/tsconfig.json rename to extensions/jake/tsconfig.json diff --git a/extensions/jake/yarn.lock b/extensions/jake/yarn.lock new file mode 100644 index 000000000000..f7a30098ef45 --- /dev/null +++ b/extensions/jake/yarn.lock @@ -0,0 +1,13 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== + +vscode-nls@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" + integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== diff --git a/lib/vscode/extensions/java/.vscodeignore b/extensions/java/.vscodeignore similarity index 100% rename from lib/vscode/extensions/java/.vscodeignore rename to extensions/java/.vscodeignore diff --git a/lib/vscode/extensions/java/cgmanifest.json b/extensions/java/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/java/cgmanifest.json rename to extensions/java/cgmanifest.json diff --git a/lib/vscode/extensions/java/language-configuration.json b/extensions/java/language-configuration.json similarity index 100% rename from lib/vscode/extensions/java/language-configuration.json rename to extensions/java/language-configuration.json diff --git a/lib/vscode/extensions/java/package.json b/extensions/java/package.json similarity index 100% rename from lib/vscode/extensions/java/package.json rename to extensions/java/package.json diff --git a/lib/vscode/extensions/java/package.nls.json b/extensions/java/package.nls.json similarity index 100% rename from lib/vscode/extensions/java/package.nls.json rename to extensions/java/package.nls.json diff --git a/lib/vscode/extensions/java/snippets/java.code-snippets b/extensions/java/snippets/java.code-snippets similarity index 100% rename from lib/vscode/extensions/java/snippets/java.code-snippets rename to extensions/java/snippets/java.code-snippets diff --git a/lib/vscode/extensions/java/syntaxes/java.tmLanguage.json b/extensions/java/syntaxes/java.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/java/syntaxes/java.tmLanguage.json rename to extensions/java/syntaxes/java.tmLanguage.json diff --git a/lib/vscode/extensions/java/yarn.lock b/extensions/java/yarn.lock similarity index 100% rename from lib/vscode/extensions/java/yarn.lock rename to extensions/java/yarn.lock diff --git a/lib/vscode/extensions/javascript/.vscodeignore b/extensions/javascript/.vscodeignore similarity index 100% rename from lib/vscode/extensions/javascript/.vscodeignore rename to extensions/javascript/.vscodeignore diff --git a/lib/vscode/extensions/javascript/cgmanifest.json b/extensions/javascript/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/javascript/cgmanifest.json rename to extensions/javascript/cgmanifest.json diff --git a/lib/vscode/extensions/javascript/javascript-language-configuration.json b/extensions/javascript/javascript-language-configuration.json similarity index 100% rename from lib/vscode/extensions/javascript/javascript-language-configuration.json rename to extensions/javascript/javascript-language-configuration.json diff --git a/lib/vscode/extensions/javascript/package.json b/extensions/javascript/package.json similarity index 100% rename from lib/vscode/extensions/javascript/package.json rename to extensions/javascript/package.json diff --git a/lib/vscode/extensions/javascript/package.nls.json b/extensions/javascript/package.nls.json similarity index 100% rename from lib/vscode/extensions/javascript/package.nls.json rename to extensions/javascript/package.nls.json diff --git a/lib/vscode/extensions/javascript/snippets/javascript.code-snippets b/extensions/javascript/snippets/javascript.code-snippets similarity index 100% rename from lib/vscode/extensions/javascript/snippets/javascript.code-snippets rename to extensions/javascript/snippets/javascript.code-snippets diff --git a/lib/vscode/extensions/javascript/syntaxes/JavaScript.tmLanguage.json b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/javascript/syntaxes/JavaScript.tmLanguage.json rename to extensions/javascript/syntaxes/JavaScript.tmLanguage.json diff --git a/lib/vscode/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json b/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json rename to extensions/javascript/syntaxes/JavaScriptReact.tmLanguage.json diff --git a/lib/vscode/extensions/javascript/syntaxes/Readme.md b/extensions/javascript/syntaxes/Readme.md similarity index 100% rename from lib/vscode/extensions/javascript/syntaxes/Readme.md rename to extensions/javascript/syntaxes/Readme.md diff --git a/lib/vscode/extensions/javascript/syntaxes/Regular Expressions (JavaScript).tmLanguage b/extensions/javascript/syntaxes/Regular Expressions (JavaScript).tmLanguage similarity index 100% rename from lib/vscode/extensions/javascript/syntaxes/Regular Expressions (JavaScript).tmLanguage rename to extensions/javascript/syntaxes/Regular Expressions (JavaScript).tmLanguage diff --git a/lib/vscode/extensions/javascript/tags-language-configuration.json b/extensions/javascript/tags-language-configuration.json similarity index 100% rename from lib/vscode/extensions/javascript/tags-language-configuration.json rename to extensions/javascript/tags-language-configuration.json diff --git a/lib/vscode/extensions/javascript/yarn.lock b/extensions/javascript/yarn.lock similarity index 100% rename from lib/vscode/extensions/javascript/yarn.lock rename to extensions/javascript/yarn.lock diff --git a/lib/vscode/extensions/json-language-features/.vscode/launch.json b/extensions/json-language-features/.vscode/launch.json similarity index 100% rename from lib/vscode/extensions/json-language-features/.vscode/launch.json rename to extensions/json-language-features/.vscode/launch.json diff --git a/lib/vscode/extensions/json-language-features/.vscode/tasks.json b/extensions/json-language-features/.vscode/tasks.json similarity index 100% rename from lib/vscode/extensions/json-language-features/.vscode/tasks.json rename to extensions/json-language-features/.vscode/tasks.json diff --git a/lib/vscode/extensions/json-language-features/.vscodeignore b/extensions/json-language-features/.vscodeignore similarity index 100% rename from lib/vscode/extensions/json-language-features/.vscodeignore rename to extensions/json-language-features/.vscodeignore diff --git a/lib/vscode/extensions/json-language-features/CONTRIBUTING.md b/extensions/json-language-features/CONTRIBUTING.md similarity index 100% rename from lib/vscode/extensions/json-language-features/CONTRIBUTING.md rename to extensions/json-language-features/CONTRIBUTING.md diff --git a/lib/vscode/extensions/json-language-features/README.md b/extensions/json-language-features/README.md similarity index 100% rename from lib/vscode/extensions/json-language-features/README.md rename to extensions/json-language-features/README.md diff --git a/lib/vscode/extensions/json-language-features/client/src/browser/jsonClientMain.ts b/extensions/json-language-features/client/src/browser/jsonClientMain.ts similarity index 100% rename from lib/vscode/extensions/json-language-features/client/src/browser/jsonClientMain.ts rename to extensions/json-language-features/client/src/browser/jsonClientMain.ts diff --git a/lib/vscode/extensions/json-language-features/client/src/jsonClient.ts b/extensions/json-language-features/client/src/jsonClient.ts similarity index 99% rename from lib/vscode/extensions/json-language-features/client/src/jsonClient.ts rename to extensions/json-language-features/client/src/jsonClient.ts index c925a9181f61..611327188efc 100644 --- a/lib/vscode/extensions/json-language-features/client/src/jsonClient.ts +++ b/extensions/json-language-features/client/src/jsonClient.ts @@ -101,12 +101,8 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua const documentSelector = ['json', 'jsonc']; - const schemaResolutionErrorStatusBarItem = window.createStatusBarItem({ - id: 'status.json.resolveError', - name: localize('json.resolveError', "JSON: Schema Resolution Error"), - alignment: StatusBarAlignment.Right, - priority: 0, - }); + const schemaResolutionErrorStatusBarItem = window.createStatusBarItem('status.json.resolveError', StatusBarAlignment.Right, 0); + schemaResolutionErrorStatusBarItem.name = localize('json.resolveError', "JSON: Schema Resolution Error"); schemaResolutionErrorStatusBarItem.text = '$(alert)'; toDispose.push(schemaResolutionErrorStatusBarItem); diff --git a/lib/vscode/extensions/json-language-features/client/src/node/jsonClientMain.ts b/extensions/json-language-features/client/src/node/jsonClientMain.ts similarity index 100% rename from lib/vscode/extensions/json-language-features/client/src/node/jsonClientMain.ts rename to extensions/json-language-features/client/src/node/jsonClientMain.ts diff --git a/lib/vscode/extensions/json-language-features/client/src/requests.ts b/extensions/json-language-features/client/src/requests.ts similarity index 100% rename from lib/vscode/extensions/json-language-features/client/src/requests.ts rename to extensions/json-language-features/client/src/requests.ts diff --git a/lib/vscode/extensions/json-language-features/client/src/typings/ref.d.ts b/extensions/json-language-features/client/src/typings/ref.d.ts similarity index 100% rename from lib/vscode/extensions/json-language-features/client/src/typings/ref.d.ts rename to extensions/json-language-features/client/src/typings/ref.d.ts diff --git a/lib/vscode/extensions/json-language-features/client/src/utils/hash.ts b/extensions/json-language-features/client/src/utils/hash.ts similarity index 100% rename from lib/vscode/extensions/json-language-features/client/src/utils/hash.ts rename to extensions/json-language-features/client/src/utils/hash.ts diff --git a/lib/vscode/extensions/json-language-features/client/tsconfig.json b/extensions/json-language-features/client/tsconfig.json similarity index 100% rename from lib/vscode/extensions/json-language-features/client/tsconfig.json rename to extensions/json-language-features/client/tsconfig.json diff --git a/lib/vscode/extensions/json-language-features/extension-browser.webpack.config.js b/extensions/json-language-features/extension-browser.webpack.config.js similarity index 100% rename from lib/vscode/extensions/json-language-features/extension-browser.webpack.config.js rename to extensions/json-language-features/extension-browser.webpack.config.js diff --git a/lib/vscode/extensions/json-language-features/extension.webpack.config.js b/extensions/json-language-features/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/json-language-features/extension.webpack.config.js rename to extensions/json-language-features/extension.webpack.config.js diff --git a/lib/vscode/extensions/json-language-features/icons/json.png b/extensions/json-language-features/icons/json.png similarity index 100% rename from lib/vscode/extensions/json-language-features/icons/json.png rename to extensions/json-language-features/icons/json.png diff --git a/lib/vscode/extensions/json-language-features/package.json b/extensions/json-language-features/package.json similarity index 99% rename from lib/vscode/extensions/json-language-features/package.json rename to extensions/json-language-features/package.json index e854c07569a7..4b832e4ebb6f 100644 --- a/lib/vscode/extensions/json-language-features/package.json +++ b/extensions/json-language-features/package.json @@ -140,7 +140,7 @@ "vscode-nls": "^5.0.0" }, "devDependencies": { - "@types/node": "^12.19.9" + "@types/node": "14.x" }, "repository": { "type": "git", diff --git a/lib/vscode/extensions/json-language-features/package.nls.json b/extensions/json-language-features/package.nls.json similarity index 100% rename from lib/vscode/extensions/json-language-features/package.nls.json rename to extensions/json-language-features/package.nls.json diff --git a/lib/vscode/extensions/json-language-features/server/.npmignore b/extensions/json-language-features/server/.npmignore similarity index 100% rename from lib/vscode/extensions/json-language-features/server/.npmignore rename to extensions/json-language-features/server/.npmignore diff --git a/lib/vscode/extensions/json-language-features/server/.vscode/launch.json b/extensions/json-language-features/server/.vscode/launch.json similarity index 100% rename from lib/vscode/extensions/json-language-features/server/.vscode/launch.json rename to extensions/json-language-features/server/.vscode/launch.json diff --git a/lib/vscode/extensions/json-language-features/server/.vscode/tasks.json b/extensions/json-language-features/server/.vscode/tasks.json similarity index 100% rename from lib/vscode/extensions/json-language-features/server/.vscode/tasks.json rename to extensions/json-language-features/server/.vscode/tasks.json diff --git a/lib/vscode/extensions/json-language-features/server/README.md b/extensions/json-language-features/server/README.md similarity index 100% rename from lib/vscode/extensions/json-language-features/server/README.md rename to extensions/json-language-features/server/README.md diff --git a/lib/vscode/extensions/json-language-features/server/bin/vscode-json-languageserver b/extensions/json-language-features/server/bin/vscode-json-languageserver similarity index 100% rename from lib/vscode/extensions/json-language-features/server/bin/vscode-json-languageserver rename to extensions/json-language-features/server/bin/vscode-json-languageserver diff --git a/lib/vscode/extensions/json-language-features/server/extension-browser.webpack.config.js b/extensions/json-language-features/server/extension-browser.webpack.config.js similarity index 100% rename from lib/vscode/extensions/json-language-features/server/extension-browser.webpack.config.js rename to extensions/json-language-features/server/extension-browser.webpack.config.js diff --git a/lib/vscode/extensions/json-language-features/server/extension.webpack.config.js b/extensions/json-language-features/server/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/json-language-features/server/extension.webpack.config.js rename to extensions/json-language-features/server/extension.webpack.config.js diff --git a/lib/vscode/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json similarity index 94% rename from lib/vscode/extensions/json-language-features/server/package.json rename to extensions/json-language-features/server/package.json index 2d841f89a75e..49926f97faed 100644 --- a/lib/vscode/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -14,13 +14,13 @@ "dependencies": { "jsonc-parser": "^3.0.0", "request-light": "^0.4.0", - "vscode-json-languageservice": "^4.1.3", + "vscode-json-languageservice": "^4.1.4", "vscode-languageserver": "^7.0.0", "vscode-uri": "^3.0.2" }, "devDependencies": { "@types/mocha": "^8.2.0", - "@types/node": "^12.19.9" + "@types/node": "14.x" }, "scripts": { "prepublishOnly": "npm run clean && npm run compile", diff --git a/lib/vscode/extensions/json-language-features/server/src/browser/jsonServerMain.ts b/extensions/json-language-features/server/src/browser/jsonServerMain.ts similarity index 100% rename from lib/vscode/extensions/json-language-features/server/src/browser/jsonServerMain.ts rename to extensions/json-language-features/server/src/browser/jsonServerMain.ts diff --git a/lib/vscode/extensions/json-language-features/server/src/jsonServer.ts b/extensions/json-language-features/server/src/jsonServer.ts similarity index 90% rename from lib/vscode/extensions/json-language-features/server/src/jsonServer.ts rename to extensions/json-language-features/server/src/jsonServer.ts index 0266d536c265..bb3538a0c985 100644 --- a/lib/vscode/extensions/json-language-features/server/src/jsonServer.ts +++ b/extensions/json-language-features/server/src/jsonServer.ts @@ -6,7 +6,7 @@ import { Connection, TextDocuments, InitializeParams, InitializeResult, NotificationType, RequestType, - DocumentRangeFormattingRequest, Disposable, ServerCapabilities, TextDocumentSyncKind, TextEdit + DocumentRangeFormattingRequest, Disposable, ServerCapabilities, TextDocumentSyncKind, TextEdit, DocumentFormattingRequest, TextDocumentIdentifier, FormattingOptions } from 'vscode-languageserver'; import { formatError, runSafe, runSafeAsync } from './utils/runner'; @@ -138,6 +138,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) hoverProvider: true, documentSymbolProvider: true, documentRangeFormattingProvider: params.initializationOptions?.provideFormatter === true, + documentFormattingProvider: params.initializationOptions?.provideFormatter === true, colorProvider: {}, foldingRangeProvider: true, selectionRangeProvider: true, @@ -206,7 +207,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) let jsonConfigurationSettings: JSONSchemaSettings[] | undefined = undefined; let schemaAssociations: ISchemaAssociations | SchemaConfiguration[] | undefined = undefined; - let formatterRegistration: Thenable | null = null; + let formatterRegistrations: Thenable[] | null = null; // The settings have changed. Is send on server activation as well. connection.onDidChangeConfiguration((change) => { @@ -224,12 +225,16 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) if (dynamicFormatterRegistration) { const enableFormatter = settings && settings.json && settings.json.format && settings.json.format.enable; if (enableFormatter) { - if (!formatterRegistration) { - formatterRegistration = connection.client.register(DocumentRangeFormattingRequest.type, { documentSelector: [{ language: 'json' }, { language: 'jsonc' }] }); + if (!formatterRegistrations) { + const documentSelector = [{ language: 'json' }, { language: 'jsonc' }]; + formatterRegistrations = [ + connection.client.register(DocumentRangeFormattingRequest.type, { documentSelector }), + connection.client.register(DocumentFormattingRequest.type, { documentSelector }) + ]; } - } else if (formatterRegistration) { - formatterRegistration.then(r => r.dispose()); - formatterRegistration = null; + } else if (formatterRegistrations) { + formatterRegistrations.forEach(p => p.then(r => r.dispose())); + formatterRegistrations = null; } } }); @@ -420,19 +425,25 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) }, [], `Error while computing document symbols for ${documentSymbolParams.textDocument.uri}`, token); }); - connection.onDocumentRangeFormatting((formatParams, token) => { - return runSafe(() => { - const document = documents.get(formatParams.textDocument.uri); - if (document) { - const edits = languageService.format(document, formatParams.range, formatParams.options); - if (edits.length > formatterMaxNumberOfEdits) { - const newText = TextDocument.applyEdits(document, edits); - return [TextEdit.replace(Range.create(Position.create(0, 0), document.positionAt(document.getText().length)), newText)]; - } - return edits; + function onFormat(textDocument: TextDocumentIdentifier, range: Range | undefined, options: FormattingOptions): TextEdit[] { + const document = documents.get(textDocument.uri); + if (document) { + const edits = languageService.format(document, range ?? getFullRange(document), options); + if (edits.length > formatterMaxNumberOfEdits) { + const newText = TextDocument.applyEdits(document, edits); + return [TextEdit.replace(getFullRange(document), newText)]; } - return []; - }, [], `Error while formatting range for ${formatParams.textDocument.uri}`, token); + return edits; + } + return []; + } + + connection.onDocumentRangeFormatting((formatParams, token) => { + return runSafe(() => onFormat(formatParams.textDocument, formatParams.range, formatParams.options), [], `Error while formatting range for ${formatParams.textDocument.uri}`, token); + }); + + connection.onDocumentFormatting((formatParams, token) => { + return runSafe(() => onFormat(formatParams.textDocument, undefined, formatParams.options), [], `Error while formatting ${formatParams.textDocument.uri}`, token); }); connection.onDocumentColor((params, token) => { @@ -495,3 +506,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) // Listen on the connection connection.listen(); } + +function getFullRange(document: TextDocument): Range { + return Range.create(Position.create(0, 0), document.positionAt(document.getText().length)); +} diff --git a/lib/vscode/extensions/json-language-features/server/src/languageModelCache.ts b/extensions/json-language-features/server/src/languageModelCache.ts similarity index 100% rename from lib/vscode/extensions/json-language-features/server/src/languageModelCache.ts rename to extensions/json-language-features/server/src/languageModelCache.ts diff --git a/lib/vscode/extensions/json-language-features/server/src/node/jsonServerMain.ts b/extensions/json-language-features/server/src/node/jsonServerMain.ts similarity index 100% rename from lib/vscode/extensions/json-language-features/server/src/node/jsonServerMain.ts rename to extensions/json-language-features/server/src/node/jsonServerMain.ts diff --git a/lib/vscode/extensions/json-language-features/server/src/requests.ts b/extensions/json-language-features/server/src/requests.ts similarity index 100% rename from lib/vscode/extensions/json-language-features/server/src/requests.ts rename to extensions/json-language-features/server/src/requests.ts diff --git a/lib/vscode/extensions/json-language-features/server/src/utils/runner.ts b/extensions/json-language-features/server/src/utils/runner.ts similarity index 100% rename from lib/vscode/extensions/json-language-features/server/src/utils/runner.ts rename to extensions/json-language-features/server/src/utils/runner.ts diff --git a/lib/vscode/extensions/json-language-features/server/src/utils/strings.ts b/extensions/json-language-features/server/src/utils/strings.ts similarity index 100% rename from lib/vscode/extensions/json-language-features/server/src/utils/strings.ts rename to extensions/json-language-features/server/src/utils/strings.ts diff --git a/lib/vscode/extensions/json-language-features/server/test/mocha.opts b/extensions/json-language-features/server/test/mocha.opts similarity index 100% rename from lib/vscode/extensions/json-language-features/server/test/mocha.opts rename to extensions/json-language-features/server/test/mocha.opts diff --git a/lib/vscode/extensions/json-language-features/server/tsconfig.json b/extensions/json-language-features/server/tsconfig.json similarity index 100% rename from lib/vscode/extensions/json-language-features/server/tsconfig.json rename to extensions/json-language-features/server/tsconfig.json diff --git a/lib/vscode/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock similarity index 93% rename from lib/vscode/extensions/json-language-features/server/yarn.lock rename to extensions/json-language-features/server/yarn.lock index b754118b91d2..abe012c86ae8 100644 --- a/lib/vscode/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.0.tgz#3eb56d13a1de1d347ecb1957c6860c911704bc44" integrity sha512-/Sge3BymXo4lKc31C8OINJgXLaw+7vL1/L1pGiBNpGrBiT8FQiaFpSYV0uhTaG4y78vcMBTMFsWaHDvuD+xGzQ== -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== agent-base@4: version "4.1.2" @@ -105,10 +105,10 @@ request-light@^0.4.0: https-proxy-agent "^2.2.4" vscode-nls "^4.1.2" -vscode-json-languageservice@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-4.1.3.tgz#851564e529e649c13b844f10a80ea1d9095591a9" - integrity sha512-m/wUEt4zgCNUcvGmPr1ELo+ROQNKBgASpdOOAEpcSMwYE/6GzULZ1KfBhbX9or7qnC4E0oX+wwW+lrN3EUWCgw== +vscode-json-languageservice@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-4.1.4.tgz#c83d3d812f8f17ab525724c611d8ff5e8834fc84" + integrity sha512-/UqaE58BVFdePM9l971L6xPRLlCLNk01aovf1Pp9hB/8pytmd2s9ZNEnS1JqYyQEJ1k5/fEBsWOdhQlNo4H7VA== dependencies: jsonc-parser "^3.0.0" minimatch "^3.0.4" diff --git a/lib/vscode/extensions/json-language-features/yarn.lock b/extensions/json-language-features/yarn.lock similarity index 97% rename from lib/vscode/extensions/json-language-features/yarn.lock rename to extensions/json-language-features/yarn.lock index a4533a6e53cf..4ba9b7b63016 100644 --- a/lib/vscode/extensions/json-language-features/yarn.lock +++ b/extensions/json-language-features/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== agent-base@4: version "4.2.1" diff --git a/lib/vscode/extensions/json/.vscodeignore b/extensions/json/.vscodeignore similarity index 100% rename from lib/vscode/extensions/json/.vscodeignore rename to extensions/json/.vscodeignore diff --git a/lib/vscode/extensions/json/build/update-grammars.js b/extensions/json/build/update-grammars.js similarity index 100% rename from lib/vscode/extensions/json/build/update-grammars.js rename to extensions/json/build/update-grammars.js diff --git a/lib/vscode/extensions/json/cgmanifest.json b/extensions/json/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/json/cgmanifest.json rename to extensions/json/cgmanifest.json diff --git a/lib/vscode/extensions/json/language-configuration.json b/extensions/json/language-configuration.json similarity index 100% rename from lib/vscode/extensions/json/language-configuration.json rename to extensions/json/language-configuration.json diff --git a/lib/vscode/extensions/json/package.json b/extensions/json/package.json similarity index 94% rename from lib/vscode/extensions/json/package.json rename to extensions/json/package.json index a4ccc12cf2da..8f197c31181c 100644 --- a/lib/vscode/extensions/json/package.json +++ b/extensions/json/package.json @@ -29,7 +29,8 @@ ".ts.map", ".har", ".jslintrc", - ".jsonld" + ".jsonld", + ".ipynb" ], "filenames": [ "composer.lock", @@ -57,6 +58,8 @@ ".babelrc" ], "filenames": [ + "babel.config.json", + ".babelrc.json", ".ember-cli" ], "configuration": "./language-configuration.json" diff --git a/lib/vscode/extensions/json/package.nls.json b/extensions/json/package.nls.json similarity index 100% rename from lib/vscode/extensions/json/package.nls.json rename to extensions/json/package.nls.json diff --git a/lib/vscode/extensions/json/syntaxes/JSON.tmLanguage.json b/extensions/json/syntaxes/JSON.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/json/syntaxes/JSON.tmLanguage.json rename to extensions/json/syntaxes/JSON.tmLanguage.json diff --git a/lib/vscode/extensions/json/syntaxes/JSONC.tmLanguage.json b/extensions/json/syntaxes/JSONC.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/json/syntaxes/JSONC.tmLanguage.json rename to extensions/json/syntaxes/JSONC.tmLanguage.json diff --git a/lib/vscode/extensions/json/yarn.lock b/extensions/json/yarn.lock similarity index 100% rename from lib/vscode/extensions/json/yarn.lock rename to extensions/json/yarn.lock diff --git a/extensions/julia/.vscodeignore b/extensions/julia/.vscodeignore new file mode 100644 index 000000000000..d9011becfb64 --- /dev/null +++ b/extensions/julia/.vscodeignore @@ -0,0 +1,2 @@ +build/** +cgmanifest.json diff --git a/lib/vscode/extensions/julia/cgmanifest.json b/extensions/julia/cgmanifest.json similarity index 83% rename from lib/vscode/extensions/julia/cgmanifest.json rename to extensions/julia/cgmanifest.json index 3b2f492cc6c3..e2f4268ed2fa 100644 --- a/lib/vscode/extensions/julia/cgmanifest.json +++ b/extensions/julia/cgmanifest.json @@ -4,7 +4,7 @@ "component": { "type": "git", "git": { - "name": " JuliaEditorSupport/atom-language-julia", + "name": "JuliaEditorSupport/atom-language-julia", "repositoryUrl": "https://github.com/JuliaEditorSupport/atom-language-julia", "commitHash": "008e02c5ec9440fa9f0ea8a891712c7238f24706" } @@ -14,4 +14,4 @@ } ], "version": 1 -} \ No newline at end of file +} diff --git a/lib/vscode/extensions/julia/language-configuration.json b/extensions/julia/language-configuration.json similarity index 100% rename from lib/vscode/extensions/julia/language-configuration.json rename to extensions/julia/language-configuration.json diff --git a/lib/vscode/extensions/julia/package.json b/extensions/julia/package.json similarity index 100% rename from lib/vscode/extensions/julia/package.json rename to extensions/julia/package.json diff --git a/lib/vscode/extensions/julia/package.nls.json b/extensions/julia/package.nls.json similarity index 100% rename from lib/vscode/extensions/julia/package.nls.json rename to extensions/julia/package.nls.json diff --git a/lib/vscode/extensions/julia/syntaxes/julia.tmLanguage.json b/extensions/julia/syntaxes/julia.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/julia/syntaxes/julia.tmLanguage.json rename to extensions/julia/syntaxes/julia.tmLanguage.json diff --git a/lib/vscode/extensions/less/.vscodeignore b/extensions/less/.vscodeignore similarity index 100% rename from lib/vscode/extensions/less/.vscodeignore rename to extensions/less/.vscodeignore diff --git a/lib/vscode/extensions/less/cgmanifest.json b/extensions/less/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/less/cgmanifest.json rename to extensions/less/cgmanifest.json diff --git a/lib/vscode/extensions/less/language-configuration.json b/extensions/less/language-configuration.json similarity index 100% rename from lib/vscode/extensions/less/language-configuration.json rename to extensions/less/language-configuration.json diff --git a/lib/vscode/extensions/less/package.json b/extensions/less/package.json similarity index 100% rename from lib/vscode/extensions/less/package.json rename to extensions/less/package.json diff --git a/lib/vscode/extensions/less/package.nls.json b/extensions/less/package.nls.json similarity index 100% rename from lib/vscode/extensions/less/package.nls.json rename to extensions/less/package.nls.json diff --git a/lib/vscode/extensions/less/syntaxes/less.tmLanguage.json b/extensions/less/syntaxes/less.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/less/syntaxes/less.tmLanguage.json rename to extensions/less/syntaxes/less.tmLanguage.json diff --git a/lib/vscode/extensions/less/yarn.lock b/extensions/less/yarn.lock similarity index 100% rename from lib/vscode/extensions/less/yarn.lock rename to extensions/less/yarn.lock diff --git a/lib/vscode/extensions/log/.vscodeignore b/extensions/log/.vscodeignore similarity index 100% rename from lib/vscode/extensions/log/.vscodeignore rename to extensions/log/.vscodeignore diff --git a/lib/vscode/extensions/log/cgmanifest.json b/extensions/log/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/log/cgmanifest.json rename to extensions/log/cgmanifest.json diff --git a/lib/vscode/extensions/log/package.json b/extensions/log/package.json similarity index 100% rename from lib/vscode/extensions/log/package.json rename to extensions/log/package.json diff --git a/lib/vscode/extensions/log/package.nls.json b/extensions/log/package.nls.json similarity index 100% rename from lib/vscode/extensions/log/package.nls.json rename to extensions/log/package.nls.json diff --git a/lib/vscode/extensions/log/syntaxes/log.tmLanguage.json b/extensions/log/syntaxes/log.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/log/syntaxes/log.tmLanguage.json rename to extensions/log/syntaxes/log.tmLanguage.json diff --git a/lib/vscode/extensions/log/yarn.lock b/extensions/log/yarn.lock similarity index 100% rename from lib/vscode/extensions/log/yarn.lock rename to extensions/log/yarn.lock diff --git a/lib/vscode/extensions/lua/.vscodeignore b/extensions/lua/.vscodeignore similarity index 100% rename from lib/vscode/extensions/lua/.vscodeignore rename to extensions/lua/.vscodeignore diff --git a/lib/vscode/extensions/lua/cgmanifest.json b/extensions/lua/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/lua/cgmanifest.json rename to extensions/lua/cgmanifest.json diff --git a/lib/vscode/extensions/lua/language-configuration.json b/extensions/lua/language-configuration.json similarity index 100% rename from lib/vscode/extensions/lua/language-configuration.json rename to extensions/lua/language-configuration.json diff --git a/lib/vscode/extensions/lua/package.json b/extensions/lua/package.json similarity index 100% rename from lib/vscode/extensions/lua/package.json rename to extensions/lua/package.json diff --git a/lib/vscode/extensions/lua/package.nls.json b/extensions/lua/package.nls.json similarity index 100% rename from lib/vscode/extensions/lua/package.nls.json rename to extensions/lua/package.nls.json diff --git a/lib/vscode/extensions/lua/syntaxes/lua.tmLanguage.json b/extensions/lua/syntaxes/lua.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/lua/syntaxes/lua.tmLanguage.json rename to extensions/lua/syntaxes/lua.tmLanguage.json diff --git a/lib/vscode/extensions/lua/yarn.lock b/extensions/lua/yarn.lock similarity index 100% rename from lib/vscode/extensions/lua/yarn.lock rename to extensions/lua/yarn.lock diff --git a/lib/vscode/extensions/make/.vscodeignore b/extensions/make/.vscodeignore similarity index 100% rename from lib/vscode/extensions/make/.vscodeignore rename to extensions/make/.vscodeignore diff --git a/lib/vscode/extensions/make/cgmanifest.json b/extensions/make/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/make/cgmanifest.json rename to extensions/make/cgmanifest.json diff --git a/lib/vscode/extensions/make/language-configuration.json b/extensions/make/language-configuration.json similarity index 100% rename from lib/vscode/extensions/make/language-configuration.json rename to extensions/make/language-configuration.json diff --git a/lib/vscode/extensions/make/package.json b/extensions/make/package.json similarity index 98% rename from lib/vscode/extensions/make/package.json rename to extensions/make/package.json index ef8209df01c8..89a5134c64de 100644 --- a/lib/vscode/extensions/make/package.json +++ b/extensions/make/package.json @@ -20,6 +20,7 @@ "makefile" ], "extensions": [ + ".mak", ".mk" ], "filenames": [ diff --git a/lib/vscode/extensions/make/package.nls.json b/extensions/make/package.nls.json similarity index 100% rename from lib/vscode/extensions/make/package.nls.json rename to extensions/make/package.nls.json diff --git a/lib/vscode/extensions/make/syntaxes/make.tmLanguage.json b/extensions/make/syntaxes/make.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/make/syntaxes/make.tmLanguage.json rename to extensions/make/syntaxes/make.tmLanguage.json diff --git a/lib/vscode/extensions/make/yarn.lock b/extensions/make/yarn.lock similarity index 100% rename from lib/vscode/extensions/make/yarn.lock rename to extensions/make/yarn.lock diff --git a/lib/vscode/extensions/markdown-basics/.vscodeignore b/extensions/markdown-basics/.vscodeignore similarity index 100% rename from lib/vscode/extensions/markdown-basics/.vscodeignore rename to extensions/markdown-basics/.vscodeignore diff --git a/lib/vscode/extensions/markdown-basics/cgmanifest.json b/extensions/markdown-basics/cgmanifest.json similarity index 95% rename from lib/vscode/extensions/markdown-basics/cgmanifest.json rename to extensions/markdown-basics/cgmanifest.json index 92288d403b93..f3f0717c5adb 100644 --- a/lib/vscode/extensions/markdown-basics/cgmanifest.json +++ b/extensions/markdown-basics/cgmanifest.json @@ -33,7 +33,7 @@ "git": { "name": "microsoft/vscode-markdown-tm-grammar", "repositoryUrl": "https://github.com/microsoft/vscode-markdown-tm-grammar", - "commitHash": "7019b191c3ee38b6c345f3a2a843f223eb92ca1e" + "commitHash": "a612b96d62aa1ce305c4a55dc9d577316fab39da" } }, "license": "MIT", diff --git a/lib/vscode/extensions/markdown-basics/language-configuration.json b/extensions/markdown-basics/language-configuration.json similarity index 100% rename from lib/vscode/extensions/markdown-basics/language-configuration.json rename to extensions/markdown-basics/language-configuration.json diff --git a/lib/vscode/extensions/markdown-basics/package.json b/extensions/markdown-basics/package.json similarity index 100% rename from lib/vscode/extensions/markdown-basics/package.json rename to extensions/markdown-basics/package.json diff --git a/lib/vscode/extensions/markdown-basics/package.nls.json b/extensions/markdown-basics/package.nls.json similarity index 100% rename from lib/vscode/extensions/markdown-basics/package.nls.json rename to extensions/markdown-basics/package.nls.json diff --git a/lib/vscode/extensions/markdown-basics/snippets/markdown.code-snippets b/extensions/markdown-basics/snippets/markdown.code-snippets similarity index 100% rename from lib/vscode/extensions/markdown-basics/snippets/markdown.code-snippets rename to extensions/markdown-basics/snippets/markdown.code-snippets diff --git a/lib/vscode/extensions/markdown-basics/syntaxes/markdown.tmLanguage.json b/extensions/markdown-basics/syntaxes/markdown.tmLanguage.json similarity index 95% rename from lib/vscode/extensions/markdown-basics/syntaxes/markdown.tmLanguage.json rename to extensions/markdown-basics/syntaxes/markdown.tmLanguage.json index a61af0d0c060..aaa4c774b407 100644 --- a/lib/vscode/extensions/markdown-basics/syntaxes/markdown.tmLanguage.json +++ b/extensions/markdown-basics/syntaxes/markdown.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/microsoft/vscode-markdown-tm-grammar/commit/7019b191c3ee38b6c345f3a2a843f223eb92ca1e", + "version": "https://github.com/microsoft/vscode-markdown-tm-grammar/commit/a612b96d62aa1ce305c4a55dc9d577316fab39da", "name": "Markdown", "scopeName": "text.html.markdown", "patterns": [ @@ -63,7 +63,7 @@ "while": "(^|\\G)\\s*(>) ?" }, "fenced_code_block_css": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(css|css.erb)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(css|css.erb)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -96,7 +96,7 @@ ] }, "fenced_code_block_basic": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(html|htm|shtml|xhtml|inc|tmpl|tpl)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(html|htm|shtml|xhtml|inc|tmpl|tpl)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -129,7 +129,7 @@ ] }, "fenced_code_block_ini": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(ini|conf)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(ini|conf)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -162,7 +162,7 @@ ] }, "fenced_code_block_java": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(java|bsh)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(java|bsh)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -195,7 +195,7 @@ ] }, "fenced_code_block_lua": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(lua)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(lua)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -228,7 +228,7 @@ ] }, "fenced_code_block_makefile": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(Makefile|makefile|GNUmakefile|OCamlMakefile)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(Makefile|makefile|GNUmakefile|OCamlMakefile)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -261,7 +261,7 @@ ] }, "fenced_code_block_perl": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(perl|pl|pm|pod|t|PL|psgi|vcl)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(perl|pl|pm|pod|t|PL|psgi|vcl)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -294,7 +294,7 @@ ] }, "fenced_code_block_r": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(R|r|s|S|Rprofile|\\{\\.r.+?\\})((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(R|r|s|S|Rprofile|\\{\\.r.+?\\})((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -327,7 +327,7 @@ ] }, "fenced_code_block_ruby": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(ruby|rb|rbx|rjs|Rakefile|rake|cgi|fcgi|gemspec|irbrc|Capfile|ru|prawn|Cheffile|Gemfile|Guardfile|Hobofile|Vagrantfile|Appraisals|Rantfile|Berksfile|Berksfile.lock|Thorfile|Puppetfile)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(ruby|rb|rbx|rjs|Rakefile|rake|cgi|fcgi|gemspec|irbrc|Capfile|ru|prawn|Cheffile|Gemfile|Guardfile|Hobofile|Vagrantfile|Appraisals|Rantfile|Berksfile|Berksfile.lock|Thorfile|Puppetfile)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -360,7 +360,7 @@ ] }, "fenced_code_block_php": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(php|php3|php4|php5|phpt|phtml|aw|ctp)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(php|php3|php4|php5|phpt|phtml|aw|ctp)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -396,7 +396,7 @@ ] }, "fenced_code_block_sql": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(sql|ddl|dml)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(sql|ddl|dml)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -429,7 +429,7 @@ ] }, "fenced_code_block_vs_net": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(vb)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(vb)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -462,7 +462,7 @@ ] }, "fenced_code_block_xml": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(xml|xsd|tld|jsp|pt|cpt|dtml|rss|opml)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(xml|xsd|tld|jsp|pt|cpt|dtml|rss|opml)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -495,7 +495,7 @@ ] }, "fenced_code_block_xsl": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(xsl|xslt)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(xsl|xslt)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -528,7 +528,7 @@ ] }, "fenced_code_block_yaml": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(yaml|yml)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(yaml|yml)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -561,7 +561,7 @@ ] }, "fenced_code_block_dosbatch": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(bat|batch)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(bat|batch)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -594,7 +594,7 @@ ] }, "fenced_code_block_clojure": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(clj|cljs|clojure)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(clj|cljs|clojure)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -627,7 +627,7 @@ ] }, "fenced_code_block_coffee": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(coffee|Cakefile|coffee.erb)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(coffee|Cakefile|coffee.erb)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -660,7 +660,7 @@ ] }, "fenced_code_block_c": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(c|h)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(c|h)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -693,7 +693,7 @@ ] }, "fenced_code_block_cpp": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(cpp|c\\+\\+|cxx)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(cpp|c\\+\\+|cxx)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -726,7 +726,7 @@ ] }, "fenced_code_block_diff": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(patch|diff|rej)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(patch|diff|rej)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -759,7 +759,7 @@ ] }, "fenced_code_block_dockerfile": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(dockerfile|Dockerfile)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(dockerfile|Dockerfile)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -792,7 +792,7 @@ ] }, "fenced_code_block_git_commit": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(COMMIT_EDITMSG|MERGE_MSG)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(COMMIT_EDITMSG|MERGE_MSG)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -825,7 +825,7 @@ ] }, "fenced_code_block_git_rebase": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(git-rebase-todo)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(git-rebase-todo)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -858,7 +858,7 @@ ] }, "fenced_code_block_go": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(go|golang)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(go|golang)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -891,7 +891,7 @@ ] }, "fenced_code_block_groovy": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(groovy|gvy)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(groovy|gvy)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -924,7 +924,7 @@ ] }, "fenced_code_block_pug": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(jade|pug)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(jade|pug)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -957,7 +957,7 @@ ] }, "fenced_code_block_js": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(js|jsx|javascript|es6|mjs|cjs|\\{\\.js.+?\\})((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(js|jsx|javascript|es6|mjs|cjs|\\{\\.js.+?\\})((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -990,7 +990,7 @@ ] }, "fenced_code_block_js_regexp": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(regexp)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(regexp)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1023,7 +1023,7 @@ ] }, "fenced_code_block_json": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(json|json5|sublime-settings|sublime-menu|sublime-keymap|sublime-mousemap|sublime-theme|sublime-build|sublime-project|sublime-completions)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(json|json5|sublime-settings|sublime-menu|sublime-keymap|sublime-mousemap|sublime-theme|sublime-build|sublime-project|sublime-completions)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1056,7 +1056,7 @@ ] }, "fenced_code_block_jsonc": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(jsonc)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(jsonc)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1089,7 +1089,7 @@ ] }, "fenced_code_block_less": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(less)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(less)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1122,7 +1122,7 @@ ] }, "fenced_code_block_objc": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(objectivec|objective-c|mm|objc|obj-c|m|h)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(objectivec|objective-c|mm|objc|obj-c|m|h)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1155,7 +1155,7 @@ ] }, "fenced_code_block_swift": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(swift)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(swift)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1188,7 +1188,7 @@ ] }, "fenced_code_block_scss": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(scss)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(scss)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1221,7 +1221,7 @@ ] }, "fenced_code_block_perl6": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(perl6|p6|pl6|pm6|nqp)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(perl6|p6|pl6|pm6|nqp)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1254,7 +1254,7 @@ ] }, "fenced_code_block_powershell": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(powershell|ps1|psm1|psd1)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(powershell|ps1|psm1|psd1)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1287,7 +1287,7 @@ ] }, "fenced_code_block_python": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(python|py|py3|rpy|pyw|cpy|SConstruct|Sconstruct|sconstruct|SConscript|gyp|gypi|\\{\\.python.+?\\})((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(python|py|py3|rpy|pyw|cpy|SConstruct|Sconstruct|sconstruct|SConscript|gyp|gypi|\\{\\.python.+?\\})((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1320,7 +1320,7 @@ ] }, "fenced_code_block_regexp_python": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(re)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(re)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1353,7 +1353,7 @@ ] }, "fenced_code_block_rust": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(rust|rs|\\{\\.rust.+?\\})((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(rust|rs|\\{\\.rust.+?\\})((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1386,7 +1386,7 @@ ] }, "fenced_code_block_scala": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(scala|sbt)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(scala|sbt)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1419,7 +1419,7 @@ ] }, "fenced_code_block_shell": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(shell|sh|bash|zsh|bashrc|bash_profile|bash_login|profile|bash_logout|.textmate_init|\\{\\.bash.+?\\})((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(shell|sh|bash|zsh|bashrc|bash_profile|bash_login|profile|bash_logout|.textmate_init|\\{\\.bash.+?\\})((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1452,7 +1452,7 @@ ] }, "fenced_code_block_ts": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(typescript|ts)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(typescript|ts)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1485,7 +1485,7 @@ ] }, "fenced_code_block_tsx": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(tsx)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(tsx)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1518,7 +1518,7 @@ ] }, "fenced_code_block_csharp": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(cs|csharp|c#)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(cs|csharp|c#)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1551,7 +1551,7 @@ ] }, "fenced_code_block_fsharp": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(fs|fsharp|f#)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(fs|fsharp|f#)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1584,7 +1584,7 @@ ] }, "fenced_code_block_dart": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(dart)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(dart)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1617,7 +1617,7 @@ ] }, "fenced_code_block_handlebars": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(handlebars|hbs)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(handlebars|hbs)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1650,7 +1650,7 @@ ] }, "fenced_code_block_markdown": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(markdown|md)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(markdown|md)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1683,7 +1683,7 @@ ] }, "fenced_code_block_log": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(log)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(log)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1716,7 +1716,7 @@ ] }, "fenced_code_block_erlang": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(erlang)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(erlang)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1749,7 +1749,7 @@ ] }, "fenced_code_block_elixir": { - "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(elixir)((\\s+|:|\\{)[^`~]*)?$)", + "begin": "(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?i:(elixir)((\\s+|:|\\{|\\?)[^`~]*)?$)", "name": "markup.fenced_code.block.markdown", "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", "beginCaptures": { @@ -1975,7 +1975,15 @@ "name": "punctuation.definition.heading.markdown" }, "2": { - "name": "entity.name.section.markdown" + "name": "entity.name.section.markdown", + "patterns": [ + { + "include": "#inline" + }, + { + "include": "text.html.derivative" + } + ] }, "3": { "name": "punctuation.definition.heading.markdown" @@ -1990,7 +1998,15 @@ "name": "punctuation.definition.heading.markdown" }, "2": { - "name": "entity.name.section.markdown" + "name": "entity.name.section.markdown", + "patterns": [ + { + "include": "#inline" + }, + { + "include": "text.html.derivative" + } + ] }, "3": { "name": "punctuation.definition.heading.markdown" @@ -2005,7 +2021,15 @@ "name": "punctuation.definition.heading.markdown" }, "2": { - "name": "entity.name.section.markdown" + "name": "entity.name.section.markdown", + "patterns": [ + { + "include": "#inline" + }, + { + "include": "text.html.derivative" + } + ] }, "3": { "name": "punctuation.definition.heading.markdown" @@ -2020,7 +2044,15 @@ "name": "punctuation.definition.heading.markdown" }, "2": { - "name": "entity.name.section.markdown" + "name": "entity.name.section.markdown", + "patterns": [ + { + "include": "#inline" + }, + { + "include": "text.html.derivative" + } + ] }, "3": { "name": "punctuation.definition.heading.markdown" @@ -2035,7 +2067,15 @@ "name": "punctuation.definition.heading.markdown" }, "2": { - "name": "entity.name.section.markdown" + "name": "entity.name.section.markdown", + "patterns": [ + { + "include": "#inline" + }, + { + "include": "text.html.derivative" + } + ] }, "3": { "name": "punctuation.definition.heading.markdown" @@ -2050,7 +2090,15 @@ "name": "punctuation.definition.heading.markdown" }, "2": { - "name": "entity.name.section.markdown" + "name": "entity.name.section.markdown", + "patterns": [ + { + "include": "#inline" + }, + { + "include": "text.html.derivative" + } + ] }, "3": { "name": "punctuation.definition.heading.markdown" diff --git a/lib/vscode/extensions/markdown-basics/yarn.lock b/extensions/markdown-basics/yarn.lock similarity index 100% rename from lib/vscode/extensions/markdown-basics/yarn.lock rename to extensions/markdown-basics/yarn.lock diff --git a/lib/vscode/extensions/markdown-language-features/.gitignore b/extensions/markdown-language-features/.gitignore similarity index 100% rename from lib/vscode/extensions/markdown-language-features/.gitignore rename to extensions/markdown-language-features/.gitignore diff --git a/lib/vscode/extensions/markdown-language-features/.vscodeignore b/extensions/markdown-language-features/.vscodeignore similarity index 100% rename from lib/vscode/extensions/markdown-language-features/.vscodeignore rename to extensions/markdown-language-features/.vscodeignore diff --git a/lib/vscode/extensions/markdown-language-features/README.md b/extensions/markdown-language-features/README.md similarity index 100% rename from lib/vscode/extensions/markdown-language-features/README.md rename to extensions/markdown-language-features/README.md diff --git a/lib/vscode/extensions/markdown-language-features/esbuild.js b/extensions/markdown-language-features/esbuild.js similarity index 100% rename from lib/vscode/extensions/markdown-language-features/esbuild.js rename to extensions/markdown-language-features/esbuild.js diff --git a/lib/vscode/extensions/markdown-language-features/extension-browser.webpack.config.js b/extensions/markdown-language-features/extension-browser.webpack.config.js similarity index 100% rename from lib/vscode/extensions/markdown-language-features/extension-browser.webpack.config.js rename to extensions/markdown-language-features/extension-browser.webpack.config.js diff --git a/lib/vscode/extensions/markdown-language-features/extension.webpack.config.js b/extensions/markdown-language-features/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/markdown-language-features/extension.webpack.config.js rename to extensions/markdown-language-features/extension.webpack.config.js diff --git a/lib/vscode/extensions/markdown-language-features/icon.png b/extensions/markdown-language-features/icon.png similarity index 100% rename from lib/vscode/extensions/markdown-language-features/icon.png rename to extensions/markdown-language-features/icon.png diff --git a/lib/vscode/extensions/markdown-language-features/media/highlight.css b/extensions/markdown-language-features/media/highlight.css similarity index 100% rename from lib/vscode/extensions/markdown-language-features/media/highlight.css rename to extensions/markdown-language-features/media/highlight.css diff --git a/lib/vscode/extensions/markdown-language-features/media/markdown.css b/extensions/markdown-language-features/media/markdown.css similarity index 98% rename from lib/vscode/extensions/markdown-language-features/media/markdown.css rename to extensions/markdown-language-features/media/markdown.css index edaa6f925d16..e12805e1de55 100644 --- a/lib/vscode/extensions/markdown-language-features/media/markdown.css +++ b/extensions/markdown-language-features/media/markdown.css @@ -106,6 +106,13 @@ body.showEditorSelection li.code-line:hover:before { border-left: none; } +ul ul, +ul ol, +ol ul, +ol ol { + margin-bottom: 0; +} + img { max-width: 100%; max-height: 100%; @@ -152,6 +159,7 @@ h1 { table { border-collapse: collapse; + margin-bottom: 0.7em; } th { diff --git a/lib/vscode/extensions/markdown-language-features/media/preview-dark.svg b/extensions/markdown-language-features/media/preview-dark.svg similarity index 100% rename from lib/vscode/extensions/markdown-language-features/media/preview-dark.svg rename to extensions/markdown-language-features/media/preview-dark.svg diff --git a/lib/vscode/extensions/markdown-language-features/media/preview-light.svg b/extensions/markdown-language-features/media/preview-light.svg similarity index 100% rename from lib/vscode/extensions/markdown-language-features/media/preview-light.svg rename to extensions/markdown-language-features/media/preview-light.svg diff --git a/extensions/markdown-language-features/notebook/index.ts b/extensions/markdown-language-features/notebook/index.ts new file mode 100644 index 000000000000..371091691b7a --- /dev/null +++ b/extensions/markdown-language-features/notebook/index.ts @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +const MarkdownIt = require('markdown-it'); + +export function activate() { + let markdownIt = new MarkdownIt({ + html: true + }); + + return { + renderOutputItem: (outputInfo: { text(): string }, element: HTMLElement) => { + const rendered = markdownIt.render(outputInfo.text()); + element.innerHTML = rendered; + + // Insert styles into markdown preview shadow dom so that they are applied + for (const markdownStyleNode of document.getElementsByClassName('markdown-style')) { + element.insertAdjacentElement('beforebegin', markdownStyleNode.cloneNode(true) as Element); + } + }, + extendMarkdownIt: (f: (md: typeof markdownIt) => void) => { + f(markdownIt); + } + }; +} diff --git a/lib/vscode/extensions/markdown-language-features/notebook/tsconfig.json b/extensions/markdown-language-features/notebook/tsconfig.json similarity index 100% rename from lib/vscode/extensions/markdown-language-features/notebook/tsconfig.json rename to extensions/markdown-language-features/notebook/tsconfig.json diff --git a/lib/vscode/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json similarity index 99% rename from lib/vscode/extensions/markdown-language-features/package.json rename to extensions/markdown-language-features/package.json index 19d1354c2068..ec72a0d53441 100644 --- a/lib/vscode/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -40,7 +40,7 @@ } }, "contributes": { - "notebookMarkupRenderers": [ + "notebookRenderer": [ { "id": "markdownItRenderer", "displayName": "Markdown it renderer", @@ -361,7 +361,8 @@ "@types/highlight.js": "10.1.0", "@types/lodash.throttle": "^4.1.3", "@types/markdown-it": "0.0.2", - "@types/node": "^12.19.9", + "@types/node": "14.x", + "@types/vscode-webview": "^1.57.0", "lodash.throttle": "^4.1.1" }, "repository": { diff --git a/lib/vscode/extensions/markdown-language-features/package.nls.json b/extensions/markdown-language-features/package.nls.json similarity index 100% rename from lib/vscode/extensions/markdown-language-features/package.nls.json rename to extensions/markdown-language-features/package.nls.json diff --git a/lib/vscode/extensions/markdown-language-features/preview-src/activeLineMarker.ts b/extensions/markdown-language-features/preview-src/activeLineMarker.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/preview-src/activeLineMarker.ts rename to extensions/markdown-language-features/preview-src/activeLineMarker.ts diff --git a/lib/vscode/extensions/markdown-language-features/preview-src/csp.ts b/extensions/markdown-language-features/preview-src/csp.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/preview-src/csp.ts rename to extensions/markdown-language-features/preview-src/csp.ts diff --git a/lib/vscode/extensions/markdown-language-features/preview-src/events.ts b/extensions/markdown-language-features/preview-src/events.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/preview-src/events.ts rename to extensions/markdown-language-features/preview-src/events.ts diff --git a/lib/vscode/extensions/markdown-language-features/preview-src/index.ts b/extensions/markdown-language-features/preview-src/index.ts similarity index 99% rename from lib/vscode/extensions/markdown-language-features/preview-src/index.ts rename to extensions/markdown-language-features/preview-src/index.ts index 4d57d5f3a372..13f4f1f7770e 100644 --- a/lib/vscode/extensions/markdown-language-features/preview-src/index.ts +++ b/extensions/markdown-language-features/preview-src/index.ts @@ -10,8 +10,6 @@ import { getEditorLineNumberForPageOffset, scrollToRevealSourceLine, getLineElem import { getSettings, getData } from './settings'; import throttle = require('lodash.throttle'); -declare let acquireVsCodeApi: any; - let scrollDisabledCount = 0; const marker = new ActiveLineMarker(); const settings = getSettings(); diff --git a/lib/vscode/extensions/markdown-language-features/preview-src/loading.ts b/extensions/markdown-language-features/preview-src/loading.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/preview-src/loading.ts rename to extensions/markdown-language-features/preview-src/loading.ts diff --git a/lib/vscode/extensions/markdown-language-features/preview-src/messaging.ts b/extensions/markdown-language-features/preview-src/messaging.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/preview-src/messaging.ts rename to extensions/markdown-language-features/preview-src/messaging.ts diff --git a/lib/vscode/extensions/markdown-language-features/preview-src/pre.ts b/extensions/markdown-language-features/preview-src/pre.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/preview-src/pre.ts rename to extensions/markdown-language-features/preview-src/pre.ts diff --git a/lib/vscode/extensions/markdown-language-features/preview-src/scroll-sync.ts b/extensions/markdown-language-features/preview-src/scroll-sync.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/preview-src/scroll-sync.ts rename to extensions/markdown-language-features/preview-src/scroll-sync.ts diff --git a/lib/vscode/extensions/markdown-language-features/preview-src/settings.ts b/extensions/markdown-language-features/preview-src/settings.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/preview-src/settings.ts rename to extensions/markdown-language-features/preview-src/settings.ts diff --git a/lib/vscode/extensions/markdown-language-features/preview-src/strings.ts b/extensions/markdown-language-features/preview-src/strings.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/preview-src/strings.ts rename to extensions/markdown-language-features/preview-src/strings.ts diff --git a/lib/vscode/extensions/simple-browser/preview-src/tsconfig.json b/extensions/markdown-language-features/preview-src/tsconfig.json similarity index 69% rename from lib/vscode/extensions/simple-browser/preview-src/tsconfig.json rename to extensions/markdown-language-features/preview-src/tsconfig.json index b1bede72c17e..62af34c62f84 100644 --- a/lib/vscode/extensions/simple-browser/preview-src/tsconfig.json +++ b/extensions/markdown-language-features/preview-src/tsconfig.json @@ -8,5 +8,10 @@ "DOM", "DOM.Iterable" ] + }, + "typeAcquisition": { + "include": [ + "@types/vscode-webview" + ] } } diff --git a/lib/vscode/extensions/markdown-language-features/schemas/package.schema.json b/extensions/markdown-language-features/schemas/package.schema.json similarity index 100% rename from lib/vscode/extensions/markdown-language-features/schemas/package.schema.json rename to extensions/markdown-language-features/schemas/package.schema.json diff --git a/lib/vscode/extensions/markdown-language-features/src/commandManager.ts b/extensions/markdown-language-features/src/commandManager.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/commandManager.ts rename to extensions/markdown-language-features/src/commandManager.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/commands/index.ts b/extensions/markdown-language-features/src/commands/index.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/commands/index.ts rename to extensions/markdown-language-features/src/commands/index.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/commands/moveCursorToPosition.ts b/extensions/markdown-language-features/src/commands/moveCursorToPosition.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/commands/moveCursorToPosition.ts rename to extensions/markdown-language-features/src/commands/moveCursorToPosition.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/commands/openDocumentLink.ts b/extensions/markdown-language-features/src/commands/openDocumentLink.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/commands/openDocumentLink.ts rename to extensions/markdown-language-features/src/commands/openDocumentLink.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/commands/refreshPreview.ts b/extensions/markdown-language-features/src/commands/refreshPreview.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/commands/refreshPreview.ts rename to extensions/markdown-language-features/src/commands/refreshPreview.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/commands/renderDocument.ts b/extensions/markdown-language-features/src/commands/renderDocument.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/commands/renderDocument.ts rename to extensions/markdown-language-features/src/commands/renderDocument.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/commands/showPreview.ts b/extensions/markdown-language-features/src/commands/showPreview.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/commands/showPreview.ts rename to extensions/markdown-language-features/src/commands/showPreview.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/commands/showPreviewSecuritySelector.ts b/extensions/markdown-language-features/src/commands/showPreviewSecuritySelector.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/commands/showPreviewSecuritySelector.ts rename to extensions/markdown-language-features/src/commands/showPreviewSecuritySelector.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/commands/showSource.ts b/extensions/markdown-language-features/src/commands/showSource.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/commands/showSource.ts rename to extensions/markdown-language-features/src/commands/showSource.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/commands/toggleLock.ts b/extensions/markdown-language-features/src/commands/toggleLock.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/commands/toggleLock.ts rename to extensions/markdown-language-features/src/commands/toggleLock.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/extension.ts b/extensions/markdown-language-features/src/extension.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/extension.ts rename to extensions/markdown-language-features/src/extension.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/features/documentLinkProvider.ts b/extensions/markdown-language-features/src/features/documentLinkProvider.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/features/documentLinkProvider.ts rename to extensions/markdown-language-features/src/features/documentLinkProvider.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/features/documentSymbolProvider.ts b/extensions/markdown-language-features/src/features/documentSymbolProvider.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/features/documentSymbolProvider.ts rename to extensions/markdown-language-features/src/features/documentSymbolProvider.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/features/foldingProvider.ts b/extensions/markdown-language-features/src/features/foldingProvider.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/features/foldingProvider.ts rename to extensions/markdown-language-features/src/features/foldingProvider.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/features/preview.ts b/extensions/markdown-language-features/src/features/preview.ts similarity index 93% rename from lib/vscode/extensions/markdown-language-features/src/features/preview.ts rename to extensions/markdown-language-features/src/features/preview.ts index 42d6f08fc072..fb3fbeca1832 100644 --- a/lib/vscode/extensions/markdown-language-features/src/features/preview.ts +++ b/extensions/markdown-language-features/src/features/preview.ts @@ -11,8 +11,8 @@ import { Logger } from '../logger'; import { MarkdownContributionProvider } from '../markdownExtensions'; import { Disposable } from '../util/dispose'; import { isMarkdownFile } from '../util/file'; -import { normalizeResource, WebviewResourceProvider } from '../util/resources'; -import { getVisibleLine, TopmostLineMonitor } from '../util/topmostLineMonitor'; +import { WebviewResourceProvider } from '../util/resources'; +import { getVisibleLine, LastScrollLocation, TopmostLineMonitor } from '../util/topmostLineMonitor'; import { MarkdownPreviewConfigurationManager } from './previewConfig'; import { MarkdownContentProvider, MarkdownContentProviderOutput } from './previewContentProvider'; import { MarkdownEngine } from '../markdownEngine'; @@ -120,6 +120,8 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider { private imageInfo: { readonly id: string, readonly width: number, readonly height: number; }[] = []; private readonly _fileWatchersBySrc = new Map(); + private readonly _onScrollEmitter = this._register(new vscode.EventEmitter()); + public readonly onScroll = this._onScrollEmitter.event; constructor( webview: vscode.WebviewPanel, @@ -324,7 +326,7 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider { private onDidScrollPreview(line: number) { this.line = line; - + this._onScrollEmitter.fire({ line: this.line, uri: this._resource }); const config = this._previewConfigurations.loadAndCacheConfiguration(this._resource); if (!config.scrollEditorWithPreview) { return; @@ -336,13 +338,7 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider { } this.isScrolling = true; - const sourceLine = Math.floor(line); - const fraction = line - sourceLine; - const text = editor.document.lineAt(sourceLine).text; - const start = Math.floor(fraction * text.length); - editor.revealRange( - new vscode.Range(sourceLine, start, sourceLine + 1, 0), - vscode.TextEditorRevealType.AtTop); + scrollEditorToLine(line, editor); } } @@ -427,12 +423,12 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider { baseRoots.push(vscode.Uri.file(path.dirname(this._resource.fsPath))); } - return baseRoots.map(root => normalizeResource(this._resource, root)); + return baseRoots; } private async onDidClickPreviewLink(href: string) { - let [hrefPath, fragment] = decodeURIComponent(href).split('#'); + let [hrefPath, fragment] = href.split('#').map(c => decodeURIComponent(c)); if (hrefPath[0] !== '/') { // We perviously already resolve absolute paths. @@ -460,7 +456,7 @@ class MarkdownPreview extends Disposable implements WebviewResourceProvider { //#region WebviewResourceProvider asWebviewUri(resource: vscode.Uri) { - return this._webviewPanel.webview.asWebviewUri(normalizeResource(this._resource, resource)); + return this._webviewPanel.webview.asWebviewUri(resource); } get cspSource() { @@ -497,11 +493,13 @@ export class StaticMarkdownPreview extends Disposable implements ManagedMarkdown webview: vscode.WebviewPanel, contentProvider: MarkdownContentProvider, previewConfigurations: MarkdownPreviewConfigurationManager, + topmostLineMonitor: TopmostLineMonitor, logger: Logger, contributionProvider: MarkdownContributionProvider, engine: MarkdownEngine, + scrollLine?: number, ): StaticMarkdownPreview { - return new StaticMarkdownPreview(webview, resource, contentProvider, previewConfigurations, logger, contributionProvider, engine); + return new StaticMarkdownPreview(webview, resource, contentProvider, previewConfigurations, topmostLineMonitor, logger, contributionProvider, engine, scrollLine); } private readonly preview: MarkdownPreview; @@ -511,13 +509,15 @@ export class StaticMarkdownPreview extends Disposable implements ManagedMarkdown resource: vscode.Uri, contentProvider: MarkdownContentProvider, private readonly _previewConfigurations: MarkdownPreviewConfigurationManager, + topmostLineMonitor: TopmostLineMonitor, logger: Logger, contributionProvider: MarkdownContributionProvider, engine: MarkdownEngine, + scrollLine?: number, ) { super(); - - this.preview = this._register(new MarkdownPreview(this._webviewPanel, resource, undefined, { + const topScrollLocation = scrollLine ? new StartingScrollLine(scrollLine) : undefined; + this.preview = this._register(new MarkdownPreview(this._webviewPanel, resource, topScrollLocation, { getAdditionalState: () => { return {}; }, openPreviewLinkToMarkdownFile: () => { /* todo */ } }, engine, contentProvider, _previewConfigurations, logger, contributionProvider)); @@ -529,6 +529,16 @@ export class StaticMarkdownPreview extends Disposable implements ManagedMarkdown this._register(this._webviewPanel.onDidChangeViewState(e => { this._onDidChangeViewState.fire(e); })); + + this._register(this.preview.onScroll((scrollInfo) => { + topmostLineMonitor.setPreviousEditorLine(scrollInfo); + })); + + this._register(topmostLineMonitor.onDidChanged(event => { + if (this.preview.isPreviewOf(event.resource)) { + this.preview.scrollTo(event.line); + } + })); } private readonly _onDispose = this._register(new vscode.EventEmitter()); @@ -789,3 +799,18 @@ export class DynamicMarkdownPreview extends Disposable implements ManagedMarkdow } } +/** + * Change the top-most visible line of `editor` to be at `line` + */ +export function scrollEditorToLine( + line: number, + editor: vscode.TextEditor +) { + const sourceLine = Math.floor(line); + const fraction = line - sourceLine; + const text = editor.document.lineAt(sourceLine).text; + const start = Math.floor(fraction * text.length); + editor.revealRange( + new vscode.Range(sourceLine, start, sourceLine + 1, 0), + vscode.TextEditorRevealType.AtTop); +} diff --git a/lib/vscode/extensions/markdown-language-features/src/features/previewConfig.ts b/extensions/markdown-language-features/src/features/previewConfig.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/features/previewConfig.ts rename to extensions/markdown-language-features/src/features/previewConfig.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/features/previewContentProvider.ts b/extensions/markdown-language-features/src/features/previewContentProvider.ts similarity index 99% rename from lib/vscode/extensions/markdown-language-features/src/features/previewContentProvider.ts rename to extensions/markdown-language-features/src/features/previewContentProvider.ts index 474b1864ed7d..e2b28c092cbc 100644 --- a/lib/vscode/extensions/markdown-language-features/src/features/previewContentProvider.ts +++ b/extensions/markdown-language-features/src/features/previewContentProvider.ts @@ -81,7 +81,7 @@ export class MarkdownContentProvider { const nonce = new Date().getTime() + '' + new Date().getMilliseconds(); const csp = this.getCsp(resourceProvider, sourceUri, nonce); - const body = await this.engine.render(markdownDocument); + const body = await this.engine.render(markdownDocument, resourceProvider); const html = ` diff --git a/lib/vscode/extensions/markdown-language-features/src/features/previewManager.ts b/extensions/markdown-language-features/src/features/previewManager.ts similarity index 88% rename from lib/vscode/extensions/markdown-language-features/src/features/previewManager.ts rename to extensions/markdown-language-features/src/features/previewManager.ts index 05729e0873a7..7f30abb1c84d 100644 --- a/lib/vscode/extensions/markdown-language-features/src/features/previewManager.ts +++ b/extensions/markdown-language-features/src/features/previewManager.ts @@ -9,9 +9,10 @@ import { MarkdownEngine } from '../markdownEngine'; import { MarkdownContributionProvider } from '../markdownExtensions'; import { Disposable, disposeAll } from '../util/dispose'; import { TopmostLineMonitor } from '../util/topmostLineMonitor'; -import { DynamicMarkdownPreview, ManagedMarkdownPreview, StartingScrollFragment, StaticMarkdownPreview } from './preview'; +import { DynamicMarkdownPreview, ManagedMarkdownPreview, StartingScrollFragment, StaticMarkdownPreview, scrollEditorToLine } from './preview'; import { MarkdownPreviewConfigurationManager } from './previewConfig'; import { MarkdownContentProvider } from './previewContentProvider'; +import { isMarkdownFile } from '../util/file'; export interface DynamicPreviewSettings { readonly resourceColumn: vscode.ViewColumn; @@ -75,6 +76,17 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview super(); this._register(vscode.window.registerWebviewPanelSerializer(DynamicMarkdownPreview.viewType, this)); this._register(vscode.window.registerCustomEditorProvider(this.customEditorViewType, this)); + + this._register(vscode.window.onDidChangeActiveTextEditor(textEditor => { + + // When at a markdown file, apply existing scroll settings + if (textEditor && textEditor.document && isMarkdownFile(textEditor.document)) { + const line = this._topmostLineMonitor.getPreviousEditorLineByUri(textEditor.document.uri); + if (line) { + scrollEditorToLine(line, textEditor); + } + } + })); } public refresh() { @@ -160,14 +172,18 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview document: vscode.TextDocument, webview: vscode.WebviewPanel ): Promise { + const lineNumber = this._topmostLineMonitor.getPreviousEditorLineByUri(document.uri); const preview = StaticMarkdownPreview.revive( document.uri, webview, this._contentProvider, this._previewConfigurations, + this._topmostLineMonitor, this._logger, this._contributions, - this._engine); + this._engine, + lineNumber + ); this.registerStaticPreview(preview); } @@ -175,11 +191,14 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview resource: vscode.Uri, previewSettings: DynamicPreviewSettings ): DynamicMarkdownPreview { + const activeTextEditorURI = vscode.window.activeTextEditor?.document.uri; + const scrollLine = (activeTextEditorURI?.toString() === resource.toString()) ? vscode.window.activeTextEditor?.visibleRanges[0].start.line : undefined; const preview = DynamicMarkdownPreview.create( { resource, resourceColumn: previewSettings.resourceColumn, locked: previewSettings.locked, + line: scrollLine, }, previewSettings.previewColumn, this._contentProvider, diff --git a/lib/vscode/extensions/markdown-language-features/src/features/smartSelect.ts b/extensions/markdown-language-features/src/features/smartSelect.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/features/smartSelect.ts rename to extensions/markdown-language-features/src/features/smartSelect.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts b/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts rename to extensions/markdown-language-features/src/features/workspaceSymbolProvider.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/logger.ts b/extensions/markdown-language-features/src/logger.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/logger.ts rename to extensions/markdown-language-features/src/logger.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/markdownEngine.ts b/extensions/markdown-language-features/src/markdownEngine.ts similarity index 74% rename from lib/vscode/extensions/markdown-language-features/src/markdownEngine.ts rename to extensions/markdown-language-features/src/markdownEngine.ts index 3d84a24ad305..346547f3da9f 100644 --- a/lib/vscode/extensions/markdown-language-features/src/markdownEngine.ts +++ b/extensions/markdown-language-features/src/markdownEngine.ts @@ -4,13 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { MarkdownIt, Token } from 'markdown-it'; -import * as path from 'path'; import * as vscode from 'vscode'; import { MarkdownContributionProvider as MarkdownContributionProvider } from './markdownExtensions'; import { Slugifier } from './slugify'; import { SkinnyTextDocument } from './tableOfContentsProvider'; import { hash } from './util/hash'; -import { isOfScheme, MarkdownFileExtensions, Schemes } from './util/links'; +import { isOfScheme, Schemes } from './util/links'; +import { WebviewResourceProvider } from './util/resources'; const UNICODE_NEWLINE_REGEX = /\u2028|\u2029/g; @@ -62,12 +62,13 @@ export interface RenderOutput { interface RenderEnv { containingImages: { src: string }[]; + currentDocument: vscode.Uri | undefined; + resourceProvider: WebviewResourceProvider | undefined; } export class MarkdownEngine { private md?: Promise; - private currentDocument?: vscode.Uri; private _slugCount = new Map(); private _tokenCache = new TokenCache(); @@ -113,7 +114,7 @@ export class MarkdownEngine { this.addLineNumberRenderer(md, renderName); } - this.addImageStabilizer(md); + this.addImageRenderer(md); this.addFencedRenderer(md); this.addLinkNormalizer(md); this.addLinkValidator(md); @@ -138,8 +139,6 @@ export class MarkdownEngine { return cached; } - this.currentDocument = document.uri; - const tokens = this.tokenizeString(document.getText(), engine); this._tokenCache.update(document, config, tokens); return tokens; @@ -151,7 +150,7 @@ export class MarkdownEngine { return engine.parse(text.replace(UNICODE_NEWLINE_REGEX, ''), {}); } - public async render(input: SkinnyTextDocument | string): Promise { + public async render(input: SkinnyTextDocument | string, resourceProvider?: WebviewResourceProvider): Promise { const config = this.getConfig(typeof input === 'string' ? undefined : input.uri); const engine = await this.getEngine(config); @@ -160,7 +159,9 @@ export class MarkdownEngine { : this.tokenizeDocument(input, config, engine); const env: RenderEnv = { - containingImages: [] + containingImages: [], + currentDocument: typeof input === 'string' ? undefined : input.uri, + resourceProvider, }; const html = engine.renderer.render(tokens, { @@ -193,12 +194,12 @@ export class MarkdownEngine { }; } - private addLineNumberRenderer(md: any, ruleName: string): void { + private addLineNumberRenderer(md: MarkdownIt, ruleName: string): void { const original = md.renderer.rules[ruleName]; - md.renderer.rules[ruleName] = (tokens: any, idx: number, options: any, env: any, self: any) => { + md.renderer.rules[ruleName] = (tokens: Token[], idx: number, options: any, env: any, self: any) => { const token = tokens[idx]; if (token.map && token.map.length) { - token.attrSet('data-line', token.map[0]); + token.attrSet('data-line', token.map[0] + ''); token.attrJoin('class', 'code-line'); } @@ -210,9 +211,9 @@ export class MarkdownEngine { }; } - private addImageStabilizer(md: any): void { + private addImageRenderer(md: MarkdownIt): void { const original = md.renderer.rules.image; - md.renderer.rules.image = (tokens: any, idx: number, options: any, env: RenderEnv, self: any) => { + md.renderer.rules.image = (tokens: Token[], idx: number, options: any, env: RenderEnv, self: any) => { const token = tokens[idx]; token.attrJoin('class', 'loading'); @@ -221,6 +222,11 @@ export class MarkdownEngine { env.containingImages?.push({ src }); const imgHash = hash(src); token.attrSet('id', `image-hash-${imgHash}`); + + if (!token.attrGet('data-src')) { + token.attrSet('src', this.toResourceUri(src, env.currentDocument, env.resourceProvider)); + token.attrSet('data-src', src); + } } if (original) { @@ -231,9 +237,9 @@ export class MarkdownEngine { }; } - private addFencedRenderer(md: any): void { + private addFencedRenderer(md: MarkdownIt): void { const original = md.renderer.rules['fenced']; - md.renderer.rules['fenced'] = (tokens: any, idx: number, options: any, env: any, self: any) => { + md.renderer.rules['fenced'] = (tokens: Token[], idx: number, options: any, env: any, self: any) => { const token = tokens[idx]; if (token.map && token.map.length) { token.attrJoin('class', 'hljs'); @@ -243,7 +249,7 @@ export class MarkdownEngine { }; } - private addLinkNormalizer(md: any): void { + private addLinkNormalizer(md: MarkdownIt): void { const normalizeLink = md.normalizeLink; md.normalizeLink = (link: string) => { try { @@ -252,43 +258,6 @@ export class MarkdownEngine { return normalizeLink(vscode.Uri.parse(link).with({ scheme: vscode.env.uriScheme }).toString()); } - // Support file:// links - if (isOfScheme(Schemes.file, link)) { - // Ensure link is relative by prepending `/` so that it uses the element URI - // when resolving the absolute URL - return normalizeLink('/' + link.replace(/^file:/, 'file')); - } - - // If original link doesn't look like a url with a scheme, assume it must be a link to a file in workspace - if (!/^[a-z\-]+:/i.test(link)) { - // Use a fake scheme for parsing - let uri = vscode.Uri.parse('markdown-link:' + link); - - // Relative paths should be resolved correctly inside the preview but we need to - // handle absolute paths specially (for images) to resolve them relative to the workspace root - if (uri.path[0] === '/') { - const root = vscode.workspace.getWorkspaceFolder(this.currentDocument!); - if (root) { - const fileUri = vscode.Uri.joinPath(root.uri, uri.fsPath).with({ - fragment: uri.fragment, - query: uri.query, - }); - - // Ensure fileUri is relative by prepending `/` so that it uses the element URI - // when resolving the absolute URL - uri = vscode.Uri.parse('markdown-link:' + '/' + fileUri.toString(true).replace(/^\S+?:/, fileUri.scheme)); - } - } - - const extname = path.extname(uri.fsPath); - - if (uri.fragment && (extname === '' || MarkdownFileExtensions.includes(extname))) { - uri = uri.with({ - fragment: this.slugifier.fromHeading(uri.fragment).value - }); - } - return normalizeLink(uri.toString(true).replace(/^markdown-link:/, '')); - } } catch (e) { // noop } @@ -296,7 +265,7 @@ export class MarkdownEngine { }; } - private addLinkValidator(md: any): void { + private addLinkValidator(md: MarkdownIt): void { const validateLink = md.validateLink; md.validateLink = (link: string) => { return validateLink(link) @@ -306,9 +275,9 @@ export class MarkdownEngine { }; } - private addNamedHeaders(md: any): void { + private addNamedHeaders(md: MarkdownIt): void { const original = md.renderer.rules.heading_open; - md.renderer.rules.heading_open = (tokens: any, idx: number, options: any, env: any, self: any) => { + md.renderer.rules.heading_open = (tokens: Token[], idx: number, options: any, env: any, self: any) => { const title = tokens[idx + 1].children.reduce((acc: string, t: any) => acc + t.content, ''); let slug = this.slugifier.fromHeading(title); @@ -331,12 +300,12 @@ export class MarkdownEngine { }; } - private addLinkRenderer(md: any): void { - const old_render = md.renderer.rules.link_open || ((tokens: any, idx: number, options: any, _env: any, self: any) => { + private addLinkRenderer(md: MarkdownIt): void { + const old_render = md.renderer.rules.link_open || ((tokens: Token[], idx: number, options: any, _env: any, self: any) => { return self.renderToken(tokens, idx, options); }); - md.renderer.rules.link_open = (tokens: any, idx: number, options: any, env: any, self: any) => { + md.renderer.rules.link_open = (tokens: Token[], idx: number, options: any, env: any, self: any) => { const token = tokens[idx]; const hrefIndex = token.attrIndex('href'); if (hrefIndex >= 0) { @@ -346,6 +315,50 @@ export class MarkdownEngine { return old_render(tokens, idx, options, env, self); }; } + + private toResourceUri(href: string, currentDocument: vscode.Uri | undefined, resourceProvider: WebviewResourceProvider | undefined): string { + try { + // Support file:// links + if (isOfScheme(Schemes.file, href)) { + const uri = vscode.Uri.parse(href); + if (resourceProvider) { + return resourceProvider.asWebviewUri(uri).toString(true); + } + // Not sure how to resolve this + return href; + } + + // If original link doesn't look like a url with a scheme, assume it must be a link to a file in workspace + if (!/^[a-z\-]+:/i.test(href)) { + // Use a fake scheme for parsing + let uri = vscode.Uri.parse('markdown-link:' + href); + + // Relative paths should be resolved correctly inside the preview but we need to + // handle absolute paths specially to resolve them relative to the workspace root + if (uri.path[0] === '/' && currentDocument) { + const root = vscode.workspace.getWorkspaceFolder(currentDocument); + if (root) { + uri = vscode.Uri.joinPath(root.uri, uri.fsPath).with({ + fragment: uri.fragment, + query: uri.query, + }); + + if (resourceProvider) { + return resourceProvider.asWebviewUri(uri).toString(true); + } else { + uri = uri.with({ scheme: 'markdown-link' }); + } + } + } + + return uri.toString(true).replace(/^markdown-link:/, ''); + } + + return href; + } catch { + return href; + } + } } async function getMarkdownOptions(md: () => MarkdownIt) { diff --git a/lib/vscode/extensions/markdown-language-features/src/markdownExtensions.ts b/extensions/markdown-language-features/src/markdownExtensions.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/markdownExtensions.ts rename to extensions/markdown-language-features/src/markdownExtensions.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/security.ts b/extensions/markdown-language-features/src/security.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/security.ts rename to extensions/markdown-language-features/src/security.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/slugify.ts b/extensions/markdown-language-features/src/slugify.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/slugify.ts rename to extensions/markdown-language-features/src/slugify.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/tableOfContentsProvider.ts b/extensions/markdown-language-features/src/tableOfContentsProvider.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/tableOfContentsProvider.ts rename to extensions/markdown-language-features/src/tableOfContentsProvider.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/telemetryReporter.ts b/extensions/markdown-language-features/src/telemetryReporter.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/telemetryReporter.ts rename to extensions/markdown-language-features/src/telemetryReporter.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/test/documentLink.test.ts b/extensions/markdown-language-features/src/test/documentLink.test.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/test/documentLink.test.ts rename to extensions/markdown-language-features/src/test/documentLink.test.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts b/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts rename to extensions/markdown-language-features/src/test/documentLinkProvider.test.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/test/documentSymbolProvider.test.ts b/extensions/markdown-language-features/src/test/documentSymbolProvider.test.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/test/documentSymbolProvider.test.ts rename to extensions/markdown-language-features/src/test/documentSymbolProvider.test.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/test/engine.test.ts b/extensions/markdown-language-features/src/test/engine.test.ts similarity index 91% rename from lib/vscode/extensions/markdown-language-features/src/test/engine.test.ts rename to extensions/markdown-language-features/src/test/engine.test.ts index c3eb7c850566..e398ed088ce9 100644 --- a/lib/vscode/extensions/markdown-language-features/src/test/engine.test.ts +++ b/extensions/markdown-language-features/src/test/engine.test.ts @@ -37,11 +37,11 @@ suite('markdown.engine', () => { const engine = createNewMarkdownEngine(); assert.deepStrictEqual((await engine.render(input)), { html: '

    ' - + ' ' + + ' ' + ' ' - + ' ' - + ' ' - + '' + + ' ' + + ' ' + + '' + '

    \n' , containingImages: [{ src: 'img.png' }, { src: 'http://example.org/img.png' }, { src: 'img.png' }, { src: './img2.png' }], diff --git a/lib/vscode/extensions/markdown-language-features/src/test/engine.ts b/extensions/markdown-language-features/src/test/engine.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/test/engine.ts rename to extensions/markdown-language-features/src/test/engine.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/test/foldingProvider.test.ts b/extensions/markdown-language-features/src/test/foldingProvider.test.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/test/foldingProvider.test.ts rename to extensions/markdown-language-features/src/test/foldingProvider.test.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/test/inMemoryDocument.ts b/extensions/markdown-language-features/src/test/inMemoryDocument.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/test/inMemoryDocument.ts rename to extensions/markdown-language-features/src/test/inMemoryDocument.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/test/index.ts b/extensions/markdown-language-features/src/test/index.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/test/index.ts rename to extensions/markdown-language-features/src/test/index.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/test/smartSelect.test.ts b/extensions/markdown-language-features/src/test/smartSelect.test.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/test/smartSelect.test.ts rename to extensions/markdown-language-features/src/test/smartSelect.test.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/test/tableOfContentsProvider.test.ts b/extensions/markdown-language-features/src/test/tableOfContentsProvider.test.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/test/tableOfContentsProvider.test.ts rename to extensions/markdown-language-features/src/test/tableOfContentsProvider.test.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/test/urlToUri.test.ts b/extensions/markdown-language-features/src/test/urlToUri.test.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/test/urlToUri.test.ts rename to extensions/markdown-language-features/src/test/urlToUri.test.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/test/util.ts b/extensions/markdown-language-features/src/test/util.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/test/util.ts rename to extensions/markdown-language-features/src/test/util.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts b/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts similarity index 98% rename from lib/vscode/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts rename to extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts index e74d3b592bcb..d66cbf198b2b 100644 --- a/lib/vscode/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts +++ b/extensions/markdown-language-features/src/test/workspaceSymbolProvider.test.ts @@ -18,7 +18,7 @@ suite('markdown.WorkspaceSymbolProvider', () => { test('Should not return anything for empty workspace', async () => { const provider = new MarkdownWorkspaceSymbolProvider(symbolProvider, new InMemoryWorkspaceMarkdownDocumentProvider([])); - assert.deepEqual(await provider.provideWorkspaceSymbols(''), []); + assert.deepStrictEqual(await provider.provideWorkspaceSymbols(''), []); }); test('Should return symbols from workspace with one markdown file', async () => { diff --git a/lib/vscode/extensions/markdown-language-features/src/typings/ref.d.ts b/extensions/markdown-language-features/src/typings/ref.d.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/typings/ref.d.ts rename to extensions/markdown-language-features/src/typings/ref.d.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/util/arrays.ts b/extensions/markdown-language-features/src/util/arrays.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/util/arrays.ts rename to extensions/markdown-language-features/src/util/arrays.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/util/dispose.ts b/extensions/markdown-language-features/src/util/dispose.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/util/dispose.ts rename to extensions/markdown-language-features/src/util/dispose.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/util/file.ts b/extensions/markdown-language-features/src/util/file.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/util/file.ts rename to extensions/markdown-language-features/src/util/file.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/util/hash.ts b/extensions/markdown-language-features/src/util/hash.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/util/hash.ts rename to extensions/markdown-language-features/src/util/hash.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/util/lazy.ts b/extensions/markdown-language-features/src/util/lazy.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/util/lazy.ts rename to extensions/markdown-language-features/src/util/lazy.ts diff --git a/lib/vscode/extensions/markdown-language-features/src/util/links.ts b/extensions/markdown-language-features/src/util/links.ts similarity index 96% rename from lib/vscode/extensions/markdown-language-features/src/util/links.ts rename to extensions/markdown-language-features/src/util/links.ts index 3545d03a54d4..02e5aba6590b 100644 --- a/lib/vscode/extensions/markdown-language-features/src/util/links.ts +++ b/extensions/markdown-language-features/src/util/links.ts @@ -14,7 +14,6 @@ export const Schemes = { data: 'data:', vscode: 'vscode:', 'vscode-insiders': 'vscode-insiders:', - 'vscode-resource': 'vscode-resource:', }; const knownSchemes = [ diff --git a/lib/vscode/extensions/notebook-markdown-extensions/notebook/emoji.ts b/extensions/markdown-language-features/src/util/resources.ts similarity index 66% rename from lib/vscode/extensions/notebook-markdown-extensions/notebook/emoji.ts rename to extensions/markdown-language-features/src/util/resources.ts index bf82f98ba0f7..f1f2d0886ab2 100644 --- a/lib/vscode/extensions/notebook-markdown-extensions/notebook/emoji.ts +++ b/extensions/markdown-language-features/src/util/resources.ts @@ -2,10 +2,12 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type * as markdownIt from 'markdown-it'; -const emoji = require('markdown-it-emoji'); +import * as vscode from 'vscode'; -export function extendMarkdownIt(md: markdownIt.MarkdownIt) { - return md.use(emoji); +export interface WebviewResourceProvider { + asWebviewUri(resource: vscode.Uri): vscode.Uri; + + readonly cspSource: string; } + diff --git a/lib/vscode/extensions/markdown-language-features/src/util/topmostLineMonitor.ts b/extensions/markdown-language-features/src/util/topmostLineMonitor.ts similarity index 71% rename from lib/vscode/extensions/markdown-language-features/src/util/topmostLineMonitor.ts rename to extensions/markdown-language-features/src/util/topmostLineMonitor.ts index 57395fbc691c..62f5b5c194b1 100644 --- a/lib/vscode/extensions/markdown-language-features/src/util/topmostLineMonitor.ts +++ b/extensions/markdown-language-features/src/util/topmostLineMonitor.ts @@ -7,18 +7,32 @@ import * as vscode from 'vscode'; import { Disposable } from '../util/dispose'; import { isMarkdownFile } from './file'; +export interface LastScrollLocation { + readonly line: number; + readonly uri: vscode.Uri; +} + export class TopmostLineMonitor extends Disposable { private readonly pendingUpdates = new Map(); private readonly throttle = 50; + private previousEditorInfo = new Map(); + public isPrevEditorCustom = false; constructor() { super(); + + if (vscode.window.activeTextEditor) { + const line = getVisibleLine(vscode.window.activeTextEditor); + this.setPreviousEditorLine({ uri: vscode.window.activeTextEditor.document.uri, line: line ?? 0 }); + } + this._register(vscode.window.onDidChangeTextEditorVisibleRanges(event => { if (isMarkdownFile(event.textEditor.document)) { const line = getVisibleLine(event.textEditor); if (typeof line === 'number') { this.updateLine(event.textEditor.document.uri, line); + this.setPreviousEditorLine({ uri: event.textEditor.document.uri, line: line }); } } })); @@ -27,7 +41,16 @@ export class TopmostLineMonitor extends Disposable { private readonly _onChanged = this._register(new vscode.EventEmitter<{ readonly resource: vscode.Uri, readonly line: number }>()); public readonly onDidChanged = this._onChanged.event; - private updateLine( + public setPreviousEditorLine(scrollLocation: LastScrollLocation): void { + this.previousEditorInfo.set(scrollLocation.uri.toString(), scrollLocation); + } + + public getPreviousEditorLineByUri(resource: vscode.Uri): number | undefined { + const scrollLoc = this.previousEditorInfo.get(resource.toString()); + return scrollLoc?.line; + } + + public updateLine( resource: vscode.Uri, line: number ) { diff --git a/lib/vscode/extensions/markdown-language-features/src/util/url.ts b/extensions/markdown-language-features/src/util/url.ts similarity index 100% rename from lib/vscode/extensions/markdown-language-features/src/util/url.ts rename to extensions/markdown-language-features/src/util/url.ts diff --git a/lib/vscode/extensions/markdown-language-features/test-workspace/a.md b/extensions/markdown-language-features/test-workspace/a.md similarity index 100% rename from lib/vscode/extensions/markdown-language-features/test-workspace/a.md rename to extensions/markdown-language-features/test-workspace/a.md diff --git a/lib/vscode/extensions/markdown-language-features/test-workspace/b.md b/extensions/markdown-language-features/test-workspace/b.md similarity index 100% rename from lib/vscode/extensions/markdown-language-features/test-workspace/b.md rename to extensions/markdown-language-features/test-workspace/b.md diff --git a/lib/vscode/extensions/markdown-language-features/test-workspace/sub/c.md b/extensions/markdown-language-features/test-workspace/sub/c.md similarity index 100% rename from lib/vscode/extensions/markdown-language-features/test-workspace/sub/c.md rename to extensions/markdown-language-features/test-workspace/sub/c.md diff --git a/lib/vscode/extensions/markdown-language-features/test-workspace/sub/d.md b/extensions/markdown-language-features/test-workspace/sub/d.md similarity index 100% rename from lib/vscode/extensions/markdown-language-features/test-workspace/sub/d.md rename to extensions/markdown-language-features/test-workspace/sub/d.md diff --git a/lib/vscode/extensions/markdown-language-features/tsconfig.json b/extensions/markdown-language-features/tsconfig.json similarity index 100% rename from lib/vscode/extensions/markdown-language-features/tsconfig.json rename to extensions/markdown-language-features/tsconfig.json diff --git a/lib/vscode/extensions/markdown-language-features/webpack.config.js b/extensions/markdown-language-features/webpack.config.js similarity index 100% rename from lib/vscode/extensions/markdown-language-features/webpack.config.js rename to extensions/markdown-language-features/webpack.config.js diff --git a/lib/vscode/extensions/markdown-language-features/yarn.lock b/extensions/markdown-language-features/yarn.lock similarity index 93% rename from lib/vscode/extensions/markdown-language-features/yarn.lock rename to extensions/markdown-language-features/yarn.lock index 216abe3066b9..3f1174c3684f 100644 --- a/lib/vscode/extensions/markdown-language-features/yarn.lock +++ b/extensions/markdown-language-features/yarn.lock @@ -26,10 +26,15 @@ resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-0.0.2.tgz#5d9ad19e6e6508cdd2f2596df86fd0aade598660" integrity sha1-XZrRnm5lCM3S8llt+G/Qqt5ZhmA= -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== + +"@types/vscode-webview@^1.57.0": + version "1.57.0" + resolved "https://registry.yarnpkg.com/@types/vscode-webview/-/vscode-webview-1.57.0.tgz#bad5194d45ae8d03afc1c0f67f71ff5e7a243bbf" + integrity sha512-x3Cb/SMa1IwRHfSvKaZDZOTh4cNoG505c3NjTqGlMC082m++x/ETUmtYniDsw6SSmYzZXO8KBNhYxR0+VqymqA== applicationinsights@1.7.4: version "1.7.4" diff --git a/lib/vscode/extensions/merge-conflict/.vscodeignore b/extensions/merge-conflict/.vscodeignore similarity index 100% rename from lib/vscode/extensions/merge-conflict/.vscodeignore rename to extensions/merge-conflict/.vscodeignore diff --git a/lib/vscode/extensions/merge-conflict/README.md b/extensions/merge-conflict/README.md similarity index 100% rename from lib/vscode/extensions/merge-conflict/README.md rename to extensions/merge-conflict/README.md diff --git a/lib/vscode/extensions/merge-conflict/extension-browser.webpack.config.js b/extensions/merge-conflict/extension-browser.webpack.config.js similarity index 100% rename from lib/vscode/extensions/merge-conflict/extension-browser.webpack.config.js rename to extensions/merge-conflict/extension-browser.webpack.config.js diff --git a/lib/vscode/extensions/merge-conflict/extension.webpack.config.js b/extensions/merge-conflict/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/merge-conflict/extension.webpack.config.js rename to extensions/merge-conflict/extension.webpack.config.js diff --git a/lib/vscode/extensions/merge-conflict/media/icon.png b/extensions/merge-conflict/media/icon.png similarity index 100% rename from lib/vscode/extensions/merge-conflict/media/icon.png rename to extensions/merge-conflict/media/icon.png diff --git a/lib/vscode/extensions/merge-conflict/package.json b/extensions/merge-conflict/package.json similarity index 99% rename from lib/vscode/extensions/merge-conflict/package.json rename to extensions/merge-conflict/package.json index 74f7b848fa82..2c4719f4b71a 100644 --- a/lib/vscode/extensions/merge-conflict/package.json +++ b/extensions/merge-conflict/package.json @@ -159,7 +159,7 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "^12.19.9" + "@types/node": "14.x" }, "repository": { "type": "git", diff --git a/lib/vscode/extensions/merge-conflict/package.nls.json b/extensions/merge-conflict/package.nls.json similarity index 100% rename from lib/vscode/extensions/merge-conflict/package.nls.json rename to extensions/merge-conflict/package.nls.json diff --git a/lib/vscode/extensions/merge-conflict/src/codelensProvider.ts b/extensions/merge-conflict/src/codelensProvider.ts similarity index 100% rename from lib/vscode/extensions/merge-conflict/src/codelensProvider.ts rename to extensions/merge-conflict/src/codelensProvider.ts diff --git a/lib/vscode/extensions/merge-conflict/src/commandHandler.ts b/extensions/merge-conflict/src/commandHandler.ts similarity index 100% rename from lib/vscode/extensions/merge-conflict/src/commandHandler.ts rename to extensions/merge-conflict/src/commandHandler.ts diff --git a/lib/vscode/extensions/merge-conflict/src/contentProvider.ts b/extensions/merge-conflict/src/contentProvider.ts similarity index 100% rename from lib/vscode/extensions/merge-conflict/src/contentProvider.ts rename to extensions/merge-conflict/src/contentProvider.ts diff --git a/lib/vscode/extensions/merge-conflict/src/delayer.ts b/extensions/merge-conflict/src/delayer.ts similarity index 100% rename from lib/vscode/extensions/merge-conflict/src/delayer.ts rename to extensions/merge-conflict/src/delayer.ts diff --git a/lib/vscode/extensions/merge-conflict/src/documentMergeConflict.ts b/extensions/merge-conflict/src/documentMergeConflict.ts similarity index 100% rename from lib/vscode/extensions/merge-conflict/src/documentMergeConflict.ts rename to extensions/merge-conflict/src/documentMergeConflict.ts diff --git a/lib/vscode/extensions/merge-conflict/src/documentTracker.ts b/extensions/merge-conflict/src/documentTracker.ts similarity index 100% rename from lib/vscode/extensions/merge-conflict/src/documentTracker.ts rename to extensions/merge-conflict/src/documentTracker.ts diff --git a/lib/vscode/extensions/merge-conflict/src/interfaces.ts b/extensions/merge-conflict/src/interfaces.ts similarity index 100% rename from lib/vscode/extensions/merge-conflict/src/interfaces.ts rename to extensions/merge-conflict/src/interfaces.ts diff --git a/lib/vscode/extensions/merge-conflict/src/mergeConflictMain.ts b/extensions/merge-conflict/src/mergeConflictMain.ts similarity index 100% rename from lib/vscode/extensions/merge-conflict/src/mergeConflictMain.ts rename to extensions/merge-conflict/src/mergeConflictMain.ts diff --git a/lib/vscode/extensions/merge-conflict/src/mergeConflictParser.ts b/extensions/merge-conflict/src/mergeConflictParser.ts similarity index 100% rename from lib/vscode/extensions/merge-conflict/src/mergeConflictParser.ts rename to extensions/merge-conflict/src/mergeConflictParser.ts diff --git a/lib/vscode/extensions/merge-conflict/src/mergeDecorator.ts b/extensions/merge-conflict/src/mergeDecorator.ts similarity index 100% rename from lib/vscode/extensions/merge-conflict/src/mergeDecorator.ts rename to extensions/merge-conflict/src/mergeDecorator.ts diff --git a/lib/vscode/extensions/merge-conflict/src/services.ts b/extensions/merge-conflict/src/services.ts similarity index 100% rename from lib/vscode/extensions/merge-conflict/src/services.ts rename to extensions/merge-conflict/src/services.ts diff --git a/lib/vscode/extensions/merge-conflict/src/typings/refs.d.ts b/extensions/merge-conflict/src/typings/refs.d.ts similarity index 100% rename from lib/vscode/extensions/merge-conflict/src/typings/refs.d.ts rename to extensions/merge-conflict/src/typings/refs.d.ts diff --git a/lib/vscode/extensions/merge-conflict/tsconfig.json b/extensions/merge-conflict/tsconfig.json similarity index 100% rename from lib/vscode/extensions/merge-conflict/tsconfig.json rename to extensions/merge-conflict/tsconfig.json diff --git a/extensions/merge-conflict/yarn.lock b/extensions/merge-conflict/yarn.lock new file mode 100644 index 000000000000..f7a30098ef45 --- /dev/null +++ b/extensions/merge-conflict/yarn.lock @@ -0,0 +1,13 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== + +vscode-nls@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" + integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== diff --git a/lib/vscode/extensions/microsoft-authentication/.vscodeignore b/extensions/microsoft-authentication/.vscodeignore similarity index 100% rename from lib/vscode/extensions/microsoft-authentication/.vscodeignore rename to extensions/microsoft-authentication/.vscodeignore diff --git a/lib/vscode/extensions/microsoft-authentication/extension-browser.webpack.config.js b/extensions/microsoft-authentication/extension-browser.webpack.config.js similarity index 100% rename from lib/vscode/extensions/microsoft-authentication/extension-browser.webpack.config.js rename to extensions/microsoft-authentication/extension-browser.webpack.config.js diff --git a/lib/vscode/extensions/microsoft-authentication/extension.webpack.config.js b/extensions/microsoft-authentication/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/microsoft-authentication/extension.webpack.config.js rename to extensions/microsoft-authentication/extension.webpack.config.js diff --git a/lib/vscode/extensions/microsoft-authentication/media/auth.css b/extensions/microsoft-authentication/media/auth.css similarity index 100% rename from lib/vscode/extensions/microsoft-authentication/media/auth.css rename to extensions/microsoft-authentication/media/auth.css diff --git a/lib/vscode/extensions/microsoft-authentication/media/auth.html b/extensions/microsoft-authentication/media/auth.html similarity index 100% rename from lib/vscode/extensions/microsoft-authentication/media/auth.html rename to extensions/microsoft-authentication/media/auth.html diff --git a/lib/vscode/extensions/microsoft-authentication/media/icon.png b/extensions/microsoft-authentication/media/icon.png similarity index 100% rename from lib/vscode/extensions/microsoft-authentication/media/icon.png rename to extensions/microsoft-authentication/media/icon.png diff --git a/lib/vscode/extensions/microsoft-authentication/package.json b/extensions/microsoft-authentication/package.json similarity index 98% rename from lib/vscode/extensions/microsoft-authentication/package.json rename to extensions/microsoft-authentication/package.json index 7b47354df0fb..148b5c3625c0 100644 --- a/lib/vscode/extensions/microsoft-authentication/package.json +++ b/extensions/microsoft-authentication/package.json @@ -46,7 +46,7 @@ "watch-web": "npx webpack-cli --config extension-browser.webpack.config --mode none --watch --info-verbosity verbose" }, "devDependencies": { - "@types/node": "^12.19.9", + "@types/node": "14.x", "@types/node-fetch": "^2.5.7", "@types/randombytes": "^2.0.0", "@types/sha.js": "^2.4.0", diff --git a/lib/vscode/extensions/microsoft-authentication/package.nls.json b/extensions/microsoft-authentication/package.nls.json similarity index 100% rename from lib/vscode/extensions/microsoft-authentication/package.nls.json rename to extensions/microsoft-authentication/package.nls.json diff --git a/lib/vscode/extensions/microsoft-authentication/src/AADHelper.ts b/extensions/microsoft-authentication/src/AADHelper.ts similarity index 96% rename from lib/vscode/extensions/microsoft-authentication/src/AADHelper.ts rename to extensions/microsoft-authentication/src/AADHelper.ts index 2414055c282c..77618032c12c 100644 --- a/lib/vscode/extensions/microsoft-authentication/src/AADHelper.ts +++ b/extensions/microsoft-authentication/src/AADHelper.ts @@ -396,19 +396,19 @@ export class AzureActiveDirectoryService { } private getCallbackEnvironment(callbackUri: vscode.Uri): string { - if (callbackUri.authority.endsWith('.workspaces.github.com') || callbackUri.authority.endsWith('.github.dev')) { - return `${callbackUri.authority},`; + if (callbackUri.scheme !== 'https' && callbackUri.scheme !== 'http') { + return callbackUri.scheme; } switch (callbackUri.authority) { case 'online.visualstudio.com': - return 'vso,'; + return 'vso'; case 'online-ppe.core.vsengsaas.visualstudio.com': - return 'vsoppe,'; + return 'vsoppe'; case 'online.dev.core.vsengsaas.visualstudio.com': - return 'vsodev,'; + return 'vsodev'; default: - return `${callbackUri.scheme},`; + return callbackUri.authority; } } @@ -417,7 +417,7 @@ export class AzureActiveDirectoryService { const nonce = randomBytes(16).toString('base64'); const port = (callbackUri.authority.match(/:([0-9]*)$/) || [])[1] || (callbackUri.scheme === 'https' ? 443 : 80); const callbackEnvironment = this.getCallbackEnvironment(callbackUri); - const state = `${callbackEnvironment}${port},${encodeURIComponent(nonce)},${encodeURIComponent(callbackUri.query)}`; + const state = `${callbackEnvironment},${port},${encodeURIComponent(nonce)},${encodeURIComponent(callbackUri.query)}`; const signInUrl = `${loginEndpointUrl}${tenant}/oauth2/v2.0/authorize`; let uri = vscode.Uri.parse(signInUrl); const codeVerifier = toBase64UrlEncoding(randomBytes(32).toString('base64')); @@ -566,7 +566,8 @@ export class AzureActiveDirectoryService { }); const proxyEndpoints: { [providerId: string]: string } | undefined = await vscode.commands.executeCommand('workbench.getCodeExchangeProxyEndpoints'); - const endpoint = proxyEndpoints && proxyEndpoints['microsoft'] || `${loginEndpointUrl}${tenant}/oauth2/v2.0/token`; + const endpointUrl = proxyEndpoints?.microsoft || loginEndpointUrl; + const endpoint = `${endpointUrl}${tenant}/oauth2/v2.0/token`; const result = await fetch(endpoint, { method: 'POST', @@ -602,7 +603,10 @@ export class AzureActiveDirectoryService { let result: Response; try { - result = await fetch(`https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token`, { + const proxyEndpoints: { [providerId: string]: string } | undefined = await vscode.commands.executeCommand('workbench.getCodeExchangeProxyEndpoints'); + const endpointUrl = proxyEndpoints?.microsoft || loginEndpointUrl; + const endpoint = `${endpointUrl}${tenant}/oauth2/v2.0/token`; + result = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', diff --git a/lib/vscode/extensions/microsoft-authentication/src/authServer.ts b/extensions/microsoft-authentication/src/authServer.ts similarity index 100% rename from lib/vscode/extensions/microsoft-authentication/src/authServer.ts rename to extensions/microsoft-authentication/src/authServer.ts diff --git a/lib/vscode/extensions/microsoft-authentication/src/env/browser/authServer.ts b/extensions/microsoft-authentication/src/env/browser/authServer.ts similarity index 100% rename from lib/vscode/extensions/microsoft-authentication/src/env/browser/authServer.ts rename to extensions/microsoft-authentication/src/env/browser/authServer.ts diff --git a/lib/vscode/extensions/microsoft-authentication/src/env/browser/sha256.ts b/extensions/microsoft-authentication/src/env/browser/sha256.ts similarity index 100% rename from lib/vscode/extensions/microsoft-authentication/src/env/browser/sha256.ts rename to extensions/microsoft-authentication/src/env/browser/sha256.ts diff --git a/lib/vscode/extensions/microsoft-authentication/src/env/node/sha256.ts b/extensions/microsoft-authentication/src/env/node/sha256.ts similarity index 100% rename from lib/vscode/extensions/microsoft-authentication/src/env/node/sha256.ts rename to extensions/microsoft-authentication/src/env/node/sha256.ts diff --git a/lib/vscode/extensions/microsoft-authentication/src/extension.ts b/extensions/microsoft-authentication/src/extension.ts similarity index 100% rename from lib/vscode/extensions/microsoft-authentication/src/extension.ts rename to extensions/microsoft-authentication/src/extension.ts diff --git a/lib/vscode/extensions/microsoft-authentication/src/keychain.ts b/extensions/microsoft-authentication/src/keychain.ts similarity index 100% rename from lib/vscode/extensions/microsoft-authentication/src/keychain.ts rename to extensions/microsoft-authentication/src/keychain.ts diff --git a/lib/vscode/extensions/microsoft-authentication/src/logger.ts b/extensions/microsoft-authentication/src/logger.ts similarity index 100% rename from lib/vscode/extensions/microsoft-authentication/src/logger.ts rename to extensions/microsoft-authentication/src/logger.ts diff --git a/lib/vscode/extensions/microsoft-authentication/src/microsoft-authentication.d.ts b/extensions/microsoft-authentication/src/microsoft-authentication.d.ts similarity index 100% rename from lib/vscode/extensions/microsoft-authentication/src/microsoft-authentication.d.ts rename to extensions/microsoft-authentication/src/microsoft-authentication.d.ts diff --git a/lib/vscode/extensions/search-result/src/typings/refs.d.ts b/extensions/microsoft-authentication/src/typings/refs.d.ts similarity index 100% rename from lib/vscode/extensions/search-result/src/typings/refs.d.ts rename to extensions/microsoft-authentication/src/typings/refs.d.ts diff --git a/lib/vscode/extensions/microsoft-authentication/src/utils.ts b/extensions/microsoft-authentication/src/utils.ts similarity index 100% rename from lib/vscode/extensions/microsoft-authentication/src/utils.ts rename to extensions/microsoft-authentication/src/utils.ts diff --git a/lib/vscode/extensions/microsoft-authentication/tsconfig.json b/extensions/microsoft-authentication/tsconfig.json similarity index 100% rename from lib/vscode/extensions/microsoft-authentication/tsconfig.json rename to extensions/microsoft-authentication/tsconfig.json diff --git a/lib/vscode/extensions/microsoft-authentication/yarn.lock b/extensions/microsoft-authentication/yarn.lock similarity index 97% rename from lib/vscode/extensions/microsoft-authentication/yarn.lock rename to extensions/microsoft-authentication/yarn.lock index fada1d6e8bf5..54025e55a213 100644 --- a/lib/vscode/extensions/microsoft-authentication/yarn.lock +++ b/extensions/microsoft-authentication/yarn.lock @@ -15,10 +15,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.23.tgz#676fa0883450ed9da0bb24156213636290892806" integrity sha512-Z4U8yDAl5TFkmYsZdFPdjeMa57NOvnaf1tljHzhouaPEp7LCj2JKkejpI1ODviIAQuW4CcQmxkQ77rnLsOOoKw== -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== "@types/randombytes@^2.0.0": version "2.0.0" diff --git a/lib/vscode/extensions/notebook-markdown-extensions/.gitignore b/extensions/notebook-markdown-extensions/.gitignore similarity index 100% rename from lib/vscode/extensions/notebook-markdown-extensions/.gitignore rename to extensions/notebook-markdown-extensions/.gitignore diff --git a/lib/vscode/extensions/notebook-markdown-extensions/.vscodeignore b/extensions/notebook-markdown-extensions/.vscodeignore similarity index 100% rename from lib/vscode/extensions/notebook-markdown-extensions/.vscodeignore rename to extensions/notebook-markdown-extensions/.vscodeignore diff --git a/lib/vscode/extensions/notebook-markdown-extensions/README.md b/extensions/notebook-markdown-extensions/README.md similarity index 100% rename from lib/vscode/extensions/notebook-markdown-extensions/README.md rename to extensions/notebook-markdown-extensions/README.md diff --git a/lib/vscode/extensions/notebook-markdown-extensions/esbuild.js b/extensions/notebook-markdown-extensions/esbuild.js similarity index 100% rename from lib/vscode/extensions/notebook-markdown-extensions/esbuild.js rename to extensions/notebook-markdown-extensions/esbuild.js diff --git a/lib/vscode/extensions/notebook-markdown-extensions/icon.png b/extensions/notebook-markdown-extensions/icon.png similarity index 100% rename from lib/vscode/extensions/notebook-markdown-extensions/icon.png rename to extensions/notebook-markdown-extensions/icon.png diff --git a/lib/vscode/extensions/notebook-markdown-extensions/notebook/katex.ts b/extensions/notebook-markdown-extensions/notebook/emoji.ts similarity index 51% rename from lib/vscode/extensions/notebook-markdown-extensions/notebook/katex.ts rename to extensions/notebook-markdown-extensions/notebook/emoji.ts index f862fd94940a..28557b47047f 100644 --- a/lib/vscode/extensions/notebook-markdown-extensions/notebook/katex.ts +++ b/extensions/notebook-markdown-extensions/notebook/emoji.ts @@ -4,17 +4,17 @@ *--------------------------------------------------------------------------------------------*/ import type * as markdownIt from 'markdown-it'; -const styleHref = import.meta.url.replace(/katex.js$/, 'katex.min.css'); +const emoji = require('markdown-it-emoji'); -const link = document.createElement('link'); -link.rel = 'stylesheet'; -link.classList.add('markdown-style'); -link.href = styleHref; +export async function activate(ctx: { + getRenderer: (id: string) => any +}) { + const markdownItRenderer = await ctx.getRenderer('markdownItRenderer'); + if (!markdownItRenderer) { + throw new Error('Could not load markdownItRenderer'); + } -document.head.append(link); - -const katex = require('@iktakahiro/markdown-it-katex'); - -export function extendMarkdownIt(md: markdownIt.MarkdownIt) { - return md.use(katex); + markdownItRenderer.extendMarkdownIt((md: markdownIt.MarkdownIt) => { + return md.use(emoji); + }); } diff --git a/extensions/notebook-markdown-extensions/notebook/katex.ts b/extensions/notebook-markdown-extensions/notebook/katex.ts new file mode 100644 index 000000000000..27d7be58be73 --- /dev/null +++ b/extensions/notebook-markdown-extensions/notebook/katex.ts @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import type * as markdownIt from 'markdown-it'; + +const styleHref = import.meta.url.replace(/katex.js$/, 'katex.min.css'); + +export async function activate(ctx: { + getRenderer: (id: string) => Promise +}) { + const markdownItRenderer = await ctx.getRenderer('markdownItRenderer'); + if (!markdownItRenderer) { + throw new Error('Could not load markdownItRenderer'); + } + + const link = document.createElement('link'); + link.rel = 'stylesheet'; + link.classList.add('markdown-style'); + link.href = styleHref; + document.head.append(link); + + const style = document.createElement('style'); + style.classList.add('markdown-style'); + style.textContent = ` + .katex-error { + color: var(--vscode-editorError-foreground); + } + `; + document.head.append(style); + + const katex = require('@iktakahiro/markdown-it-katex'); + markdownItRenderer.extendMarkdownIt((md: markdownIt.MarkdownIt) => { + return md.use(katex); + }); +} diff --git a/lib/vscode/extensions/notebook-markdown-extensions/notebook/tsconfig.json b/extensions/notebook-markdown-extensions/notebook/tsconfig.json similarity index 100% rename from lib/vscode/extensions/notebook-markdown-extensions/notebook/tsconfig.json rename to extensions/notebook-markdown-extensions/notebook/tsconfig.json diff --git a/lib/vscode/extensions/notebook-markdown-extensions/package.json b/extensions/notebook-markdown-extensions/package.json similarity index 75% rename from lib/vscode/extensions/notebook-markdown-extensions/package.json rename to extensions/notebook-markdown-extensions/package.json index 1622659825ff..981566798f6f 100644 --- a/lib/vscode/extensions/notebook-markdown-extensions/package.json +++ b/extensions/notebook-markdown-extensions/package.json @@ -15,21 +15,28 @@ "Other" ], "capabilities": { - "virtualWorkspaces": false + "virtualWorkspaces": true, + "untrustedWorkspaces": { + "supported": true + } }, "contributes": { - "notebookMarkupRenderers": [ + "notebookRenderer": [ { "id": "markdownItRenderer-katex", "displayName": "Markdown it katex renderer", - "entrypoint": "./notebook-out/katex.js", - "dependsOn": "markdownItRenderer" + "entrypoint": { + "extends": "markdownItRenderer", + "path": "./notebook-out/katex.js" + } }, { "id": "markdownItRenderer-emoji", "displayName": "Markdown it emoji renderer", - "entrypoint": "./notebook-out/emoji.js", - "dependsOn": "markdownItRenderer" + "entrypoint": { + "extends": "markdownItRenderer", + "path": "./notebook-out/emoji.js" + } } ] }, diff --git a/lib/vscode/extensions/notebook-markdown-extensions/package.nls.json b/extensions/notebook-markdown-extensions/package.nls.json similarity index 100% rename from lib/vscode/extensions/notebook-markdown-extensions/package.nls.json rename to extensions/notebook-markdown-extensions/package.nls.json diff --git a/lib/vscode/extensions/notebook-markdown-extensions/yarn.lock b/extensions/notebook-markdown-extensions/yarn.lock similarity index 96% rename from lib/vscode/extensions/notebook-markdown-extensions/yarn.lock rename to extensions/notebook-markdown-extensions/yarn.lock index 58952667358a..1ae78c16ae80 100644 --- a/lib/vscode/extensions/notebook-markdown-extensions/yarn.lock +++ b/extensions/notebook-markdown-extensions/yarn.lock @@ -4,7 +4,7 @@ "@iktakahiro/markdown-it-katex@https://github.com/mjbvz/markdown-it-katex.git": version "4.0.1" - resolved "https://github.com/mjbvz/markdown-it-katex.git#e88925a7cb3fd593a14ed117fb43627c4ba910b6" + resolved "https://github.com/mjbvz/markdown-it-katex.git#2bf0b89c6c22ef0b585f55ccab66d1f7c5356bea" dependencies: katex "^0.13.0" diff --git a/lib/vscode/extensions/npm/.vscode/launch.json b/extensions/npm/.vscode/launch.json similarity index 100% rename from lib/vscode/extensions/npm/.vscode/launch.json rename to extensions/npm/.vscode/launch.json diff --git a/lib/vscode/extensions/npm/.vscode/tasks.json b/extensions/npm/.vscode/tasks.json similarity index 100% rename from lib/vscode/extensions/npm/.vscode/tasks.json rename to extensions/npm/.vscode/tasks.json diff --git a/lib/vscode/extensions/npm/.vscodeignore b/extensions/npm/.vscodeignore similarity index 100% rename from lib/vscode/extensions/npm/.vscodeignore rename to extensions/npm/.vscodeignore diff --git a/lib/vscode/extensions/npm/README.md b/extensions/npm/README.md similarity index 100% rename from lib/vscode/extensions/npm/README.md rename to extensions/npm/README.md diff --git a/lib/vscode/extensions/npm/extension-browser.webpack.config.js b/extensions/npm/extension-browser.webpack.config.js similarity index 100% rename from lib/vscode/extensions/npm/extension-browser.webpack.config.js rename to extensions/npm/extension-browser.webpack.config.js diff --git a/lib/vscode/extensions/npm/extension.webpack.config.js b/extensions/npm/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/npm/extension.webpack.config.js rename to extensions/npm/extension.webpack.config.js diff --git a/lib/vscode/extensions/npm/images/code.svg b/extensions/npm/images/code.svg similarity index 100% rename from lib/vscode/extensions/npm/images/code.svg rename to extensions/npm/images/code.svg diff --git a/lib/vscode/extensions/npm/images/npm_icon.png b/extensions/npm/images/npm_icon.png similarity index 100% rename from lib/vscode/extensions/npm/images/npm_icon.png rename to extensions/npm/images/npm_icon.png diff --git a/lib/vscode/extensions/npm/package.json b/extensions/npm/package.json similarity index 99% rename from lib/vscode/extensions/npm/package.json rename to extensions/npm/package.json index ab75bdf34eb4..038f091b78e8 100644 --- a/lib/vscode/extensions/npm/package.json +++ b/extensions/npm/package.json @@ -29,7 +29,7 @@ }, "devDependencies": { "@types/minimatch": "^3.0.3", - "@types/node": "^12.19.9", + "@types/node": "14.x", "@types/which": "^2.0.0" }, "resolutions": { diff --git a/lib/vscode/extensions/npm/package.nls.json b/extensions/npm/package.nls.json similarity index 95% rename from lib/vscode/extensions/npm/package.nls.json rename to extensions/npm/package.nls.json index b8570d0da82e..b3ff9a4d2292 100644 --- a/lib/vscode/extensions/npm/package.nls.json +++ b/extensions/npm/package.nls.json @@ -1,7 +1,7 @@ { "description": "Extension to add task support for npm scripts.", "displayName": "NPM support for VS Code", - "workspaceTrust": "This extension calls the `tasks.executeTask()` API, which requires trust to run.", + "workspaceTrust": "This extension executes tasks, which require trust to run.", "config.npm.autoDetect": "Controls whether npm scripts should be automatically detected.", "config.npm.runSilent": "Run npm commands with the `--silent` option.", "config.npm.packageManager": "The package manager used to run scripts.", diff --git a/lib/vscode/extensions/npm/src/commands.ts b/extensions/npm/src/commands.ts similarity index 100% rename from lib/vscode/extensions/npm/src/commands.ts rename to extensions/npm/src/commands.ts diff --git a/lib/vscode/extensions/npm/src/features/bowerJSONContribution.ts b/extensions/npm/src/features/bowerJSONContribution.ts similarity index 100% rename from lib/vscode/extensions/npm/src/features/bowerJSONContribution.ts rename to extensions/npm/src/features/bowerJSONContribution.ts diff --git a/lib/vscode/extensions/npm/src/features/jsonContributions.ts b/extensions/npm/src/features/jsonContributions.ts similarity index 100% rename from lib/vscode/extensions/npm/src/features/jsonContributions.ts rename to extensions/npm/src/features/jsonContributions.ts diff --git a/lib/vscode/extensions/npm/src/features/packageJSONContribution.ts b/extensions/npm/src/features/packageJSONContribution.ts similarity index 100% rename from lib/vscode/extensions/npm/src/features/packageJSONContribution.ts rename to extensions/npm/src/features/packageJSONContribution.ts diff --git a/lib/vscode/extensions/npm/src/npmBrowserMain.ts b/extensions/npm/src/npmBrowserMain.ts similarity index 100% rename from lib/vscode/extensions/npm/src/npmBrowserMain.ts rename to extensions/npm/src/npmBrowserMain.ts diff --git a/lib/vscode/extensions/npm/src/npmMain.ts b/extensions/npm/src/npmMain.ts similarity index 100% rename from lib/vscode/extensions/npm/src/npmMain.ts rename to extensions/npm/src/npmMain.ts diff --git a/lib/vscode/extensions/npm/src/npmScriptLens.ts b/extensions/npm/src/npmScriptLens.ts similarity index 100% rename from lib/vscode/extensions/npm/src/npmScriptLens.ts rename to extensions/npm/src/npmScriptLens.ts diff --git a/lib/vscode/extensions/npm/src/npmView.ts b/extensions/npm/src/npmView.ts similarity index 100% rename from lib/vscode/extensions/npm/src/npmView.ts rename to extensions/npm/src/npmView.ts diff --git a/lib/vscode/extensions/npm/src/preferred-pm.ts b/extensions/npm/src/preferred-pm.ts similarity index 100% rename from lib/vscode/extensions/npm/src/preferred-pm.ts rename to extensions/npm/src/preferred-pm.ts diff --git a/lib/vscode/extensions/npm/src/readScripts.ts b/extensions/npm/src/readScripts.ts similarity index 100% rename from lib/vscode/extensions/npm/src/readScripts.ts rename to extensions/npm/src/readScripts.ts diff --git a/lib/vscode/extensions/npm/src/scriptHover.ts b/extensions/npm/src/scriptHover.ts similarity index 100% rename from lib/vscode/extensions/npm/src/scriptHover.ts rename to extensions/npm/src/scriptHover.ts diff --git a/lib/vscode/extensions/npm/src/tasks.ts b/extensions/npm/src/tasks.ts similarity index 100% rename from lib/vscode/extensions/npm/src/tasks.ts rename to extensions/npm/src/tasks.ts diff --git a/lib/vscode/extensions/npm/src/typings/refs.d.ts b/extensions/npm/src/typings/refs.d.ts similarity index 100% rename from lib/vscode/extensions/npm/src/typings/refs.d.ts rename to extensions/npm/src/typings/refs.d.ts diff --git a/lib/vscode/extensions/npm/tsconfig.json b/extensions/npm/tsconfig.json similarity index 100% rename from lib/vscode/extensions/npm/tsconfig.json rename to extensions/npm/tsconfig.json diff --git a/lib/vscode/extensions/npm/yarn.lock b/extensions/npm/yarn.lock similarity index 97% rename from lib/vscode/extensions/npm/yarn.lock rename to extensions/npm/yarn.lock index 6b653dec9d99..29712f0dcc0c 100644 --- a/lib/vscode/extensions/npm/yarn.lock +++ b/extensions/npm/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== "@types/which@^2.0.0": version "2.0.0" diff --git a/lib/vscode/extensions/objective-c/.vscodeignore b/extensions/objective-c/.vscodeignore similarity index 100% rename from lib/vscode/extensions/objective-c/.vscodeignore rename to extensions/objective-c/.vscodeignore diff --git a/lib/vscode/extensions/objective-c/build/update-grammars.js b/extensions/objective-c/build/update-grammars.js similarity index 100% rename from lib/vscode/extensions/objective-c/build/update-grammars.js rename to extensions/objective-c/build/update-grammars.js diff --git a/lib/vscode/extensions/objective-c/cgmanifest.json b/extensions/objective-c/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/objective-c/cgmanifest.json rename to extensions/objective-c/cgmanifest.json diff --git a/lib/vscode/extensions/objective-c/language-configuration.json b/extensions/objective-c/language-configuration.json similarity index 100% rename from lib/vscode/extensions/objective-c/language-configuration.json rename to extensions/objective-c/language-configuration.json diff --git a/lib/vscode/extensions/objective-c/package.json b/extensions/objective-c/package.json similarity index 100% rename from lib/vscode/extensions/objective-c/package.json rename to extensions/objective-c/package.json diff --git a/lib/vscode/extensions/objective-c/package.nls.json b/extensions/objective-c/package.nls.json similarity index 100% rename from lib/vscode/extensions/objective-c/package.nls.json rename to extensions/objective-c/package.nls.json diff --git a/lib/vscode/extensions/objective-c/syntaxes/objective-c++.tmLanguage.json b/extensions/objective-c/syntaxes/objective-c++.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/objective-c/syntaxes/objective-c++.tmLanguage.json rename to extensions/objective-c/syntaxes/objective-c++.tmLanguage.json diff --git a/lib/vscode/extensions/objective-c/syntaxes/objective-c.tmLanguage.json b/extensions/objective-c/syntaxes/objective-c.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/objective-c/syntaxes/objective-c.tmLanguage.json rename to extensions/objective-c/syntaxes/objective-c.tmLanguage.json diff --git a/lib/vscode/extensions/objective-c/yarn.lock b/extensions/objective-c/yarn.lock similarity index 100% rename from lib/vscode/extensions/objective-c/yarn.lock rename to extensions/objective-c/yarn.lock diff --git a/lib/vscode/extensions/package.json b/extensions/package.json similarity index 92% rename from lib/vscode/extensions/package.json rename to extensions/package.json index 645ea5c23cb1..06af3843aea1 100644 --- a/lib/vscode/extensions/package.json +++ b/extensions/package.json @@ -4,7 +4,7 @@ "license": "MIT", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "4.2.4" + "typescript": "4.3.2" }, "scripts": { "postinstall": "node ./postinstall" diff --git a/lib/vscode/extensions/perl/.vscodeignore b/extensions/perl/.vscodeignore similarity index 100% rename from lib/vscode/extensions/perl/.vscodeignore rename to extensions/perl/.vscodeignore diff --git a/lib/vscode/extensions/perl/cgmanifest.json b/extensions/perl/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/perl/cgmanifest.json rename to extensions/perl/cgmanifest.json diff --git a/lib/vscode/extensions/perl/package.json b/extensions/perl/package.json similarity index 100% rename from lib/vscode/extensions/perl/package.json rename to extensions/perl/package.json diff --git a/lib/vscode/extensions/perl/package.nls.json b/extensions/perl/package.nls.json similarity index 100% rename from lib/vscode/extensions/perl/package.nls.json rename to extensions/perl/package.nls.json diff --git a/lib/vscode/extensions/perl/perl.language-configuration.json b/extensions/perl/perl.language-configuration.json similarity index 100% rename from lib/vscode/extensions/perl/perl.language-configuration.json rename to extensions/perl/perl.language-configuration.json diff --git a/lib/vscode/extensions/perl/perl6.language-configuration.json b/extensions/perl/perl6.language-configuration.json similarity index 100% rename from lib/vscode/extensions/perl/perl6.language-configuration.json rename to extensions/perl/perl6.language-configuration.json diff --git a/lib/vscode/extensions/perl/syntaxes/perl.tmLanguage.json b/extensions/perl/syntaxes/perl.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/perl/syntaxes/perl.tmLanguage.json rename to extensions/perl/syntaxes/perl.tmLanguage.json diff --git a/lib/vscode/extensions/perl/syntaxes/perl6.tmLanguage.json b/extensions/perl/syntaxes/perl6.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/perl/syntaxes/perl6.tmLanguage.json rename to extensions/perl/syntaxes/perl6.tmLanguage.json diff --git a/lib/vscode/extensions/perl/yarn.lock b/extensions/perl/yarn.lock similarity index 100% rename from lib/vscode/extensions/perl/yarn.lock rename to extensions/perl/yarn.lock diff --git a/lib/vscode/extensions/php-language-features/.vscodeignore b/extensions/php-language-features/.vscodeignore similarity index 100% rename from lib/vscode/extensions/php-language-features/.vscodeignore rename to extensions/php-language-features/.vscodeignore diff --git a/lib/vscode/extensions/php-language-features/README.md b/extensions/php-language-features/README.md similarity index 100% rename from lib/vscode/extensions/php-language-features/README.md rename to extensions/php-language-features/README.md diff --git a/lib/vscode/extensions/php-language-features/extension.webpack.config.js b/extensions/php-language-features/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/php-language-features/extension.webpack.config.js rename to extensions/php-language-features/extension.webpack.config.js diff --git a/lib/vscode/extensions/php-language-features/icons/logo.png b/extensions/php-language-features/icons/logo.png similarity index 100% rename from lib/vscode/extensions/php-language-features/icons/logo.png rename to extensions/php-language-features/icons/logo.png diff --git a/lib/vscode/extensions/php-language-features/package.json b/extensions/php-language-features/package.json similarity index 98% rename from lib/vscode/extensions/php-language-features/package.json rename to extensions/php-language-features/package.json index 3763949d6477..79ae40954769 100644 --- a/lib/vscode/extensions/php-language-features/package.json +++ b/extensions/php-language-features/package.json @@ -94,7 +94,7 @@ "which": "^2.0.2" }, "devDependencies": { - "@types/node": "^12.19.9", + "@types/node": "14.x", "@types/which": "^2.0.0" }, "repository": { diff --git a/lib/vscode/extensions/php-language-features/package.nls.json b/extensions/php-language-features/package.nls.json similarity index 100% rename from lib/vscode/extensions/php-language-features/package.nls.json rename to extensions/php-language-features/package.nls.json diff --git a/lib/vscode/extensions/php-language-features/src/features/completionItemProvider.ts b/extensions/php-language-features/src/features/completionItemProvider.ts similarity index 100% rename from lib/vscode/extensions/php-language-features/src/features/completionItemProvider.ts rename to extensions/php-language-features/src/features/completionItemProvider.ts diff --git a/lib/vscode/extensions/php-language-features/src/features/hoverProvider.ts b/extensions/php-language-features/src/features/hoverProvider.ts similarity index 100% rename from lib/vscode/extensions/php-language-features/src/features/hoverProvider.ts rename to extensions/php-language-features/src/features/hoverProvider.ts diff --git a/lib/vscode/extensions/php-language-features/src/features/phpGlobalFunctions.ts b/extensions/php-language-features/src/features/phpGlobalFunctions.ts similarity index 100% rename from lib/vscode/extensions/php-language-features/src/features/phpGlobalFunctions.ts rename to extensions/php-language-features/src/features/phpGlobalFunctions.ts diff --git a/lib/vscode/extensions/php-language-features/src/features/phpGlobals.ts b/extensions/php-language-features/src/features/phpGlobals.ts similarity index 100% rename from lib/vscode/extensions/php-language-features/src/features/phpGlobals.ts rename to extensions/php-language-features/src/features/phpGlobals.ts diff --git a/lib/vscode/extensions/php-language-features/src/features/signatureHelpProvider.ts b/extensions/php-language-features/src/features/signatureHelpProvider.ts similarity index 100% rename from lib/vscode/extensions/php-language-features/src/features/signatureHelpProvider.ts rename to extensions/php-language-features/src/features/signatureHelpProvider.ts diff --git a/lib/vscode/extensions/php-language-features/src/features/utils/async.ts b/extensions/php-language-features/src/features/utils/async.ts similarity index 100% rename from lib/vscode/extensions/php-language-features/src/features/utils/async.ts rename to extensions/php-language-features/src/features/utils/async.ts diff --git a/lib/vscode/extensions/php-language-features/src/features/utils/markedTextUtil.ts b/extensions/php-language-features/src/features/utils/markedTextUtil.ts similarity index 100% rename from lib/vscode/extensions/php-language-features/src/features/utils/markedTextUtil.ts rename to extensions/php-language-features/src/features/utils/markedTextUtil.ts diff --git a/lib/vscode/extensions/php-language-features/src/features/validationProvider.ts b/extensions/php-language-features/src/features/validationProvider.ts similarity index 94% rename from lib/vscode/extensions/php-language-features/src/features/validationProvider.ts rename to extensions/php-language-features/src/features/validationProvider.ts index acc6beaf2b57..fb4111c874b8 100644 --- a/lib/vscode/extensions/php-language-features/src/features/validationProvider.ts +++ b/extensions/php-language-features/src/features/validationProvider.ts @@ -23,7 +23,7 @@ export class LineDecoder { private stringDecoder: StringDecoder; private remaining: string | null; - constructor(encoding: string = 'utf8') { + constructor(encoding: BufferEncoding = 'utf8') { this.stringDecoder = new StringDecoder(encoding); this.remaining = null; } @@ -194,15 +194,17 @@ export default class PHPValidationProvider { if (vscode.workspace.isTrusted) { trigger(); } - } else if (this.config!.executableIsUserDefined !== undefined && !this.config!.executableIsUserDefined) { - const checkedExecutablePath = this.workspaceStore.get(Setting.CheckedExecutablePath, undefined); - if (!checkedExecutablePath || checkedExecutablePath !== this.config!.executable) { - if (await this.showCustomTrustDialog()) { - this.workspaceStore.update(Setting.CheckedExecutablePath, this.config!.executable); - vscode.commands.executeCommand('setContext', 'php.untrustValidationExecutableContext', true); - } else { - this.pauseValidation = true; - return; + } else { + if (this.config!.executableIsUserDefined !== undefined && !this.config!.executableIsUserDefined) { + const checkedExecutablePath = this.workspaceStore.get(Setting.CheckedExecutablePath, undefined); + if (!checkedExecutablePath || checkedExecutablePath !== this.config!.executable) { + if (await this.showCustomTrustDialog()) { + this.workspaceStore.update(Setting.CheckedExecutablePath, this.config!.executable); + vscode.commands.executeCommand('setContext', 'php.untrustValidationExecutableContext', true); + } else { + this.pauseValidation = true; + return; + } } } diff --git a/lib/vscode/extensions/php-language-features/src/phpMain.ts b/extensions/php-language-features/src/phpMain.ts similarity index 100% rename from lib/vscode/extensions/php-language-features/src/phpMain.ts rename to extensions/php-language-features/src/phpMain.ts diff --git a/lib/vscode/extensions/php-language-features/src/typings/node.additions.d.ts b/extensions/php-language-features/src/typings/node.additions.d.ts similarity index 100% rename from lib/vscode/extensions/php-language-features/src/typings/node.additions.d.ts rename to extensions/php-language-features/src/typings/node.additions.d.ts diff --git a/lib/vscode/extensions/php-language-features/src/typings/refs.d.ts b/extensions/php-language-features/src/typings/refs.d.ts similarity index 100% rename from lib/vscode/extensions/php-language-features/src/typings/refs.d.ts rename to extensions/php-language-features/src/typings/refs.d.ts diff --git a/lib/vscode/extensions/php-language-features/tsconfig.json b/extensions/php-language-features/tsconfig.json similarity index 100% rename from lib/vscode/extensions/php-language-features/tsconfig.json rename to extensions/php-language-features/tsconfig.json diff --git a/lib/vscode/extensions/php-language-features/yarn.lock b/extensions/php-language-features/yarn.lock similarity index 80% rename from lib/vscode/extensions/php-language-features/yarn.lock rename to extensions/php-language-features/yarn.lock index b0fa5625a6df..09b31c801237 100644 --- a/lib/vscode/extensions/php-language-features/yarn.lock +++ b/extensions/php-language-features/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== "@types/which@^2.0.0": version "2.0.0" diff --git a/lib/vscode/extensions/php/.vscode/launch.json b/extensions/php/.vscode/launch.json similarity index 100% rename from lib/vscode/extensions/php/.vscode/launch.json rename to extensions/php/.vscode/launch.json diff --git a/lib/vscode/extensions/php/.vscode/tasks.json b/extensions/php/.vscode/tasks.json similarity index 100% rename from lib/vscode/extensions/php/.vscode/tasks.json rename to extensions/php/.vscode/tasks.json diff --git a/lib/vscode/extensions/php/.vscodeignore b/extensions/php/.vscodeignore similarity index 100% rename from lib/vscode/extensions/php/.vscodeignore rename to extensions/php/.vscodeignore diff --git a/lib/vscode/extensions/php/build/update-grammar.js b/extensions/php/build/update-grammar.js similarity index 100% rename from lib/vscode/extensions/php/build/update-grammar.js rename to extensions/php/build/update-grammar.js diff --git a/lib/vscode/extensions/php/cgmanifest.json b/extensions/php/cgmanifest.json similarity index 72% rename from lib/vscode/extensions/php/cgmanifest.json rename to extensions/php/cgmanifest.json index 15b73aeaf6c8..e9abbe63e635 100644 --- a/lib/vscode/extensions/php/cgmanifest.json +++ b/extensions/php/cgmanifest.json @@ -6,11 +6,11 @@ "git": { "name": "language-php", "repositoryUrl": "https://github.com/atom/language-php", - "commitHash": "72739e6341b1b4bf4aa185e928932983baca449e" + "commitHash": "2bf736a814e1a58aa63470c1a29590bd02e924e7" } }, "license": "MIT", - "version": "0.46.0" + "version": "0.46.2" } ], "version": 1 diff --git a/lib/vscode/extensions/php/language-configuration.json b/extensions/php/language-configuration.json similarity index 93% rename from lib/vscode/extensions/php/language-configuration.json rename to extensions/php/language-configuration.json index 9c24c7b724bc..b785c0092ab4 100644 --- a/lib/vscode/extensions/php/language-configuration.json +++ b/extensions/php/language-configuration.json @@ -26,7 +26,7 @@ ], "indentationRules": { "increaseIndentPattern": "({(?!.*}).*|\\(|\\[|((else(\\s)?)?if|else|for(each)?|while|switch|case).*:)\\s*((/[/*].*|)?$|\\?>)", - "decreaseIndentPattern": "^(.*\\*\\/)?\\s*((\\})|(\\)+[;,])|(\\][;,])|\\b(else:)|\\b((end(if|for(each)?|while|switch));))" + "decreaseIndentPattern": "^(.*\\*\\/)?\\s*((\\})|(\\)+[;,])|(\\]\\)*[;,])|\\b(else:)|\\b((end(if|for(each)?|while|switch));))" }, "folding": { "markers": { diff --git a/lib/vscode/extensions/php/package.json b/extensions/php/package.json similarity index 100% rename from lib/vscode/extensions/php/package.json rename to extensions/php/package.json diff --git a/lib/vscode/extensions/php/package.nls.json b/extensions/php/package.nls.json similarity index 100% rename from lib/vscode/extensions/php/package.nls.json rename to extensions/php/package.nls.json diff --git a/lib/vscode/extensions/php/snippets/php.code-snippets b/extensions/php/snippets/php.code-snippets similarity index 100% rename from lib/vscode/extensions/php/snippets/php.code-snippets rename to extensions/php/snippets/php.code-snippets diff --git a/extensions/php/syntaxes/html.tmLanguage.json b/extensions/php/syntaxes/html.tmLanguage.json new file mode 100644 index 000000000000..a8dff09d0a02 --- /dev/null +++ b/extensions/php/syntaxes/html.tmLanguage.json @@ -0,0 +1,88 @@ +{ + "information_for_contributors": [ + "This file has been converted from https://github.com/atom/language-php/blob/master/grammars/html.cson", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": "https://github.com/atom/language-php/commit/2bf736a814e1a58aa63470c1a29590bd02e924e7", + "name": "PHP", + "scopeName": "text.html.php", + "injections": { + "text.html.php - (meta.embedded | meta.tag), L:((text.html.php meta.tag) - (meta.embedded.block.php | meta.embedded.line.php)), L:(source.js - (meta.embedded.block.php | meta.embedded.line.php)), L:(source.css - (meta.embedded.block.php | meta.embedded.line.php))": { + "patterns": [ + { + "include": "#php-tag" + } + ] + } + }, + "patterns": [ + { + "begin": "\\A#!", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.php" + } + }, + "end": "$", + "name": "comment.line.shebang.php" + }, + { + "include": "text.html.derivative" + } + ], + "repository": { + "php-tag": { + "patterns": [ + { + "begin": "<\\?(?i:php|=)?(?![^?]*\\?>)", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + } + }, + "end": "(\\?)>", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "source.php" + } + }, + "name": "meta.embedded.block.php", + "contentName": "source.php", + "patterns": [ + { + "include": "source.php" + } + ] + }, + { + "begin": "<\\?(?i:php|=)?", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.php" + } + }, + "end": "(\\?)>", + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.php" + }, + "1": { + "name": "source.php" + } + }, + "name": "meta.embedded.line.php", + "contentName": "source.php", + "patterns": [ + { + "include": "source.php" + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/lib/vscode/extensions/php/syntaxes/php.tmLanguage.json b/extensions/php/syntaxes/php.tmLanguage.json similarity index 98% rename from lib/vscode/extensions/php/syntaxes/php.tmLanguage.json rename to extensions/php/syntaxes/php.tmLanguage.json index 0dcfc8295c99..d8d7e067384a 100644 --- a/lib/vscode/extensions/php/syntaxes/php.tmLanguage.json +++ b/extensions/php/syntaxes/php.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/atom/language-php/commit/5fae657cf989701e9594912772daff33249839b3", + "version": "https://github.com/atom/language-php/commit/2bf736a814e1a58aa63470c1a29590bd02e924e7", "scopeName": "source.php", "patterns": [ { @@ -2824,6 +2824,59 @@ }, "name": "string.quoted.double.sql.php", "patterns": [ + { + "match": "(#)(\\\\\"|[^\"])*(?=\"|$)", + "name": "comment.line.number-sign.sql", + "captures": { + "1": { + "name": "punctuation.definition.comment.sql" + } + } + }, + { + "match": "(--)(\\\\\"|[^\"])*(?=\"|$)", + "name": "comment.line.double-dash.sql", + "captures": { + "1": { + "name": "punctuation.definition.comment.sql" + } + } + }, + { + "match": "\\\\[\\\\\"`']", + "name": "constant.character.escape.php" + }, + { + "match": "'(?=((\\\\')|[^'\"])*(\"|$))", + "name": "string.quoted.single.unclosed.sql" + }, + { + "match": "`(?=((\\\\`)|[^`\"])*(\"|$))", + "name": "string.quoted.other.backtick.unclosed.sql" + }, + { + "begin": "'", + "end": "'", + "name": "string.quoted.single.sql", + "patterns": [ + { + "include": "#interpolation_double_quoted" + } + ] + }, + { + "begin": "`", + "end": "`", + "name": "string.quoted.other.backtick.sql", + "patterns": [ + { + "include": "#interpolation_double_quoted" + } + ] + }, + { + "include": "#interpolation_double_quoted" + }, { "include": "source.sql" } @@ -2845,6 +2898,36 @@ }, "name": "string.quoted.single.sql.php", "patterns": [ + { + "match": "(#)(\\\\'|[^'])*(?='|$)", + "name": "comment.line.number-sign.sql", + "captures": { + "1": { + "name": "punctuation.definition.comment.sql" + } + } + }, + { + "match": "(--)(\\\\'|[^'])*(?='|$)", + "name": "comment.line.double-dash.sql", + "captures": { + "1": { + "name": "punctuation.definition.comment.sql" + } + } + }, + { + "match": "\\\\[\\\\'`\"]", + "name": "constant.character.escape.php" + }, + { + "match": "`(?=((\\\\`)|[^`'])*('|$))", + "name": "string.quoted.other.backtick.unclosed.sql" + }, + { + "match": "\"(?=((\\\\\")|[^\"'])*('|$))", + "name": "string.quoted.double.unclosed.sql" + }, { "include": "source.sql" } @@ -3685,4 +3768,4 @@ "name": "keyword.operator.null-coalescing.php" } } -} +} \ No newline at end of file diff --git a/lib/vscode/extensions/php/yarn.lock b/extensions/php/yarn.lock similarity index 100% rename from lib/vscode/extensions/php/yarn.lock rename to extensions/php/yarn.lock diff --git a/lib/vscode/extensions/postinstall.js b/extensions/postinstall.js similarity index 91% rename from lib/vscode/extensions/postinstall.js rename to extensions/postinstall.js index 50f3e1144f80..da4fa3e9d044 100644 --- a/lib/vscode/extensions/postinstall.js +++ b/extensions/postinstall.js @@ -24,9 +24,6 @@ function processRoot() { rimraf.sync(filePath); } } - - // Delete .bin so it doesn't contain broken symlinks that trip up nfpm. - rimraf.sync(path.join(__dirname, 'node_modules', '.bin')); } function processLib() { diff --git a/lib/vscode/extensions/powershell/.vscodeignore b/extensions/powershell/.vscodeignore similarity index 100% rename from lib/vscode/extensions/powershell/.vscodeignore rename to extensions/powershell/.vscodeignore diff --git a/lib/vscode/extensions/powershell/cgmanifest.json b/extensions/powershell/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/powershell/cgmanifest.json rename to extensions/powershell/cgmanifest.json diff --git a/lib/vscode/extensions/powershell/language-configuration.json b/extensions/powershell/language-configuration.json similarity index 100% rename from lib/vscode/extensions/powershell/language-configuration.json rename to extensions/powershell/language-configuration.json diff --git a/lib/vscode/extensions/powershell/package.json b/extensions/powershell/package.json similarity index 100% rename from lib/vscode/extensions/powershell/package.json rename to extensions/powershell/package.json diff --git a/lib/vscode/extensions/powershell/package.nls.json b/extensions/powershell/package.nls.json similarity index 100% rename from lib/vscode/extensions/powershell/package.nls.json rename to extensions/powershell/package.nls.json diff --git a/lib/vscode/extensions/powershell/snippets/powershell.code-snippets b/extensions/powershell/snippets/powershell.code-snippets similarity index 100% rename from lib/vscode/extensions/powershell/snippets/powershell.code-snippets rename to extensions/powershell/snippets/powershell.code-snippets diff --git a/lib/vscode/extensions/powershell/syntaxes/powershell.tmLanguage.json b/extensions/powershell/syntaxes/powershell.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/powershell/syntaxes/powershell.tmLanguage.json rename to extensions/powershell/syntaxes/powershell.tmLanguage.json diff --git a/lib/vscode/extensions/powershell/yarn.lock b/extensions/powershell/yarn.lock similarity index 100% rename from lib/vscode/extensions/powershell/yarn.lock rename to extensions/powershell/yarn.lock diff --git a/lib/vscode/extensions/pug/.vscodeignore b/extensions/pug/.vscodeignore similarity index 100% rename from lib/vscode/extensions/pug/.vscodeignore rename to extensions/pug/.vscodeignore diff --git a/lib/vscode/extensions/pug/cgmanifest.json b/extensions/pug/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/pug/cgmanifest.json rename to extensions/pug/cgmanifest.json diff --git a/lib/vscode/extensions/pug/language-configuration.json b/extensions/pug/language-configuration.json similarity index 100% rename from lib/vscode/extensions/pug/language-configuration.json rename to extensions/pug/language-configuration.json diff --git a/lib/vscode/extensions/pug/package.json b/extensions/pug/package.json similarity index 100% rename from lib/vscode/extensions/pug/package.json rename to extensions/pug/package.json diff --git a/lib/vscode/extensions/pug/package.nls.json b/extensions/pug/package.nls.json similarity index 100% rename from lib/vscode/extensions/pug/package.nls.json rename to extensions/pug/package.nls.json diff --git a/lib/vscode/extensions/pug/syntaxes/pug.tmLanguage.json b/extensions/pug/syntaxes/pug.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/pug/syntaxes/pug.tmLanguage.json rename to extensions/pug/syntaxes/pug.tmLanguage.json diff --git a/lib/vscode/extensions/pug/yarn.lock b/extensions/pug/yarn.lock similarity index 100% rename from lib/vscode/extensions/pug/yarn.lock rename to extensions/pug/yarn.lock diff --git a/lib/vscode/extensions/python/.vscode/launch.json b/extensions/python/.vscode/launch.json similarity index 100% rename from lib/vscode/extensions/python/.vscode/launch.json rename to extensions/python/.vscode/launch.json diff --git a/lib/vscode/extensions/python/.vscode/tasks.json b/extensions/python/.vscode/tasks.json similarity index 100% rename from lib/vscode/extensions/python/.vscode/tasks.json rename to extensions/python/.vscode/tasks.json diff --git a/lib/vscode/extensions/python/.vscodeignore b/extensions/python/.vscodeignore similarity index 100% rename from lib/vscode/extensions/python/.vscodeignore rename to extensions/python/.vscodeignore diff --git a/lib/vscode/extensions/python/cgmanifest.json b/extensions/python/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/python/cgmanifest.json rename to extensions/python/cgmanifest.json diff --git a/lib/vscode/extensions/python/language-configuration.json b/extensions/python/language-configuration.json similarity index 100% rename from lib/vscode/extensions/python/language-configuration.json rename to extensions/python/language-configuration.json diff --git a/lib/vscode/extensions/python/package.json b/extensions/python/package.json similarity index 100% rename from lib/vscode/extensions/python/package.json rename to extensions/python/package.json diff --git a/lib/vscode/extensions/python/package.nls.json b/extensions/python/package.nls.json similarity index 100% rename from lib/vscode/extensions/python/package.nls.json rename to extensions/python/package.nls.json diff --git a/lib/vscode/extensions/python/syntaxes/MagicPython.tmLanguage.json b/extensions/python/syntaxes/MagicPython.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/python/syntaxes/MagicPython.tmLanguage.json rename to extensions/python/syntaxes/MagicPython.tmLanguage.json diff --git a/lib/vscode/extensions/python/syntaxes/MagicRegExp.tmLanguage.json b/extensions/python/syntaxes/MagicRegExp.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/python/syntaxes/MagicRegExp.tmLanguage.json rename to extensions/python/syntaxes/MagicRegExp.tmLanguage.json diff --git a/lib/vscode/extensions/python/test/colorize-fixtures/test-freeze-56377.py b/extensions/python/test/colorize-fixtures/test-freeze-56377.py similarity index 100% rename from lib/vscode/extensions/python/test/colorize-fixtures/test-freeze-56377.py rename to extensions/python/test/colorize-fixtures/test-freeze-56377.py diff --git a/lib/vscode/extensions/python/test/colorize-fixtures/test.py b/extensions/python/test/colorize-fixtures/test.py similarity index 100% rename from lib/vscode/extensions/python/test/colorize-fixtures/test.py rename to extensions/python/test/colorize-fixtures/test.py diff --git a/lib/vscode/extensions/python/test/colorize-results/test-freeze-56377_py.json b/extensions/python/test/colorize-results/test-freeze-56377_py.json similarity index 100% rename from lib/vscode/extensions/python/test/colorize-results/test-freeze-56377_py.json rename to extensions/python/test/colorize-results/test-freeze-56377_py.json diff --git a/lib/vscode/extensions/python/test/colorize-results/test_py.json b/extensions/python/test/colorize-results/test_py.json similarity index 100% rename from lib/vscode/extensions/python/test/colorize-results/test_py.json rename to extensions/python/test/colorize-results/test_py.json diff --git a/lib/vscode/extensions/python/yarn.lock b/extensions/python/yarn.lock similarity index 100% rename from lib/vscode/extensions/python/yarn.lock rename to extensions/python/yarn.lock diff --git a/lib/vscode/extensions/r/.vscodeignore b/extensions/r/.vscodeignore similarity index 100% rename from lib/vscode/extensions/r/.vscodeignore rename to extensions/r/.vscodeignore diff --git a/lib/vscode/extensions/r/cgmanifest.json b/extensions/r/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/r/cgmanifest.json rename to extensions/r/cgmanifest.json diff --git a/lib/vscode/extensions/r/language-configuration.json b/extensions/r/language-configuration.json similarity index 100% rename from lib/vscode/extensions/r/language-configuration.json rename to extensions/r/language-configuration.json diff --git a/lib/vscode/extensions/r/package.json b/extensions/r/package.json similarity index 100% rename from lib/vscode/extensions/r/package.json rename to extensions/r/package.json diff --git a/lib/vscode/extensions/r/package.nls.json b/extensions/r/package.nls.json similarity index 100% rename from lib/vscode/extensions/r/package.nls.json rename to extensions/r/package.nls.json diff --git a/lib/vscode/extensions/r/syntaxes/r.tmLanguage.json b/extensions/r/syntaxes/r.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/r/syntaxes/r.tmLanguage.json rename to extensions/r/syntaxes/r.tmLanguage.json diff --git a/lib/vscode/extensions/r/yarn.lock b/extensions/r/yarn.lock similarity index 100% rename from lib/vscode/extensions/r/yarn.lock rename to extensions/r/yarn.lock diff --git a/lib/vscode/extensions/razor/.vscodeignore b/extensions/razor/.vscodeignore similarity index 100% rename from lib/vscode/extensions/razor/.vscodeignore rename to extensions/razor/.vscodeignore diff --git a/lib/vscode/extensions/razor/cgmanifest.json b/extensions/razor/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/razor/cgmanifest.json rename to extensions/razor/cgmanifest.json diff --git a/lib/vscode/extensions/razor/language-configuration.json b/extensions/razor/language-configuration.json similarity index 100% rename from lib/vscode/extensions/razor/language-configuration.json rename to extensions/razor/language-configuration.json diff --git a/lib/vscode/extensions/razor/package.json b/extensions/razor/package.json similarity index 100% rename from lib/vscode/extensions/razor/package.json rename to extensions/razor/package.json diff --git a/lib/vscode/extensions/razor/package.nls.json b/extensions/razor/package.nls.json similarity index 100% rename from lib/vscode/extensions/razor/package.nls.json rename to extensions/razor/package.nls.json diff --git a/lib/vscode/extensions/razor/syntaxes/cshtml.tmLanguage.json b/extensions/razor/syntaxes/cshtml.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/razor/syntaxes/cshtml.tmLanguage.json rename to extensions/razor/syntaxes/cshtml.tmLanguage.json diff --git a/lib/vscode/extensions/razor/yarn.lock b/extensions/razor/yarn.lock similarity index 100% rename from lib/vscode/extensions/razor/yarn.lock rename to extensions/razor/yarn.lock diff --git a/lib/vscode/extensions/ruby/.vscodeignore b/extensions/ruby/.vscodeignore similarity index 100% rename from lib/vscode/extensions/ruby/.vscodeignore rename to extensions/ruby/.vscodeignore diff --git a/lib/vscode/extensions/ruby/cgmanifest.json b/extensions/ruby/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/ruby/cgmanifest.json rename to extensions/ruby/cgmanifest.json diff --git a/lib/vscode/extensions/ruby/language-configuration.json b/extensions/ruby/language-configuration.json similarity index 81% rename from lib/vscode/extensions/ruby/language-configuration.json rename to extensions/ruby/language-configuration.json index 81fdee540f21..a86f592e3bdb 100644 --- a/lib/vscode/extensions/ruby/language-configuration.json +++ b/extensions/ruby/language-configuration.json @@ -25,7 +25,7 @@ ["`", "`"] ], "indentationRules": { - "increaseIndentPattern": "^\\s*((begin|class|(private|protected)\\s+def|def|else|elsif|ensure|for|if|module|rescue|unless|until|when|while|case)|([^#]*\\sdo\\b)|([^#]*=\\s*(case|if|unless)))\\b([^#\\{;]|(\"|'|\/).*\\4)*(#.*)?$", - "decreaseIndentPattern": "^\\s*([}\\]]([,)]?\\s*(#|$)|\\.[a-zA-Z_]\\w*\\b)|(end|rescue|ensure|else|elsif|when)\\b)" + "increaseIndentPattern": "^\\s*((begin|class|(private|protected)\\s+def|def|else|elsif|ensure|for|if|module|rescue|unless|until|when|in|while|case)|([^#]*\\sdo\\b)|([^#]*=\\s*(case|if|unless)))\\b([^#\\{;]|(\"|'|\/).*\\4)*(#.*)?$", + "decreaseIndentPattern": "^\\s*([}\\]]([,)]?\\s*(#|$)|\\.[a-zA-Z_]\\w*\\b)|(end|rescue|ensure|else|elsif|when|in)\\b)" } } diff --git a/lib/vscode/extensions/ruby/package.json b/extensions/ruby/package.json similarity index 100% rename from lib/vscode/extensions/ruby/package.json rename to extensions/ruby/package.json diff --git a/lib/vscode/extensions/ruby/package.nls.json b/extensions/ruby/package.nls.json similarity index 100% rename from lib/vscode/extensions/ruby/package.nls.json rename to extensions/ruby/package.nls.json diff --git a/lib/vscode/extensions/ruby/syntaxes/ruby.tmLanguage.json b/extensions/ruby/syntaxes/ruby.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/ruby/syntaxes/ruby.tmLanguage.json rename to extensions/ruby/syntaxes/ruby.tmLanguage.json diff --git a/lib/vscode/extensions/ruby/yarn.lock b/extensions/ruby/yarn.lock similarity index 100% rename from lib/vscode/extensions/ruby/yarn.lock rename to extensions/ruby/yarn.lock diff --git a/lib/vscode/extensions/rust/.vscodeignore b/extensions/rust/.vscodeignore similarity index 100% rename from lib/vscode/extensions/rust/.vscodeignore rename to extensions/rust/.vscodeignore diff --git a/lib/vscode/extensions/rust/cgmanifest.json b/extensions/rust/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/rust/cgmanifest.json rename to extensions/rust/cgmanifest.json diff --git a/lib/vscode/extensions/rust/language-configuration.json b/extensions/rust/language-configuration.json similarity index 100% rename from lib/vscode/extensions/rust/language-configuration.json rename to extensions/rust/language-configuration.json diff --git a/lib/vscode/extensions/rust/package.json b/extensions/rust/package.json similarity index 100% rename from lib/vscode/extensions/rust/package.json rename to extensions/rust/package.json diff --git a/lib/vscode/extensions/rust/package.nls.json b/extensions/rust/package.nls.json similarity index 100% rename from lib/vscode/extensions/rust/package.nls.json rename to extensions/rust/package.nls.json diff --git a/lib/vscode/extensions/rust/syntaxes/rust.tmLanguage.json b/extensions/rust/syntaxes/rust.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/rust/syntaxes/rust.tmLanguage.json rename to extensions/rust/syntaxes/rust.tmLanguage.json diff --git a/lib/vscode/extensions/rust/yarn.lock b/extensions/rust/yarn.lock similarity index 100% rename from lib/vscode/extensions/rust/yarn.lock rename to extensions/rust/yarn.lock diff --git a/lib/vscode/extensions/scss/.vscodeignore b/extensions/scss/.vscodeignore similarity index 100% rename from lib/vscode/extensions/scss/.vscodeignore rename to extensions/scss/.vscodeignore diff --git a/lib/vscode/extensions/scss/cgmanifest.json b/extensions/scss/cgmanifest.json similarity index 84% rename from lib/vscode/extensions/scss/cgmanifest.json rename to extensions/scss/cgmanifest.json index a67a4f546096..12247769ce22 100644 --- a/lib/vscode/extensions/scss/cgmanifest.json +++ b/extensions/scss/cgmanifest.json @@ -6,12 +6,12 @@ "git": { "name": "atom/language-sass", "repositoryUrl": "https://github.com/atom/language-sass", - "commitHash": "303bbf0c250fe380b9e57375598cfd916110758b" + "commitHash": "f52ab12f7f9346cc2568129d8c4419bd3d506b47" } }, "license": "MIT", "description": "The file syntaxes/scss.json was derived from the Atom package https://github.com/atom/language-sass which was originally converted from the TextMate bundle https://github.com/alexsancho/SASS.tmbundle.", - "version": "0.61.4" + "version": "0.62.1" } ], "version": 1 diff --git a/lib/vscode/extensions/scss/language-configuration.json b/extensions/scss/language-configuration.json similarity index 100% rename from lib/vscode/extensions/scss/language-configuration.json rename to extensions/scss/language-configuration.json diff --git a/lib/vscode/extensions/scss/package.json b/extensions/scss/package.json similarity index 100% rename from lib/vscode/extensions/scss/package.json rename to extensions/scss/package.json diff --git a/lib/vscode/extensions/scss/package.nls.json b/extensions/scss/package.nls.json similarity index 100% rename from lib/vscode/extensions/scss/package.nls.json rename to extensions/scss/package.nls.json diff --git a/lib/vscode/extensions/scss/syntaxes/sassdoc.tmLanguage.json b/extensions/scss/syntaxes/sassdoc.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/scss/syntaxes/sassdoc.tmLanguage.json rename to extensions/scss/syntaxes/sassdoc.tmLanguage.json diff --git a/lib/vscode/extensions/scss/syntaxes/scss.tmLanguage.json b/extensions/scss/syntaxes/scss.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/scss/syntaxes/scss.tmLanguage.json rename to extensions/scss/syntaxes/scss.tmLanguage.json diff --git a/lib/vscode/extensions/scss/yarn.lock b/extensions/scss/yarn.lock similarity index 100% rename from lib/vscode/extensions/scss/yarn.lock rename to extensions/scss/yarn.lock diff --git a/lib/vscode/extensions/search-result/.vscodeignore b/extensions/search-result/.vscodeignore similarity index 100% rename from lib/vscode/extensions/search-result/.vscodeignore rename to extensions/search-result/.vscodeignore diff --git a/lib/vscode/extensions/search-result/README.md b/extensions/search-result/README.md similarity index 100% rename from lib/vscode/extensions/search-result/README.md rename to extensions/search-result/README.md diff --git a/lib/vscode/extensions/search-result/extension-browser.webpack.config.js b/extensions/search-result/extension-browser.webpack.config.js similarity index 100% rename from lib/vscode/extensions/search-result/extension-browser.webpack.config.js rename to extensions/search-result/extension-browser.webpack.config.js diff --git a/lib/vscode/extensions/search-result/extension.webpack.config.js b/extensions/search-result/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/search-result/extension.webpack.config.js rename to extensions/search-result/extension.webpack.config.js diff --git a/lib/vscode/extensions/search-result/package.json b/extensions/search-result/package.json similarity index 100% rename from lib/vscode/extensions/search-result/package.json rename to extensions/search-result/package.json diff --git a/lib/vscode/extensions/search-result/package.nls.json b/extensions/search-result/package.nls.json similarity index 100% rename from lib/vscode/extensions/search-result/package.nls.json rename to extensions/search-result/package.nls.json diff --git a/lib/vscode/extensions/search-result/src/extension.ts b/extensions/search-result/src/extension.ts similarity index 100% rename from lib/vscode/extensions/search-result/src/extension.ts rename to extensions/search-result/src/extension.ts diff --git a/lib/vscode/extensions/search-result/src/media/refresh-dark.svg b/extensions/search-result/src/media/refresh-dark.svg similarity index 100% rename from lib/vscode/extensions/search-result/src/media/refresh-dark.svg rename to extensions/search-result/src/media/refresh-dark.svg diff --git a/lib/vscode/extensions/search-result/src/media/refresh-light.svg b/extensions/search-result/src/media/refresh-light.svg similarity index 100% rename from lib/vscode/extensions/search-result/src/media/refresh-light.svg rename to extensions/search-result/src/media/refresh-light.svg diff --git a/lib/vscode/extensions/testing-editor-contributions/src/typings/refs.d.ts b/extensions/search-result/src/typings/refs.d.ts similarity index 100% rename from lib/vscode/extensions/testing-editor-contributions/src/typings/refs.d.ts rename to extensions/search-result/src/typings/refs.d.ts diff --git a/lib/vscode/extensions/search-result/syntaxes/generateTMLanguage.js b/extensions/search-result/syntaxes/generateTMLanguage.js similarity index 100% rename from lib/vscode/extensions/search-result/syntaxes/generateTMLanguage.js rename to extensions/search-result/syntaxes/generateTMLanguage.js diff --git a/lib/vscode/extensions/search-result/syntaxes/searchResult.tmLanguage.json b/extensions/search-result/syntaxes/searchResult.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/search-result/syntaxes/searchResult.tmLanguage.json rename to extensions/search-result/syntaxes/searchResult.tmLanguage.json diff --git a/lib/vscode/extensions/search-result/tsconfig.json b/extensions/search-result/tsconfig.json similarity index 100% rename from lib/vscode/extensions/search-result/tsconfig.json rename to extensions/search-result/tsconfig.json diff --git a/lib/vscode/extensions/search-result/yarn.lock b/extensions/search-result/yarn.lock similarity index 100% rename from lib/vscode/extensions/search-result/yarn.lock rename to extensions/search-result/yarn.lock diff --git a/lib/vscode/extensions/shaderlab/.vscodeignore b/extensions/shaderlab/.vscodeignore similarity index 100% rename from lib/vscode/extensions/shaderlab/.vscodeignore rename to extensions/shaderlab/.vscodeignore diff --git a/lib/vscode/extensions/shaderlab/cgmanifest.json b/extensions/shaderlab/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/shaderlab/cgmanifest.json rename to extensions/shaderlab/cgmanifest.json diff --git a/lib/vscode/extensions/shaderlab/language-configuration.json b/extensions/shaderlab/language-configuration.json similarity index 100% rename from lib/vscode/extensions/shaderlab/language-configuration.json rename to extensions/shaderlab/language-configuration.json diff --git a/lib/vscode/extensions/shaderlab/package.json b/extensions/shaderlab/package.json similarity index 100% rename from lib/vscode/extensions/shaderlab/package.json rename to extensions/shaderlab/package.json diff --git a/lib/vscode/extensions/shaderlab/package.nls.json b/extensions/shaderlab/package.nls.json similarity index 100% rename from lib/vscode/extensions/shaderlab/package.nls.json rename to extensions/shaderlab/package.nls.json diff --git a/lib/vscode/extensions/shaderlab/syntaxes/shaderlab.tmLanguage.json b/extensions/shaderlab/syntaxes/shaderlab.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/shaderlab/syntaxes/shaderlab.tmLanguage.json rename to extensions/shaderlab/syntaxes/shaderlab.tmLanguage.json diff --git a/lib/vscode/extensions/shaderlab/yarn.lock b/extensions/shaderlab/yarn.lock similarity index 100% rename from lib/vscode/extensions/shaderlab/yarn.lock rename to extensions/shaderlab/yarn.lock diff --git a/lib/vscode/extensions/shared.webpack.config.js b/extensions/shared.webpack.config.js similarity index 100% rename from lib/vscode/extensions/shared.webpack.config.js rename to extensions/shared.webpack.config.js diff --git a/lib/vscode/extensions/shellscript/.vscodeignore b/extensions/shellscript/.vscodeignore similarity index 100% rename from lib/vscode/extensions/shellscript/.vscodeignore rename to extensions/shellscript/.vscodeignore diff --git a/lib/vscode/extensions/shellscript/cgmanifest.json b/extensions/shellscript/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/shellscript/cgmanifest.json rename to extensions/shellscript/cgmanifest.json diff --git a/lib/vscode/extensions/shellscript/language-configuration.json b/extensions/shellscript/language-configuration.json similarity index 100% rename from lib/vscode/extensions/shellscript/language-configuration.json rename to extensions/shellscript/language-configuration.json diff --git a/lib/vscode/extensions/shellscript/package.json b/extensions/shellscript/package.json similarity index 99% rename from lib/vscode/extensions/shellscript/package.json rename to extensions/shellscript/package.json index a8ecba9b104c..3e1e3f3e9c8d 100644 --- a/lib/vscode/extensions/shellscript/package.json +++ b/extensions/shellscript/package.json @@ -32,7 +32,6 @@ ".bash_profile", ".bash_login", ".ebuild", - ".install", ".profile", ".bash_logout", ".xprofile", diff --git a/lib/vscode/extensions/shellscript/package.nls.json b/extensions/shellscript/package.nls.json similarity index 100% rename from lib/vscode/extensions/shellscript/package.nls.json rename to extensions/shellscript/package.nls.json diff --git a/lib/vscode/extensions/shellscript/syntaxes/shell-unix-bash.tmLanguage.json b/extensions/shellscript/syntaxes/shell-unix-bash.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/shellscript/syntaxes/shell-unix-bash.tmLanguage.json rename to extensions/shellscript/syntaxes/shell-unix-bash.tmLanguage.json diff --git a/lib/vscode/extensions/shellscript/yarn.lock b/extensions/shellscript/yarn.lock similarity index 100% rename from lib/vscode/extensions/shellscript/yarn.lock rename to extensions/shellscript/yarn.lock diff --git a/lib/vscode/extensions/simple-browser/.gitignore b/extensions/simple-browser/.gitignore similarity index 100% rename from lib/vscode/extensions/simple-browser/.gitignore rename to extensions/simple-browser/.gitignore diff --git a/lib/vscode/extensions/simple-browser/.vscodeignore b/extensions/simple-browser/.vscodeignore similarity index 100% rename from lib/vscode/extensions/simple-browser/.vscodeignore rename to extensions/simple-browser/.vscodeignore diff --git a/lib/vscode/extensions/simple-browser/README.md b/extensions/simple-browser/README.md similarity index 100% rename from lib/vscode/extensions/simple-browser/README.md rename to extensions/simple-browser/README.md diff --git a/lib/vscode/extensions/simple-browser/extension-browser.webpack.config.js b/extensions/simple-browser/extension-browser.webpack.config.js similarity index 100% rename from lib/vscode/extensions/simple-browser/extension-browser.webpack.config.js rename to extensions/simple-browser/extension-browser.webpack.config.js diff --git a/lib/vscode/extensions/simple-browser/extension.webpack.config.js b/extensions/simple-browser/extension.webpack.config.js similarity index 100% rename from lib/vscode/extensions/simple-browser/extension.webpack.config.js rename to extensions/simple-browser/extension.webpack.config.js diff --git a/lib/vscode/extensions/simple-browser/media/icon.png b/extensions/simple-browser/media/icon.png similarity index 100% rename from lib/vscode/extensions/simple-browser/media/icon.png rename to extensions/simple-browser/media/icon.png diff --git a/lib/vscode/extensions/simple-browser/media/main.css b/extensions/simple-browser/media/main.css similarity index 100% rename from lib/vscode/extensions/simple-browser/media/main.css rename to extensions/simple-browser/media/main.css diff --git a/lib/vscode/extensions/simple-browser/media/preview-dark.svg b/extensions/simple-browser/media/preview-dark.svg similarity index 100% rename from lib/vscode/extensions/simple-browser/media/preview-dark.svg rename to extensions/simple-browser/media/preview-dark.svg diff --git a/lib/vscode/extensions/simple-browser/media/preview-light.svg b/extensions/simple-browser/media/preview-light.svg similarity index 100% rename from lib/vscode/extensions/simple-browser/media/preview-light.svg rename to extensions/simple-browser/media/preview-light.svg diff --git a/lib/vscode/extensions/simple-browser/package.json b/extensions/simple-browser/package.json similarity index 95% rename from lib/vscode/extensions/simple-browser/package.json rename to extensions/simple-browser/package.json index 5fd030b186aa..f2af986a046c 100644 --- a/lib/vscode/extensions/simple-browser/package.json +++ b/extensions/simple-browser/package.json @@ -70,8 +70,9 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "vscode-codicons": "^0.0.14", - "@types/node": "^12.11.7" + "@types/node": "14.x", + "@types/vscode-webview": "^1.57.0", + "vscode-codicons": "^0.0.14" }, "repository": { "type": "git", diff --git a/lib/vscode/extensions/simple-browser/package.nls.json b/extensions/simple-browser/package.nls.json similarity index 100% rename from lib/vscode/extensions/simple-browser/package.nls.json rename to extensions/simple-browser/package.nls.json diff --git a/lib/vscode/extensions/simple-browser/preview-src/events.ts b/extensions/simple-browser/preview-src/events.ts similarity index 100% rename from lib/vscode/extensions/simple-browser/preview-src/events.ts rename to extensions/simple-browser/preview-src/events.ts diff --git a/lib/vscode/extensions/simple-browser/preview-src/index.ts b/extensions/simple-browser/preview-src/index.ts similarity index 98% rename from lib/vscode/extensions/simple-browser/preview-src/index.ts rename to extensions/simple-browser/preview-src/index.ts index 36fe4eb8e158..0b8f9f93531d 100644 --- a/lib/vscode/extensions/simple-browser/preview-src/index.ts +++ b/extensions/simple-browser/preview-src/index.ts @@ -5,7 +5,6 @@ import { onceDocumentLoaded } from './events'; -declare let acquireVsCodeApi: any; const vscode = acquireVsCodeApi(); function getSettings() { diff --git a/lib/vscode/extensions/markdown-language-features/preview-src/tsconfig.json b/extensions/simple-browser/preview-src/tsconfig.json similarity index 100% rename from lib/vscode/extensions/markdown-language-features/preview-src/tsconfig.json rename to extensions/simple-browser/preview-src/tsconfig.json diff --git a/lib/vscode/extensions/simple-browser/src/dispose.ts b/extensions/simple-browser/src/dispose.ts similarity index 100% rename from lib/vscode/extensions/simple-browser/src/dispose.ts rename to extensions/simple-browser/src/dispose.ts diff --git a/lib/vscode/extensions/simple-browser/src/extension.ts b/extensions/simple-browser/src/extension.ts similarity index 100% rename from lib/vscode/extensions/simple-browser/src/extension.ts rename to extensions/simple-browser/src/extension.ts diff --git a/lib/vscode/extensions/simple-browser/src/simpleBrowserManager.ts b/extensions/simple-browser/src/simpleBrowserManager.ts similarity index 100% rename from lib/vscode/extensions/simple-browser/src/simpleBrowserManager.ts rename to extensions/simple-browser/src/simpleBrowserManager.ts diff --git a/lib/vscode/extensions/simple-browser/src/simpleBrowserView.ts b/extensions/simple-browser/src/simpleBrowserView.ts similarity index 100% rename from lib/vscode/extensions/simple-browser/src/simpleBrowserView.ts rename to extensions/simple-browser/src/simpleBrowserView.ts diff --git a/lib/vscode/extensions/github-authentication/src/typings/ref.d.ts b/extensions/simple-browser/src/typings/ref.d.ts similarity index 83% rename from lib/vscode/extensions/github-authentication/src/typings/ref.d.ts rename to extensions/simple-browser/src/typings/ref.d.ts index dfd710c06cf3..c9849d48e083 100644 --- a/lib/vscode/extensions/github-authentication/src/typings/ref.d.ts +++ b/extensions/simple-browser/src/typings/ref.d.ts @@ -5,6 +5,3 @@ /// /// -/// - -// NOTE@coder: add keytar typeref diff --git a/lib/vscode/extensions/simple-browser/tsconfig.json b/extensions/simple-browser/tsconfig.json similarity index 100% rename from lib/vscode/extensions/simple-browser/tsconfig.json rename to extensions/simple-browser/tsconfig.json diff --git a/lib/vscode/extensions/simple-browser/webpack.config.js b/extensions/simple-browser/webpack.config.js similarity index 100% rename from lib/vscode/extensions/simple-browser/webpack.config.js rename to extensions/simple-browser/webpack.config.js diff --git a/lib/vscode/extensions/simple-browser/yarn.lock b/extensions/simple-browser/yarn.lock similarity index 88% rename from lib/vscode/extensions/simple-browser/yarn.lock rename to extensions/simple-browser/yarn.lock index 804f85a68aee..eb52a2a4a63f 100644 --- a/lib/vscode/extensions/simple-browser/yarn.lock +++ b/extensions/simple-browser/yarn.lock @@ -2,10 +2,15 @@ # yarn lockfile v1 -"@types/node@^12.11.7": - version "12.12.69" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.69.tgz#7cb6a3aa0d16664bf2dcd1450ccb8477464fbd79" - integrity sha512-2F2VQRSFmzqgUEXw75L51MgnnZqc6bKWVSUPfrDPzp6mzGGibeVwyQcpvZvBr5RnsoMRHmC8EcBQiobSeqeJxg== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== + +"@types/vscode-webview@^1.57.0": + version "1.57.0" + resolved "https://registry.yarnpkg.com/@types/vscode-webview/-/vscode-webview-1.57.0.tgz#bad5194d45ae8d03afc1c0f67f71ff5e7a243bbf" + integrity sha512-x3Cb/SMa1IwRHfSvKaZDZOTh4cNoG505c3NjTqGlMC082m++x/ETUmtYniDsw6SSmYzZXO8KBNhYxR0+VqymqA== applicationinsights@1.7.4: version "1.7.4" diff --git a/lib/vscode/extensions/sql/.vscodeignore b/extensions/sql/.vscodeignore similarity index 100% rename from lib/vscode/extensions/sql/.vscodeignore rename to extensions/sql/.vscodeignore diff --git a/lib/vscode/extensions/sql/build/update-grammar.js b/extensions/sql/build/update-grammar.js similarity index 100% rename from lib/vscode/extensions/sql/build/update-grammar.js rename to extensions/sql/build/update-grammar.js diff --git a/lib/vscode/extensions/sql/cgmanifest.json b/extensions/sql/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/sql/cgmanifest.json rename to extensions/sql/cgmanifest.json diff --git a/lib/vscode/extensions/sql/language-configuration.json b/extensions/sql/language-configuration.json similarity index 100% rename from lib/vscode/extensions/sql/language-configuration.json rename to extensions/sql/language-configuration.json diff --git a/lib/vscode/extensions/sql/package.json b/extensions/sql/package.json similarity index 100% rename from lib/vscode/extensions/sql/package.json rename to extensions/sql/package.json diff --git a/lib/vscode/extensions/sql/package.nls.json b/extensions/sql/package.nls.json similarity index 100% rename from lib/vscode/extensions/sql/package.nls.json rename to extensions/sql/package.nls.json diff --git a/lib/vscode/extensions/sql/syntaxes/sql.tmLanguage.json b/extensions/sql/syntaxes/sql.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/sql/syntaxes/sql.tmLanguage.json rename to extensions/sql/syntaxes/sql.tmLanguage.json diff --git a/lib/vscode/extensions/sql/yarn.lock b/extensions/sql/yarn.lock similarity index 100% rename from lib/vscode/extensions/sql/yarn.lock rename to extensions/sql/yarn.lock diff --git a/lib/vscode/extensions/swift/.vscodeignore b/extensions/swift/.vscodeignore similarity index 100% rename from lib/vscode/extensions/swift/.vscodeignore rename to extensions/swift/.vscodeignore diff --git a/lib/vscode/extensions/swift/LICENSE.md b/extensions/swift/LICENSE.md similarity index 100% rename from lib/vscode/extensions/swift/LICENSE.md rename to extensions/swift/LICENSE.md diff --git a/lib/vscode/extensions/swift/cgmanifest.json b/extensions/swift/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/swift/cgmanifest.json rename to extensions/swift/cgmanifest.json diff --git a/lib/vscode/extensions/swift/language-configuration.json b/extensions/swift/language-configuration.json similarity index 100% rename from lib/vscode/extensions/swift/language-configuration.json rename to extensions/swift/language-configuration.json diff --git a/lib/vscode/extensions/swift/package.json b/extensions/swift/package.json similarity index 100% rename from lib/vscode/extensions/swift/package.json rename to extensions/swift/package.json diff --git a/lib/vscode/extensions/swift/package.nls.json b/extensions/swift/package.nls.json similarity index 100% rename from lib/vscode/extensions/swift/package.nls.json rename to extensions/swift/package.nls.json diff --git a/lib/vscode/extensions/swift/snippets/swift.code-snippets b/extensions/swift/snippets/swift.code-snippets similarity index 100% rename from lib/vscode/extensions/swift/snippets/swift.code-snippets rename to extensions/swift/snippets/swift.code-snippets diff --git a/lib/vscode/extensions/swift/syntaxes/swift.tmLanguage.json b/extensions/swift/syntaxes/swift.tmLanguage.json similarity index 99% rename from lib/vscode/extensions/swift/syntaxes/swift.tmLanguage.json rename to extensions/swift/syntaxes/swift.tmLanguage.json index 3396ff07de9e..be1b132172e1 100644 --- a/lib/vscode/extensions/swift/syntaxes/swift.tmLanguage.json +++ b/extensions/swift/syntaxes/swift.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/textmate/swift.tmbundle/commit/2ee3d7c63f7dd2c769167278b48e3716d1b60b26", + "version": "https://github.com/textmate/swift.tmbundle/commit/8c7672d74c1baa4e6944a05ac6c57a623532f18b", "name": "Swift", "scopeName": "source.swift", "comment": "See swift.tmbundle/grammar-test.swift for test cases.", @@ -1280,7 +1280,7 @@ "name": "meta.import.swift", "patterns": [ { - "begin": "\\G(?!;|$|//|/\\*)(?:(typealias|struct|class|enum|protocol|var|func)\\s+)?", + "begin": "\\G(?!;|$|//|/\\*)(?:(typealias|struct|class|actor|enum|protocol|var|func)\\s+)?", "beginCaptures": { "1": { "name": "storage.modifier.swift" @@ -1908,7 +1908,7 @@ "type": { "patterns": [ { - "begin": "\\b(class(?!\\s+(?:func|var|let)\\b)|struct)\\s+((?`?)[\\p{L}_][\\p{L}_\\p{N}\\p{M}]*(\\k))", + "begin": "\\b(class(?!\\s+(?:func|var|let)\\b)|struct|actor)\\s+((?`?)[\\p{L}_][\\p{L}_\\p{N}\\p{M}]*(\\k))", "beginCaptures": { "1": { "name": "storage.type.$1.swift" @@ -2337,7 +2337,7 @@ ], "repository": { "availability-condition": { - "begin": "\\B(#available)(\\()", + "begin": "\\B(#(?:un)?available)(\\()", "beginCaptures": { "1": { "name": "support.function.availability-condition.swift" @@ -2645,7 +2645,7 @@ "name": "keyword.other.declaration-specifier.swift" }, { - "match": "(? /// -/// - -// NOTE@coder: add keytar typeref diff --git a/lib/vscode/extensions/testing-editor-contributions/tsconfig.json b/extensions/testing-editor-contributions/tsconfig.json similarity index 100% rename from lib/vscode/extensions/testing-editor-contributions/tsconfig.json rename to extensions/testing-editor-contributions/tsconfig.json diff --git a/lib/vscode/extensions/testing-editor-contributions/yarn.lock b/extensions/testing-editor-contributions/yarn.lock similarity index 100% rename from lib/vscode/extensions/testing-editor-contributions/yarn.lock rename to extensions/testing-editor-contributions/yarn.lock diff --git a/lib/vscode/extensions/theme-abyss/.vscodeignore b/extensions/theme-abyss/.vscodeignore similarity index 100% rename from lib/vscode/extensions/theme-abyss/.vscodeignore rename to extensions/theme-abyss/.vscodeignore diff --git a/lib/vscode/extensions/theme-abyss/cgmanifest.json b/extensions/theme-abyss/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/theme-abyss/cgmanifest.json rename to extensions/theme-abyss/cgmanifest.json diff --git a/lib/vscode/extensions/theme-abyss/package.json b/extensions/theme-abyss/package.json similarity index 100% rename from lib/vscode/extensions/theme-abyss/package.json rename to extensions/theme-abyss/package.json diff --git a/lib/vscode/extensions/theme-abyss/package.nls.json b/extensions/theme-abyss/package.nls.json similarity index 100% rename from lib/vscode/extensions/theme-abyss/package.nls.json rename to extensions/theme-abyss/package.nls.json diff --git a/lib/vscode/extensions/theme-abyss/themes/abyss-color-theme.json b/extensions/theme-abyss/themes/abyss-color-theme.json similarity index 100% rename from lib/vscode/extensions/theme-abyss/themes/abyss-color-theme.json rename to extensions/theme-abyss/themes/abyss-color-theme.json diff --git a/lib/vscode/extensions/theme-abyss/yarn.lock b/extensions/theme-abyss/yarn.lock similarity index 100% rename from lib/vscode/extensions/theme-abyss/yarn.lock rename to extensions/theme-abyss/yarn.lock diff --git a/lib/vscode/extensions/theme-defaults/fileicons/images/document-dark.svg b/extensions/theme-defaults/fileicons/images/document-dark.svg similarity index 100% rename from lib/vscode/extensions/theme-defaults/fileicons/images/document-dark.svg rename to extensions/theme-defaults/fileicons/images/document-dark.svg diff --git a/lib/vscode/extensions/theme-defaults/fileicons/images/document-light.svg b/extensions/theme-defaults/fileicons/images/document-light.svg similarity index 100% rename from lib/vscode/extensions/theme-defaults/fileicons/images/document-light.svg rename to extensions/theme-defaults/fileicons/images/document-light.svg diff --git a/lib/vscode/extensions/theme-defaults/fileicons/images/folder-dark.svg b/extensions/theme-defaults/fileicons/images/folder-dark.svg similarity index 100% rename from lib/vscode/extensions/theme-defaults/fileicons/images/folder-dark.svg rename to extensions/theme-defaults/fileicons/images/folder-dark.svg diff --git a/lib/vscode/extensions/theme-defaults/fileicons/images/folder-light.svg b/extensions/theme-defaults/fileicons/images/folder-light.svg similarity index 100% rename from lib/vscode/extensions/theme-defaults/fileicons/images/folder-light.svg rename to extensions/theme-defaults/fileicons/images/folder-light.svg diff --git a/lib/vscode/extensions/theme-defaults/fileicons/images/folder-open-dark.svg b/extensions/theme-defaults/fileicons/images/folder-open-dark.svg similarity index 100% rename from lib/vscode/extensions/theme-defaults/fileicons/images/folder-open-dark.svg rename to extensions/theme-defaults/fileicons/images/folder-open-dark.svg diff --git a/lib/vscode/extensions/theme-defaults/fileicons/images/folder-open-light.svg b/extensions/theme-defaults/fileicons/images/folder-open-light.svg similarity index 100% rename from lib/vscode/extensions/theme-defaults/fileicons/images/folder-open-light.svg rename to extensions/theme-defaults/fileicons/images/folder-open-light.svg diff --git a/lib/vscode/extensions/theme-defaults/fileicons/images/root-folder-dark.svg b/extensions/theme-defaults/fileicons/images/root-folder-dark.svg similarity index 100% rename from lib/vscode/extensions/theme-defaults/fileicons/images/root-folder-dark.svg rename to extensions/theme-defaults/fileicons/images/root-folder-dark.svg diff --git a/lib/vscode/extensions/theme-defaults/fileicons/images/root-folder-light.svg b/extensions/theme-defaults/fileicons/images/root-folder-light.svg similarity index 100% rename from lib/vscode/extensions/theme-defaults/fileicons/images/root-folder-light.svg rename to extensions/theme-defaults/fileicons/images/root-folder-light.svg diff --git a/lib/vscode/extensions/theme-defaults/fileicons/images/root-folder-open-dark.svg b/extensions/theme-defaults/fileicons/images/root-folder-open-dark.svg similarity index 100% rename from lib/vscode/extensions/theme-defaults/fileicons/images/root-folder-open-dark.svg rename to extensions/theme-defaults/fileicons/images/root-folder-open-dark.svg diff --git a/lib/vscode/extensions/theme-defaults/fileicons/images/root-folder-open-light.svg b/extensions/theme-defaults/fileicons/images/root-folder-open-light.svg similarity index 100% rename from lib/vscode/extensions/theme-defaults/fileicons/images/root-folder-open-light.svg rename to extensions/theme-defaults/fileicons/images/root-folder-open-light.svg diff --git a/lib/vscode/extensions/theme-defaults/fileicons/vs_minimal-icon-theme.json b/extensions/theme-defaults/fileicons/vs_minimal-icon-theme.json similarity index 100% rename from lib/vscode/extensions/theme-defaults/fileicons/vs_minimal-icon-theme.json rename to extensions/theme-defaults/fileicons/vs_minimal-icon-theme.json diff --git a/lib/vscode/extensions/theme-defaults/package.json b/extensions/theme-defaults/package.json similarity index 100% rename from lib/vscode/extensions/theme-defaults/package.json rename to extensions/theme-defaults/package.json diff --git a/lib/vscode/extensions/theme-defaults/package.nls.json b/extensions/theme-defaults/package.nls.json similarity index 100% rename from lib/vscode/extensions/theme-defaults/package.nls.json rename to extensions/theme-defaults/package.nls.json diff --git a/lib/vscode/extensions/theme-defaults/themes/dark_plus.json b/extensions/theme-defaults/themes/dark_plus.json similarity index 100% rename from lib/vscode/extensions/theme-defaults/themes/dark_plus.json rename to extensions/theme-defaults/themes/dark_plus.json diff --git a/lib/vscode/extensions/theme-defaults/themes/dark_vs.json b/extensions/theme-defaults/themes/dark_vs.json similarity index 100% rename from lib/vscode/extensions/theme-defaults/themes/dark_vs.json rename to extensions/theme-defaults/themes/dark_vs.json diff --git a/lib/vscode/extensions/theme-defaults/themes/hc_black.json b/extensions/theme-defaults/themes/hc_black.json similarity index 98% rename from lib/vscode/extensions/theme-defaults/themes/hc_black.json rename to extensions/theme-defaults/themes/hc_black.json index ef3ca5591d88..7faf68ddab71 100644 --- a/lib/vscode/extensions/theme-defaults/themes/hc_black.json +++ b/extensions/theme-defaults/themes/hc_black.json @@ -10,7 +10,8 @@ "selection.background": "#008000", "editor.selectionBackground": "#FFFFFF", "statusBarItem.remoteBackground": "#00000000", - "ports.iconRunningProcessForeground": "#FFFFFF" + "ports.iconRunningProcessForeground": "#FFFFFF", + "editorWhitespace.foreground": "#7c7c7c" }, "tokenColors": [ { diff --git a/lib/vscode/extensions/theme-defaults/themes/light_plus.json b/extensions/theme-defaults/themes/light_plus.json similarity index 100% rename from lib/vscode/extensions/theme-defaults/themes/light_plus.json rename to extensions/theme-defaults/themes/light_plus.json diff --git a/lib/vscode/extensions/theme-defaults/themes/light_vs.json b/extensions/theme-defaults/themes/light_vs.json similarity index 98% rename from lib/vscode/extensions/theme-defaults/themes/light_vs.json rename to extensions/theme-defaults/themes/light_vs.json index f48e636a18a8..b58b9f883219 100644 --- a/lib/vscode/extensions/theme-defaults/themes/light_vs.json +++ b/extensions/theme-defaults/themes/light_vs.json @@ -24,7 +24,8 @@ "tab.lastPinnedBorder": "#61616130", "notebook.cellBorderColor": "#E8E8E8", "notebook.selectedCellBackground": "#c8ddf150", - "statusBarItem.errorBackground": "#c72e0f" + "statusBarItem.errorBackground": "#c72e0f", + "list.focusHighlightForeground": "#9DDDFF" }, "tokenColors": [ { diff --git a/lib/vscode/extensions/theme-defaults/yarn.lock b/extensions/theme-defaults/yarn.lock similarity index 100% rename from lib/vscode/extensions/theme-defaults/yarn.lock rename to extensions/theme-defaults/yarn.lock diff --git a/lib/vscode/extensions/theme-kimbie-dark/.vscodeignore b/extensions/theme-kimbie-dark/.vscodeignore similarity index 100% rename from lib/vscode/extensions/theme-kimbie-dark/.vscodeignore rename to extensions/theme-kimbie-dark/.vscodeignore diff --git a/lib/vscode/extensions/theme-kimbie-dark/cgmanifest.json b/extensions/theme-kimbie-dark/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/theme-kimbie-dark/cgmanifest.json rename to extensions/theme-kimbie-dark/cgmanifest.json diff --git a/lib/vscode/extensions/theme-kimbie-dark/package.json b/extensions/theme-kimbie-dark/package.json similarity index 100% rename from lib/vscode/extensions/theme-kimbie-dark/package.json rename to extensions/theme-kimbie-dark/package.json diff --git a/lib/vscode/extensions/theme-kimbie-dark/package.nls.json b/extensions/theme-kimbie-dark/package.nls.json similarity index 100% rename from lib/vscode/extensions/theme-kimbie-dark/package.nls.json rename to extensions/theme-kimbie-dark/package.nls.json diff --git a/lib/vscode/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json b/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json similarity index 100% rename from lib/vscode/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json rename to extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json diff --git a/lib/vscode/extensions/theme-kimbie-dark/yarn.lock b/extensions/theme-kimbie-dark/yarn.lock similarity index 100% rename from lib/vscode/extensions/theme-kimbie-dark/yarn.lock rename to extensions/theme-kimbie-dark/yarn.lock diff --git a/lib/vscode/extensions/theme-monokai-dimmed/.vscodeignore b/extensions/theme-monokai-dimmed/.vscodeignore similarity index 100% rename from lib/vscode/extensions/theme-monokai-dimmed/.vscodeignore rename to extensions/theme-monokai-dimmed/.vscodeignore diff --git a/lib/vscode/extensions/theme-monokai-dimmed/cgmanifest.json b/extensions/theme-monokai-dimmed/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/theme-monokai-dimmed/cgmanifest.json rename to extensions/theme-monokai-dimmed/cgmanifest.json diff --git a/lib/vscode/extensions/theme-monokai-dimmed/package.json b/extensions/theme-monokai-dimmed/package.json similarity index 100% rename from lib/vscode/extensions/theme-monokai-dimmed/package.json rename to extensions/theme-monokai-dimmed/package.json diff --git a/lib/vscode/extensions/theme-monokai-dimmed/package.nls.json b/extensions/theme-monokai-dimmed/package.nls.json similarity index 100% rename from lib/vscode/extensions/theme-monokai-dimmed/package.nls.json rename to extensions/theme-monokai-dimmed/package.nls.json diff --git a/lib/vscode/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json similarity index 100% rename from lib/vscode/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json rename to extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json diff --git a/lib/vscode/extensions/theme-monokai-dimmed/yarn.lock b/extensions/theme-monokai-dimmed/yarn.lock similarity index 100% rename from lib/vscode/extensions/theme-monokai-dimmed/yarn.lock rename to extensions/theme-monokai-dimmed/yarn.lock diff --git a/lib/vscode/extensions/theme-monokai/.vscodeignore b/extensions/theme-monokai/.vscodeignore similarity index 100% rename from lib/vscode/extensions/theme-monokai/.vscodeignore rename to extensions/theme-monokai/.vscodeignore diff --git a/lib/vscode/extensions/theme-monokai/cgmanifest.json b/extensions/theme-monokai/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/theme-monokai/cgmanifest.json rename to extensions/theme-monokai/cgmanifest.json diff --git a/lib/vscode/extensions/theme-monokai/package.json b/extensions/theme-monokai/package.json similarity index 100% rename from lib/vscode/extensions/theme-monokai/package.json rename to extensions/theme-monokai/package.json diff --git a/lib/vscode/extensions/theme-monokai/package.nls.json b/extensions/theme-monokai/package.nls.json similarity index 100% rename from lib/vscode/extensions/theme-monokai/package.nls.json rename to extensions/theme-monokai/package.nls.json diff --git a/lib/vscode/extensions/theme-monokai/themes/monokai-color-theme.json b/extensions/theme-monokai/themes/monokai-color-theme.json similarity index 99% rename from lib/vscode/extensions/theme-monokai/themes/monokai-color-theme.json rename to extensions/theme-monokai/themes/monokai-color-theme.json index d96060d9710b..2b9b207a5a79 100644 --- a/lib/vscode/extensions/theme-monokai/themes/monokai-color-theme.json +++ b/extensions/theme-monokai/themes/monokai-color-theme.json @@ -18,7 +18,7 @@ "button.background": "#75715E", "editor.background": "#272822", "editor.foreground": "#f8f8f2", - "selection.background": "#ccccc7", + "selection.background": "#878b9180", "editor.selectionHighlightBackground": "#575b6180", "editor.selectionBackground": "#878b9180", "minimap.selectionHighlight": "#878b9180", diff --git a/lib/vscode/extensions/theme-monokai/yarn.lock b/extensions/theme-monokai/yarn.lock similarity index 100% rename from lib/vscode/extensions/theme-monokai/yarn.lock rename to extensions/theme-monokai/yarn.lock diff --git a/lib/vscode/extensions/theme-quietlight/.vscodeignore b/extensions/theme-quietlight/.vscodeignore similarity index 100% rename from lib/vscode/extensions/theme-quietlight/.vscodeignore rename to extensions/theme-quietlight/.vscodeignore diff --git a/lib/vscode/extensions/theme-quietlight/cgmanifest.json b/extensions/theme-quietlight/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/theme-quietlight/cgmanifest.json rename to extensions/theme-quietlight/cgmanifest.json diff --git a/lib/vscode/extensions/theme-quietlight/package.json b/extensions/theme-quietlight/package.json similarity index 100% rename from lib/vscode/extensions/theme-quietlight/package.json rename to extensions/theme-quietlight/package.json diff --git a/lib/vscode/extensions/theme-quietlight/package.nls.json b/extensions/theme-quietlight/package.nls.json similarity index 100% rename from lib/vscode/extensions/theme-quietlight/package.nls.json rename to extensions/theme-quietlight/package.nls.json diff --git a/lib/vscode/extensions/theme-quietlight/themes/quietlight-color-theme.json b/extensions/theme-quietlight/themes/quietlight-color-theme.json similarity index 100% rename from lib/vscode/extensions/theme-quietlight/themes/quietlight-color-theme.json rename to extensions/theme-quietlight/themes/quietlight-color-theme.json diff --git a/lib/vscode/extensions/theme-quietlight/yarn.lock b/extensions/theme-quietlight/yarn.lock similarity index 100% rename from lib/vscode/extensions/theme-quietlight/yarn.lock rename to extensions/theme-quietlight/yarn.lock diff --git a/lib/vscode/extensions/theme-red/.vscodeignore b/extensions/theme-red/.vscodeignore similarity index 100% rename from lib/vscode/extensions/theme-red/.vscodeignore rename to extensions/theme-red/.vscodeignore diff --git a/lib/vscode/extensions/theme-red/cgmanifest.json b/extensions/theme-red/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/theme-red/cgmanifest.json rename to extensions/theme-red/cgmanifest.json diff --git a/lib/vscode/extensions/theme-red/package.json b/extensions/theme-red/package.json similarity index 100% rename from lib/vscode/extensions/theme-red/package.json rename to extensions/theme-red/package.json diff --git a/lib/vscode/extensions/theme-red/package.nls.json b/extensions/theme-red/package.nls.json similarity index 100% rename from lib/vscode/extensions/theme-red/package.nls.json rename to extensions/theme-red/package.nls.json diff --git a/lib/vscode/extensions/theme-red/themes/Red-color-theme.json b/extensions/theme-red/themes/Red-color-theme.json similarity index 100% rename from lib/vscode/extensions/theme-red/themes/Red-color-theme.json rename to extensions/theme-red/themes/Red-color-theme.json diff --git a/lib/vscode/extensions/theme-red/yarn.lock b/extensions/theme-red/yarn.lock similarity index 100% rename from lib/vscode/extensions/theme-red/yarn.lock rename to extensions/theme-red/yarn.lock diff --git a/lib/vscode/extensions/theme-seti/.vscodeignore b/extensions/theme-seti/.vscodeignore similarity index 100% rename from lib/vscode/extensions/theme-seti/.vscodeignore rename to extensions/theme-seti/.vscodeignore diff --git a/extensions/theme-seti/CONTRIBUTING.md b/extensions/theme-seti/CONTRIBUTING.md new file mode 100644 index 000000000000..548a437615fb --- /dev/null +++ b/extensions/theme-seti/CONTRIBUTING.md @@ -0,0 +1,33 @@ +# theme-seti + +This is an icon theme that uses the icons from [`seti-ui`](https://github.com/jesseweed/seti-ui). + +## Previewing icons + +There is a [`./icons/preview.html`](./icons/preview.html) file that can be opened to see all of the icons included in the theme. +To view this, it needs to be hosted by a web server. The easiest way is to open the file with the `Open with Live Server` command from the [Live Server extension](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer). + + +## Updating icons + +- Make a PR against https://github.com/jesseweed/seti-ui` with your icon changes. +- Once accepted there, ping us or make a PR yourself that updates the theme and font here + +To adopt the latest changes from https://github.com/jesseweed/seti-ui: + +- have the main branches of `https://github.com/jesseweed/seti-ui` and `https://github.com/microsoft/vscode` cloned in the same parent folder +- in the `seti-ui` folder, run `npm install` and `npm run prepublishOnly`. This will generate updated icons and fonts. +- in the `vscode/extensions/theme-seti` folder run `npm run update`. This will launch the [icon theme update script](build/update-icon-theme.js) that updates the theme as well as the font based on content in `seti-ui`. +- to test the icon theme, look at the icon preview as described above. +- when done, create a PR with the changes in https://github.com/microsoft/vscode. +Add a screenshot of the preview page to accompany it. + + +### Languages not shipped with `vscode` + +Languages that are not shipped with `vscode` must be added to the `nonBuiltInLanguages` object inside of `update-icon-theme.js`. + +These should match [the file mapping in `seti-ui`](https://github.com/jesseweed/seti-ui/blob/master/styles/components/icons/mapping.less). + +Please try and keep this list in alphabetical order! Thank you. + diff --git a/lib/vscode/extensions/theme-seti/README.md b/extensions/theme-seti/README.md similarity index 100% rename from lib/vscode/extensions/theme-seti/README.md rename to extensions/theme-seti/README.md diff --git a/lib/vscode/extensions/theme-seti/ThirdPartyNotices.txt b/extensions/theme-seti/ThirdPartyNotices.txt similarity index 100% rename from lib/vscode/extensions/theme-seti/ThirdPartyNotices.txt rename to extensions/theme-seti/ThirdPartyNotices.txt diff --git a/lib/vscode/extensions/theme-seti/build/update-icon-theme.js b/extensions/theme-seti/build/update-icon-theme.js similarity index 100% rename from lib/vscode/extensions/theme-seti/build/update-icon-theme.js rename to extensions/theme-seti/build/update-icon-theme.js diff --git a/lib/vscode/extensions/theme-seti/cgmanifest.json b/extensions/theme-seti/cgmanifest.json similarity index 77% rename from lib/vscode/extensions/theme-seti/cgmanifest.json rename to extensions/theme-seti/cgmanifest.json index c13fbcb15bef..1dd5ab5bc3ef 100644 --- a/lib/vscode/extensions/theme-seti/cgmanifest.json +++ b/extensions/theme-seti/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "seti-ui", "repositoryUrl": "https://github.com/jesseweed/seti-ui", - "commitHash": "894c49fa9f5ce43dd4f012173a7bb107346e524e" + "commitHash": "2b078f89a535a9f6dda47817bac01f02a4350078" } }, "version": "0.1.0" diff --git a/lib/vscode/extensions/theme-seti/icons/preview.html b/extensions/theme-seti/icons/preview.html similarity index 100% rename from lib/vscode/extensions/theme-seti/icons/preview.html rename to extensions/theme-seti/icons/preview.html diff --git a/lib/vscode/extensions/theme-seti/icons/seti-circular-128x128.png b/extensions/theme-seti/icons/seti-circular-128x128.png similarity index 100% rename from lib/vscode/extensions/theme-seti/icons/seti-circular-128x128.png rename to extensions/theme-seti/icons/seti-circular-128x128.png diff --git a/extensions/theme-seti/icons/seti.woff b/extensions/theme-seti/icons/seti.woff new file mode 100644 index 0000000000000000000000000000000000000000..a3793630a711fd873b1425754dfa529b7a7b65d4 GIT binary patch literal 36572 zcmY&;bxa*ju=T~ExVyW%ySuwXad&rjcXx{G#idA#UfkW?9SW4!-}faid6S&XoU>=L z**`X$O~y-EN(ul5_!o(r0Qmp%>hAyN|JDCDq}4UW001!9e=7e!XpqEF`YNk4v;ET~ z{&Asy(BdMIP%v{ab^fP?0{{^E0KhlByfg4)D|;VH0043q00?6O00#XtLJJ41ElkY; zfM}F|eg8B77lF&gru9GZpC0-=akMR#3Q!)#PfXWUq6@#d?z)O;_<>C<=r zu+q4%mtlA3q3GkF*4t4@!&R1f45WE(D@|MmmM~sfE5q>3S9jV;TXoN7IJ*CU5j>N0 z`ZJpq_-F-y!2M+s$&zl0UbvL&S1$N)deyW zf{z^%!)nf^WU#=U)E$)5!dzLZGiAJp^$^5g9i!rEji|Rbbo=(hT$0_ zMRE%-BRJrp<{76|a*J%uKM=s~9HV4%i>Ng?;N$KbXLNLn>e)OHLiQdbCwd6~A#lLU z99uLXZ*-T--FrlM^EM!T{`SkN|2D&k2GkP=@{0!f#e)1|Kz?zc_h`_2Ea*K3^d1L-i3Y*Mf?#4m zFma%$Xi!uvC@KaN6$g@z21&<)q+>wRaiCF}px<<6lE()U#|M(f=n}{1lE-Np+sax# z!jk4Y8Yuw_63>d*Yuw`II|?ZQtrE{uSZmzU<~s%{0T2HO_F9LC`HomhK%B%gBi34n zg!ztI#?LqlvVR@L$j+42tE@(#)J z4$Y(Yju>D^9MCHo=oJg}iUE4X0binlFR{Rv7~o4B5IGu%91BE_0V2l%lcIr1vB0Dl zU{V}VIU1-O3sjB)D#rn5qJcB9z?m4}OdOCo8ps?AWR3wc#{nCofsL`i#u#8@9MCBm z=oAZdiUB&s0dJy#H?hE*7~oADkT@Dh91A3l0TRani=u%=vB07jU{M^5qJcZHz?~T2P8?9U>cjX}^)TNz#Z4$C|3UXKpPB5$ACvbaZ;Ti5Uxm&4-5dPMCv+S^e<7mPVf9n7ztnCYX(o%|L#_LA6##~wg&>qb&~IwQO5f!&G7L% zKZE|r^BC#awW=)~8ox?gyd+F!Qq&aj$?ssUctdvoQd9bj?cAOJfky5#u$>u$z-WtO zU83x+ivQeG?eUV*%h+{%>nFW%F27Mrz`MMs0rzIJnKg^0Yl2ztO{LI@hFJynXYV&{HYXDW8jJAFzzG)EAVxiD ziBqFa!AC^VnRt{T1sx%36~Vgm=rOr#iEFJY;v{ofLW)-bTgC&Wb+k>%-n{nig8CKb z*|iAhgF$bI1nG+^ZD|+b>z883zB)t#$Se(29O--Q?$l%&J20mCJre=Gm)O1Ww?)L9 zNe1$!%UJqN5$5$BIt$Va0&kAovzFUa<7JS{kf>rxzORy%x@HakeJh6e+ zPDf|4uC>F0UYb?b^m<(n!tj2TI!-&JAK9JF4%tI=>wK8mhspNhA3L(_R$}naiiTiwe5N{dOo=ZvVc`#>qbBWtXUa*|F16#(g^VG%wVB(zCPGc2Q&ZReWFr znq_db&c*gNotm;^$666@z}1_L?n@nexbfeG*ztKRc?odWi<106?visP_i9Tm!ou*v z4Fe*;sBuIdphk-vMv-A&G2#MLC(L0Y#jFI*X>($VJ-3`MP65y{0(|K|#`%AdK~@{6 zVT=0NlW@*|e-v1HttKLMddzm%8opV02-OKMhLVFfP2g*v#$lUnA2sN}-v)<%W0}h={^*JMJ0hO9FxV*p>{za29Ek4&0T2 zOhBt3lPjI0N-PulNKHkhx+lX4ckU#9I`VLK3=#+pp?gws;(*S7C&k%GVhx;Fh- zKrdE)<+)(ywB?=?*|uKHlKwL+Y!LcMu>c8L$3&rQz9h>OMOgtClMAcYe56?!yVQS!)8)6ZVE`_in9JRC#?T+f zgx!pat)5N)$>)1nj{qVw({J@Bege~3=a9Z}IPqGBk;Yt?4BrgxI%flHSdpPZN>Q%y zicwfcDP~iocA-z=ZIuK`~pRN^{iJ5dtkA-NpwoTR|$^5hBd;b~43&SMB?$;csbt#2(qU`f+=} z@7t#5biZD#W}{7a>Rr7>1OgQ+3juq3f&N?f$n}|7iPF4K}8IIT@_5yr30t0J#3jX_v~n@})^W+ocn z6VQC&)G=LaN{JFe@`y++=Q?L3#Cv7yNeW;uYzB;j0tuhor4bLU!032 z_zIv*A{h>qcD_?tL$HvAAtyytF&1J9xhUZ<^k!KtMqvWrUb|bgjvveK2hPWp)NOHS zeQQnQQ;|$IvNIm)D1eEkkwEUY;WsGVx`n+_Y7Q->Us66Eh-)TU#bMYKvn z-pGR#Gc3wDb`#7PdAeq8u(=fm6#Fvp9;M&)Bd)D?KQY5Np_7n3L}^;Vt5A_9O?IJ(IbI5LT`;z|FVMO4v2gost#56R)&6>{y>=lU_m1-ooI z)~wfM4a(y2f=EVQ6B_P@`!>)840xJ2Lswd3i%#&U!n8~rMF?Z7ynvk^fQ|2ie}dY| zd65q`Hn~J=I$u07>48g3^Y>3k%>IqKRN+aPeJMM^r1SEt#?Kj^f}!cIWbZ83DbpSF zZh=g$2h9(lcH0V7Mf4?XkC07JudlFltGMGu`Xg?gt+z_m9nv?=_!B zZZBp*r=y!^x)#>6llp4oPX}Oy@vX8Od{>-X6qq8yVO0h)+Bb24v$HeCkT+N-pVFet zD!BWVM)`sJs`gF4iW3XXeL>^_)8&_zpBXD5Gcn!ug1|6r0S|H3y~ocDcrq&|Od^(_ z0z1x(Q?YXk9<^p(nQxb=TkYq!g;#f7gP&%<8!Qsjl^Suisy-OJa$8kKUcePmHyq8~tx5I!T;U=|B$-%xXPMFV_n zv3Hy(=C;!GeSs9V4V~Do`oNr+q z|3233UTJw;tpQA!OT~D75#b#^aj;a>uNDamnk#zFk9FAT=L)T~)}VV=*MT2@XvAr? z?Gi$KG0q2`q!;SlNf4TfG-R$}dt(^j-s8@fic_b!@F`G8}d@L8n9GX z=K<`j$A7ywz3aqXNhQzQth#xWdY zdNK%YLe1)ddQ86WZAjWA)oJKn5PdpzMgRWH16+cBj*9T868>_BSj2I&m28qU{sk;o zpBcNzoDHuZ#7$Imzz&gpWMl#Uj+L4vYl}8|1hYc3=nZy?opnog#PkR6VPVq8axrcg zHJTg4Z?Fts%Kc&Xi)V=4#|i9GdzKcGuur4;oY2b$B{NY^OeaMG#<|PF_3k0tExU*2 zMQvQM^*Tfwb{JbvgR4g36)lK#3E~#dgMuNCtYkZS@fKQZbnz@k08)&bV5!`GO!y25 zprs-y{@9nOHMg9}KbOx$f8vN_C))=8Xq`xHzp})r%x(%8M*X2n_!0?vmj}LA_Bd^e zc+XhBUnk((CImsPw)Dw}+?-`U={wRHywMvv;-wPg1GMl*SNwvo#zN42xo zYl?o=?~&9?D}^1uyd0ynp?1Vty1}5BPj~-zK|}} z-hdNv^@3*{kIJqNP^G)BCpJ-Evf71l4x;5awuu6Es(e$A<*=7oXId2P6yc=%Q=(c- zLF?zS#rA~0q*W`2czuFcm7V3)zuLaxRx7RT-|_v|!<1(sf$wL9iun9KfKUZx4KFwqPLnbE4 z9}`FP1v!>E7<3y~9~F&1%XNt_2n2lwc`Qu=i(zjs<2*G|9fr78D;k}=+8++N>@R*g4pfyq@0!!(;Uu&ZYz;RysUz`)(u1aUe4Xv_Ggjv!mlnH{&M_nHA z6rRIO{}jOBJS>2lJtk(c{UHPj8oiDk-4GfFZfpH8H=d5NYB=Vq7=;821ouyix3h+T z$iFWk=W4S54wGi=jUZt>kA+16>2%p|fy40OarG0l<9zIV?%40m(eJ76|5}-KL-)d* zk89X-I^$pZ2*XaDbkndNMjj`hRsOc6O-#Q8QUY>y?OS1gvafmFPW$=JWPG(@E;IAG z9ccEA=S;D46UUr1;&;3t(VezGT{z{wtKApT8@W8ZYQmgQB|Rk>_fZQk==N6QQ+@@1 z!%w>@T6y3eN5+XMp4~eg0FnEBo+10GHGD64nU@7D*&iT zi860#)nE)qM_KArO%wlQqSc5M?a^Qh$!O{Xl+i(jg3q*1JghJo{yvS%S^?MIho6c^ zAWkPGlj%VIm6~8TgtlEbN$_({_Z%tI)TLpb?J{@?3qO?1obN4`MI@e;&ngL?qR5Zs zr3pAX3Cptq&@+Qj*hOhPX5{P*Hu?On68C0rNBy!=3ir?T1Rjz zJUp+!YbwT)Z_E|+^u31b{hBnd0!f0@1IEj)ekEC7L3dd+34i9PITc2SAA|vNH+l*y z7!G$H?7#yO@b&#EaEIm>O{x#z)`Vmz=#nf1If+FMfDN7)j4#h;=$v zk{8pO8gV~J=bCPNH+OOO?v0HKalQXp`FX2_EqL3|h3_QR?Chq6s@hw>AyC}R(_VS$B+wvOxxfS)2FX;E&DxCETT^Ri+y>Z&#Hh+d7em!RXLq76gJPhA4Gc|?SvEAC*%3C-NXF9OF z-lf|F5#>r<4y3Wpj|Q<;n4D@Tr2D&DaK6Lol=Y{U^sB`-U5!OgGXWEQIT5tXh!V(o zB4JEeQF0u1y1Ja2oSL^7epQCZ%T~{AL-R9vJ6ItxV30ZoeArC#-K zKDSa(PlH6@xn z$`n$E=@tNE%8>~FM5i0StJT|M;_%xx1Hu$%^HI@cf%^;d1VKNucvtx1PMXqtw5K1Xj;CsVB^%P3NKWD<0&A| z1+bvaE>*KRo^`cS1_e(mX$VLVs*jNH117+mcJ31kG4+Qm7pkj8gPy!x8iDmT*zpN*QQ8FS9=qUanDt{{n^wJ%xmanuBQW<=#xLoo0Cc+ET zd(%jN&%0dG#iy!x(?tnipZ5|1(FHlW{@#2U1(t3f%Ad-YDJKaF777RnB|Y33)8z*h z9A2qg6U#bPsWjCs84~7~>EI@5Gbu|RWfa(T?3y19Wr$nB<_Au|l*eJ{sY_xWqiU<< z|K=b$tYFqv>Q1UjvZ%-9a7 zm|3Jh%2n?F^qQ3Be-N?a_5iW2CXoP&0T@IO70jUa7}F@ZtnIO zaV8<_n1fH9^He~dw<-zd5MxFCXtI{}5#=`UHLlpjw5)@lZ&1GHY{`AvGM44>k-lC* zgI@am{M8y%6O#}L@QCZ7(1rKaf3Y;D^g4#yH)q6nhkvA)Zi^~A)&#*Ej+UHZoe%i6 zp8kFtpoJq;xcw0RdAx!nlT71&va;RmH(Jb%f6)pZAGAfD*0Q(We9^xUPp75UkxhAj zyo>pohd&b8cei||{}eZwJ+ z%Eeqay*^QESz7znv#oRwTT&`RGV+Jl^WjPNlWpMQ&T1c<9E4MQfKRARz3ZIDsN$`* z$N@ha7hVj-IU6hFAOV%I_xT`9(a@gyP2h_<&)>&!ziZw%8*t;pLOUT3CE>srf)Jv@ z45GgJ+1@b|52{7ok`m?^HDW`RNloi8zHHBh%3gK-GlMz8a`-~@Lo5E3cCbRi><2V5 zqL;|mX4fSr&>?=?bNg`E8;>%Bm*w3q)F_jX|E?6bp-v8lyZI7CW6pcm{Uw;4M}xr6 zP7XK{!iG>$x*>Q#J3Sln_`kO$IUa`cB+g&VEyyNh@4B+tr@Y_b>Apb9CYvWiugi5W z;1A=p>H2c$cKf+Mu5A1=?bYvg zf8r#Oz`e!pgB0L(U+^Ay@MT~8=b=ctC*>i;Yx_kBcwfn_*zY#u^WGdC1ZzD$BiXgd z196z5Wh1Wp-Z8Z)EMCYLaC+|(+TgPvGtQ2W ze{$Uce~B9A`mP3%R*c*9?^7UgMFZA6{FB?~>wPClX-D{NF-=*B_ia(|WmEieoSm)d zt55%@$BN;O@BW~86p=vp(hf0&W>sJOqwEoj1|;u8#~9m?h#r|5vsGaT&2{ZxX{X+d z&2}Qq8@fydM$7^c<}W4`np$lmH0Up{BL{$nq)j>A7RpE0hM@Oqo->NJKjzw4@EZukJ{!ZX-_ae zT|S?7yqo$hHf~!FDdNq}%o=5iKtCZ?(IX zpFg=R^D4*t-y@g}A{;^*HyLDR6D4e7kb9&*NT4Ox6wQp-F z#srh!Wv+z}`?KG3@AqTf7omd3DyXijoXwYCbNqy3N(dGZpjh07L0RM@xTUAhm{lr7 z+DB(8p2bY)Xk6yML|Ud9MEEiRi;|zLvoFoAS)K=c*IvfSPi*I&<#mpwqzB)6gBg|f z=Qyfrb|+;?ZdF&B|D_bDza_m zgAo|ZRbxB*YM1{0tE@(`Wz>@<$JeQ4eJk+MS^7eExJ~e zM#85jr6opwC3`GG@Mj`AbJzs=4%#`&pNk9z`W|4e-!Oa%xIErvQJkYLVyp>k)U>KG zQ5rL~PwKr*PK^CU1NgB3)*OiFNx8YhvZkzb?8iI}CtAk`Q0UIgD}bMXh6jO2un`;M z->1K4b=Kqi9AphZw5ea6ttPNxF$YF#aUWuPAKq`@e99&eZ9|ci!DipekbDjfpMM`8 zLf=Cgkr@5xdJXc&FS2DSd=dZi8fW6R(FM^ZzdPX`J9SQ@MvI>(Q;{hfO~dNw)fo?U zkuV}^+`Y9Jc*cxJ!>SwsPM7KdhC1|8)C?;bT%5lE#$CXEh?!_}=G0*?PhzB-UG%Y0 z<=D^Z9d*QB|M5GvJ`4r*<|+jBc7Kid`q1ulF80xfUBtF~I%4hhZ&DsrRvth(a>Y34 zON@}P$iHTJQE=wKnT!RmY)f7Nh3@9>`!)Xx6DjSHQYeuc=a4LOs+KAe9^4yYQ!v|W z!*^ws4VoBR7W>^F$<5(=GL8rtSK(lg8PfvBHr)6d&bxWhXbpnlw|Ec(4r(Aq^nven zcERhi$YH;4C=gZxrlZ1nC^xKOW+(d%t3RsrK80YZO<3cgFyCLAXXlbU5+HsBF%NCf zLKH{hzAH|*sqx-q$U}elN-IZRhedPV8-<=l$(edxI%}h5P|c`SOxu zskmV((thNq!diHCn@MX-9=v6P^&-PxGqFYc5zn@oLF3e~kffu@I_5|hmMT~AG!jf$ zIrbeQj4kDdC26`LEKxAFgs8ogMU=Cpnm8J{ItIiLvkOM5_;q3>PoJ_~|V=V}X_b?n8SoRbgGR5usm zwmgFNce~`hkBN#%7)vvrVwF_ah}rg~+?Q$!N!XoOMCgQTEh)#I5@}P~+ zVTVrd=WRt6QFq@M!imahXij2!z#H))k4eJ!hCKZ#!l{DktwKNXYvYv2?;H~EbDF1= zrx~Z(vvza(a{;GkLsddPhcrfp~? z3))A*6c_R3`h?|tC-RCcS=pG>%K)Fq{A^a=WbBo5wXGF!saHu{B<36BzHev*@Fn*v zplsS??pVWOCu)i)@N$k!;EXw8I>&s+nKaFRG}o&Zi&iPtNW7`1m_#t}%yiLG+MSp` zqxCKxat%Z1SxMe32=THpNzHtWrka<=yX)k}#HEd6O#Y?BM!6wUwPb%JRpK>WeUzL8ETQO#tq`7N9}VmyqMLhniRhNN zzply|vWF^dCq_eoR-S^}*$G!`;>}HM7jYik&s7pO^3^9YxsV&s!NX+Bgm1l3(r64_ z#U|!Ex|dp*_#$wP(H#SSOo>_zGuqqpWFCY{wJR!GzVIwcu`pPqa8kK}cS4yVT_8*t zr%vtXGB$bNjIWDDJ!DIWa^p*kf?7MFGQDw?UP)$6SmKkizE#YwL|BK5>Lzn;wLbtd zv=xdqi`Vu}8l2SOa$kCkA7Iq9a!Hd$`xNHp+bLTXb%nD9(;8eCp zpr%g%wv?MQsM%_v_hfTeM(jt+mo%wcV&5P_B=-m)6vizBIGj|;VzpRXaNyfohUM|t zFFhd=9r1}zRYC>nh{t(IeTCTcjd*b@HEb;jYs}rMedFpB+$Ug1kWi0E?0G8j#T1<^ z;xcGP>N0QEr)dGKCTn1A){zQ7f{Rk7d11ueLBqPH9@1vuc>;_bO8)(jw>K73|lr;7Dh;P~o0qIExUZGRUt~S@Po0D!op|u*I zV!snUnb4H)W7|uUDQwVXW|9udAPp#{L;3E8pXU3?&q-FGr&h<#w3xFGd^?v|m#K&m zu`xiD!<>6TEjRrTZ2Po=9K491h!mjhaC(+wl&iJ@O*55P+B7>F($X{|&=E<=)HV=p zZx}BDD>CGnFDrxsHm)Odrwo`b^Lt*UrZ%&Ginuk3`>(FLd#h#V;O^tKv$T)ZeXxxa zu(Gm_Et&9&Dh=jl+8)d^>{b7`lcQl!*1x*s8c4J^0J<$S>y0zKV=v0S!*JnMHzC{S zZyE%Le8NP-&fD8eTiUEWhPK#$XMOThbj=G+O*~dQGRk_N+WcfAgG=Xi!<8#XSjTZ! z(#Sf;SjW9hQJb7MB}KM!HtjBGXcy6RE#hTiwIXd%U1|@7i-68N|nVaKFvx2 z*QpiEnO{xJ(DvyBn~`H%nBPBTe?XMrz~4=#Nk11oHGm)T!>uCw^L^m>l5Oa;t)F;N z9%@gG3966vWVM(PRE`LY@zlBKf;Eu@{Pve4$XsBJijoq$1rerD9^F`cHq!# z>{fh7M3vE3pysy=Lw;JI-Ze5!?d) z^i213Vj&*ekbMh=P(6Tl`#J_y8bLz3d32=+zg+#A=NI*}DoFNDJS!y=>nD(ZJ$Xh{ zY3}QXXM2!$qV*pCMk2E9angPPKRg?`8ueQ_+lt~)%g$QP^`_5mlihi(-j--^z8q;4 zhMfKuk8WGm^NKzykfDh~0&5w&su*Gd)o`^Lz!CkNBVx2FILDwH38M3KAAQr?=VgWM zfiIgV+}aM=qYBN%M4iV{Jdu-LV8Fgbwzf!Hgm1SPmG;v%@}sBW)4TGlO?L`_@3!-h z_L%9vbM}nu*n#yo;qv0~$}@+ctKqFTJFXz)Ha7XxbVmpL)}rB=c%C@k>MmcpO3)CS z8~r{5`8)T))1BUzxf0pU&ttB=Ixro-e973g35TL1 za_A%+@5v1XZ%g*O$u+9=6o^&G!wp>i42gf?cACVnfKRa8x+b|l*9o$P@kJJk16nN& zd~{DWvzQ|6E%p!WY9pX-!a^+s39~7SMTaVWvd)$Ag)MS1uBA%qxMW9eDqNj{4O)`% z&#Rk+M5F@_mk84+`~@B6B$`hNIyYRJ+9A{;WDb{Nun&0iFV`xC1QL=cxU@o8Ba95w zim^C?0j%b#6BC5n1xqTd$Ro_SU@ie-?d*eT6eC^q2-gxKyoMMLj;b?{4ah@?PcUq7 zX#eZ0)AwkcAsS2`k4f42P#9hU6f)|?tbHf^l>A1>XjT&ma!Xi}Q6w4@^#n*s90E2a zbXH_uNuIa}Fw+!y2$j_;u;_Ud%kd_J+U(<)O7_}QOt~qw-&pd+12_OdF%O)mKcS`) zj_EM3cJGp{Y#`~cNe$|~AZa7yI=kY1uVVg10zy(ZCi5AO!^?_m7NkS_3}^T*cNjW9 z@x(IIO(^=!Ntxt{FZF&P1KyId$!(S0Eujgbpxd|tSg*T5n2GJzx^(f>zLecnsbM8T z8i0u#^6ikC(FNQM`ZCRRL9ZP_@iemx5%GK#Su`SUl&S9!))q(d^WUtWbaXv_Z>Ir= zcpTT9bZOe%OAP{#6VYxlA;xtum%Zb2pRW})0&b~K$R6JFEF10;W75ox3&$!UEGf_} zQ2HZameR8!)$ZuH*uu3~)ey9>r?j{OxTQ@I{}#%0qET*0+CdSMCr!?#ldxOoG0Ss0 zdPqyFThCoaH>4c4Zr^7S8T|t#NBng>Yg6X$!gcK!rLyZi#)vZNqVL6nvgsp7Z=RD4 zqwo`j6ko5gkPimw>$cm|8_q9mSs^dQYwi|aqWL|tvfbh%7i}p|wG0=EzSf*~NNDQE zb-Knf2JC8>Sf#p&o25Z-P2ZxSZn*^YR)NE)eCX<9G(~cJTL^Q&DQOWjUdX+RKYl#I zgq}e*Fucl;jWces%e|$f$7_-oY*rhR8y-uBH)YLUqwMgt(6I61|Gj4^XRSd2o* zAVJR{yQ^d_Lbb_eY(mL>>+w~XVqK8iP{)cYGT`t)GqY^Yh}P*V7s5c>>(l;?^Xf^0a^J&S6(OS zMe`nztGMu>n4s)4kT-^l!>BbKmZCQ0(X#631&`H&{a4256`~JgrRZzg+~Vf^d>b=; zGVoGA-;n^1keq{wQxUYs-x^MtNl3_?vM! zXp_5aJFV|mBOh{#wz2a4`@>UU4#?Pt^Y0DJ7&kHQFd!3 zXsgdc7#mKtxynFavNYU%i|Vz1Tpd|3e3|G^6uI=a*WuVs*s=$ea6s)x2j@so{Fhg< z!28Mf$}Q9TP4pY@QS{TbncjzjqQOBk>6t>oKR7;@t81;JM0pc3@jt)S^W|+6@>4lH ztKjK15a_A*9Go^{Q)8|>MnEGt9YE!@a8hRxY)Z?Sn9{qiJ; z`&?gB`%EIgEfq7i8bE9ngI*pRKq$y^|Y9}R6c4U4vR1pH6IIxx=oaJr{g1?y+d z^d#+mzzZ-Z@+{6n%p^K4c6^sY`pf$G=z1Nx`Maz3NaiVzZB9+gdNxOz5nEmpQFAIe zJbs_TwI&RY+CQIA14H#Xp(h7MfvOTg4{Zp5o$*+{LHhh)Jk&?LB+4Fw``sN`=Wp;n z*6=2zwf-KU{gf@6fQCVex(X9QVg!?AB4uwq<==!biTTbyav>6s%e%zTEH-`QcS1p>fJ(1uI6&{ajDdb`Y_z`#nyL{aG1i3!-^_7Jqh+!5Ue0%rSe5nk2JKRWe^SyF|SW zU9FsPmeQq*yb|Ook}3Z=y{!;(SkUSg9iy&!+>~7hcWqxSGcT%}S)l*hbH#R}K|6o4 z+Y^;C;cA=P&R@ekn3tWL>D@4X?%-;gW!G+#H@knAwh|i}3H^Np zPYYIkfT(N-tJikL`g&qTA0GUD7yUi+T-!h0vOa_mS>Oc|;OO*50z{i%{muHpf|#SV z!~W77Yq|Cu!m4k7+DvrTJkYe3$XHxYoDs#8W11Kr(C9k=CKWy?0TF|)^fW~NXLk_q z9aCiv8_&eAO`Ey?qDvPmFT`7rmmTSPrQUM|F!N8ii|ftCfei;MM=uSlWpDNLi*2LK zg#wA|_54Bq%w-WGPW7{GS1{L`QQHE2wxfRy&ornRQ?3StjhWvOJ7IQ6@xyn{LU?EY2R!n`)ohY}xxWA8Ttfrnb`Q5O!@qeQT|2>djfHw2<;Qm=}1ES|CzWQ zN+gj~_M_ZWf2O5JdM(~6M*9bxp)Oef9r@q+H41g-k>QZ|Him;tf`(MVP})QF7y@$v zE(JZ!v$#;ZQIiMrQXfxlmU0)8J~%*y)TB;?XG>J&iTd*}&A9ia){q)of{oOI&+;wz zb@ff)@itz9wgn#_M@PPL>Z4Z4hV}u%&o<5I>Yh|V60@E2%38WLiAuI$!ZdgL$shyi zwN8S98Rhld?PzZ;$S3tJNzUwvE?GW0Mlm$|3>9WWssj6RD_-?g#q?@!*QTpAC^~Ks2Jj@()8|Xb2Bh?m>ua1{kP^d1u zdaf-jFqNUEb$a1_IoM=-K7@?0j3L=4WNNuR1JUyE@LHv2IF+tXfM2n>FzHi(Ffyjn zUlq9(p}c>Xgq2<5SBDJ1+p!sXoy~2@M~sLdj$rF>IzJChqsYW7Z3iaX4X54doy2HS zGFYJ_;dK1N;~ipts(J-TTNN`UBg%lQ4xz0)=D8#v79@-9k>_l8*uF0Jbw6g?xYJye z=D@oi11Xpk7LF)fO=R>m>d%lw6;^O!wA65GMMcIq{4l47xH#B`qw!@(CZUv;12KoV zn5{Xzk%pS-3CO6Y*QEC>HDst!OB#-N*(JrDcGY>(yTHll)Jcm!;+y=<^FS#)(j?!M z+i(*(M^b2u_ZvxE?+uLTlgBK)!P4-eh$wOku)i`pOQNct*zC~;Bxxr9iWn66^Mw03 z-_b*@utTm)YR}YH*g3nYF6WbxD(SxXD|i%m(DM!a=#?+IIxgwWjK&LeW3ifL%MV12 z@I|K)R8g_zMa=1wPae3Z?Yz_(&!T6YmBDot2QZ`!+_ALNMB~RV{X$S3B;&K9sM6tk zkx0*~CY4wa+?d6xwPTmuit@EB)C4O#lGNbBEEz}iWxYimY0gifSFN#9=aesyQ~pt; z(N*}>{3x8}&$p0RqS6Ah15&hp=1aGL!AQy^Tz!Y*IOZdOLFsbg91y2v&So;DP@ijS zv3rC4ginn_)=?EAKCw%nxVQT>A$nomUmd=;Cf+a4sxiB{9pyqUTgw0ZL^8N>tK$yHd%G12tGfrpfj zc>2SCxYFHhwAjv1tm~0&2TY)3Bk7Pors73RsxS&I8CkS`NRw_3EPlR;{)7g6M6aMy zqd?g=bKM0pfK%a*DaM3Ej7Ci^D~35brOL8{o`13_F?n!vPL-sgUX1 zsc4OzQMupK`N-764kpp$<+Pkq&QTfCbprwr^oOJ?1R}E3zez?r5kmcNX;2N=OhLA; zCFoKsyA<-Tm>fRxLOB~Sov^?nyBJ){Hzx)xX2yAJ@^i|{>)h81=MEF-ny46cwipH) zi%3ShAx6x=$XvV+*Y8IjXnWQU!vk8_qTdKtw%!?aBlPU6l)OH{xlo$=Y-TH&Q_H(uA*$?%DM4GgGHQ{l6; zJsn>;)jN>u-AI(s=PCJU9Hbym*F#B^%BA2--b*1pcQ#sv6T*N~-9cqyz@uTh^!CG! z*xPv05q?L1UVvhMh$Zz-p@OsB`OF(b7nhgQHGEg&uvZ;t?Ca7#XJ!6#xlqyj79E)i5xg|q-agXkRe6kBlcu_wi&syR1~ zx!d}#`K}C!t6EhH0uSc3dfaK%a6yBbdy4zEEHh!^J3d=B*g3EI@L;}H!vu|<`4Ot z&MIeR7eUAdWg0*n)|gEU-lJXpDP7Ly`y!JhAbU6d*KwZdhi`p%`NG8Iz5z0VztDP~ zC!Gq>2H*m&0z+wk17u_Y24BF!*G@>pVoY0viy@wXEqSJ}ws8f9V4sxR!(=OGuL&eq zTEeii2OF3-0Qly*pF~nE>4<;@o_f0O9m>K##vTBC7M8$W7qJjT`w+s=w@jStT@LsA z$rtE+VG^ICM>Y$t%|v*$`-jA#^B?wNVWeJuEn*8me0(`y7jF8w5l;nhy`Xb?(WlZM zxtt{wFeQ^vUmz^m>K7|vaAdIrxY5@!T9t;PYLIR;2~TS%a_vx`jp*BpQ+<=0BXlyU zD6ix&tVoct`s`}bCvaEeW#`eSSBRwa9ljG0q+6RHN1b!;t_7K8`9!Ky!rB`jVRTn< z8X}<_Vixn?P8;DYsUp7YGrs5?6AqB){PmX8h{(j*J1Q}RUVqC_7Yzs$zP5L!7};hidlT$^#;l;?gt?nS0wyj+#K840;@RO&;f zuX9u6S8510PD$w)cdwx18+49=+j;)ab6iNZZ+I7E?zl}S7jt&Ad9ydg$R)^S(sMth zi$sIM|3U_!ep3Fye>9$BKP8@12GbX6e1&g)5s!Q!1wjU32uBKs2*-S(2#0*Z24MvueNlf<1mXpuep!7`+9>+k&ie;(Y=%TO zZEZwAv%yrw{^8fSgkQBWW~$?kBroee9ApBYQ_Rq3C44gf&}GWUw$zUBC-O3pHio*= zGli7ibHdMc1bX+zuw_vw=efEM+*E#S*>}+>{F$mZbNwvV@Qvd?=^eSa6%oNNYiPt$ zjwct^uW~v~LR&?oe5ioN`QxgRkSb)2r2BU}IQ}r<=z9pEH%;(P{SP1*(ffqQRGBGt zj}7>Hq%CoNYGMn_tJq zKNOl>IB7VZ7Et_Vvk2o=g}i0H=aI#tI>bsT@Zn+!`eCH8&;{i?4x(MYOsOvij49>T zIKNBACf1WA{|7lh#=jSiMXp?hNDM}OP*^f{%EyCYH0*}aP>csXF$#tH?1rte7|V}D z$P?tIi^gzT+HIu_jiZ&Jykw=H_Qmvv+U~)Jx~1BZ*X}|qKetcbBoe6%g$-RK_hj3m zx0?1hQMfAL$#UMvcop8m6*v@aq7?zZ;7cAo_XTIc9pJL=bVrw~Zyc@;qw%Ub;oR96 zJ&ToVLoowA5Lo%{5o&?LND0-1(5cEts1c&Wkp+zGKo^HVZSmV+Kz2Sv*^^WE$n=Hr z4+t=b$q%HS04;_9hfW^iB&7uX9>rLj4B-I>sGK;mDKi50ft5xFK&{Z70*t;Tmr6BZ zbijj)9!4$T$x>}XG2VmW9-o)id2&ML$$ng_$w^Pp!A3dHczqQv8SfHeex##5EYb8i?+Fa0UYgvO+<%cCbwzbtiXFjd)Z}DkDt2%qKEP1hlH-bE%m^=iKQ%VqSL(9AiZuYmg{3^xIC@)8aSBOl@c@oo2<)L{Np7@@9m>$Il zSUj4WEF3-{b6zKPLNtGqkU2uE!2JKN#voOdMDo~I?XNa`EGJV z&D7-L+`>Dp<&5}^y2ET$GMQSPrH#o+Rlxnwb5_{01K-mur)oe2`|-tr(+4c-?P+(d z#Mc~qm&s6awQ$IG!!29+LUQHoVjKh)?2T@E?U_>q^s~MhMYxdHY<=}|BhRltuIuOL zFfQUR=Hgr_SIf<-h|AW3hkdzJgIYUs9Szk4bu~%7DSc#991uv;E%WC93PiYHXf_L8 zO)MMZw6aoxzkl;@9$j8uSYAfAO|HISI7A=n?pV_+!Q{0otEbT$!!r6@bGecC()r5r z+Hz(2{ZIei^5?&C`yvtlaGew!$IqjFXvMH@BWU zkb9+MbuzY5mGPvZf_SN)t(mCu;{1W+aLuF}1=BUxlgK)z1it(UcA|EZ@O*Wwv4u%Pcy5TrZx*3ppzCso!(FQDa!eBoWJe)zXiHLnQi8A zscevk?zm&JAQxggHdwl1Y|-4)X{DbP>n^QEe9 zyH>g4rKW3mQM^8S>v%mW28M^jJWq_$>}GZHSG~q~_?pr7bX?sqi^)wlCq=Uyg&}^t zg(&5^sV}&$o3z}bljeQw2X(uipOcQ$JYTF>_)T|hDvGIGKgbieBpO#-XvEiCa)HVOU)SldLYKxkQkKby*w}p<~HvPTL6iY%~ zwy0ZE`MnX}n-fqAIa{R*V_2=9)Eu%@E~Yf>C+ag6&Fr`O#nPyM_Un(JJD&gc?A)&D8A1L@f7k|gMkvgPMR0JfrIht11ck+X2k zZP(1{QE{md=*!pKiceYd&B3U#&6<2OMIEcvn47Do?&Pmq=Y6L;h{*kR?oXsgr|l26 zG9rM6g{ewu3FA$)r4D=bY!&Qm!GiwyT&OqMT6!g$-m5~UHMz{EN{x|=YsxvmY6Stw zN#k(puFj@>D(_5BIvSHLMceNUm(Z|1mdgugQ%99knkQ=2O_jPilCGY#Ka2)oG)B^U z1CLHR-9f61T!&BnJK1wVM!8DN*;@2OdV|O!rDa`Bv71CzD*y8ZPtyRVYZ_Dkqe5sZ z&kEOw3Ch5h)8zEn6@KIywiz<4F_JIo!t#9pvH)gvyT}A{05b|w9rOURGEZJF6FV(x zxO!kjB|FN4db1rpZ|QW>qHs#JS@(o5y+Z=!U6Z*LM|v*hGMj{P^j>%l#YV-lbwE&o zE<>qEGh{%tXqOwdr8!1kfL?zdeW+*`Bj7gxvF%x5-6xPF3=C77!9OmSj)%9L@osWY z1Jh&rpyhOcvTm`GWoS!qX~_E6SZ8@d0zMsA0sq3otiU5Y) zt|nz)1`er#bR0l&*9|OFT}&eVm4E@M{O>$0AUPHtLZOAl8wG*n`Z@IgS{<20i#2(w zT(VIx;Acd4^SSAIT{bZlrmMoZ>jJJ=2E8?wxo#~<@?+^o82Y0Q+FE*Et{4`b|434~ z%G&ui{@mn-=Hg-#-QQfq3zK&>R{+&5pM2^`qW=Es$>~30EH)>%sx$9vE>7~RyZ^7o z-UVEeqdF6;h{%k{$aiH{W>(d$ciqam??*km`}V!J)vcCV>X#l3Y7mkTw2&=XjD!K3 zrx5}(k_}=k5H@bsi(vqb!3)^TAWKGAYuWOc4-H-zk0lSbj9A#ko@HkAEg*kg>^YHD zw*~ghw{>s5vNAJXC(a|{od0ZY9^UxMaCi#-d%fp|@vsC>tYWrS`hIpLXg-77cJ8v= z^|@Pexp7;GOI$1mV(&*TLplah2dY$l=ffQ~9IVmqu&)*yJF^zB*@q4=5_DL>eZE0U z3}O29A~95(JTMo&b0S|gP0N;MB{-3v{T+Wt!Fe3BOVD{8BA{BB+?szVK_6 zPI{n|*0MM9soQDi*l_#puYTuNa!uMr_5yPvtJWSCuHuiwVK zl0g=?ks%~K1CzYmlJN@FI==4dfoAAh1iHMXnLx-4G&Gs4!6a!NZk0kVOr~pGFrUpg zYYlhy^ou2$?IRkB4b!PV@j6 zO%nJDL$eNME~z-SfKu#GqsLQg*<#Dp)?y)IQUua>O4Xp%W=nnaDF6-0=CP&YRt6eq zmKifgL27tRTUe|XEnrH4{T;jKgjVq&%yWYC6ftS_8=Q!ToPj!N&yg!Dr4V5h4Bhsn zX3un?0_crzhq23b+F9uTIvLJ_A#f9@tMZ?yFs;ld37GdRL%~d9)Nm)et(=B%%Mt`7 zZV=7f>(p@`!5xu<4^l-JiYNx-i+G`U3=Eo&twY80=m}{hfplfRn)oRX&6WuoxK=I~ zJd4^Up?+b$&}ep7WA4Smuhc_ZxSs8*g&G=D8VwXmG56!X&Kl|gZ#So5Tx zc;(T-YOt?w-%*(JTP1tp)QOH^iu>Q+-U<^Jm~bFHhn9o~5(9BTOeo8(`Wu%T1rIlG zbZzAoMrGsl(%I(m#XUcHv^@pra#t$!^IV~Bxnhxhh|!N7bKV6Do1sJoBu74QF<&e9g;@fkHFa7PO0Nrtz@dxEYYWPAILqF z`@IZtRc#n0Gq|`ZTTnYn$ZTfN(Nn`MiDzgNc;PV1uz^86ab`Xba8Y}zMSu>BeMehL zIl(9*u6#wo@Ig&#Crj>;DpyApA=<{nqb`&>Q&8~A7-1I1DvAP_`G~w%FUKL5Ca?sP z0}bMoOb{S058Yr;bk||TsUOhvZoX)jcGrdu99pfrzEC0XFcKiix98iaA!vNGyt8<$ zgm7u-45l%^g5nxvy0CyTQ7A*0M!vNIrXh%ZQEO;acfDWc6j+eXa37Uvy3_*4FeR1T zB=2ZQhcnHTf}7H3Fc8LkLW$53rI48x47puez4X|nRhx^vVJ*$iH3m{gtT&8-r=j#r z(6H7vE;DQ$Q93MLudcq#^mL+gjhJBB(9s;IP4nOiH#hl6VQ#KlsgU6fH;}7r>xa(f6$k8vc56Wn zFCWT<*2P1YJ@UP%S#`|0mhIf&%~cAzm3ZOYWM!@kx0t)(hCO}$Zgy&l6_^W~Q4`~G z5XA`46oD|t5Z@n%hM6?u zI3FJA_Q-sFxU#WYaD!mZvko=eLBTXiNqJZ=(;G3)JBrF0!eZ$36PJ>>mL#4T=tqFZ z5beSXtXx^z7;Nu9-CvyiY5UIQO-u9rMssPtRj>T7g=zu*8)$C}{n?{>-t^p!6CF&qa95$bQ z?px#?lV74oC%;EdlDEF)zF+&{nZM3oySFA0utPA`h>@%Fbc{G;Va&&DjUsrK3Qz~b zsZ%O-?QdDke99ib1|5E#Lu@ zJ7p{%k&@o3H>ULR&*A1O9Lm`i!2@_yIW5l+}YaNBEzl6wy-E;>L-I(tIN4#xl_5DRh;vi_EtQ3D|7O_ z7(t%QVD8b^L`Re%$XC$|=naE8BF6Ybs_%uk z%|6gC16wOp8;dVpXjBV%$8s!Bm{iM0t2?i~<=~(gYFaBFOx_(97Rna+#qwgOSnbS} zJ7Io4teof^*y^09m|wR+Ur)}p#+H5fWUqJfuw;vwf+60yZd)W+nd`*u3enla!t3{nS6g?zIiAJMx%UqsOg7` zt8<~fwPlBMMQ)g;5zj9)I$e9~nm0B&%-lo{2zeB$a zlvd9j$X%CvS?;5`kLNy<`&{l1a$n9p0b{VA2oQhDg(GQY(Gs%+8tqX!&cb7GJ9U~_ zCJT(&A!%pOM@>(;{baaV$;EY7eN!!|s=Nj0wJBnitRWh@q`n7|&s4(1!h9mlw}+^EojLjapQ$k$W#g!Nyw6{D~9P zKnF#CO`_qBa3I1a#uC>-KCdn~R#b{CXJHisOL;1A2NZpgG=-2i`4l0Qpj4VKm%o|@ zDz=Exz*elEZBd6r753)Wkg?42m$@x zwu%c=&JlZvH?ab}nqhW6P?Ggv?H8W&H6?sC*R z<^}pg;N$DL{kapsP0m5jy(M=qXzIU}`!~5SW|7@LkqDwnnwd$NWnM)D$>A8`L14y@ zar$?&&(Jf&2(#8Eh5lv_`){Zapt(?g1jZac=~2r3rWapz*x9V%}~^pO~( zgNg^kgGe7rzMOtd<^uH>_$W2BTyQY)E^DHefp1;{&2Y6-I$ZEHJ1l@N|*y0 zv*6C$OVaH!)98ig(W$6zm`3%gx{W!T>IVOTU&2qmt84n_c+5lTx?B%mm$Sp3H#`MJs(PjN{NQ1&uH0pt3j;NRfFB%^FrpjxAitm~?Fu>^UBOFqD;j^*HuR z9(e~SgD}{(U23}JQa+6)5A`aP(x6dt;;7uv6`sw0CaBb6w^a1X!mrCylP3uV*l?|0 zEJSu<1P#vS-|du=LQi7E2`Mav=>9K+DM~>2&hcZs#D)I`&Bz-VP}13_P5vvqh;PAh zhZo6xOyAyKpt@xiJyEhP-InRjQQNUg(Pjj+X|tnorwokLw+d8fsUJzbTkn|#N63=l zH0PU+;Q)OS>hvm_O{<$GgAOS>mgSZTKJGpid$D~ipX9rK-VzU1dW`kz-0@_7$@c=; z(FG-?G&1vs3@c&DYv?fZ>iJ6K1NZc0k;kbt|CU=7Cn+R>;I1r)Qp%6!gS_xIc^e!4W%lRR;GjXrncZv#mFk; zrYZjhwojTp6`V-+z=Lrr4pAyb=nP07J_GCkIx#Wxh+^x=d?>x5qk+Bw8kvKbtW2oX zF%(F$ZZwnfvK=}+wrrh%5CdvsldlPi;}Ez>7l9tq zuQ8OrQ2`}n7Qu;d8U^^ZLiPeo(F-CQb&4t2pz**mL4n~>jbiX=w=H-dgH05+E9gB6 z)HU-+ZL2`*>~l-SX0=;G6-Mu=ZIX1@9iW8G^0R@srWnoyx?yXZsQA$Kpxtey3g-*1 z+XECE!r^oPCtx1#{s`T{&rsD#!DRB4!?cV`b9kz&Wj7qMApz_6X!dP_K6qUj|w3Ts2(QL{kD1c7cd-B2E!nETuk)WDEU3@l(Vu0eAUcDPZilZvUqIKWphSD`aX zARrxynPs$6%yXvGcyBBU*ee>g2dS8RlNkvQOpxFU1nf^@+CX7q5w&3?Kj74h zz9!{&0_abb50_BC-l6n?WsJ@MBJ-FUA$#)Q@ZB=!;KhRB{IIZ0-+Bmt@~o-6`5ygb z?&d7VFYp4~EA5RHzbOFU!d=qo%E;7iL>Apvc2ryO7G+T>3^R{RQO>%UdJof^D-Z#d zH?tr2H_5vi5l0VghXFqi@?Hd{ge^*bNjSP~LJte+TW)1RcZ6LC4BT-rbm>=jBM`~Z z-7d48kn6hbfRqC2)%$InRv**zT-R`VgFP9cx2&xT;RJ3}GA&_;KClFsE<%R_OvBY( zZ_aSBA2k^`p#-(n!QC)IZCP#iD4Xgk&#@%;%G@1UF2`)=2D$3)OzYUi+)%S^$??<> zsLfEm;BUGiImOqTS)j@d5G0zq2Hl&6)1%o>WfTCEkx4<^Ho%IDE z!}l!J@;ddsc4R>p{JE917FXt%bxml&QqwF5!@m2YWc)GSu6T{>m&>m|eaXA; zY>D8{^HGq;VE0e2zzJKfOTOVIV$lySzb35L-+cP&lgIBU_Oj1A4w7oSW z`f<=n=W+vux`Qgj-YUUx)W5jsH%g-Hc($-ORA6;##7J9x*`teblwGf~ObPlin4B(X zM9#kJdtj9xTWhZuyEV=hTAz#0sg z`pJCrsC)H-6)@)>#$4U781Mvs53@C0=)wf1B0g~sw=hpTj1`oA4~90G0SA%to_o;X z*M(*%NSJ$Y6VH?uoVvF^fY?L5+%9GvKwoK`|23Lq;IeH*YFDAV9-U44ZmYXSL6;i8 zIP~>V=^nj#)F>DG*Mf0lMk>PlK`5=HVj{%**`;U0(&+34KeKxJ#?$L-@Uli5rE+ob zk{;NHM{XJ~h8taUS$_~A6&zjyF)r?3)wz55xiwDgHN5BscsVu8vq!(1vvYB-p;pW; z$(_obRT*j#eoN($2c<};XyqX&g`MWi5m>zV1YObCun8x$qio$Q)qmoIi--5_MP6G@ zDNXzM@@d;#STJo`nS7P>Oxu1>Y44}W<+h2r$?#V^$DVv$T{i%3-66(T;RpM|)3$m4 z{cy&2TjiZ{vk5P)t3%V?vEkngrTsQ_Nd0&-`Le=p&5b#@Fe<#wSx8cUw-00@sJ-ZFOwB@#X>${Zr3#?cM^@X zVo!r_j9hP*mJ49fbe0SImV(eKoGmmD?al2!V8>ORkEoT@be8-Zy$Wq&)pPq13gw~65UvAMJoZ!WEL*;ON-5&Beq?_tf*S&bkZnv z3zsbvtHiZxMKGsdb;%Wz&q~J+9E*PM>a7!({@j&K7(DHZZ@m7JYa;hDpK3x+w9npn zs^FWxfC1-OhzFOK9Xj!Hzu9&6cT7aF*BimX-BRM9qhM*J|F8Ve_F`pzX7fK{5_(7~ z-@RsTDc8>(R5)U|Q`k+1yF`pf!*!C(@-RgIY*g?Tq_%G7iZ&Ax|7X{_)e4 zoSs|-FF#`=cDMcFS90j38zq|DL8A1+voGB&k>rla_tIaYPppo5WNvQdflWGBUj4WM zr`z`HW%ibRBj>Jq*^SQRHRQq7{^_$fx$xAC~QgysWUX7ZpgA+wbYNf{;fm41b_0D#sm*k0ul(89>9G~~!kYD0$QEE;+=_ll=^jctzX+J8l&Y*BKyzcUax)n0 zA+Zgo(+4BARrZk#KN;l#uI=_)7(3F(xCNEwgfmB0Drr4^>+6qnW6P55&Puy>bl>^I zwZFHG2$ccOA&t6pyT`ONQ z^+xeN{1$k2zO24|Hr#HQ=DqnyNK1X(r)ehG#XyF?44(o^PYNF5K1nOsUx$|7=l{g1 z0sm)Cr60Yv$hw{K?rv#wSncJ{s&9vO${Xt2nYje`_jP6?P5rqTKDIHAP)bl*UJ9Rt zXMh>#n7DkNdgX+Z|34=S9;Ugyd0l2zm6H!R6M~{)JPUe$jhp!_ ziMj)(?oiVe_1mZqLJ_Z1>5gGO7sd;@9ON5ebV&&bL5GIg+JG9@7P^_ zRf1@lJaHX0egAIXH|cTHHjC#LpIp3Vu5icEqpc3rUVDrQrZ0B1VQ*!H=r^A+W#?iJ zM>iMc(%hBV+IgZvj*y{GqmIV;sE|4GgWZmf{b~{@$C5qUEyk<_Q~rf(rRj(~|M|{7 z!PYy>VUyol-&#v!a-(#ZWletDHra6oJb2jxk+-!bR@aaHcflqDPT}q45U+EkI~7PS(sidT3zlJ0~+2Ym~>v$ zK8!{>j=MBJ8BnE034Arh6=84DVQU#BLYQcp3y;mrBlLEYw zg+DqvKI?TBJ5}EdO2C{QLs-69j1BI(K~U(-`PEu%deYKCW0?1tGriKoyG)+m*!au8 zeA*C3p_b%}1(?{t5rGS87So~OR2FLSTBpHd9+VO9eR#mkk!hTF^? z&Rq>Q+)bbZy&-pZ?nAkc=f0TxKXTv8{WqeM78#Kv(5 zgU|CtemOtMU&e3bKg-|A@8jqBL;N%R5BOL3|H;267^pk0sETE=E_z}lt`;v9KPO%% z-YI@ryjQ$md`dhf{!~0I{zm-2;vbE&(J_{cgT@i#3ga5%CgWD)^~PI`dyHQXUocsQ3A))H3Uoh-+AXm;>ML6!6&PN1F~huv$a5ow z(Tmdwvmq-_`tEStRsQ+-6_tkeI0mMd!W|P20n5?pN)-C>IE!XPy`eWoL~RcNoWO9z zglS5#K#e4A@6sODCBdEcRu@mlYm!Wj8{$UdKpjgEX=clM%NS*sDSw-o}6IZ1su?<;Lb1w=40Eml1!6h@cg485mcmt;f~}$hFVaatv=Jl;uNjTIy-2kCW7Id{*+nOt5t=?}GD!QP zfRX%33eCYCsu7fzp*10-4P3vm4M*EN9VMe=6Mq5=c#J@(#C`hW8kY}1o-W4Ms29c5USFT1k_|yCv9j1X3HIp zy0NO>U^tH2(7#b3!a#KRj-L~ZLh2#$x#*(O$~qet)iP@yt{?YDpm0I;`bjEKAf*V~ zm?lV@6@vEy6+IgFp^e?mf*20k{RjpWDmKCihUIoQK)Q|5@f_3dC^ys$HWxz}F>~Q4 z1$hB27hO!Ch|{D1UDZxS7kYXCmQtqJ_cL`5Cv}7yfwj0C#A z8x6W@psLj@?I*@Vlbstce^ zIFr*MjwS|#jTJ_OBGWPEiWq|w#z7hNaUNh85^iGyVe)o5Oh604a^Yf}tL^<{C&NWv z$2+%x@VW_-NF77qlLBt=jq08Q!9e$l;h+Z-6N^cpN<#S;fXUF^*j3}3!tE0^J~(@nyDTv7*{-x|40Iw) zW}Gscm>#9O0i6qN?Sg>;M_P))qs)XzM(VCu#}t!Zqf6ef7mxcH*K0+|0LcsI0iM)F zPrVq%RQW`pNz;e>7ZPLvFa#(<@P=5Ij8ryZ0t`^XU|jhojIT#=)Kb;Qo6rSV0mNws zCOpP5P>|P9`SB(cI)q!psP%vqahxpb$0@%CN(F)#qMHmf6gWX!fbu*Nt=U3bdxi$R zO*Y4)exWr6u>%woK}RR80*WeR3doe8?gNxyQMP&^Fd8%JwqyJP0~-O`7)Mj~n|7g1 zLuHaFUud{KRe89ujle{^1B6E!A)>TuTLEhde5@^yS->cR+#R6LVT!Sj$wty|)zLcu ze(MQD%}_)vT8dw{yBJ&tjA6{<5sv&=sm<*!kS5L`0rx8);UsN@6zidU1zrJVv_~CF>So9x%X3hFo93t_1FY(KB@vacR;=NjMfTKO)dIRE{vPTA`g|7>PnZ z5d#=MtCw5G@BzJ5x$;z*1{}kgDi#d0{T!p zCzysB?*WZTl{%9MtS3~n4YWSq0=tU#v9FRoats_%MKgWOiUu42h`Nxp6sh(%R6b`+ z<&2sIrjG3+=Y&$#6z=wc_JB=ng4EhnmOnP9g_8p53K{IiCc4oKfie&%6UY|nI^x}4 zAL|239R^oy_7t+K7}C25HLOP9It-Ty9oNvfu4{aOao;DtuTjYnQ;!kDry5%#8b{1# z(^C-8w!?I(8wO?!#iiX_aew`#nr>;jeltQ1{S48lE)D5uF7DqG11_`B`+ypfE4U%a z5phUEZ+S2VHC%op4u*gcoy#_yVfzUCgz3RB&AE}m0^wblI%ZJQfgdVV;eI>a!c zUSdEwhDNH0iloquaZ_1CK&cF{3USaQnkC)U(TU|8TuMP<)DRln!m4ZXO5BGgTp5Bg z%kspqJ7N{23qP3|URRgULIzufF}MftH27k{jqnCc0ito{ZYa~d zWXkm-JA-5QvFVR&3jKxmQI0ZHebp%Wcj|gw{j90Fe1wqmkqC*(dj zRr3R3*!z{ou=-c`dW6rm~KIH5iM*)NSucsR09iGHBEa3Azvos zHwcC6lvj|-Rf~;*QXj*L!OJH}2fJLsRjJF=8mJoQDTozz4ttztKamXe?Q391k_RbW zz`HDv55lo8O*`rjRh{AaE{4bnibPZ=Fy_MBVJz*>vF;gqTn26ZdDTl4sh5$gpV5;9 zhY8^bI2QB(A@9wajZ~!WsVENriz0XsKplvD4+^C zfhY_I^`=k96NeXCME(M<{MxiMO8yMH0|!=^Z~)OM$U33FNyvxP?^velF{lkE)5;;< zy$brqWRwVHJFSwT`UD*dO{9R#8$ophx^C$R`Hizw>yZW_COU60ecJm_X%iEbX<1kd zR2!pLaKb|g|4El{68{qhCX5qp%YlfD!0WZSA-6Z5GBq6x(zl5*F z>3q?kQL4w0j1?}QrgQrHct0W4_!25$qJCg{H$p0e+>IPh(MW=vP*Dl`wD2a)5b>rH zg$VjaVCHISQ4{xLBsPX23m{LC43mva5fI_!e@Blc4C&XAHp%~Dnu+PyIG8q{-jgYg z!WuBVKQo;^MBxCaK`x<>D*A4Lol6vgn}G;?PByC#!1d8}SOVz+D z4=5=8A@D!TxTcOHpbBFqdeZ)SHqJ;03+j480##{5lK(Q}n#o*5 z4`loqBsRtT1X)%NSA=|g4=0Y@LYRT%@IGuT74OCb;wW4UU*afnV7)?Te~R^m{t5}X z9^`|LFMTW^5G$y2m?u0<^ zQe~sCLy#(%JwlHdZMBI7bZ84xegyr#eg#^h32I7BPcVnLU|&-6loH3rDF$tNK%$`d zRYICLD_(}K@M^ww6dWU2QrLM=EhId+WCJUSb%%TDn<&kw<6>V6P3+=$=>qp%p)1)k zLs`xB2!2BU{T9PqwCKbKL}}ry)^!_)#?)Dr_%N2P3z9`(4@NAcJ{GL0Aw(*tAx55| zK&@bGD*>&Na>=+9ioJR)^P$s-$A~agx^yIL7bL$nSELByPYVd}?>WHei5dGg5Cimy zOhc%UR&OBqz8^<;yA)XvrsTk+>rsM40F9T`ybL_36wK)UB9N$}1a8}50eP<#+0s{Y zQIph!duWOi2%4{o2F_roV7bi3nP4&_uX%xlDGR66%SBr=GIAG==V~FQQNigdsIaNc zJV#(scpze+A|zxcRo__1>7jdV=zm!tK#eXsX6iV33CVaT@&}0|&&UE0yH;_NJhC?? zEo`3(V=)Bc;|N~~G=*}*QBqJY446FzdZ!|=4)g_fgvJGOF=Au>46F^wCvHX4OaWtH z2C@TPL~ARC+chymiZngReV6MD!-X{iVLYTXbpvTgVgZ~a8Y*E*+*zPs=&sOtks%?1 zF6G#M(>LGvC8V1wwp|Kq6Ga(R^O%W*DFa@{tJ_BN+@LY6x+SGaNNM z-DnuI~JLn99bP^$!k;vhlTj3VB3nTWLh$0Ygc5;JAnk4>tl1MH&Ue%EJH`ltO@0NeWDsh-#oRJwVkI zmag=9m`6Ix>Z^2TBtC_d4BeseK*4rk!ANkNn+EVviB=QNa!|&oq0$$bD7UTHLv6_c zazO|nW&>;2H4k&2=yP*J(;ty?Dzv``Jy$Z4joWs365e3*UBUZ^&;Fi=6a%;NNs@{g@cXI@a^*Up)g2y4lk~2$75N`w?Kvag~{V&XaD|h zT0TesX0WhQU0$zL+RY8OV0y(ka5>kFV7yuE+LcCU*gzXOoaM`Yp7nEExs$n@b3dQE z7x&-x0ERp=b?(Zb5o#2Jlav=zZ_lG~FI=^+{4dcleHK559Z=WyNiWQ!B1)+M(%z&FF^5S8Gxe!VJ=S+XN9Tk9h`M&Scz*y@HcZ&Y8B0%~}qvfP*sN zfC?tf8EtvY&4sxdB0$d^N>xv)C;^u5?~)D71w0_npLl25rR2o!;ZrB>?xd8Q+`Z&~ zV;30v)LHt>$xDu$I{xrTLURIr-NQvAgzBZC1{2GCRw6Ov1M4wwo4dgRXq` zx6T|teumuq_~UnzBk=b_Qh4V(C!Zx(UHBSZ{|VeKnJeZRDy}o%%(qoSV%AT__%GVH zDBOn6?QR?1+oJyr?LED)*4>|0@R6=JE4pJg|NXx8C39UaU1hq{6un8en@pbkIe0w! z=JHPK(MQ+UAG~bOH)V%@HfQGwP;!oRMSE5r;_>(4Q@;x@viw^RK`03}K%jk54Xq;<5AR zOXtr&^pW%D$?^N|JiAC%hL0beeIVuox4*mx&&hv2^U(Fb4bQvIoVgyVk;Ok=$#$Ry z>$xjnmcAwTK$Wj{ju;SZy__5c6bXKW6T$QA~Z4A>Js)IrR#}?XNAe2h2KB$#cj*fJ(6z zcMv&W_*z276{_FIbPQf&+G}DL*HcWRqO~y7{7}=JQ=wl$H4M}z(=sZ0vlKYAC_xKj zQOG0GYhSTeMP9Ej78fr3hiv`MkwFpkMafE4+4l2S9w9HdH^iVc7vSLeF+70cu9^HUxt72S{YLu-WbOy;Z;*I%@|UzR`K$FGUG!gDW!>Cn?(MlRq3159 zGQp6FwmStj;L9XmLx}5GA$#N2N)Mx)^GQ!vVyw^x;e<|1)0kJ>JjFO*j6Z8(UMGx< zR*?yC6{a3j$y{(BX@~8S0q)AQc&D&A%qzgwS)v)`MmL&fZGmI|gP&BD#yz&`THjs< z?b2GYmcy0O(Ynp-UJ297)z@WQA@n&!S!87LsR}L+p(iR2RfZzCh=sU9Uji#FaA2@I z49zA?qQvT$_FPhoRwcCLqk?z%dk=peO@c2x{BKc5g3sCa&u8BsCiL4tk?*?N^!8<_ zj-bKwiKh}XnV1b}sMKJ|$n9+9&2|Z6zm(o(E|_-DVGg^I`6_$FxuG8GtgyII0>K)d z3Q;*dyUv_mvW}`We;Xl_t$on8DkYT`0$aje8Wj~6TS?XTb)dr;zSb(M<~DN2a`yv& z{7~*UbHA1Q7-l5EaFJya;ou1zt9)?XSX&Fd zO4bxV!-(-nZ8$1mXN;lm4Km!5a_Y*jP8@9VK< ztrvSGY&4HK^yu8GT?`DPowwGLb%*_T)2GEBoKcVKt~+z)2a|tCsI_i2I?U(5!AL2D zF|DAL${lmvj6#!za3>Zbd@-74hU=ikQ#XK{v~SKH^ohxJpz-=UIQb>Z1`jpuufWB) z8U%(84k_JofaRpa5dLC#cDA73&>QGqDglTmkL-QruICZe-y?8>@nOL1I1BFt3S4 z{YDMLjTt#S98P|FIDB9@e8+J3;BdGXH}hrsrJR$isEpdEK8p4l3ZIm;RivJp7Cn{5 z6ypmkjO@gc0XzGrZye_ceOc$ya>1xn8Hu^(K9k9vDA-%i-6) zB8e-LPxba6wm>kP+P(I&q}eDIo6S88gny*p&%FV(tISs#HB;2cVKT$pNaZk{2Dfx) zZssafuisN)Nm<(FI0J|knFl*+&+#nzLVu((Z%?Ie<{OqN#Jv&u1tZ(>66J(DFmQR@ zHWCWfU+Bj$26=@^q9J^=sIP-P>YA9BQ({~y7>UI(n)X@*Qyxq$qdjK?rsql1k^bU! z2f;=YhHjb0!A9T&n(i^Zh$BHQy@9w5 zCfIFO!7;!x=FYk6m}7v_+^e)(Aa$)kv(Tv4ZQ<(1uCL)boysiCLGyi4&d;-~0{T-m zi!)g!qhO5C>Qm?b1U*GC4`WPY!;#uPpxn+fI*NMIQ0S&dejR^@QCE}S}rBO@EI=Y>n86aw?xYG z1D=WUm>`?#Loz)~jz*J*3%?r7mzW6;R+ z1S}gsB=cnkMg~+c7XUu$0~L6jV_;xlV17Xz%(8(pJ*4QzrIsa|dj7#?Cm}bI69)7Q z?}2s)NG$-gT8xtb000000001T0Tcl)0gwVX111A*1snxd1;_>P26zVi2S5jU2w({K z35*HG3N#AD3$_dx3^oj443G@U4NMJg4XzF}4pa{04}uTA58MzW5SS3o5cUxq5oi&L z5uy>?6Cx8l6Rs386w((Q7tk1_8AKWK8k`%B92gvC9UvWI9mXC89y}gc9&{e|A9x?C zASNJ&AxI&JA>1T-CFUk{CbTBdChjOEDSj7NSH{vNt{W*N=iz)OD0)TS+H7wTC`fyTMk=1 zTY_BrT_9c*UhrQqU*KRAV7_>qV_;-pV3^Cr!f>7e1ek!B3kVq){)71p04&-9kpOs{ zU68#_!!Q(uPujFVD*+M`BeED+kkX&A571659Ws-qcA6@Qqr|P$g^{OVL;45d5uWiV>=Q4%AqcN% zF7Ybd!!>roefpztNPZI@;2!V7L;4Tl5n_A_kMV@>R=a$yvqOM~l|Bqu>LxL0;aug`Bjxjc{ ziG4T$`*8p#;vi1K$v6e4;xwF&GjJx(!r3?n=i)q^j|*@iF2cpQ1efA6T#hSnC9cBN z*upiq7T4i=9KsE_5jWvx+=5$i8*axPxD$8bZXCuvxEJ@~emsB&@em%yBX|^#;c+~H zC-D@X#xr;pNAMh;#|wB7FX3gpf>-exUdJ1F6We$T3>7#82sIkCkeHx@LJtiCiyb(4 z1PqvBhB+2Eins9&-o<-(A0OaDe1wnj2|mSV_#9v0OMHc|@eRJkclaJZ;79y~pYaQR z#c%i>f8bC2g}?C+j^W=Cj%3VQMFn$>Ff*Mn-)C$P(qt8@NM)7eWV6c5$R(9m1>f>5 za~3@1tfO)nwry(<@|Jj4nfcbBcS{oG@vW3k{5<2z@UDn)GC11gM$i^lvS)!db{C$Q zda}hfrw@E?<+GtcXYfm~V}9g;?dJkEBg)*6#E=1|rcVd9=+LeVlw<%^hX zyQ8wk4LYRFplsPP-YKS=v}L^-w^1e1Qa8S6neRxcxId>nwq&{?X=$Fep;v`$v~eUh zq*8+qjzyqZB)Oqf>e^(H3CYt56BNUgjhA7Cx0sObr1sfF>Iq9H-so&HD9N&pxt`^n z36X_DMLTFuxsp4B6k{c)w7Q=zUuqMmGNwzk?Kk4w-a}F9K~DzW`ONT0LS_UDEVV+Y#ELq#VqbhGZmLM;J=d|3^?@Iw_(QSPUt0wsRhWPT>=upXi}*%Dk5qV^$r zstkVR=`_q_GY$)TT$*X@A)87;CYcVD&f-6w%vdO9RN3gVWY)x5>Zp}ZXU2(Su6#1@ VRk~nKCyQPsN2MK&{sY@*vUp%(command: T): T { - for (const id of Array.isArray(command.id) ? command.id : [command.id]) { - this.registerCommand(id, command.execute, command); + if (!this.commands.has(command.id)) { + this.commands.set(command.id, vscode.commands.registerCommand(command.id, command.execute, command)); } return command; } - - private registerCommand(id: string, impl: (...args: any[]) => void, thisArg?: any) { - if (this.commands.has(id)) { - return; - } - - this.commands.set(id, vscode.commands.registerCommand(id, impl, thisArg)); - } -} \ No newline at end of file +} diff --git a/lib/vscode/extensions/typescript-language-features/src/commands/configurePlugin.ts b/extensions/typescript-language-features/src/commands/configurePlugin.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/commands/configurePlugin.ts rename to extensions/typescript-language-features/src/commands/configurePlugin.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/commands/goToProjectConfiguration.ts b/extensions/typescript-language-features/src/commands/goToProjectConfiguration.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/commands/goToProjectConfiguration.ts rename to extensions/typescript-language-features/src/commands/goToProjectConfiguration.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/commands/index.ts b/extensions/typescript-language-features/src/commands/index.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/commands/index.ts rename to extensions/typescript-language-features/src/commands/index.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/commands/learnMoreAboutRefactorings.ts b/extensions/typescript-language-features/src/commands/learnMoreAboutRefactorings.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/commands/learnMoreAboutRefactorings.ts rename to extensions/typescript-language-features/src/commands/learnMoreAboutRefactorings.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/commands/openTsServerLog.ts b/extensions/typescript-language-features/src/commands/openTsServerLog.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/commands/openTsServerLog.ts rename to extensions/typescript-language-features/src/commands/openTsServerLog.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/commands/reloadProject.ts b/extensions/typescript-language-features/src/commands/reloadProject.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/commands/reloadProject.ts rename to extensions/typescript-language-features/src/commands/reloadProject.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/commands/restartTsServer.ts b/extensions/typescript-language-features/src/commands/restartTsServer.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/commands/restartTsServer.ts rename to extensions/typescript-language-features/src/commands/restartTsServer.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/commands/selectTypeScriptVersion.ts b/extensions/typescript-language-features/src/commands/selectTypeScriptVersion.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/commands/selectTypeScriptVersion.ts rename to extensions/typescript-language-features/src/commands/selectTypeScriptVersion.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/extension.browser.ts b/extensions/typescript-language-features/src/extension.browser.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/extension.browser.ts rename to extensions/typescript-language-features/src/extension.browser.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/extension.ts b/extensions/typescript-language-features/src/extension.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/extension.ts rename to extensions/typescript-language-features/src/extension.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/callHierarchy.ts b/extensions/typescript-language-features/src/languageFeatures/callHierarchy.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/callHierarchy.ts rename to extensions/typescript-language-features/src/languageFeatures/callHierarchy.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/codeLens/baseCodeLensProvider.ts b/extensions/typescript-language-features/src/languageFeatures/codeLens/baseCodeLensProvider.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/codeLens/baseCodeLensProvider.ts rename to extensions/typescript-language-features/src/languageFeatures/codeLens/baseCodeLensProvider.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/codeLens/implementationsCodeLens.ts b/extensions/typescript-language-features/src/languageFeatures/codeLens/implementationsCodeLens.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/codeLens/implementationsCodeLens.ts rename to extensions/typescript-language-features/src/languageFeatures/codeLens/implementationsCodeLens.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/codeLens/referencesCodeLens.ts b/extensions/typescript-language-features/src/languageFeatures/codeLens/referencesCodeLens.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/codeLens/referencesCodeLens.ts rename to extensions/typescript-language-features/src/languageFeatures/codeLens/referencesCodeLens.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/completions.ts b/extensions/typescript-language-features/src/languageFeatures/completions.ts similarity index 97% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/completions.ts rename to extensions/typescript-language-features/src/languageFeatures/completions.ts index 37d32399ffc6..b181a122adf8 100644 --- a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/completions.ts +++ b/extensions/typescript-language-features/src/languageFeatures/completions.ts @@ -79,7 +79,6 @@ class MyCompletionItem extends vscode.CompletionItem { this.sortText = tsEntry.sortText; } - // @ts-expect-error until 4.3 protocol update const { sourceDisplay, isSnippet } = tsEntry; if (sourceDisplay) { this.label2 = { name: tsEntry.name, qualifier: Previewer.plainWithLinks(sourceDisplay, client) }; @@ -184,11 +183,9 @@ class MyCompletionItem extends vscode.CompletionItem { const args: Proto.CompletionDetailsRequestArgs = { ...typeConverters.Position.toFileLocationRequestArgs(filepath, this.position), entryNames: [ - // @ts-expect-error until TypeScript 4.3 protocol update this.tsEntry.source || this.tsEntry.data ? { name: this.tsEntry.name, source: this.tsEntry.source, - // @ts-expect-error until TypeScript 4.3 protocol update data: this.tsEntry.data, } : this.tsEntry.name ] @@ -561,7 +558,6 @@ class CompletionAcceptedCommand implements Command { */ this.telemetryReporter.logTelemetry('completions.accept', { isPackageJsonImport: item.tsEntry.isPackageJsonImport ? 'true' : undefined, - // @ts-expect-error until 4.3 protocol update isImportStatementCompletion: item.tsEntry.isImportStatementCompletion ? 'true' : undefined, }); } @@ -753,7 +749,6 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider< dotAccessorContext = { range, text }; } } - // @ts-expect-error until 4.3 protocol update isIncomplete = !!response.body.isIncomplete || (response as any).metadata && (response as any).metadata.isIncomplete; entries = response.body.entries; metadata = response.metadata; @@ -792,7 +787,6 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider< }; items.push(item); includesPackageJsonImport = includesPackageJsonImport || !!entry.isPackageJsonImport; - // @ts-expect-error until 4.3 protocol update includesImportStatementCompletion = includesImportStatementCompletion || !!entry.isImportStatementCompletion; } } @@ -823,11 +817,15 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider< } */ this.telemetryReporter.logTelemetry('completions.execute', { - duration: duration, + duration: String(duration), type: response?.type ?? 'unknown', - count: response?.type === 'response' && response.body ? response.body.entries.length : 0, - updateGraphDurationMs: response?.type === 'response' ? response.performanceData?.updateGraphDurationMs : undefined, - createAutoImportProviderProgramDurationMs: response?.type === 'response' ? response.performanceData?.createAutoImportProviderProgramDurationMs : undefined, + count: String(response?.type === 'response' && response.body ? response.body.entries.length : 0), + updateGraphDurationMs: response?.type === 'response' && typeof response.performanceData?.updateGraphDurationMs === 'number' + ? String(response.performanceData.updateGraphDurationMs) + : undefined, + createAutoImportProviderProgramDurationMs: response?.type === 'response' && typeof response.performanceData?.createAutoImportProviderProgramDurationMs === 'number' + ? String(response.performanceData.createAutoImportProviderProgramDurationMs) + : undefined, includesPackageJsonImport: includesPackageJsonImport ? 'true' : undefined, includesImportStatementCompletion: includesImportStatementCompletion ? 'true' : undefined, }); @@ -842,7 +840,6 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider< return this.client.apiVersion.lt(API.v381) ? undefined : '#'; case ' ': - // @ts-expect-error until 4.3.0 protocol update const space: Proto.CompletionsTriggerCharacter = ' '; return this.client.apiVersion.gte(API.v430) ? space : undefined; diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/definitionProviderBase.ts b/extensions/typescript-language-features/src/languageFeatures/definitionProviderBase.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/definitionProviderBase.ts rename to extensions/typescript-language-features/src/languageFeatures/definitionProviderBase.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/definitions.ts b/extensions/typescript-language-features/src/languageFeatures/definitions.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/definitions.ts rename to extensions/typescript-language-features/src/languageFeatures/definitions.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/diagnostics.ts b/extensions/typescript-language-features/src/languageFeatures/diagnostics.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/diagnostics.ts rename to extensions/typescript-language-features/src/languageFeatures/diagnostics.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/directiveCommentCompletions.ts b/extensions/typescript-language-features/src/languageFeatures/directiveCommentCompletions.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/directiveCommentCompletions.ts rename to extensions/typescript-language-features/src/languageFeatures/directiveCommentCompletions.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/documentHighlight.ts b/extensions/typescript-language-features/src/languageFeatures/documentHighlight.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/documentHighlight.ts rename to extensions/typescript-language-features/src/languageFeatures/documentHighlight.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/documentSymbol.ts b/extensions/typescript-language-features/src/languageFeatures/documentSymbol.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/documentSymbol.ts rename to extensions/typescript-language-features/src/languageFeatures/documentSymbol.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts b/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts similarity index 99% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts rename to extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts index 69cb3526d5a9..2ab729661d5e 100644 --- a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts +++ b/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts @@ -183,7 +183,6 @@ export default class FileConfigurationManager extends Disposable { includeAutomaticOptionalChainCompletions: config.get('suggest.includeAutomaticOptionalChainCompletions', true), provideRefactorNotApplicableReason: true, generateReturnInDocTemplate: config.get('suggest.jsdoc.generateReturns', true), - // @ts-expect-error until 4.3 protocol update includeCompletionsForImportStatements: config.get('suggest.includeCompletionsForImportStatements', true), includeCompletionsWithSnippetText: config.get('suggest.includeCompletionsWithSnippetText', true), displayPartsForJSDoc: true, diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/fileReferences.ts b/extensions/typescript-language-features/src/languageFeatures/fileReferences.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/fileReferences.ts rename to extensions/typescript-language-features/src/languageFeatures/fileReferences.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/fixAll.ts b/extensions/typescript-language-features/src/languageFeatures/fixAll.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/fixAll.ts rename to extensions/typescript-language-features/src/languageFeatures/fixAll.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/folding.ts b/extensions/typescript-language-features/src/languageFeatures/folding.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/folding.ts rename to extensions/typescript-language-features/src/languageFeatures/folding.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/formatting.ts b/extensions/typescript-language-features/src/languageFeatures/formatting.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/formatting.ts rename to extensions/typescript-language-features/src/languageFeatures/formatting.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/hover.ts b/extensions/typescript-language-features/src/languageFeatures/hover.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/hover.ts rename to extensions/typescript-language-features/src/languageFeatures/hover.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/implementations.ts b/extensions/typescript-language-features/src/languageFeatures/implementations.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/implementations.ts rename to extensions/typescript-language-features/src/languageFeatures/implementations.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/jsDocCompletions.ts b/extensions/typescript-language-features/src/languageFeatures/jsDocCompletions.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/jsDocCompletions.ts rename to extensions/typescript-language-features/src/languageFeatures/jsDocCompletions.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/languageConfiguration.ts b/extensions/typescript-language-features/src/languageFeatures/languageConfiguration.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/languageConfiguration.ts rename to extensions/typescript-language-features/src/languageFeatures/languageConfiguration.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/organizeImports.ts b/extensions/typescript-language-features/src/languageFeatures/organizeImports.ts similarity index 63% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/organizeImports.ts rename to extensions/typescript-language-features/src/languageFeatures/organizeImports.ts index 3b8111b7c1f3..10a399bad5b8 100644 --- a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/organizeImports.ts +++ b/extensions/typescript-language-features/src/languageFeatures/organizeImports.ts @@ -29,7 +29,7 @@ class OrganizeImportsCommand implements Command { private readonly telemetryReporter: TelemetryReporter, ) { } - public async execute(file: string): Promise { + public async execute(file: string, sortOnly = false): Promise { /* __GDPR__ "organizeImports.execute" : { "${include}": [ @@ -45,7 +45,8 @@ class OrganizeImportsCommand implements Command { args: { file } - } + }, + skipDestructiveCodeActions: sortOnly, }; const response = await this.client.interruptGetErr(() => this.client.execute('organizeImports', args, nulToken)); if (response.type !== 'response' || !response.body) { @@ -57,23 +58,42 @@ class OrganizeImportsCommand implements Command { } } -export class OrganizeImportsCodeActionProvider implements vscode.CodeActionProvider { - public static readonly minVersion = API.v280; +class ImportsCodeActionProvider implements vscode.CodeActionProvider { + + static register( + client: ITypeScriptServiceClient, + minVersion: API, + kind: vscode.CodeActionKind, + title: string, + sortOnly: boolean, + commandManager: CommandManager, + fileConfigurationManager: FileConfigurationManager, + telemetryReporter: TelemetryReporter, + selector: DocumentSelector + ): vscode.Disposable { + return conditionalRegistration([ + requireMinVersion(client, minVersion), + requireSomeCapability(client, ClientCapability.Semantic), + ], () => { + const provider = new ImportsCodeActionProvider(client, kind, title, sortOnly, commandManager, fileConfigurationManager, telemetryReporter); + return vscode.languages.registerCodeActionsProvider(selector.semantic, provider, { + providedCodeActionKinds: [kind] + }); + }); + } public constructor( private readonly client: ITypeScriptServiceClient, + private readonly kind: vscode.CodeActionKind, + private readonly title: string, + private readonly sortOnly: boolean, commandManager: CommandManager, private readonly fileConfigManager: FileConfigurationManager, telemetryReporter: TelemetryReporter, - ) { commandManager.register(new OrganizeImportsCommand(client, telemetryReporter)); } - public readonly metadata: vscode.CodeActionProviderMetadata = { - providedCodeActionKinds: [vscode.CodeActionKind.SourceOrganizeImports] - }; - public provideCodeActions( document: vscode.TextDocument, _range: vscode.Range, @@ -85,16 +105,14 @@ export class OrganizeImportsCodeActionProvider implements vscode.CodeActionProvi return []; } - if (!context.only || !context.only.contains(vscode.CodeActionKind.SourceOrganizeImports)) { + if (!context.only || !context.only.contains(this.kind)) { return []; } this.fileConfigManager.ensureConfigurationForDocument(document, token); - const action = new vscode.CodeAction( - localize('organizeImportsAction.title', "Organize Imports"), - vscode.CodeActionKind.SourceOrganizeImports); - action.command = { title: '', command: OrganizeImportsCommand.Id, arguments: [file] }; + const action = new vscode.CodeAction(this.title, this.kind); + action.command = { title: '', command: OrganizeImportsCommand.Id, arguments: [file, this.sortOnly] }; return [action]; } } @@ -106,13 +124,28 @@ export function register( fileConfigurationManager: FileConfigurationManager, telemetryReporter: TelemetryReporter, ) { - return conditionalRegistration([ - requireMinVersion(client, OrganizeImportsCodeActionProvider.minVersion), - requireSomeCapability(client, ClientCapability.Semantic), - ], () => { - const organizeImportsProvider = new OrganizeImportsCodeActionProvider(client, commandManager, fileConfigurationManager, telemetryReporter); - return vscode.languages.registerCodeActionsProvider(selector.semantic, - organizeImportsProvider, - organizeImportsProvider.metadata); - }); + return vscode.Disposable.from( + ImportsCodeActionProvider.register( + client, + API.v280, + vscode.CodeActionKind.SourceOrganizeImports, + localize('organizeImportsAction.title', "Organize Imports"), + false, + commandManager, + fileConfigurationManager, + telemetryReporter, + selector + ), + ImportsCodeActionProvider.register( + client, + API.v430, + vscode.CodeActionKind.Source.append('sortImports'), + localize('sortImportsAction.title', "Sort Imports"), + true, + commandManager, + fileConfigurationManager, + telemetryReporter, + selector + ), + ); } diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/quickFix.ts b/extensions/typescript-language-features/src/languageFeatures/quickFix.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/quickFix.ts rename to extensions/typescript-language-features/src/languageFeatures/quickFix.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/refactor.ts b/extensions/typescript-language-features/src/languageFeatures/refactor.ts similarity index 98% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/refactor.ts rename to extensions/typescript-language-features/src/languageFeatures/refactor.ts index 4284366e2731..d1b861a97fa3 100644 --- a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/refactor.ts +++ b/extensions/typescript-language-features/src/languageFeatures/refactor.ts @@ -310,10 +310,12 @@ class TypeScriptRefactorProvider implements vscode.CodeActionProvider { - // Don't show 'infer return type' refactoring unless it has been explicitly requested - // https://github.com/microsoft/TypeScript/issues/42993 - if (!context.only && action.kind?.value === 'refactor.rewrite.function.returnType') { - return false; + if (this.client.apiVersion.lt(API.v430)) { + // Don't show 'infer return type' refactoring unless it has been explicitly requested + // https://github.com/microsoft/TypeScript/issues/42993 + if (!context.only && action.kind?.value === 'refactor.rewrite.function.returnType') { + return false; + } } return true; }); diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/references.ts b/extensions/typescript-language-features/src/languageFeatures/references.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/references.ts rename to extensions/typescript-language-features/src/languageFeatures/references.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/rename.ts b/extensions/typescript-language-features/src/languageFeatures/rename.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/rename.ts rename to extensions/typescript-language-features/src/languageFeatures/rename.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/semanticTokens.ts b/extensions/typescript-language-features/src/languageFeatures/semanticTokens.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/semanticTokens.ts rename to extensions/typescript-language-features/src/languageFeatures/semanticTokens.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/signatureHelp.ts b/extensions/typescript-language-features/src/languageFeatures/signatureHelp.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/signatureHelp.ts rename to extensions/typescript-language-features/src/languageFeatures/signatureHelp.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/smartSelect.ts b/extensions/typescript-language-features/src/languageFeatures/smartSelect.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/smartSelect.ts rename to extensions/typescript-language-features/src/languageFeatures/smartSelect.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/tagClosing.ts b/extensions/typescript-language-features/src/languageFeatures/tagClosing.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/tagClosing.ts rename to extensions/typescript-language-features/src/languageFeatures/tagClosing.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/tsconfig.ts b/extensions/typescript-language-features/src/languageFeatures/tsconfig.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/tsconfig.ts rename to extensions/typescript-language-features/src/languageFeatures/tsconfig.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/typeDefinitions.ts b/extensions/typescript-language-features/src/languageFeatures/typeDefinitions.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/typeDefinitions.ts rename to extensions/typescript-language-features/src/languageFeatures/typeDefinitions.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/updatePathsOnRename.ts b/extensions/typescript-language-features/src/languageFeatures/updatePathsOnRename.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/updatePathsOnRename.ts rename to extensions/typescript-language-features/src/languageFeatures/updatePathsOnRename.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageFeatures/workspaceSymbols.ts b/extensions/typescript-language-features/src/languageFeatures/workspaceSymbols.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageFeatures/workspaceSymbols.ts rename to extensions/typescript-language-features/src/languageFeatures/workspaceSymbols.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/languageProvider.ts b/extensions/typescript-language-features/src/languageProvider.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/languageProvider.ts rename to extensions/typescript-language-features/src/languageProvider.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/lazyClientHost.ts b/extensions/typescript-language-features/src/lazyClientHost.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/lazyClientHost.ts rename to extensions/typescript-language-features/src/lazyClientHost.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/protocol.const.ts b/extensions/typescript-language-features/src/protocol.const.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/protocol.const.ts rename to extensions/typescript-language-features/src/protocol.const.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/protocol.d.ts b/extensions/typescript-language-features/src/protocol.d.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/protocol.d.ts rename to extensions/typescript-language-features/src/protocol.d.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/task/taskProvider.ts b/extensions/typescript-language-features/src/task/taskProvider.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/task/taskProvider.ts rename to extensions/typescript-language-features/src/task/taskProvider.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/task/tsconfigProvider.ts b/extensions/typescript-language-features/src/task/tsconfigProvider.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/task/tsconfigProvider.ts rename to extensions/typescript-language-features/src/task/tsconfigProvider.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/test-all.ts b/extensions/typescript-language-features/src/test-all.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/test-all.ts rename to extensions/typescript-language-features/src/test-all.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/test/index.ts b/extensions/typescript-language-features/src/test/index.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/test/index.ts rename to extensions/typescript-language-features/src/test/index.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/test/smoke/completions.test.ts b/extensions/typescript-language-features/src/test/smoke/completions.test.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/test/smoke/completions.test.ts rename to extensions/typescript-language-features/src/test/smoke/completions.test.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/test/smoke/fixAll.test.ts b/extensions/typescript-language-features/src/test/smoke/fixAll.test.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/test/smoke/fixAll.test.ts rename to extensions/typescript-language-features/src/test/smoke/fixAll.test.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/test/smoke/index.ts b/extensions/typescript-language-features/src/test/smoke/index.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/test/smoke/index.ts rename to extensions/typescript-language-features/src/test/smoke/index.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/test/smoke/jsDocCompletions.test.ts b/extensions/typescript-language-features/src/test/smoke/jsDocCompletions.test.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/test/smoke/jsDocCompletions.test.ts rename to extensions/typescript-language-features/src/test/smoke/jsDocCompletions.test.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/test/smoke/quickFix.test.ts b/extensions/typescript-language-features/src/test/smoke/quickFix.test.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/test/smoke/quickFix.test.ts rename to extensions/typescript-language-features/src/test/smoke/quickFix.test.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/test/smoke/referencesCodeLens.test.ts b/extensions/typescript-language-features/src/test/smoke/referencesCodeLens.test.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/test/smoke/referencesCodeLens.test.ts rename to extensions/typescript-language-features/src/test/smoke/referencesCodeLens.test.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/test/suggestTestHelpers.ts b/extensions/typescript-language-features/src/test/suggestTestHelpers.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/test/suggestTestHelpers.ts rename to extensions/typescript-language-features/src/test/suggestTestHelpers.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/test/testUtils.ts b/extensions/typescript-language-features/src/test/testUtils.ts similarity index 99% rename from lib/vscode/extensions/typescript-language-features/src/test/testUtils.ts rename to extensions/typescript-language-features/src/test/testUtils.ts index c0ba9a477305..28f3dfc7d928 100644 --- a/lib/vscode/extensions/typescript-language-features/src/test/testUtils.ts +++ b/extensions/typescript-language-features/src/test/testUtils.ts @@ -89,7 +89,7 @@ export function assertEditorContents(editor: vscode.TextEditor, expectedDocConte if (cursorIndex >= 0) { const expectedCursorPos = editor.document.positionAt(cursorIndex); - assert.deepEqual( + assert.deepStrictEqual( { line: editor.selection.active.line, character: editor.selection.active.line }, { line: expectedCursorPos.line, character: expectedCursorPos.line }, 'Cursor position' diff --git a/lib/vscode/extensions/typescript-language-features/src/test/unit/cachedResponse.test.ts b/extensions/typescript-language-features/src/test/unit/cachedResponse.test.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/test/unit/cachedResponse.test.ts rename to extensions/typescript-language-features/src/test/unit/cachedResponse.test.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/test/unit/functionCallSnippet.test.ts b/extensions/typescript-language-features/src/test/unit/functionCallSnippet.test.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/test/unit/functionCallSnippet.test.ts rename to extensions/typescript-language-features/src/test/unit/functionCallSnippet.test.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/test/unit/index.ts b/extensions/typescript-language-features/src/test/unit/index.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/test/unit/index.ts rename to extensions/typescript-language-features/src/test/unit/index.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/test/unit/jsdocSnippet.test.ts b/extensions/typescript-language-features/src/test/unit/jsdocSnippet.test.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/test/unit/jsdocSnippet.test.ts rename to extensions/typescript-language-features/src/test/unit/jsdocSnippet.test.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/test/unit/onEnter.test.ts b/extensions/typescript-language-features/src/test/unit/onEnter.test.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/test/unit/onEnter.test.ts rename to extensions/typescript-language-features/src/test/unit/onEnter.test.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/test/unit/previewer.test.ts b/extensions/typescript-language-features/src/test/unit/previewer.test.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/test/unit/previewer.test.ts rename to extensions/typescript-language-features/src/test/unit/previewer.test.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/test/unit/requestQueue.test.ts b/extensions/typescript-language-features/src/test/unit/requestQueue.test.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/test/unit/requestQueue.test.ts rename to extensions/typescript-language-features/src/test/unit/requestQueue.test.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/test/unit/server.test.ts b/extensions/typescript-language-features/src/test/unit/server.test.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/test/unit/server.test.ts rename to extensions/typescript-language-features/src/test/unit/server.test.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/tsServer/bufferSyncSupport.ts b/extensions/typescript-language-features/src/tsServer/bufferSyncSupport.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/tsServer/bufferSyncSupport.ts rename to extensions/typescript-language-features/src/tsServer/bufferSyncSupport.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/tsServer/cachedResponse.ts b/extensions/typescript-language-features/src/tsServer/cachedResponse.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/tsServer/cachedResponse.ts rename to extensions/typescript-language-features/src/tsServer/cachedResponse.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/tsServer/callbackMap.ts b/extensions/typescript-language-features/src/tsServer/callbackMap.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/tsServer/callbackMap.ts rename to extensions/typescript-language-features/src/tsServer/callbackMap.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/tsServer/cancellation.electron.ts b/extensions/typescript-language-features/src/tsServer/cancellation.electron.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/tsServer/cancellation.electron.ts rename to extensions/typescript-language-features/src/tsServer/cancellation.electron.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/tsServer/cancellation.ts b/extensions/typescript-language-features/src/tsServer/cancellation.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/tsServer/cancellation.ts rename to extensions/typescript-language-features/src/tsServer/cancellation.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/tsServer/logDirectoryProvider.electron.ts b/extensions/typescript-language-features/src/tsServer/logDirectoryProvider.electron.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/tsServer/logDirectoryProvider.electron.ts rename to extensions/typescript-language-features/src/tsServer/logDirectoryProvider.electron.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/tsServer/logDirectoryProvider.ts b/extensions/typescript-language-features/src/tsServer/logDirectoryProvider.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/tsServer/logDirectoryProvider.ts rename to extensions/typescript-language-features/src/tsServer/logDirectoryProvider.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/tsServer/requestQueue.ts b/extensions/typescript-language-features/src/tsServer/requestQueue.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/tsServer/requestQueue.ts rename to extensions/typescript-language-features/src/tsServer/requestQueue.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/tsServer/server.ts b/extensions/typescript-language-features/src/tsServer/server.ts similarity index 86% rename from lib/vscode/extensions/typescript-language-features/src/tsServer/server.ts rename to extensions/typescript-language-features/src/tsServer/server.ts index 5ede4ef49fc6..b97a1a8b73de 100644 --- a/lib/vscode/extensions/typescript-language-features/src/tsServer/server.ts +++ b/extensions/typescript-language-features/src/tsServer/server.ts @@ -32,9 +32,11 @@ export interface ITypeScriptServer { kill(): void; - executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean, executionTarget?: ExecutionTarget }): undefined; - executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExecutionTarget }): Promise>; - executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExecutionTarget }): Promise> | undefined; + /** + * @return A list of all execute requests. If there are multiple entries, the first item is the primary + * request while the rest are secondary ones. + */ + executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExecutionTarget }): Array> | undefined>; dispose(): void; } @@ -202,9 +204,7 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe } } - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean, executionTarget?: ExecutionTarget }): undefined; - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExecutionTarget }): Promise>; - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExecutionTarget }): Promise> | undefined { + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExecutionTarget }): Array> | undefined> { const request = this._requestQueue.createRequest(command, args); const requestInfo: RequestItem = { request, @@ -244,7 +244,7 @@ export class ProcessBasedTsServer extends Disposable implements ITypeScriptServe this._requestQueue.enqueue(requestInfo); this.sendNextRequests(); - return result; + return [result]; } private sendNextRequests(): void { @@ -328,9 +328,13 @@ class RequestRouter { private readonly delegate: TsServerDelegate, ) { } - public execute(command: keyof TypeScriptRequests, args: any, executeInfo: ExecuteInfo): Promise> | undefined { + public execute( + command: keyof TypeScriptRequests, + args: any, + executeInfo: ExecuteInfo, + ): Array> | undefined> { if (RequestRouter.sharedCommands.has(command) && typeof executeInfo.executionTarget === 'undefined') { - // Dispatch shared commands to all servers but only return from first one + // Dispatch shared commands to all servers but use first one as the primary response const requestStates: RequestState.State[] = this.servers.map(() => RequestState.Unresolved); @@ -350,15 +354,13 @@ class RequestRouter { token = source.token; } - let firstRequest: Promise> | undefined; + const allRequests: Array> | undefined> = []; for (let serverIndex = 0; serverIndex < this.servers.length; ++serverIndex) { const server = this.servers[serverIndex].server; - const request = server.executeImpl(command, args, { ...executeInfo, token }) as Promise> | undefined; - if (serverIndex === 0) { - firstRequest = request; - } + const request = server.executeImpl(command, args, { ...executeInfo, token })[0]; + allRequests.push(request); if (request) { request .then(result => { @@ -380,7 +382,7 @@ class RequestRouter { } } - return firstRequest; + return allRequests; } for (const { canRun, server } of this.servers) { @@ -460,9 +462,7 @@ export class GetErrRoutingTsServer extends Disposable implements ITypeScriptServ this.mainServer.kill(); } - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean, executionTarget?: ExecutionTarget }): undefined; - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExecutionTarget }): Promise>; - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExecutionTarget }): Promise> | undefined { + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExecutionTarget }): Array> | undefined> { return this.router.execute(command, args, executeInfo); } } @@ -602,9 +602,7 @@ export class SyntaxRoutingTsServer extends Disposable implements ITypeScriptServ this.semanticServer.kill(); } - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean, executionTarget?: ExecutionTarget }): undefined; - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExecutionTarget }): Promise>; - public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExecutionTarget }): Promise> | undefined { + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, executionTarget?: ExecutionTarget }): Array> | undefined> { return this.router.execute(command, args, executeInfo); } } diff --git a/lib/vscode/extensions/typescript-language-features/src/tsServer/serverError.ts b/extensions/typescript-language-features/src/tsServer/serverError.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/tsServer/serverError.ts rename to extensions/typescript-language-features/src/tsServer/serverError.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/tsServer/serverProcess.browser.ts b/extensions/typescript-language-features/src/tsServer/serverProcess.browser.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/tsServer/serverProcess.browser.ts rename to extensions/typescript-language-features/src/tsServer/serverProcess.browser.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/tsServer/serverProcess.electron.ts b/extensions/typescript-language-features/src/tsServer/serverProcess.electron.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/tsServer/serverProcess.electron.ts rename to extensions/typescript-language-features/src/tsServer/serverProcess.electron.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/tsServer/spawner.ts b/extensions/typescript-language-features/src/tsServer/spawner.ts similarity index 98% rename from lib/vscode/extensions/typescript-language-features/src/tsServer/spawner.ts rename to extensions/typescript-language-features/src/tsServer/spawner.ts index 58fd431edc72..f499c67465ff 100644 --- a/lib/vscode/extensions/typescript-language-features/src/tsServer/spawner.ts +++ b/extensions/typescript-language-features/src/tsServer/spawner.ts @@ -99,6 +99,9 @@ export class TypeScriptServerSpawner { } switch (configuration.separateSyntaxServer) { + case SeparateSyntaxServerConfiguration.ForAllRequests: + return CompositeServerType.SyntaxOnly; + case SeparateSyntaxServerConfiguration.Disabled: return CompositeServerType.Single; diff --git a/lib/vscode/extensions/typescript-language-features/src/tsServer/versionManager.ts b/extensions/typescript-language-features/src/tsServer/versionManager.ts similarity index 99% rename from lib/vscode/extensions/typescript-language-features/src/tsServer/versionManager.ts rename to extensions/typescript-language-features/src/tsServer/versionManager.ts index 54d88c1192ec..bb06e4505e27 100644 --- a/lib/vscode/extensions/typescript-language-features/src/tsServer/versionManager.ts +++ b/extensions/typescript-language-features/src/tsServer/versionManager.ts @@ -115,7 +115,7 @@ export class TypeScriptVersionManager extends Disposable { description: version.displayName, detail: version.pathLabel, run: async () => { - const trusted = await vscode.workspace.requestWorkspaceTrust({ modal: true }); + const trusted = await vscode.workspace.requestWorkspaceTrust(); if (trusted) { await this.workspaceState.update(useWorkspaceTsdkStorageKey, true); const tsConfig = vscode.workspace.getConfiguration('typescript'); diff --git a/lib/vscode/extensions/typescript-language-features/src/tsServer/versionProvider.electron.ts b/extensions/typescript-language-features/src/tsServer/versionProvider.electron.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/tsServer/versionProvider.electron.ts rename to extensions/typescript-language-features/src/tsServer/versionProvider.electron.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/tsServer/versionProvider.ts b/extensions/typescript-language-features/src/tsServer/versionProvider.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/tsServer/versionProvider.ts rename to extensions/typescript-language-features/src/tsServer/versionProvider.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/tsServer/versionStatus.ts b/extensions/typescript-language-features/src/tsServer/versionStatus.ts similarity index 96% rename from lib/vscode/extensions/typescript-language-features/src/tsServer/versionStatus.ts rename to extensions/typescript-language-features/src/tsServer/versionStatus.ts index a868c3e2502b..2560f3e8be94 100644 --- a/lib/vscode/extensions/typescript-language-features/src/tsServer/versionStatus.ts +++ b/extensions/typescript-language-features/src/tsServer/versionStatus.ts @@ -135,12 +135,8 @@ export default class VersionStatus extends Disposable { ) { super(); - this._statusBarEntry = this._register(vscode.window.createStatusBarItem({ - id: 'status.typescript', - name: localize('projectInfo.name', "TypeScript: Project Info"), - alignment: vscode.StatusBarAlignment.Right, - priority: 99 /* to the right of editor status (100) */ - })); + this._statusBarEntry = this._register(vscode.window.createStatusBarItem('status.typescript', vscode.StatusBarAlignment.Right, 99 /* to the right of editor status (100) */)); + this._statusBarEntry.name = localize('projectInfo.name', "TypeScript: Project Info"); const command = new ProjectStatusCommand(this._client, () => this._state); commandManager.register(command); diff --git a/lib/vscode/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts similarity index 99% rename from lib/vscode/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts rename to extensions/typescript-language-features/src/typeScriptServiceClientHost.ts index db53b5cf4d34..4f417c27fbfe 100644 --- a/lib/vscode/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts +++ b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts @@ -30,6 +30,7 @@ import * as typeConverters from './utils/typeConverters'; import TypingsStatus, { AtaProgressReporter } from './utils/typingsStatus'; import * as ProjectStatus from './utils/largeProjectStatus'; import { ActiveJsTsEditorTracker } from './utils/activeJsTsEditorTracker'; +import { LogLevelMonitor } from './utils/logLevelMonitor'; // Style check diagnostics that can be reported as warnings const styleCheckDiagnostics = new Set([ @@ -147,6 +148,7 @@ export default class TypeScriptServiceClientHost extends Disposable { vscode.workspace.onDidChangeConfiguration(this.configurationChanged, this, this._disposables); this.configurationChanged(); + this._register(new LogLevelMonitor(context)); } private registerExtensionLanguageProvider(description: LanguageDescription, onCompletionAccepted: (item: vscode.CompletionItem) => void) { diff --git a/lib/vscode/extensions/typescript-language-features/src/typescriptService.ts b/extensions/typescript-language-features/src/typescriptService.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/typescriptService.ts rename to extensions/typescript-language-features/src/typescriptService.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts similarity index 96% rename from lib/vscode/extensions/typescript-language-features/src/typescriptServiceClient.ts rename to extensions/typescript-language-features/src/typescriptServiceClient.ts index 2bdf9d855b7a..4990b4ce1c73 100644 --- a/lib/vscode/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -19,7 +19,7 @@ import { TypeScriptVersionManager } from './tsServer/versionManager'; import { ITypeScriptVersionProvider, TypeScriptVersion } from './tsServer/versionProvider'; import { ClientCapabilities, ClientCapability, ExecConfig, ITypeScriptServiceClient, ServerResponse, TypeScriptRequests } from './typescriptService'; import API from './utils/api'; -import { TsServerLogLevel, TypeScriptServiceConfiguration } from './utils/configuration'; +import { SeparateSyntaxServerConfiguration, TsServerLogLevel, TypeScriptServiceConfiguration } from './utils/configuration'; import { Disposable } from './utils/dispose'; import * as fileSchemes from './utils/fileSchemes'; import { Logger } from './utils/logger'; @@ -224,6 +224,12 @@ export default class TypeScriptServiceClient extends Disposable implements IType } public get capabilities() { + if (this._configuration.separateSyntaxServer === SeparateSyntaxServerConfiguration.ForAllRequests) { + return new ClientCapabilities( + ClientCapability.Syntax, + ClientCapability.EnhancedSyntax); + } + if (isWeb()) { return new ClientCapabilities( ClientCapability.Syntax, @@ -676,6 +682,10 @@ export default class TypeScriptServiceClient extends Disposable implements IType } public hasCapabilityForResource(resource: vscode.Uri, capability: ClientCapability): boolean { + if (!this.capabilities.has(capability)) { + return false; + } + switch (capability) { case ClientCapability.Semantic: { @@ -727,7 +737,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType } public execute(command: keyof TypeScriptRequests, args: any, token: vscode.CancellationToken, config?: ExecConfig): Promise> { - let execution: Promise>; + let executions: Array> | undefined>; if (config?.cancelOnResourceChange) { const runningServerState = this.service(); @@ -741,17 +751,18 @@ export default class TypeScriptServiceClient extends Disposable implements IType }; runningServerState.toCancelOnResourceChange.add(inFlight); - execution = this.executeImpl(command, args, { + executions = this.executeImpl(command, args, { isAsync: false, token: source.token, expectsResult: true, ...config, - }).finally(() => { + }); + executions[0]!.finally(() => { runningServerState.toCancelOnResourceChange.delete(inFlight); source.dispose(); }); } else { - execution = this.executeImpl(command, args, { + executions = this.executeImpl(command, args, { isAsync: false, token, expectsResult: true, @@ -760,25 +771,25 @@ export default class TypeScriptServiceClient extends Disposable implements IType } if (config?.nonRecoverable) { - execution.catch(err => this.fatalError(command, err)); + executions[0]!.catch(err => this.fatalError(command, err)); } - return execution; + if (command === 'updateOpen') { + // If update open has completed, consider that the project has loaded + Promise.all(executions).then(() => { + this.loadingIndicator.reset(); + }); + } + + return executions[0]!; } public executeWithoutWaitingForResponse(command: keyof TypeScriptRequests, args: any): void { - const promise = this.executeImpl(command, args, { + this.executeImpl(command, args, { isAsync: false, token: undefined, - expectsResult: command === 'updateOpen' + expectsResult: false }); - - if (command === 'updateOpen') { - // If update open has completed, consider that the project has loaded - promise.then(() => { - this.loadingIndicator.reset(); - }); - } } public executeAsync(command: keyof TypeScriptRequests, args: Proto.GeterrRequestArgs, token: vscode.CancellationToken): Promise> { @@ -786,12 +797,10 @@ export default class TypeScriptServiceClient extends Disposable implements IType isAsync: true, token, expectsResult: true - }); + })[0]!; } - private executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean, requireSemantic?: boolean }): undefined; - private executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, requireSemantic?: boolean }): Promise>; - private executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, requireSemantic?: boolean }): Promise> | undefined { + private executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean, requireSemantic?: boolean }): Array> | undefined> { this.bufferSyncSupport.beforeCommand(command); const runningServerState = this.service(); return runningServerState.server.executeImpl(command, args, executeInfo); @@ -812,7 +821,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType } */ this.logTelemetry('fatalError', { ...(error instanceof TypeScriptServerError ? error.telemetry : { command }) }); - console.error(`A non-recoverable error occured while executing tsserver command: ${command}`); + console.error(`A non-recoverable error occurred while executing tsserver command: ${command}`); if (error instanceof TypeScriptServerError && error.serverErrorText) { console.error(error.serverErrorText); } @@ -1056,4 +1065,3 @@ class ServerInitializingIndicator extends Disposable { } } } - diff --git a/lib/vscode/extensions/typescript-language-features/src/typings/ref.d.ts b/extensions/typescript-language-features/src/typings/ref.d.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/typings/ref.d.ts rename to extensions/typescript-language-features/src/typings/ref.d.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/activeJsTsEditorTracker.ts b/extensions/typescript-language-features/src/utils/activeJsTsEditorTracker.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/activeJsTsEditorTracker.ts rename to extensions/typescript-language-features/src/utils/activeJsTsEditorTracker.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/api.ts b/extensions/typescript-language-features/src/utils/api.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/api.ts rename to extensions/typescript-language-features/src/utils/api.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/arrays.ts b/extensions/typescript-language-features/src/utils/arrays.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/arrays.ts rename to extensions/typescript-language-features/src/utils/arrays.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/async.ts b/extensions/typescript-language-features/src/utils/async.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/async.ts rename to extensions/typescript-language-features/src/utils/async.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/cancellation.ts b/extensions/typescript-language-features/src/utils/cancellation.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/cancellation.ts rename to extensions/typescript-language-features/src/utils/cancellation.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/codeAction.ts b/extensions/typescript-language-features/src/utils/codeAction.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/codeAction.ts rename to extensions/typescript-language-features/src/utils/codeAction.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/configuration.ts b/extensions/typescript-language-features/src/utils/configuration.ts similarity index 96% rename from lib/vscode/extensions/typescript-language-features/src/utils/configuration.ts rename to extensions/typescript-language-features/src/utils/configuration.ts index c43a121079cb..92d5122bbcd6 100644 --- a/lib/vscode/extensions/typescript-language-features/src/utils/configuration.ts +++ b/extensions/typescript-language-features/src/utils/configuration.ts @@ -48,6 +48,8 @@ export namespace TsServerLogLevel { export const enum SeparateSyntaxServerConfiguration { Disabled, Enabled, + /** Use a single syntax server for every request, even on desktop */ + ForAllRequests, } export class ImplicitProjectConfiguration { @@ -180,7 +182,10 @@ export class TypeScriptServiceConfiguration { } private static readUseSeparateSyntaxServer(configuration: vscode.WorkspaceConfiguration): SeparateSyntaxServerConfiguration { - const value = configuration.get('typescript.tsserver.useSeparateSyntaxServer', true); + const value = configuration.get('typescript.tsserver.useSeparateSyntaxServer', true); + if (value === 'forAllRequests') { + return SeparateSyntaxServerConfiguration.ForAllRequests; + } if (value === true) { return SeparateSyntaxServerConfiguration.Enabled; } diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/dependentRegistration.ts b/extensions/typescript-language-features/src/utils/dependentRegistration.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/dependentRegistration.ts rename to extensions/typescript-language-features/src/utils/dependentRegistration.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/dispose.ts b/extensions/typescript-language-features/src/utils/dispose.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/dispose.ts rename to extensions/typescript-language-features/src/utils/dispose.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/documentSelector.ts b/extensions/typescript-language-features/src/utils/documentSelector.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/documentSelector.ts rename to extensions/typescript-language-features/src/utils/documentSelector.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/errorCodes.ts b/extensions/typescript-language-features/src/utils/errorCodes.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/errorCodes.ts rename to extensions/typescript-language-features/src/utils/errorCodes.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/fileSchemes.ts b/extensions/typescript-language-features/src/utils/fileSchemes.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/fileSchemes.ts rename to extensions/typescript-language-features/src/utils/fileSchemes.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/fileSystem.electron.ts b/extensions/typescript-language-features/src/utils/fileSystem.electron.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/fileSystem.electron.ts rename to extensions/typescript-language-features/src/utils/fileSystem.electron.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/fixNames.ts b/extensions/typescript-language-features/src/utils/fixNames.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/fixNames.ts rename to extensions/typescript-language-features/src/utils/fixNames.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/fs.ts b/extensions/typescript-language-features/src/utils/fs.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/fs.ts rename to extensions/typescript-language-features/src/utils/fs.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/languageDescription.ts b/extensions/typescript-language-features/src/utils/languageDescription.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/languageDescription.ts rename to extensions/typescript-language-features/src/utils/languageDescription.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/languageModeIds.ts b/extensions/typescript-language-features/src/utils/languageModeIds.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/languageModeIds.ts rename to extensions/typescript-language-features/src/utils/languageModeIds.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/largeProjectStatus.ts b/extensions/typescript-language-features/src/utils/largeProjectStatus.ts similarity index 93% rename from lib/vscode/extensions/typescript-language-features/src/utils/largeProjectStatus.ts rename to extensions/typescript-language-features/src/utils/largeProjectStatus.ts index 223d7cb47167..346f95c69796 100644 --- a/lib/vscode/extensions/typescript-language-features/src/utils/largeProjectStatus.ts +++ b/extensions/typescript-language-features/src/utils/largeProjectStatus.ts @@ -23,12 +23,8 @@ class ExcludeHintItem { constructor( private readonly telemetryReporter: TelemetryReporter ) { - this._item = vscode.window.createStatusBarItem({ - id: 'status.typescript.exclude', - name: localize('statusExclude', "TypeScript: Configure Excludes"), - alignment: vscode.StatusBarAlignment.Right, - priority: 98 /* to the right of typescript version status (99) */ - }); + this._item = vscode.window.createStatusBarItem('status.typescript.exclude', vscode.StatusBarAlignment.Right, 98 /* to the right of typescript version status (99) */); + this._item.name = localize('statusExclude', "TypeScript: Configure Excludes"); this._item.command = 'js.projectStatus.command'; } diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/lazy.ts b/extensions/typescript-language-features/src/utils/lazy.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/lazy.ts rename to extensions/typescript-language-features/src/utils/lazy.ts diff --git a/extensions/typescript-language-features/src/utils/logLevelMonitor.ts b/extensions/typescript-language-features/src/utils/logLevelMonitor.ts new file mode 100644 index 000000000000..7a3c752194ea --- /dev/null +++ b/extensions/typescript-language-features/src/utils/logLevelMonitor.ts @@ -0,0 +1,106 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { Disposable } from './dispose'; +import { localize } from '../tsServer/versionProvider'; +import { TsServerLogLevel } from './configuration'; + +export class LogLevelMonitor extends Disposable { + + private static readonly logLevelConfigKey = 'typescript.tsserver.log'; + private static readonly logLevelChangedStorageKey = 'typescript.tsserver.logLevelChanged'; + private static readonly doNotPromptLogLevelStorageKey = 'typescript.tsserver.doNotPromptLogLevel'; + + constructor(private readonly context: vscode.ExtensionContext) { + super(); + + this._register(vscode.workspace.onDidChangeConfiguration(this.onConfigurationChange, this, this._disposables)); + + if (this.shouldNotifyExtendedLogging()) { + this.notifyExtendedLogging(); + } + } + + private onConfigurationChange(event: vscode.ConfigurationChangeEvent) { + const logLevelChanged = event.affectsConfiguration(LogLevelMonitor.logLevelConfigKey); + if (!logLevelChanged) { + return; + } + this.context.globalState.update(LogLevelMonitor.logLevelChangedStorageKey, new Date()); + } + + private get logLevel(): TsServerLogLevel { + return TsServerLogLevel.fromString(vscode.workspace.getConfiguration().get(LogLevelMonitor.logLevelConfigKey, 'off')); + } + + /** + * Last date change if it exists and can be parsed as a date, + * otherwise undefined. + */ + private get lastLogLevelChange(): Date | undefined { + const lastChange = this.context.globalState.get(LogLevelMonitor.logLevelChangedStorageKey); + + if (lastChange) { + const date = new Date(lastChange); + if (date instanceof Date && !isNaN(date.valueOf())) { + return date; + } + } + return undefined; + } + + private get doNotPrompt(): boolean { + return this.context.globalState.get(LogLevelMonitor.doNotPromptLogLevelStorageKey) || false; + } + + private shouldNotifyExtendedLogging(): boolean { + const lastChangeMilliseconds = this.lastLogLevelChange ? new Date(this.lastLogLevelChange).valueOf() : 0; + const lastChangePlusOneWeek = new Date(lastChangeMilliseconds + /* 7 days in milliseconds */ 86400000 * 7); + + if (!this.doNotPrompt && this.logLevel !== TsServerLogLevel.Off && lastChangePlusOneWeek.valueOf() < Date.now()) { + return true; + } + return false; + } + + private notifyExtendedLogging() { + const enum Choice { + DisableLogging = 0, + DoNotShowAgain = 1 + } + interface Item extends vscode.MessageItem { + readonly choice: Choice; + } + + vscode.window.showInformationMessage( + localize( + 'typescript.extendedLogging.isEnabled', + "TS Server logging is currently enabled which may impact performance."), + { + title: localize( + 'typescript.extendedLogging.disableLogging', + "Disable logging"), + choice: Choice.DisableLogging + }, + { + title: localize( + 'typescript.extendedLogging.doNotShowAgain', + "Don't show again"), + choice: Choice.DoNotShowAgain + }) + .then(selection => { + if (!selection) { + return; + } + if (selection.choice === Choice.DisableLogging) { + return vscode.workspace.getConfiguration().update(LogLevelMonitor.logLevelConfigKey, 'off', true); + } else if (selection.choice === Choice.DoNotShowAgain) { + return this.context.globalState.update(LogLevelMonitor.doNotPromptLogLevelStorageKey, true); + } + return; + }); + } +} diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/logger.ts b/extensions/typescript-language-features/src/utils/logger.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/logger.ts rename to extensions/typescript-language-features/src/utils/logger.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/managedFileContext.ts b/extensions/typescript-language-features/src/utils/managedFileContext.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/managedFileContext.ts rename to extensions/typescript-language-features/src/utils/managedFileContext.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/memoize.ts b/extensions/typescript-language-features/src/utils/memoize.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/memoize.ts rename to extensions/typescript-language-features/src/utils/memoize.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/modifiers.ts b/extensions/typescript-language-features/src/utils/modifiers.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/modifiers.ts rename to extensions/typescript-language-features/src/utils/modifiers.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/objects.ts b/extensions/typescript-language-features/src/utils/objects.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/objects.ts rename to extensions/typescript-language-features/src/utils/objects.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/platform.ts b/extensions/typescript-language-features/src/utils/platform.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/platform.ts rename to extensions/typescript-language-features/src/utils/platform.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/pluginPathsProvider.ts b/extensions/typescript-language-features/src/utils/pluginPathsProvider.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/pluginPathsProvider.ts rename to extensions/typescript-language-features/src/utils/pluginPathsProvider.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/plugins.ts b/extensions/typescript-language-features/src/utils/plugins.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/plugins.ts rename to extensions/typescript-language-features/src/utils/plugins.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/previewer.ts b/extensions/typescript-language-features/src/utils/previewer.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/previewer.ts rename to extensions/typescript-language-features/src/utils/previewer.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/regexp.ts b/extensions/typescript-language-features/src/utils/regexp.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/regexp.ts rename to extensions/typescript-language-features/src/utils/regexp.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/relativePathResolver.ts b/extensions/typescript-language-features/src/utils/relativePathResolver.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/relativePathResolver.ts rename to extensions/typescript-language-features/src/utils/relativePathResolver.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/resourceMap.ts b/extensions/typescript-language-features/src/utils/resourceMap.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/resourceMap.ts rename to extensions/typescript-language-features/src/utils/resourceMap.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/snippetForFunctionCall.ts b/extensions/typescript-language-features/src/utils/snippetForFunctionCall.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/snippetForFunctionCall.ts rename to extensions/typescript-language-features/src/utils/snippetForFunctionCall.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/telemetry.ts b/extensions/typescript-language-features/src/utils/telemetry.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/telemetry.ts rename to extensions/typescript-language-features/src/utils/telemetry.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/temp.electron.ts b/extensions/typescript-language-features/src/utils/temp.electron.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/temp.electron.ts rename to extensions/typescript-language-features/src/utils/temp.electron.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/tracer.ts b/extensions/typescript-language-features/src/utils/tracer.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/tracer.ts rename to extensions/typescript-language-features/src/utils/tracer.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/tsconfig.ts b/extensions/typescript-language-features/src/utils/tsconfig.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/tsconfig.ts rename to extensions/typescript-language-features/src/utils/tsconfig.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/typeConverters.ts b/extensions/typescript-language-features/src/utils/typeConverters.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/typeConverters.ts rename to extensions/typescript-language-features/src/utils/typeConverters.ts diff --git a/lib/vscode/extensions/typescript-language-features/src/utils/typingsStatus.ts b/extensions/typescript-language-features/src/utils/typingsStatus.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/src/utils/typingsStatus.ts rename to extensions/typescript-language-features/src/utils/typingsStatus.ts diff --git a/lib/vscode/extensions/typescript-language-features/test-workspace/bar.ts b/extensions/typescript-language-features/test-workspace/bar.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/test-workspace/bar.ts rename to extensions/typescript-language-features/test-workspace/bar.ts diff --git a/lib/vscode/extensions/typescript-language-features/test-workspace/foo.ts b/extensions/typescript-language-features/test-workspace/foo.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/test-workspace/foo.ts rename to extensions/typescript-language-features/test-workspace/foo.ts diff --git a/lib/vscode/extensions/typescript-language-features/test-workspace/foojs.js b/extensions/typescript-language-features/test-workspace/foojs.js similarity index 100% rename from lib/vscode/extensions/typescript-language-features/test-workspace/foojs.js rename to extensions/typescript-language-features/test-workspace/foojs.js diff --git a/lib/vscode/extensions/typescript-language-features/test-workspace/index.ts b/extensions/typescript-language-features/test-workspace/index.ts similarity index 100% rename from lib/vscode/extensions/typescript-language-features/test-workspace/index.ts rename to extensions/typescript-language-features/test-workspace/index.ts diff --git a/lib/vscode/extensions/typescript-language-features/test-workspace/tsconfig.json b/extensions/typescript-language-features/test-workspace/tsconfig.json similarity index 100% rename from lib/vscode/extensions/typescript-language-features/test-workspace/tsconfig.json rename to extensions/typescript-language-features/test-workspace/tsconfig.json diff --git a/lib/vscode/extensions/typescript-language-features/tsconfig.json b/extensions/typescript-language-features/tsconfig.json similarity index 100% rename from lib/vscode/extensions/typescript-language-features/tsconfig.json rename to extensions/typescript-language-features/tsconfig.json diff --git a/lib/vscode/extensions/typescript-language-features/yarn.lock b/extensions/typescript-language-features/yarn.lock similarity index 95% rename from lib/vscode/extensions/typescript-language-features/yarn.lock rename to extensions/typescript-language-features/yarn.lock index 5ac428c1065f..a94f34e248ee 100644 --- a/lib/vscode/extensions/typescript-language-features/yarn.lock +++ b/extensions/typescript-language-features/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== "@types/semver@^5.5.0": version "5.5.0" diff --git a/lib/vscode/extensions/vb/.vscodeignore b/extensions/vb/.vscodeignore similarity index 100% rename from lib/vscode/extensions/vb/.vscodeignore rename to extensions/vb/.vscodeignore diff --git a/lib/vscode/extensions/vb/cgmanifest.json b/extensions/vb/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/vb/cgmanifest.json rename to extensions/vb/cgmanifest.json diff --git a/lib/vscode/extensions/vb/language-configuration.json b/extensions/vb/language-configuration.json similarity index 100% rename from lib/vscode/extensions/vb/language-configuration.json rename to extensions/vb/language-configuration.json diff --git a/lib/vscode/extensions/vb/package.json b/extensions/vb/package.json similarity index 100% rename from lib/vscode/extensions/vb/package.json rename to extensions/vb/package.json diff --git a/lib/vscode/extensions/vb/package.nls.json b/extensions/vb/package.nls.json similarity index 100% rename from lib/vscode/extensions/vb/package.nls.json rename to extensions/vb/package.nls.json diff --git a/lib/vscode/extensions/vb/snippets/vb.code-snippets b/extensions/vb/snippets/vb.code-snippets similarity index 100% rename from lib/vscode/extensions/vb/snippets/vb.code-snippets rename to extensions/vb/snippets/vb.code-snippets diff --git a/lib/vscode/extensions/vb/syntaxes/asp-vb-net.tmlanguage.json b/extensions/vb/syntaxes/asp-vb-net.tmlanguage.json similarity index 100% rename from lib/vscode/extensions/vb/syntaxes/asp-vb-net.tmlanguage.json rename to extensions/vb/syntaxes/asp-vb-net.tmlanguage.json diff --git a/lib/vscode/extensions/vb/yarn.lock b/extensions/vb/yarn.lock similarity index 100% rename from lib/vscode/extensions/vb/yarn.lock rename to extensions/vb/yarn.lock diff --git a/lib/vscode/extensions/vscode-api-tests/.gitignore b/extensions/vscode-api-tests/.gitignore similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/.gitignore rename to extensions/vscode-api-tests/.gitignore diff --git a/lib/vscode/extensions/vscode-api-tests/.vscode/launch.json b/extensions/vscode-api-tests/.vscode/launch.json similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/.vscode/launch.json rename to extensions/vscode-api-tests/.vscode/launch.json diff --git a/lib/vscode/extensions/vscode-api-tests/.vscode/tasks.json b/extensions/vscode-api-tests/.vscode/tasks.json similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/.vscode/tasks.json rename to extensions/vscode-api-tests/.vscode/tasks.json diff --git a/lib/vscode/extensions/vscode-api-tests/.vscodeignore b/extensions/vscode-api-tests/.vscodeignore similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/.vscodeignore rename to extensions/vscode-api-tests/.vscodeignore diff --git a/lib/vscode/extensions/vscode-api-tests/media/icon.png b/extensions/vscode-api-tests/media/icon.png similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/media/icon.png rename to extensions/vscode-api-tests/media/icon.png diff --git a/lib/vscode/extensions/vscode-api-tests/package.json b/extensions/vscode-api-tests/package.json similarity index 95% rename from lib/vscode/extensions/vscode-api-tests/package.json rename to extensions/vscode-api-tests/package.json index e1c16dace634..dcdd8b608a95 100644 --- a/lib/vscode/extensions/vscode-api-tests/package.json +++ b/extensions/vscode-api-tests/package.json @@ -117,9 +117,9 @@ ] } ], - "notebookProvider": [ + "notebooks": [ { - "viewType": "notebookCoreTest", + "type": "notebookCoreTest", "displayName": "Notebook Core Test", "selector": [ { @@ -129,7 +129,7 @@ ] }, { - "viewType": "notebook.nbdtest", + "type": "notebook.nbdtest", "displayName": "notebook.nbdtest", "selector": [ { @@ -138,7 +138,7 @@ ] }, { - "viewType": "notebook.nbdserializer", + "type": "notebook.nbdserializer", "displayName": "notebook.nbdserializer", "selector": [ { @@ -154,7 +154,7 @@ }, "devDependencies": { "@types/mocha": "^8.2.0", - "@types/node": "^12.19.9" + "@types/node": "14.x" }, "repository": { "type": "git", diff --git a/lib/vscode/extensions/vscode-api-tests/src/extension.ts b/extensions/vscode-api-tests/src/extension.ts similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/src/extension.ts rename to extensions/vscode-api-tests/src/extension.ts diff --git a/lib/vscode/extensions/vscode-api-tests/src/memfs.ts b/extensions/vscode-api-tests/src/memfs.ts similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/src/memfs.ts rename to extensions/vscode-api-tests/src/memfs.ts diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts similarity index 96% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts index f9f971bdbdab..7c906ba0fe45 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts @@ -52,8 +52,8 @@ suite('vscode API - commands', () => { await commands.executeCommand('t1', 'start'); registration.dispose(); assert.ok(args!); - assert.equal(args!.length, 1); - assert.equal(args![0], 'start'); + assert.strictEqual(args!.length, 1); + assert.strictEqual(args![0], 'start'); }); test('editorCommand with extra args', function () { @@ -68,7 +68,7 @@ suite('vscode API - commands', () => { return commands.executeCommand('t1', 12345, commands); }).then(() => { assert.ok(args); - assert.equal(args.length, 4); + assert.strictEqual(args.length, 4); assert.ok(args[2] === 12345); assert.ok(args[3] === commands); registration.dispose(); diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/configuration.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/configuration.test.ts similarity index 72% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/configuration.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/configuration.test.ts index 0a9ddf7aa2d6..9c7fa1acff51 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/configuration.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/configuration.test.ts @@ -15,7 +15,7 @@ suite('vscode API - configuration', () => { test('configurations, language defaults', function () { const defaultLanguageSettings = vscode.workspace.getConfiguration().get('[abcLang]'); - assert.deepEqual(defaultLanguageSettings, { + assert.deepStrictEqual(defaultLanguageSettings, { 'editor.lineNumbers': 'off', 'editor.tabSize': 2 }); @@ -25,25 +25,25 @@ suite('vscode API - configuration', () => { const config = vscode.workspace.getConfiguration('farboo'); assert.ok(config.has('config0')); - assert.equal(config.get('config0'), true); - assert.equal(config.get('config4'), ''); - assert.equal(config['config0'], true); - assert.equal(config['config4'], ''); + assert.strictEqual(config.get('config0'), true); + assert.strictEqual(config.get('config4'), ''); + assert.strictEqual(config['config0'], true); + assert.strictEqual(config['config4'], ''); assert.throws(() => (config)['config4'] = 'valuevalue'); assert.ok(config.has('nested.config1')); - assert.equal(config.get('nested.config1'), 42); + assert.strictEqual(config.get('nested.config1'), 42); assert.ok(config.has('nested.config2')); - assert.equal(config.get('nested.config2'), 'Das Pferd frisst kein Reis.'); + assert.strictEqual(config.get('nested.config2'), 'Das Pferd frisst kein Reis.'); }); test('configuration, name vs property', () => { const config = vscode.workspace.getConfiguration('farboo'); assert.ok(config.has('get')); - assert.equal(config.get('get'), 'get-prop'); - assert.deepEqual(config['get'], config.get); + assert.strictEqual(config.get('get'), 'get-prop'); + assert.deepStrictEqual(config['get'], config.get); assert.throws(() => config['get'] = 'get-prop'); }); }); diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/debug.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/debug.test.ts similarity index 80% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/debug.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/debug.test.ts index 145c2ee3bce8..f79a2000cb3f 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/debug.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/debug.test.ts @@ -13,7 +13,7 @@ suite('vscode API - debug', function () { teardown(assertNoRpc); test('breakpoints', async function () { - assert.equal(debug.breakpoints.length, 0); + assert.strictEqual(debug.breakpoints.length, 0); let onDidChangeBreakpointsCounter = 0; const toDispose: Disposable[] = []; @@ -22,19 +22,19 @@ suite('vscode API - debug', function () { })); debug.addBreakpoints([{ id: '1', enabled: true }, { id: '2', enabled: false, condition: '2 < 5' }]); - assert.equal(onDidChangeBreakpointsCounter, 1); - assert.equal(debug.breakpoints.length, 2); - assert.equal(debug.breakpoints[0].id, '1'); - assert.equal(debug.breakpoints[1].id, '2'); - assert.equal(debug.breakpoints[1].condition, '2 < 5'); + assert.strictEqual(onDidChangeBreakpointsCounter, 1); + assert.strictEqual(debug.breakpoints.length, 2); + assert.strictEqual(debug.breakpoints[0].id, '1'); + assert.strictEqual(debug.breakpoints[1].id, '2'); + assert.strictEqual(debug.breakpoints[1].condition, '2 < 5'); debug.removeBreakpoints([{ id: '1', enabled: true }]); - assert.equal(onDidChangeBreakpointsCounter, 2); - assert.equal(debug.breakpoints.length, 1); + assert.strictEqual(onDidChangeBreakpointsCounter, 2); + assert.strictEqual(debug.breakpoints.length, 1); debug.removeBreakpoints([{ id: '2', enabled: false }]); - assert.equal(onDidChangeBreakpointsCounter, 3); - assert.equal(debug.breakpoints.length, 0); + assert.strictEqual(onDidChangeBreakpointsCounter, 3); + assert.strictEqual(debug.breakpoints.length, 0); disposeAll(toDispose); }); @@ -79,36 +79,36 @@ suite('vscode API - debug', function () { const initializedPromise = new Promise(resolve => initializedReceived = resolve); const configurationDonePromise = new Promise(resolve => configurationDoneReceived = resolve); const success = await debug.startDebugging(workspace.workspaceFolders![0], 'Launch debug.js'); - assert.equal(success, true); + assert.strictEqual(success, true); await initializedPromise; await configurationDonePromise; await firstVariablesRetrieved; - assert.notEqual(debug.activeDebugSession, undefined); - assert.equal(stoppedEvents, 1); + assert.notStrictEqual(debug.activeDebugSession, undefined); + assert.strictEqual(stoppedEvents, 1); const secondVariablesRetrieved = new Promise(resolve => variablesReceived = resolve); await commands.executeCommand('workbench.action.debug.stepOver'); await secondVariablesRetrieved; - assert.equal(stoppedEvents, 2); + assert.strictEqual(stoppedEvents, 2); const editor = window.activeTextEditor; - assert.notEqual(editor, undefined); - assert.equal(basename(editor!.document.fileName), 'debug.js'); + assert.notStrictEqual(editor, undefined); + assert.strictEqual(basename(editor!.document.fileName), 'debug.js'); const thirdVariablesRetrieved = new Promise(resolve => variablesReceived = resolve); await commands.executeCommand('workbench.action.debug.stepOver'); await thirdVariablesRetrieved; - assert.equal(stoppedEvents, 3); + assert.strictEqual(stoppedEvents, 3); const fourthVariablesRetrieved = new Promise(resolve => variablesReceived = resolve); await commands.executeCommand('workbench.action.debug.stepInto'); await fourthVariablesRetrieved; - assert.equal(stoppedEvents, 4); + assert.strictEqual(stoppedEvents, 4); const fifthVariablesRetrieved = new Promise(resolve => variablesReceived = resolve); await commands.executeCommand('workbench.action.debug.stepOut'); await fifthVariablesRetrieved; - assert.equal(stoppedEvents, 5); + assert.strictEqual(stoppedEvents, 5); let sessionTerminated: () => void; toDispose.push(debug.onDidTerminateDebugSession(() => { @@ -127,6 +127,6 @@ suite('vscode API - debug', function () { } catch (e) { errorCount++; } - assert.equal(errorCount, 1); + assert.strictEqual(errorCount, 1); }); }); diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts similarity index 81% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts index ef16bbe1c61a..faf2f7d80133 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts @@ -44,7 +44,7 @@ suite('vscode API - editors', () => { return withRandomFileEditor('', (editor, doc) => { return editor.insertSnippet(snippetString).then(inserted => { assert.ok(inserted); - assert.equal(doc.getText(), 'This is a placeholder snippet'); + assert.strictEqual(doc.getText(), 'This is a placeholder snippet'); assert.ok(doc.isDirty); }); }); @@ -69,7 +69,7 @@ suite('vscode API - editors', () => { await withRandomFileEditor('', async (editor, doc) => { const inserted = await editor.insertSnippet(snippetString); assert.ok(inserted); - assert.equal(doc.getText(), 'running: INTEGRATION-TESTS'); + assert.strictEqual(doc.getText(), 'running: INTEGRATION-TESTS'); assert.ok(doc.isDirty); }); @@ -88,7 +88,7 @@ suite('vscode API - editors', () => { return editor.insertSnippet(snippetString).then(inserted => { assert.ok(inserted); - assert.equal(doc.getText(), 'This has been replaced'); + assert.strictEqual(doc.getText(), 'This has been replaced'); assert.ok(doc.isDirty); }); }); @@ -106,7 +106,7 @@ suite('vscode API - editors', () => { return editor.insertSnippet(snippetString, selection).then(inserted => { assert.ok(inserted); - assert.equal(doc.getText(), 'This has been replaced'); + assert.strictEqual(doc.getText(), 'This has been replaced'); assert.ok(doc.isDirty); }); }); @@ -118,7 +118,7 @@ suite('vscode API - editors', () => { builder.insert(new Position(0, 0), 'Hello World'); }).then(applied => { assert.ok(applied); - assert.equal(doc.getText(), 'Hello World'); + assert.strictEqual(doc.getText(), 'Hello World'); assert.ok(doc.isDirty); }); }); @@ -130,7 +130,7 @@ suite('vscode API - editors', () => { builder.replace(new Range(0, 0, Number.MAX_VALUE, Number.MAX_VALUE), 'new'); }).then(applied => { assert.ok(applied); - assert.equal(doc.getText(), 'new'); + assert.strictEqual(doc.getText(), 'new'); assert.ok(doc.isDirty); }); }); @@ -146,12 +146,12 @@ suite('vscode API - editors', () => { return withRandomFileEditor('Hello world!', async (editor, doc) => { const applied1 = await executeReplace(editor, new Range(0, 0, 0, 1), 'h', false, false); assert.ok(applied1); - assert.equal(doc.getText(), 'hello world!'); + assert.strictEqual(doc.getText(), 'hello world!'); assert.ok(doc.isDirty); const applied2 = await executeReplace(editor, new Range(0, 1, 0, 5), 'ELLO', false, false); assert.ok(applied2); - assert.equal(doc.getText(), 'hELLO world!'); + assert.strictEqual(doc.getText(), 'hELLO world!'); assert.ok(doc.isDirty); await commands.executeCommand('undo'); @@ -161,7 +161,7 @@ suite('vscode API - editors', () => { // it is unclear why this happens, but it can happen for a multitude of reasons await commands.executeCommand('undo'); } - assert.equal(doc.getText(), 'Hello world!'); + assert.strictEqual(doc.getText(), 'Hello world!'); }); }); @@ -169,16 +169,16 @@ suite('vscode API - editors', () => { return withRandomFileEditor('Hello world!', (editor, doc) => { return executeReplace(editor, new Range(0, 0, 0, 1), 'h', false, false).then(applied => { assert.ok(applied); - assert.equal(doc.getText(), 'hello world!'); + assert.strictEqual(doc.getText(), 'hello world!'); assert.ok(doc.isDirty); return executeReplace(editor, new Range(0, 1, 0, 5), 'ELLO', true, false); }).then(applied => { assert.ok(applied); - assert.equal(doc.getText(), 'hELLO world!'); + assert.strictEqual(doc.getText(), 'hELLO world!'); assert.ok(doc.isDirty); return commands.executeCommand('undo'); }).then(_ => { - assert.equal(doc.getText(), 'hello world!'); + assert.strictEqual(doc.getText(), 'hello world!'); }); }); }); @@ -186,26 +186,26 @@ suite('vscode API - editors', () => { test('issue #16573: Extension API: insertSpaces and tabSize are undefined', () => { return withRandomFileEditor('Hello world!\n\tHello world!', (editor, _doc) => { - assert.equal(editor.options.tabSize, 4); - assert.equal(editor.options.insertSpaces, false); - assert.equal(editor.options.cursorStyle, TextEditorCursorStyle.Line); - assert.equal(editor.options.lineNumbers, TextEditorLineNumbersStyle.On); + assert.strictEqual(editor.options.tabSize, 4); + assert.strictEqual(editor.options.insertSpaces, false); + assert.strictEqual(editor.options.cursorStyle, TextEditorCursorStyle.Line); + assert.strictEqual(editor.options.lineNumbers, TextEditorLineNumbersStyle.On); editor.options = { tabSize: 2 }; - assert.equal(editor.options.tabSize, 2); - assert.equal(editor.options.insertSpaces, false); - assert.equal(editor.options.cursorStyle, TextEditorCursorStyle.Line); - assert.equal(editor.options.lineNumbers, TextEditorLineNumbersStyle.On); + assert.strictEqual(editor.options.tabSize, 2); + assert.strictEqual(editor.options.insertSpaces, false); + assert.strictEqual(editor.options.cursorStyle, TextEditorCursorStyle.Line); + assert.strictEqual(editor.options.lineNumbers, TextEditorLineNumbersStyle.On); editor.options.tabSize = 'invalid'; - assert.equal(editor.options.tabSize, 2); - assert.equal(editor.options.insertSpaces, false); - assert.equal(editor.options.cursorStyle, TextEditorCursorStyle.Line); - assert.equal(editor.options.lineNumbers, TextEditorLineNumbersStyle.On); + assert.strictEqual(editor.options.tabSize, 2); + assert.strictEqual(editor.options.insertSpaces, false); + assert.strictEqual(editor.options.cursorStyle, TextEditorCursorStyle.Line); + assert.strictEqual(editor.options.lineNumbers, TextEditorLineNumbersStyle.On); return Promise.resolve(); }); @@ -262,6 +262,6 @@ suite('vscode API - editors', () => { const file = Uri.parse(root.toString() + relativePath); const document = await workspace.openTextDocument(file); - assert.equal(document.getText(), Buffer.from(await workspace.fs.readFile(file)).toString()); + assert.strictEqual(document.getText(), Buffer.from(await workspace.fs.readFile(file)).toString()); } }); diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts similarity index 77% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts index 42e25bafddd1..73b799525910 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts @@ -12,12 +12,12 @@ suite('vscode API - env', () => { teardown(assertNoRpc); test('env is set', function () { - assert.equal(typeof env.language, 'string'); - assert.equal(typeof env.appRoot, 'string'); - assert.equal(typeof env.appName, 'string'); - assert.equal(typeof env.machineId, 'string'); - assert.equal(typeof env.sessionId, 'string'); - assert.equal(typeof env.shell, 'string'); + assert.strictEqual(typeof env.language, 'string'); + assert.strictEqual(typeof env.appRoot, 'string'); + assert.strictEqual(typeof env.appName, 'string'); + assert.strictEqual(typeof env.machineId, 'string'); + assert.strictEqual(typeof env.sessionId, 'string'); + assert.strictEqual(typeof env.shell, 'string'); }); test('env is readonly', function () { @@ -37,7 +37,7 @@ suite('vscode API - env', () => { // not running in remote, so we expect both extensions assert.ok(knownWorkspaceExtension); assert.ok(knownUiAndWorkspaceExtension); - assert.equal(ExtensionKind.UI, knownUiAndWorkspaceExtension!.extensionKind); + assert.strictEqual(ExtensionKind.UI, knownUiAndWorkspaceExtension!.extensionKind); } else if (typeof remoteName === 'string') { // running in remote, so we only expect workspace extensions assert.ok(knownWorkspaceExtension); @@ -46,7 +46,7 @@ suite('vscode API - env', () => { } else { assert.ok(knownUiAndWorkspaceExtension); } - assert.equal(ExtensionKind.Workspace, knownWorkspaceExtension!.extensionKind); + assert.strictEqual(ExtensionKind.Workspace, knownWorkspaceExtension!.extensionKind); } else { assert.fail(); } @@ -58,9 +58,9 @@ suite('vscode API - env', () => { const kind = env.uiKind; if (result.scheme === 'http' || result.scheme === 'https') { - assert.equal(kind, UIKind.Web); + assert.strictEqual(kind, UIKind.Web); } else { - assert.equal(kind, UIKind.Desktop); + assert.strictEqual(kind, UIKind.Desktop); } }); @@ -70,9 +70,9 @@ suite('vscode API - env', () => { assert.ok(result); if (env.uiKind === UIKind.Desktop) { - assert.equal(uri.scheme, result.scheme); - assert.equal(uri.authority, result.authority); - assert.equal(uri.path, result.path); + assert.strictEqual(uri.scheme, result.scheme); + assert.strictEqual(uri.authority, result.authority); + assert.strictEqual(uri.path, result.path); } else { assert.ok(result.scheme === 'http' || result.scheme === 'https'); } diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/extensions.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/extensions.test.ts similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/extensions.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/extensions.test.ts diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/index.ts b/extensions/vscode-api-tests/src/singlefolder-tests/index.ts similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/index.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/index.ts diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts similarity index 90% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts index 0553a4444dbe..ed75f597dc5b 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts @@ -23,7 +23,7 @@ suite('vscode API - languages', () => { } function assertEqualRange(actual: vscode.Range, expected: vscode.Range, message?: string) { - assert.equal(rangeToString(actual), rangeToString(expected), message); + assert.strictEqual(rangeToString(actual), rangeToString(expected), message); } test('setTextDocumentLanguage -> close/open event', async function () { @@ -36,8 +36,8 @@ suite('vscode API - languages', () => { let close = new Promise(resolve => { disposables.push(vscode.workspace.onDidCloseTextDocument(e => { if (e === doc) { - assert.equal(doc.languageId, langIdNow); - assert.equal(clock, 0); + assert.strictEqual(doc.languageId, langIdNow); + assert.strictEqual(clock, 0); clock += 1; resolve(); } @@ -46,8 +46,8 @@ suite('vscode API - languages', () => { let open = new Promise(resolve => { disposables.push(vscode.workspace.onDidOpenTextDocument(e => { if (e === doc) { // same instance! - assert.equal(doc.languageId, 'json'); - assert.equal(clock, 1); + assert.strictEqual(doc.languageId, 'json'); + assert.strictEqual(clock, 1); clock += 1; resolve(); } @@ -55,8 +55,8 @@ suite('vscode API - languages', () => { }); let change = vscode.languages.setTextDocumentLanguage(doc, 'json'); await Promise.all([change, close, open]); - assert.equal(clock, 2); - assert.equal(doc.languageId, 'json'); + assert.strictEqual(clock, 2); + assert.strictEqual(doc.languageId, 'json'); disposables.forEach(disposable => disposable.dispose()); disposables.length = 0; }); @@ -82,7 +82,7 @@ suite('vscode API - languages', () => { col2.set(uri, [new vscode.Diagnostic(new vscode.Range(0, 0, 0, 12), 'error1')]); let diag = vscode.languages.getDiagnostics(uri); - assert.equal(diag.length, 2); + assert.strictEqual(diag.length, 2); let tuples = vscode.languages.getDiagnostics(); let found = false; @@ -111,13 +111,13 @@ suite('vscode API - languages', () => { vscode.languages.registerDocumentLinkProvider({ language: 'java', scheme: testFs.scheme }, linkProvider); const links = await vscode.commands.executeCommand('vscode.executeLinkProvider', doc.uri); - assert.equal(2, links && links.length); + assert.strictEqual(2, links && links.length); let [link1, link2] = links!.sort((l1, l2) => l1.range.start.compareTo(l2.range.start)); - assert.equal(target.toString(), link1.target && link1.target.toString()); + assert.strictEqual(target.toString(), link1.target && link1.target.toString()); assertEqualRange(range, link1.range); - assert.equal('http://a.com/', link2.target && link2.target.toString()); + assert.strictEqual('http://a.com/', link2.target && link2.target.toString()); assertEqualRange(new vscode.Range(new vscode.Position(0, 13), new vscode.Position(0, 25)), link2.range); }); @@ -139,7 +139,7 @@ suite('vscode API - languages', () => { let r1 = vscode.languages.registerCodeActionsProvider({ pattern: '*.far', scheme: 'ttt' }, { provideCodeActions(_document, _range, ctx): vscode.Command[] { - assert.equal(ctx.diagnostics.length, 2); + assert.strictEqual(ctx.diagnostics.length, 2); let [first, second] = ctx.diagnostics; assert.ok(first === diag1); assert.ok(second === diag2); diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts similarity index 73% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts index 70e6e7042315..701de344f331 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.document.test.ts @@ -13,7 +13,6 @@ suite('Notebook Document', function () { deserializeNotebook(_data: Uint8Array): vscode.NotebookData | Thenable { return new vscode.NotebookData( [new vscode.NotebookCellData(vscode.NotebookCellKind.Code, '// SIMPLE', 'javascript')], - new vscode.NotebookDocumentMetadata() ); } serializeNotebook(_data: vscode.NotebookData): Uint8Array | Thenable { @@ -25,7 +24,6 @@ suite('Notebook Document', function () { async openNotebook(uri: vscode.Uri, _openContext: vscode.NotebookDocumentOpenContext): Promise { return new vscode.NotebookData( [new vscode.NotebookCellData(vscode.NotebookCellKind.Code, uri.toString(), 'javascript')], - new vscode.NotebookDocumentMetadata() ); } async saveNotebook(_document: vscode.NotebookDocument, _cancellation: vscode.CancellationToken) { @@ -47,29 +45,25 @@ suite('Notebook Document', function () { await utils.closeAllEditors(); utils.disposeAll(disposables); disposables.length = 0; - - for (let doc of vscode.notebook.notebookDocuments) { - assert.strictEqual(doc.isDirty, false, doc.uri.toString()); - } }); suiteSetup(function () { - disposables.push(vscode.notebook.registerNotebookContentProvider('notebook.nbdtest', complexContentProvider)); - disposables.push(vscode.notebook.registerNotebookSerializer('notebook.nbdserializer', simpleContentProvider)); + disposables.push(vscode.workspace.registerNotebookContentProvider('notebook.nbdtest', complexContentProvider)); + disposables.push(vscode.workspace.registerNotebookSerializer('notebook.nbdserializer', simpleContentProvider)); }); test('cannot register sample provider multiple times', function () { assert.throws(() => { - vscode.notebook.registerNotebookContentProvider('notebook.nbdtest', complexContentProvider); + vscode.workspace.registerNotebookContentProvider('notebook.nbdtest', complexContentProvider); }); // assert.throws(() => { - // vscode.notebook.registerNotebookSerializer('notebook.nbdserializer', simpleContentProvider); + // vscode.workspace.registerNotebookSerializer('notebook.nbdserializer', simpleContentProvider); // }); }); test('cannot open unknown types', async function () { try { - await vscode.notebook.openNotebookDocument(vscode.Uri.parse('some:///thing.notTypeKnown')); + await vscode.workspace.openNotebookDocument(vscode.Uri.parse('some:///thing.notTypeKnown')); assert.ok(false); } catch { assert.ok(true); @@ -78,32 +72,43 @@ suite('Notebook Document', function () { test('document basics', async function () { const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); - const notebook = await vscode.notebook.openNotebookDocument(uri); + const notebook = await vscode.workspace.openNotebookDocument(uri); assert.strictEqual(notebook.uri.toString(), uri.toString()); assert.strictEqual(notebook.isDirty, false); assert.strictEqual(notebook.isUntitled, false); assert.strictEqual(notebook.cellCount, 1); - assert.strictEqual(notebook.viewType, 'notebook.nbdtest'); + assert.strictEqual(notebook.notebookType, 'notebook.nbdtest'); }); test('notebook open/close, notebook ready when cell-document open event is fired', async function () { const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); let didHappen = false; - const p = utils.asPromise(vscode.workspace.onDidOpenTextDocument).then(doc => { - if (doc.uri.scheme !== 'vscode-notebook-cell') { - return; - } - const notebook = vscode.notebook.notebookDocuments.find(notebook => { - const cell = notebook.getCells().find(cell => cell.document === doc); - return Boolean(cell); + + const p = new Promise((resolve, reject) => { + const sub = vscode.workspace.onDidOpenTextDocument(doc => { + if (doc.uri.scheme !== 'vscode-notebook-cell') { + // ignore other open events + return; + } + const notebook = vscode.workspace.notebookDocuments.find(notebook => { + const cell = notebook.getCells().find(cell => cell.document === doc); + return Boolean(cell); + }); + assert.ok(notebook, `notebook for cell ${doc.uri} NOT found`); + didHappen = true; + sub.dispose(); + resolve(); }); - assert.ok(notebook, `notebook for cell ${doc.uri} NOT found`); - didHappen = true; + + setTimeout(() => { + sub.dispose(); + reject(new Error('TIMEOUT')); + }, 15000); }); - await vscode.notebook.openNotebookDocument(uri); + await vscode.workspace.openNotebookDocument(uri); await p; assert.strictEqual(didHappen, true); }); @@ -111,7 +116,7 @@ suite('Notebook Document', function () { test('notebook open/close, all cell-documents are ready', async function () { const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); - const p = utils.asPromise(vscode.notebook.onDidOpenNotebookDocument).then(notebook => { + const p = utils.asPromise(vscode.workspace.onDidOpenNotebookDocument).then(notebook => { for (let i = 0; i < notebook.cellCount; i++) { let cell = notebook.cellAt(i); @@ -125,32 +130,56 @@ suite('Notebook Document', function () { } }); - await vscode.notebook.openNotebookDocument(uri); + await vscode.workspace.openNotebookDocument(uri); await p; }); + test('open untitled notebook', async function () { + const nb = await vscode.workspace.openNotebookDocument('notebook.nbdserializer'); + assert.strictEqual(nb.isUntitled, true); + assert.strictEqual(nb.isClosed, false); + assert.strictEqual(nb.uri.scheme, 'untitled'); + // assert.strictEqual(nb.cellCount, 0); // NotebookSerializer ALWAYS returns something here + }); + + test('open untitled with data', async function () { + const nb = await vscode.workspace.openNotebookDocument( + 'notebook.nbdserializer', + new vscode.NotebookData([ + new vscode.NotebookCellData(vscode.NotebookCellKind.Code, 'console.log()', 'javascript'), + new vscode.NotebookCellData(vscode.NotebookCellKind.Markup, 'Hey', 'markdown'), + ]) + ); + assert.strictEqual(nb.isUntitled, true); + assert.strictEqual(nb.isClosed, false); + assert.strictEqual(nb.uri.scheme, 'untitled'); + assert.strictEqual(nb.cellCount, 2); + assert.strictEqual(nb.cellAt(0).kind, vscode.NotebookCellKind.Code); + assert.strictEqual(nb.cellAt(1).kind, vscode.NotebookCellKind.Markup); + }); + test('workspace edit API (replaceCells)', async function () { const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); - const document = await vscode.notebook.openNotebookDocument(uri); + const document = await vscode.workspace.openNotebookDocument(uri); assert.strictEqual(document.cellCount, 1); // inserting two new cells { const edit = new vscode.WorkspaceEdit(); edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(0, 0), [{ - kind: vscode.NotebookCellKind.Markdown, - language: 'markdown', + kind: vscode.NotebookCellKind.Markup, + languageId: 'markdown', metadata: undefined, outputs: [], - source: 'new_markdown' + value: 'new_markdown' }, { kind: vscode.NotebookCellKind.Code, - language: 'fooLang', + languageId: 'fooLang', metadata: undefined, outputs: [], - source: 'new_code' + value: 'new_code' }]); const success = await vscode.workspace.applyEdit(edit); @@ -177,17 +206,17 @@ suite('Notebook Document', function () { { const edit = new vscode.WorkspaceEdit(); edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(0, 1), [{ - kind: vscode.NotebookCellKind.Markdown, - language: 'markdown', + kind: vscode.NotebookCellKind.Markup, + languageId: 'markdown', metadata: undefined, outputs: [], - source: 'new2_markdown' + value: 'new2_markdown' }, { kind: vscode.NotebookCellKind.Code, - language: 'fooLang', + languageId: 'fooLang', metadata: undefined, outputs: [], - source: 'new2_code' + value: 'new2_code' }]); const success = await vscode.workspace.applyEdit(edit); assert.strictEqual(success, true); @@ -208,25 +237,25 @@ suite('Notebook Document', function () { test('workspace edit API (replaceCells, event)', async function () { const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); - const document = await vscode.notebook.openNotebookDocument(uri); + const document = await vscode.workspace.openNotebookDocument(uri); assert.strictEqual(document.cellCount, 1); const edit = new vscode.WorkspaceEdit(); edit.replaceNotebookCells(document.uri, new vscode.NotebookRange(0, 0), [{ - kind: vscode.NotebookCellKind.Markdown, - language: 'markdown', + kind: vscode.NotebookCellKind.Markup, + languageId: 'markdown', metadata: undefined, outputs: [], - source: 'new_markdown' + value: 'new_markdown' }, { kind: vscode.NotebookCellKind.Code, - language: 'fooLang', + languageId: 'fooLang', metadata: undefined, outputs: [], - source: 'new_code' + value: 'new_code' }]); - const event = utils.asPromise(vscode.notebook.onDidChangeNotebookCells); + const event = utils.asPromise(vscode.notebooks.onDidChangeNotebookCells); const success = await vscode.workspace.applyEdit(edit); assert.strictEqual(success, true); @@ -250,27 +279,27 @@ suite('Notebook Document', function () { test('document save API', async function () { const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); - const notebook = await vscode.notebook.openNotebookDocument(uri); + const notebook = await vscode.workspace.openNotebookDocument(uri); assert.strictEqual(notebook.uri.toString(), uri.toString()); assert.strictEqual(notebook.isDirty, false); assert.strictEqual(notebook.isUntitled, false); assert.strictEqual(notebook.cellCount, 1); - assert.strictEqual(notebook.viewType, 'notebook.nbdtest'); + assert.strictEqual(notebook.notebookType, 'notebook.nbdtest'); const edit = new vscode.WorkspaceEdit(); edit.replaceNotebookCells(notebook.uri, new vscode.NotebookRange(0, 0), [{ - kind: vscode.NotebookCellKind.Markdown, - language: 'markdown', + kind: vscode.NotebookCellKind.Markup, + languageId: 'markdown', metadata: undefined, outputs: [], - source: 'new_markdown' + value: 'new_markdown' }, { kind: vscode.NotebookCellKind.Code, - language: 'fooLang', + languageId: 'fooLang', metadata: undefined, outputs: [], - source: 'new_code' + value: 'new_code' }]); const success = await vscode.workspace.applyEdit(edit); @@ -285,7 +314,7 @@ suite('Notebook Document', function () { test('setTextDocumentLanguage for notebook cells', async function () { const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); - const notebook = await vscode.notebook.openNotebookDocument(uri); + const notebook = await vscode.workspace.openNotebookDocument(uri); const first = notebook.cellAt(0); assert.strictEqual(first.document.languageId, 'javascript'); @@ -305,7 +334,7 @@ suite('Notebook Document', function () { test('setTextDocumentLanguage when notebook editor is not open', async function () { const uri = await utils.createRandomFile('', undefined, '.nbdtest'); - const notebook = await vscode.notebook.openNotebookDocument(uri); + const notebook = await vscode.workspace.openNotebookDocument(uri); const firstCelUri = notebook.cellAt(0).document.uri; await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); @@ -316,7 +345,7 @@ suite('Notebook Document', function () { test('dirty state - complex', async function () { const resource = await utils.createRandomFile(undefined, undefined, '.nbdtest'); - const document = await vscode.notebook.openNotebookDocument(resource); + const document = await vscode.workspace.openNotebookDocument(resource); assert.strictEqual(document.isDirty, false); const edit = new vscode.WorkspaceEdit(); @@ -331,7 +360,7 @@ suite('Notebook Document', function () { test('dirty state - serializer', async function () { const resource = await utils.createRandomFile(undefined, undefined, '.nbdserializer'); - const document = await vscode.notebook.openNotebookDocument(resource); + const document = await vscode.workspace.openNotebookDocument(resource); assert.strictEqual(document.isDirty, false); const edit = new vscode.WorkspaceEdit(); diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts similarity index 83% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts index 11792c4f5bbc..c4b290e984b7 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.editor.test.ts @@ -13,7 +13,6 @@ suite('Notebook Editor', function () { deserializeNotebook() { return new vscode.NotebookData( [new vscode.NotebookCellData(vscode.NotebookCellKind.Code, '// code cell', 'javascript')], - new vscode.NotebookDocumentMetadata() ); } serializeNotebook() { @@ -30,21 +29,19 @@ suite('Notebook Editor', function () { utils.disposeAll(disposables); disposables.length = 0; - for (let doc of vscode.notebook.notebookDocuments) { + for (let doc of vscode.workspace.notebookDocuments) { assert.strictEqual(doc.isDirty, false, doc.uri.toString()); } }); suiteSetup(function () { - disposables.push(vscode.notebook.registerNotebookSerializer('notebook.nbdtest', contentSerializer)); + disposables.push(vscode.workspace.registerNotebookSerializer('notebook.nbdtest', contentSerializer)); }); test('showNotebookDocment', async function () { - const count1 = vscode.notebook.notebookDocuments.length; - - const p = utils.asPromise(vscode.notebook.onDidOpenNotebookDocument); + const p = utils.asPromise(vscode.workspace.onDidOpenNotebookDocument); const uri = await utils.createRandomFile(undefined, undefined, '.nbdtest'); const editor = await vscode.window.showNotebookDocument(uri); @@ -53,12 +50,12 @@ suite('Notebook Editor', function () { const event = await p; assert.strictEqual(event.uri.toString(), uri.toString()); - const count2 = vscode.notebook.notebookDocuments.length; - assert.strictEqual(count1 + 1, count2); - + const includes = vscode.workspace.notebookDocuments.includes(editor.document); + assert.strictEqual(true, includes); }); - test('notebook editor has viewColumn', async function () { + // TODO@rebornix deal with getting started + test.skip('notebook editor has viewColumn', async function () { const uri1 = await utils.createRandomFile(undefined, undefined, '.nbdtest'); const editor1 = await vscode.window.showNotebookDocument(uri1); diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts similarity index 76% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts index 1aff42f1ea64..0e8dc300ed46 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.test.ts @@ -7,49 +7,20 @@ import 'mocha'; import * as assert from 'assert'; import * as vscode from 'vscode'; import { createRandomFile, asPromise, disposeAll, closeAllEditors, revertAllDirty, saveAllEditors, assertNoRpc } from '../utils'; +import { TextDecoder } from 'util'; async function createRandomNotebookFile() { return createRandomFile('', undefined, '.vsctestnb'); } -// Since `workbench.action.splitEditor` command does await properly -// Notebook editor/document events are not guaranteed to be sent to the ext host when promise resolves -// The workaround here is waiting for the first visible notebook editor change event. -async function splitEditor() { - const once = asPromise(vscode.window.onDidChangeVisibleNotebookEditors); - await vscode.commands.executeCommand('workbench.action.splitEditor'); - await once; +async function openRandomNotebookDocument() { + const uri = await createRandomNotebookFile(); + return vscode.workspace.openNotebookDocument(uri); } -async function saveFileAndCloseAll(resource: vscode.Uri) { - const documentClosed = new Promise((resolve, _reject) => { - const d = vscode.notebook.onDidCloseNotebookDocument(e => { - if (e.uri.toString() === resource.toString()) { - d.dispose(); - resolve(); - } - }); - }); - await vscode.commands.executeCommand('workbench.action.files.save'); - await closeAllEditors(); - await documentClosed; -} - -async function saveAllFilesAndCloseAll(resource: vscode.Uri | undefined) { - const documentClosed = new Promise((resolve, _reject) => { - if (!resource) { - return resolve(); - } - const d = vscode.notebook.onDidCloseNotebookDocument(e => { - if (e.uri.toString() === resource.toString()) { - d.dispose(); - resolve(); - } - }); - }); - await vscode.commands.executeCommand('workbench.action.files.saveAll'); +async function saveAllFilesAndCloseAll() { + await saveAllEditors(); await closeAllEditors(); - await documentClosed; } async function withEvent(event: vscode.Event, callback: (e: Promise) => Promise) { @@ -62,11 +33,20 @@ class Kernel { readonly controller: vscode.NotebookController; + readonly associatedNotebooks = new Set(); + constructor(id: string, label: string) { - this.controller = vscode.notebook.createNotebookController(id, 'notebookCoreTest', label); + this.controller = vscode.notebooks.createNotebookController(id, 'notebookCoreTest', label); this.controller.executeHandler = this._execute.bind(this); - this.controller.hasExecutionOrder = true; + this.controller.supportsExecutionOrder = true; this.controller.supportedLanguages = ['typescript', 'javascript']; + this.controller.onDidChangeSelectedNotebooks(e => { + if (e.selected) { + this.associatedNotebooks.add(e.notebook.uri.toString()); + } else { + this.associatedNotebooks.delete(e.notebook.uri.toString()); + } + }); } protected async _execute(cells: vscode.NotebookCell[]): Promise { @@ -76,20 +56,20 @@ class Kernel { } protected async _runCell(cell: vscode.NotebookCell) { - const task = this.controller.createNotebookCellExecutionTask(cell); + const task = this.controller.createNotebookCellExecution(cell); task.start(); task.executionOrder = 1; if (cell.notebook.uri.path.endsWith('customRenderer.vsctestnb')) { await task.replaceOutput([new vscode.NotebookCellOutput([ - new vscode.NotebookCellOutputItem('text/custom', ['test'], undefined) + vscode.NotebookCellOutputItem.text('test', 'text/custom') ])]); return; } await task.replaceOutput([new vscode.NotebookCellOutput([ - new vscode.NotebookCellOutputItem('text/plain', ['my output'], undefined) + vscode.NotebookCellOutputItem.text('my output', 'text/plain') ])]); - task.end({ success: true }); + task.end(true); } } @@ -98,12 +78,13 @@ function getFocusedCell(editor?: vscode.NotebookEditor) { return editor ? editor.document.cellAt(editor.selections[0].start) : undefined; } -async function assertKernel(controller: vscode.NotebookController): Promise { +async function assertKernel(kernel: Kernel, notebook: vscode.NotebookDocument): Promise { const success = await vscode.commands.executeCommand('notebook.selectKernel', { extension: 'vscode.vscode-api-tests', - id: controller.id + id: kernel.controller.id }); - assert.ok(success, `expected selected kernel to be ${controller.id}`); + assert.ok(success, `expected selected kernel to be ${kernel.controller.id}`); + assert.ok(kernel.associatedNotebooks.has(notebook.uri.toString())); } suite('Notebook API tests', function () { @@ -123,38 +104,41 @@ suite('Notebook API tests', function () { }); suiteSetup(function () { - suiteDisposables.push(vscode.notebook.registerNotebookContentProvider('notebookCoreTest', { - openNotebook: async (_resource: vscode.Uri): Promise => { - if (/.*empty\-.*\.vsctestnb$/.test(_resource.path)) { + suiteDisposables.push(vscode.workspace.registerNotebookContentProvider('notebookCoreTest', { + openNotebook: async (resource: vscode.Uri): Promise => { + if (/.*empty\-.*\.vsctestnb$/.test(resource.path)) { return { - metadata: new vscode.NotebookDocumentMetadata(), + metadata: {}, cells: [] }; } const dto: vscode.NotebookData = { - metadata: new vscode.NotebookDocumentMetadata().with({ custom: { testMetadata: false } }), + metadata: { custom: { testMetadata: false } }, cells: [ { - source: 'test', - language: 'typescript', + value: 'test', + languageId: 'typescript', kind: vscode.NotebookCellKind.Code, outputs: [], - metadata: new vscode.NotebookCellMetadata().with({ custom: { testCellMetadata: 123 } }), - latestExecutionSummary: { startTime: 10, endTime: 20 } + metadata: { custom: { testCellMetadata: 123 } }, + executionSummary: { timing: { startTime: 10, endTime: 20 } } }, { - source: 'test2', - language: 'typescript', + value: 'test2', + languageId: 'typescript', kind: vscode.NotebookCellKind.Code, outputs: [ new vscode.NotebookCellOutput([ - new vscode.NotebookCellOutputItem('text/plain', 'Hello World', { testOutputItemMetadata: true }) + vscode.NotebookCellOutputItem.text('Hello World', 'text/plain') ], - { testOutputMetadata: true }) + { + testOutputMetadata: true, + ['text/plain']: { testOutputItemMetadata: true } + }) ], - latestExecutionSummary: { executionOrder: 5, success: true }, - metadata: new vscode.NotebookCellMetadata().with({ custom: { testCellMetadata: 456 } }) + executionSummary: { executionOrder: 5, success: true }, + metadata: { custom: { testCellMetadata: 456 } } } ] }; @@ -178,12 +162,12 @@ suite('Notebook API tests', function () { let kernel1: Kernel; let kernel2: Kernel; - setup(() => { + setup(async function () { kernel1 = new Kernel('mainKernel', 'Notebook Primary Test Kernel'); - const listener = vscode.notebook.onDidOpenNotebookDocument(async notebook => { - if (notebook.viewType === kernel1.controller.viewType) { + const listener = vscode.workspace.onDidOpenNotebookDocument(async notebook => { + if (notebook.notebookType === kernel1.controller.notebookType) { await vscode.commands.executeCommand('notebook.selectKernel', { extension: 'vscode.vscode-api-tests', id: kernel1.controller.id @@ -195,52 +179,51 @@ suite('Notebook API tests', function () { kernel2 = new class extends Kernel { constructor() { super('secondaryKernel', 'Notebook Secondary Test Kernel'); - this.controller.hasExecutionOrder = false; + this.controller.supportsExecutionOrder = false; } override async _runCell(cell: vscode.NotebookCell) { - const task = this.controller.createNotebookCellExecutionTask(cell); + const task = this.controller.createNotebookCellExecution(cell); task.start(); await task.replaceOutput([new vscode.NotebookCellOutput([ - new vscode.NotebookCellOutputItem('text/plain', ['my second output'], undefined) + vscode.NotebookCellOutputItem.text('my second output', 'text/plain') ])]); - task.end({ success: true }); + task.end(true); } }; testDisposables.push(kernel1.controller, listener, kernel2.controller); + await saveAllFilesAndCloseAll(); }); - teardown(() => { + teardown(async function () { disposeAll(testDisposables); testDisposables.length = 0; + await saveAllFilesAndCloseAll(); }); test('shared document in notebook editors', async function () { - const resource = await createRandomNotebookFile(); let counter = 0; - const disposables: vscode.Disposable[] = []; - disposables.push(vscode.notebook.onDidOpenNotebookDocument(() => { + testDisposables.push(vscode.workspace.onDidOpenNotebookDocument(() => { counter++; })); - disposables.push(vscode.notebook.onDidCloseNotebookDocument(() => { - counter--; - })); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + + const notebook = await openRandomNotebookDocument(); assert.strictEqual(counter, 1); - await splitEditor(); + await vscode.window.showNotebookDocument(notebook, { viewColumn: vscode.ViewColumn.Active }); assert.strictEqual(counter, 1); - await closeAllEditors(); - assert.strictEqual(counter, 0); + assert.strictEqual(vscode.window.visibleNotebookEditors.length, 1); - disposables.forEach(d => d.dispose()); + await vscode.window.showNotebookDocument(notebook, { viewColumn: vscode.ViewColumn.Beside }); + assert.strictEqual(counter, 1); + assert.strictEqual(vscode.window.visibleNotebookEditors.length, 2); }); - test('editor open/close event', async function () { + test('editor onDidChangeVisibleNotebookEditors-event', async function () { const resource = await createRandomNotebookFile(); const firstEditorOpen = asPromise(vscode.window.onDidChangeVisibleNotebookEditors); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + await vscode.window.showNotebookDocument(resource); await firstEditorOpen; const firstEditorClose = asPromise(vscode.window.onDidChangeVisibleNotebookEditors); @@ -248,7 +231,7 @@ suite('Notebook API tests', function () { await firstEditorClose; }); - test('editor open/close event 2', async function () { + test('editor onDidChangeVisibleNotebookEditors-event 2', async function () { const resource = await createRandomNotebookFile(); let count = 0; const disposables: vscode.Disposable[] = []; @@ -256,10 +239,10 @@ suite('Notebook API tests', function () { count = vscode.window.visibleNotebookEditors.length; })); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + await vscode.window.showNotebookDocument(resource, { viewColumn: vscode.ViewColumn.Active }); assert.strictEqual(count, 1); - await splitEditor(); + await vscode.window.showNotebookDocument(resource, { viewColumn: vscode.ViewColumn.Beside }); assert.strictEqual(count, 2); await closeAllEditors(); @@ -289,7 +272,7 @@ suite('Notebook API tests', function () { const resource = await createRandomNotebookFile(); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const cellsChangeEvent = asPromise(vscode.notebook.onDidChangeNotebookCells); + const cellsChangeEvent = asPromise(vscode.notebooks.onDidChangeNotebookCells); await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); const cellChangeEventRet = await cellsChangeEvent; assert.strictEqual(cellChangeEventRet.document, vscode.window.activeNotebookEditor?.document); @@ -303,11 +286,11 @@ suite('Notebook API tests', function () { ] }); - const moveCellEvent = asPromise(vscode.notebook.onDidChangeNotebookCells); + const moveCellEvent = asPromise(vscode.notebooks.onDidChangeNotebookCells); await vscode.commands.executeCommand('notebook.cell.moveUp'); await moveCellEvent; - const cellOutputChange = asPromise(vscode.notebook.onDidChangeCellOutputs); + const cellOutputChange = asPromise(vscode.notebooks.onDidChangeCellOutputs); await vscode.commands.executeCommand('notebook.cell.execute'); const cellOutputsAddedRet = await cellOutputChange; assert.deepStrictEqual(cellOutputsAddedRet, { @@ -316,7 +299,7 @@ suite('Notebook API tests', function () { }); assert.strictEqual(cellOutputsAddedRet.cells[0].outputs.length, 1); - const cellOutputClear = asPromise(vscode.notebook.onDidChangeCellOutputs); + const cellOutputClear = asPromise(vscode.notebooks.onDidChangeCellOutputs); await vscode.commands.executeCommand('notebook.cell.clearOutputs'); const cellOutputsCleardRet = await cellOutputClear; assert.deepStrictEqual(cellOutputsCleardRet, { @@ -325,7 +308,7 @@ suite('Notebook API tests', function () { }); assert.strictEqual(cellOutputsAddedRet.cells[0].outputs.length, 0); - // const cellChangeLanguage = getEventOncePromise(vscode.notebook.onDidChangeCellLanguage); + // const cellChangeLanguage = getEventOncePromise(vscode.notebooks.onDidChangeCellLanguage); // await vscode.commands.executeCommand('notebook.cell.changeToMarkdown'); // const cellChangeLanguageRet = await cellChangeLanguage; // assert.deepStrictEqual(cellChangeLanguageRet, { @@ -333,8 +316,6 @@ suite('Notebook API tests', function () { // cells: vscode.window.activeNotebookEditor!.document.cellAt(0), // language: 'markdown' // }); - - await saveAllFilesAndCloseAll(undefined); }); test('editor move cell event', async function () { @@ -346,7 +327,7 @@ suite('Notebook API tests', function () { const activeCell = getFocusedCell(vscode.window.activeNotebookEditor); assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 0); - const moveChange = asPromise(vscode.notebook.onDidChangeNotebookCells); + const moveChange = asPromise(vscode.notebooks.onDidChangeNotebookCells); await vscode.commands.executeCommand('notebook.cell.moveDown'); await moveChange; await saveAllEditors(); @@ -355,20 +336,20 @@ suite('Notebook API tests', function () { await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); const firstEditor = vscode.window.activeNotebookEditor; assert.strictEqual(firstEditor?.document.cellCount, 2); - await saveAllFilesAndCloseAll(undefined); }); test('notebook editor active/visible', async function () { const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const firstEditor = vscode.window.activeNotebookEditor; - assert.strictEqual(firstEditor && vscode.window.visibleNotebookEditors.indexOf(firstEditor) >= 0, true); + const firstEditor = await vscode.window.showNotebookDocument(resource, { viewColumn: vscode.ViewColumn.Active }); + assert.strictEqual(firstEditor === vscode.window.activeNotebookEditor, true); + assert.strictEqual(vscode.window.visibleNotebookEditors.includes(firstEditor), true); + + const secondEditor = await vscode.window.showNotebookDocument(resource, { viewColumn: vscode.ViewColumn.Beside }); + assert.strictEqual(secondEditor === vscode.window.activeNotebookEditor, true); - await splitEditor(); - const secondEditor = vscode.window.activeNotebookEditor; - assert.strictEqual(secondEditor && vscode.window.visibleNotebookEditors.indexOf(secondEditor) >= 0, true); assert.notStrictEqual(firstEditor, secondEditor); - assert.strictEqual(firstEditor && vscode.window.visibleNotebookEditors.indexOf(firstEditor) >= 0, true); + assert.strictEqual(vscode.window.visibleNotebookEditors.includes(secondEditor), true); + assert.strictEqual(vscode.window.visibleNotebookEditors.includes(firstEditor), true); assert.strictEqual(vscode.window.visibleNotebookEditors.length, 2); const untitledEditorChange = asPromise(vscode.window.onDidChangeActiveNotebookEditor); @@ -386,8 +367,6 @@ suite('Notebook API tests', function () { assert.strictEqual(secondEditor, vscode.window.activeNotebookEditor); assert.strictEqual(vscode.window.visibleNotebookEditors.length, 2); assert.strictEqual(secondEditor && vscode.window.visibleNotebookEditors.indexOf(secondEditor) >= 0, true); - - await saveAllFilesAndCloseAll(undefined); }); test('notebook active editor change', async function () { @@ -399,8 +378,6 @@ suite('Notebook API tests', function () { const firstEditorDeactivate = asPromise(vscode.window.onDidChangeActiveNotebookEditor); await vscode.commands.executeCommand('workbench.action.splitEditor'); await firstEditorDeactivate; - - await saveFileAndCloseAll(resource); }); test('edit API (replaceMetadata)', async function () { @@ -408,7 +385,7 @@ suite('Notebook API tests', function () { await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await vscode.window.activeNotebookEditor!.edit(editBuilder => { - editBuilder.replaceCellMetadata(0, new vscode.NotebookCellMetadata().with({ inputCollapsed: true })); + editBuilder.replaceCellMetadata(0, { inputCollapsed: true }); }); const document = vscode.window.activeNotebookEditor?.document!; @@ -416,17 +393,16 @@ suite('Notebook API tests', function () { assert.strictEqual(document.cellAt(0).metadata.inputCollapsed, true); assert.strictEqual(document.isDirty, true); - await saveFileAndCloseAll(resource); }); test('edit API (replaceMetadata, event)', async function () { const resource = await createRandomNotebookFile(); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const event = asPromise(vscode.notebook.onDidChangeCellMetadata); + const event = asPromise(vscode.notebooks.onDidChangeCellMetadata); await vscode.window.activeNotebookEditor!.edit(editBuilder => { - editBuilder.replaceCellMetadata(0, new vscode.NotebookCellMetadata().with({ inputCollapsed: true })); + editBuilder.replaceCellMetadata(0, { inputCollapsed: true }); }); const data = await event; @@ -434,67 +410,59 @@ suite('Notebook API tests', function () { assert.strictEqual(data.cell.metadata.inputCollapsed, true); assert.strictEqual(data.document.isDirty, true); - await saveFileAndCloseAll(resource); }); test('edit API batch edits', async function () { const resource = await createRandomNotebookFile(); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const cellsChangeEvent = asPromise(vscode.notebook.onDidChangeNotebookCells); - const cellMetadataChangeEvent = asPromise(vscode.notebook.onDidChangeCellMetadata); + const cellsChangeEvent = asPromise(vscode.notebooks.onDidChangeNotebookCells); + const cellMetadataChangeEvent = asPromise(vscode.notebooks.onDidChangeCellMetadata); const version = vscode.window.activeNotebookEditor!.document.version; await vscode.window.activeNotebookEditor!.edit(editBuilder => { - editBuilder.replaceCells(1, 0, [{ kind: vscode.NotebookCellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]); - editBuilder.replaceCellMetadata(0, new vscode.NotebookCellMetadata().with({ inputCollapsed: false })); + editBuilder.replaceCells(1, 0, [{ kind: vscode.NotebookCellKind.Code, languageId: 'javascript', value: 'test 2', outputs: [], metadata: undefined }]); + editBuilder.replaceCellMetadata(0, { inputCollapsed: false }); }); await cellsChangeEvent; await cellMetadataChangeEvent; assert.strictEqual(version + 1, vscode.window.activeNotebookEditor!.document.version); - await saveAllFilesAndCloseAll(resource); }); test('edit API batch edits undo/redo', async function () { const resource = await createRandomNotebookFile(); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const cellsChangeEvent = asPromise(vscode.notebook.onDidChangeNotebookCells); - const cellMetadataChangeEvent = asPromise(vscode.notebook.onDidChangeCellMetadata); + const cellsChangeEvent = asPromise(vscode.notebooks.onDidChangeNotebookCells); + const cellMetadataChangeEvent = asPromise(vscode.notebooks.onDidChangeCellMetadata); const version = vscode.window.activeNotebookEditor!.document.version; await vscode.window.activeNotebookEditor!.edit(editBuilder => { - editBuilder.replaceCells(1, 0, [{ kind: vscode.NotebookCellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]); - editBuilder.replaceCellMetadata(0, new vscode.NotebookCellMetadata().with({ inputCollapsed: false })); + editBuilder.replaceCells(1, 0, [{ kind: vscode.NotebookCellKind.Code, languageId: 'javascript', value: 'test 2', outputs: [], metadata: undefined }]); + editBuilder.replaceCellMetadata(0, { inputCollapsed: false }); }); await cellsChangeEvent; await cellMetadataChangeEvent; assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 3); - assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0)?.metadata?.inputCollapsed, false); + assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0)?.metadata.inputCollapsed, false); assert.strictEqual(version + 1, vscode.window.activeNotebookEditor!.document.version); await vscode.commands.executeCommand('undo'); assert.strictEqual(version + 2, vscode.window.activeNotebookEditor!.document.version); - assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0)?.metadata?.inputCollapsed, undefined); + assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0)?.metadata.inputCollapsed, undefined); assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 2); - - await saveAllFilesAndCloseAll(resource); }); test('initialzation should not emit cell change events.', async function () { const resource = await createRandomNotebookFile(); let count = 0; - const disposables: vscode.Disposable[] = []; - disposables.push(vscode.notebook.onDidChangeNotebookCells(() => { + + testDisposables.push(vscode.notebooks.onDidChangeNotebookCells(() => { count++; })); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); assert.strictEqual(count, 0); - - disposables.forEach(d => d.dispose()); - - await saveFileAndCloseAll(resource); }); // }); @@ -509,20 +477,19 @@ suite('Notebook API tests', function () { const secondCell = vscode.window.activeNotebookEditor!.document.cellAt(1); assert.strictEqual(secondCell!.outputs.length, 1); - assert.deepStrictEqual(secondCell!.outputs[0].metadata, { testOutputMetadata: true }); - assert.strictEqual(secondCell!.outputs[0].outputs.length, 1); - assert.strictEqual(secondCell!.outputs[0].outputs[0].mime, 'text/plain'); - assert.strictEqual(secondCell!.outputs[0].outputs[0].value, 'Hello World'); - assert.deepStrictEqual(secondCell!.outputs[0].outputs[0].metadata, { testOutputItemMetadata: true }); - assert.strictEqual(secondCell!.latestExecutionSummary?.executionOrder, 5); - assert.strictEqual(secondCell!.latestExecutionSummary?.success, true); + assert.deepStrictEqual(secondCell!.outputs[0].metadata, { testOutputMetadata: true, ['text/plain']: { testOutputItemMetadata: true } }); + assert.strictEqual(secondCell!.outputs[0].items.length, 1); + assert.strictEqual(secondCell!.outputs[0].items[0].mime, 'text/plain'); + assert.strictEqual(new TextDecoder().decode(secondCell!.outputs[0].items[0].data), 'Hello World'); + assert.strictEqual(secondCell!.executionSummary?.executionOrder, 5); + assert.strictEqual(secondCell!.executionSummary?.success, true); await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), ''); await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove'); const activeCell = getFocusedCell(vscode.window.activeNotebookEditor); - assert.notEqual(getFocusedCell(vscode.window.activeNotebookEditor), undefined); + assert.notStrictEqual(getFocusedCell(vscode.window.activeNotebookEditor), undefined); assert.strictEqual(activeCell!.document.getText(), ''); assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 4); assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 1); @@ -545,7 +512,7 @@ suite('Notebook API tests', function () { // ---- insert cell above and focus ---- // await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove'); let activeCell = getFocusedCell(vscode.window.activeNotebookEditor); - assert.notEqual(getFocusedCell(vscode.window.activeNotebookEditor), undefined); + assert.notStrictEqual(getFocusedCell(vscode.window.activeNotebookEditor), undefined); assert.strictEqual(activeCell!.document.getText(), ''); assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 4); assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 1); @@ -617,7 +584,7 @@ suite('Notebook API tests', function () { edit.insert(getFocusedCell(vscode.window.activeNotebookEditor)!.document.uri, new vscode.Position(0, 0), 'var abc = 0;'); await vscode.workspace.applyEdit(edit); - const cellsChangeEvent = asPromise(vscode.notebook.onDidChangeNotebookCells); + const cellsChangeEvent = asPromise(vscode.notebooks.onDidChangeNotebookCells); await vscode.commands.executeCommand('notebook.cell.joinAbove'); await cellsChangeEvent; @@ -641,8 +608,6 @@ suite('Notebook API tests', function () { const newActiveCell = getFocusedCell(vscode.window.activeNotebookEditor); assert.deepStrictEqual(activeCell, newActiveCell); - - await saveFileAndCloseAll(resource); }); // test('document runnable based on kernel count', async () => { @@ -660,7 +625,7 @@ suite('Notebook API tests', function () { // currentKernelProvider.setHasKernels(true); - // await withEvent(vscode.notebook.onDidChangeCellOutputs, async (event) => { + // await withEvent(vscode.notebooks.onDidChangeCellOutputs, async (event) => { // await vscode.commands.executeCommand('notebook.execute'); // await event; // assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked @@ -680,8 +645,6 @@ suite('Notebook API tests', function () { await vscode.commands.executeCommand('notebook.execute'); assert.strictEqual(cell.outputs.length, 0, 'should not execute'); // not runnable, didn't work - - await saveAllFilesAndCloseAll(undefined); }); test('cell execute command takes arguments 2', async () => { @@ -691,13 +654,13 @@ suite('Notebook API tests', function () { const editor = vscode.window.activeNotebookEditor!; const cell = editor.document.cellAt(0); - await withEvent(vscode.notebook.onDidChangeCellOutputs, async (event) => { + await withEvent(vscode.notebooks.onDidChangeCellOutputs, async (event) => { await vscode.commands.executeCommand('notebook.execute'); await event; assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked }); - await withEvent(vscode.notebook.onDidChangeCellOutputs, async event => { + await withEvent(vscode.notebooks.onDidChangeCellOutputs, async event => { await vscode.commands.executeCommand('notebook.cell.clearOutputs'); await event; assert.strictEqual(cell.outputs.length, 0, 'should clear'); @@ -706,14 +669,42 @@ suite('Notebook API tests', function () { const secondResource = await createRandomNotebookFile(); await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest'); - await withEvent(vscode.notebook.onDidChangeCellOutputs, async (event) => { + await withEvent(vscode.notebooks.onDidChangeCellOutputs, async (event) => { await vscode.commands.executeCommand('notebook.cell.execute', { start: 0, end: 1 }, resource); await event; assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked assert.strictEqual(vscode.window.activeNotebookEditor?.document.uri.fsPath, secondResource.fsPath); }); + }); - await saveAllFilesAndCloseAll(undefined); + test('cell execute command takes arguments ICellRange[]', async () => { + const resource = await createRandomNotebookFile(); + await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + + vscode.commands.executeCommand('notebook.cell.execute', { ranges: [{ start: 0, end: 1 }, { start: 1, end: 2 }] }); + let firstCellExecuted = false; + let secondCellExecuted = false; + let resolve: () => void; + const p = new Promise(r => resolve = r); + const listener = vscode.notebooks.onDidChangeCellOutputs(e => { + e.cells.forEach(cell => { + if (cell.index === 0) { + firstCellExecuted = true; + } + + if (cell.index === 1) { + secondCellExecuted = true; + } + }); + + if (firstCellExecuted && secondCellExecuted) { + resolve(); + } + }); + + await p; + listener.dispose(); + await saveAllFilesAndCloseAll(); }); test('document execute command takes arguments', async () => { @@ -723,13 +714,13 @@ suite('Notebook API tests', function () { const editor = vscode.window.activeNotebookEditor!; const cell = editor.document.cellAt(0); - await withEvent(vscode.notebook.onDidChangeCellOutputs, async (event) => { + await withEvent(vscode.notebooks.onDidChangeCellOutputs, async (event) => { await vscode.commands.executeCommand('notebook.execute'); await event; assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked }); - const clearChangeEvent = asPromise(vscode.notebook.onDidChangeCellOutputs); + const clearChangeEvent = asPromise(vscode.notebooks.onDidChangeCellOutputs); await vscode.commands.executeCommand('notebook.cell.clearOutputs'); await clearChangeEvent; assert.strictEqual(cell.outputs.length, 0, 'should clear'); @@ -737,47 +728,40 @@ suite('Notebook API tests', function () { const secondResource = await createRandomNotebookFile(); await vscode.commands.executeCommand('vscode.openWith', secondResource, 'notebookCoreTest'); - await withEvent(vscode.notebook.onDidChangeCellOutputs, async (event) => { + await withEvent(vscode.notebooks.onDidChangeCellOutputs, async (event) => { await vscode.commands.executeCommand('notebook.execute', resource); await event; assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked assert.strictEqual(vscode.window.activeNotebookEditor?.document.uri.fsPath, secondResource.fsPath); }); - - await saveAllFilesAndCloseAll(undefined); }); test('cell execute and select kernel', async function () { - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - assert.strictEqual(vscode.window.activeNotebookEditor !== undefined, true, 'notebook first'); - const editor = vscode.window.activeNotebookEditor!; + const notebook = await openRandomNotebookDocument(); + const editor = await vscode.window.showNotebookDocument(notebook); + assert.strictEqual(vscode.window.activeNotebookEditor === editor, true, 'notebook first'); + const cell = editor.document.cellAt(0); - await withEvent(vscode.notebook.onDidChangeCellOutputs, async (event) => { + await withEvent(vscode.notebooks.onDidChangeCellOutputs, async (event) => { + await assertKernel(kernel1, notebook); await vscode.commands.executeCommand('notebook.cell.execute'); await event; assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked - assert.strictEqual(cell.outputs[0].outputs.length, 1); - assert.strictEqual(cell.outputs[0].outputs[0].mime, 'text/plain'); - assert.deepStrictEqual(cell.outputs[0].outputs[0].value, [ - 'my output' - ]); + assert.strictEqual(cell.outputs[0].items.length, 1); + assert.strictEqual(cell.outputs[0].items[0].mime, 'text/plain'); + assert.deepStrictEqual(new TextDecoder().decode(cell.outputs[0].items[0].data), 'my output'); }); - await withEvent(vscode.notebook.onDidChangeCellOutputs, async (event) => { - await assertKernel(kernel2.controller); + await withEvent(vscode.notebooks.onDidChangeCellOutputs, async (event) => { + await assertKernel(kernel2, notebook); await vscode.commands.executeCommand('notebook.cell.execute'); await event; assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked - assert.strictEqual(cell.outputs[0].outputs.length, 1); - assert.strictEqual(cell.outputs[0].outputs[0].mime, 'text/plain'); - assert.deepStrictEqual(cell.outputs[0].outputs[0].value, [ - 'my second output' - ]); + assert.strictEqual(cell.outputs[0].items.length, 1); + assert.strictEqual(cell.outputs[0].items[0].mime, 'text/plain'); + assert.deepStrictEqual(new TextDecoder().decode(cell.outputs[0].items[0].data), 'my second output'); }); - - await saveAllFilesAndCloseAll(undefined); }); test('set outputs on cancel', async () => { @@ -790,87 +774,78 @@ suite('Notebook API tests', function () { override async _execute(cells: vscode.NotebookCell[]) { for (const cell of cells) { - const task = this.controller.createNotebookCellExecutionTask(cell); + const task = this.controller.createNotebookCellExecution(cell); task.start(); task.token.onCancellationRequested(async () => { await task.replaceOutput([new vscode.NotebookCellOutput([ - new vscode.NotebookCellOutputItem('text/plain', ['Canceled'], undefined) + vscode.NotebookCellOutputItem.text('Canceled', 'text/plain') ])]); - task.end({}); + task.end(undefined); }); } } }; - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const editor = vscode.window.activeNotebookEditor!; + const notebook = await openRandomNotebookDocument(); + const editor = await vscode.window.showNotebookDocument(notebook); const cell = editor.document.cellAt(0); - await assertKernel(cancelableKernel.controller); - await withEvent(vscode.notebook.onDidChangeCellOutputs, async (event) => { + await withEvent(vscode.notebooks.onDidChangeCellOutputs, async (event) => { + await assertKernel(cancelableKernel, notebook); + assert.ok(editor === vscode.window.activeNotebookEditor); await vscode.commands.executeCommand('notebook.cell.execute'); await vscode.commands.executeCommand('notebook.cell.cancelExecution'); await event; assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked - assert.strictEqual(cell.outputs[0].outputs.length, 1); - assert.strictEqual(cell.outputs[0].outputs[0].mime, 'text/plain'); - assert.deepStrictEqual(cell.outputs[0].outputs[0].value, [ - 'Canceled' - ]); + assert.strictEqual(cell.outputs[0].items.length, 1); + assert.strictEqual(cell.outputs[0].items[0].mime, 'text/plain'); + assert.deepStrictEqual(new TextDecoder().decode(cell.outputs[0].items[0].data), 'Canceled'); }); cancelableKernel.controller.dispose(); - await saveAllFilesAndCloseAll(undefined); }); test('set outputs on interrupt', async () => { const interruptableKernel = new class extends Kernel { - constructor() { super('interruptableKernel', 'Notebook Interruptable Test Kernel'); this.controller.interruptHandler = this.interrupt.bind(this); } - private _task: vscode.NotebookCellExecutionTask | undefined; + private _task: vscode.NotebookCellExecution | undefined; override async _execute(cells: vscode.NotebookCell[]) { - this._task = this.controller.createNotebookCellExecutionTask(cells[0]); + this._task = this.controller.createNotebookCellExecution(cells[0]); this._task.start(); } - async interrupt() { await this._task!.replaceOutput([new vscode.NotebookCellOutput([ - new vscode.NotebookCellOutputItem('text/plain', ['Interrupted'], undefined) + vscode.NotebookCellOutputItem.text('Interrupted', 'text/plain') ])]); - this._task!.end({}); + this._task!.end(undefined); } }; - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const editor = vscode.window.activeNotebookEditor!; + const notebook = await openRandomNotebookDocument(); + const editor = await vscode.window.showNotebookDocument(notebook); const cell = editor.document.cellAt(0); - await assertKernel(interruptableKernel.controller); - - await withEvent(vscode.notebook.onDidChangeCellOutputs, async (event) => { + await withEvent(vscode.notebooks.onDidChangeCellOutputs, async (event) => { + await assertKernel(interruptableKernel, notebook); + assert.ok(editor === vscode.window.activeNotebookEditor); await vscode.commands.executeCommand('notebook.cell.execute'); await vscode.commands.executeCommand('notebook.cell.cancelExecution'); await event; assert.strictEqual(cell.outputs.length, 1, 'should execute'); // runnable, it worked - assert.strictEqual(cell.outputs[0].outputs.length, 1); - assert.strictEqual(cell.outputs[0].outputs[0].mime, 'text/plain'); - assert.deepStrictEqual(cell.outputs[0].outputs[0].value, [ - 'Interrupted' - ]); + assert.strictEqual(cell.outputs[0].items.length, 1); + assert.strictEqual(cell.outputs[0].items[0].mime, 'text/plain'); + assert.deepStrictEqual(new TextDecoder().decode(cell.outputs[0].items[0].data), 'Interrupted'); }); interruptableKernel.controller.dispose(); - await saveAllFilesAndCloseAll(undefined); }); test('onDidChangeCellExecutionState is fired', async () => { @@ -883,14 +858,14 @@ suite('Notebook API tests', function () { let eventCount = 0; let resolve: () => void; const p = new Promise(r => resolve = r); - const listener = vscode.notebook.onDidChangeCellExecutionState(e => { + const listener = vscode.notebooks.onDidChangeNotebookCellExecutionState(e => { if (eventCount === 0) { - assert.strictEqual(e.executionState, vscode.NotebookCellExecutionState.Pending, 'should be set to Pending'); + assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Pending, 'should be set to Pending'); } else if (eventCount === 1) { - assert.strictEqual(e.executionState, vscode.NotebookCellExecutionState.Executing, 'should be set to Executing'); + assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Executing, 'should be set to Executing'); assert.strictEqual(cell.outputs.length, 0, 'no outputs yet: ' + JSON.stringify(cell.outputs[0])); } else if (eventCount === 2) { - assert.strictEqual(e.executionState, vscode.NotebookCellExecutionState.Idle, 'should be set to Idle'); + assert.strictEqual(e.state, vscode.NotebookCellExecutionState.Idle, 'should be set to Idle'); assert.strictEqual(cell.outputs.length, 1, 'should have an output'); resolve(); } @@ -900,7 +875,6 @@ suite('Notebook API tests', function () { await p; listener.dispose(); - await saveAllFilesAndCloseAll(undefined); }); // suite('notebook dirty state', () => { @@ -930,8 +904,6 @@ suite('Notebook API tests', function () { assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellAt(1), getFocusedCell(vscode.window.activeNotebookEditor)); assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'var abc = 0;'); }); - - await saveFileAndCloseAll(resource); }); // }); @@ -974,8 +946,6 @@ suite('Notebook API tests', function () { // assert.strictEqual(vscode.window.activeNotebookEditor!.document.cellCount, 2); // assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(getFocusedCell(vscode.window.activeNotebookEditor)!), 1); // assert.strictEqual(vscode.window.activeNotebookEditor?.selection?.document.getText(), 'test'); - - await saveFileAndCloseAll(resource); }); test('multiple tabs: dirty + clean', async function () { @@ -999,10 +969,9 @@ suite('Notebook API tests', function () { assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellCount, 4); assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), 'var abc = 0;'); - await saveFileAndCloseAll(resource); }); - test('multiple tabs: two dirty tabs and switching', async function () { + test.skip('multiple tabs: two dirty tabs and switching', async function () { const resource = await createRandomNotebookFile(); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); @@ -1032,27 +1001,26 @@ suite('Notebook API tests', function () { assert.deepStrictEqual(vscode.window.activeNotebookEditor?.document.cellCount, 3); assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.getText(), ''); - await saveAllFilesAndCloseAll(secondResource); }); - test.skip('multiple tabs: different editors with same document', async function () { - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const firstNotebookEditor = vscode.window.activeNotebookEditor; + test('multiple tabs: different editors with same document', async function () { + + const notebook = await openRandomNotebookDocument(); + const firstNotebookEditor = await vscode.window.showNotebookDocument(notebook, { viewColumn: vscode.ViewColumn.One }); + assert.ok(firstNotebookEditor === vscode.window.activeNotebookEditor); + assert.strictEqual(firstNotebookEditor !== undefined, true, 'notebook first'); assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.getText(), 'test'); assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.languageId, 'typescript'); - await splitEditor(); - const secondNotebookEditor = vscode.window.activeNotebookEditor; + const secondNotebookEditor = await vscode.window.showNotebookDocument(notebook, { viewColumn: vscode.ViewColumn.Beside }); assert.strictEqual(secondNotebookEditor !== undefined, true, 'notebook first'); assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.getText(), 'test'); assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor!)?.document.languageId, 'typescript'); - assert.notEqual(firstNotebookEditor, secondNotebookEditor); + assert.notStrictEqual(firstNotebookEditor, secondNotebookEditor); assert.strictEqual(firstNotebookEditor?.document, secondNotebookEditor?.document, 'split notebook editors share the same document'); - await saveAllFilesAndCloseAll(resource); }); test('custom metadata should be supported', async function () { @@ -1063,7 +1031,6 @@ suite('Notebook API tests', function () { assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.metadata.custom!['testCellMetadata'] as number, 123); assert.strictEqual(getFocusedCell(vscode.window.activeNotebookEditor)?.document.languageId, 'typescript'); - await saveFileAndCloseAll(resource); }); @@ -1082,42 +1049,37 @@ suite('Notebook API tests', function () { // assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().indexOf(activeCell!), 1); // assert.strictEqual(activeCell?.metadata.custom!['testCellMetadata'] as number, 123); - await saveFileAndCloseAll(resource); }); - test('#106657. Opening a notebook from markers view is broken ', async function () { - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + test.skip('#106657. Opening a notebook from markers view is broken ', async function () { - const document = vscode.window.activeNotebookEditor?.document!; + const document = await openRandomNotebookDocument(); const [cell] = document.getCells(); - await saveAllFilesAndCloseAll(document.uri); assert.strictEqual(vscode.window.activeNotebookEditor, undefined); // opening a cell-uri opens a notebook editor - await vscode.commands.executeCommand('vscode.open', cell.document.uri, vscode.ViewColumn.Active); + await vscode.window.showTextDocument(cell.document, { viewColumn: vscode.ViewColumn.Active }); + // await vscode.commands.executeCommand('vscode.open', cell.document.uri, vscode.ViewColumn.Active); assert.strictEqual(!!vscode.window.activeNotebookEditor, true); - assert.strictEqual(vscode.window.activeNotebookEditor!.document.uri.toString(), resource.toString()); + assert.strictEqual(vscode.window.activeNotebookEditor!.document.uri.toString(), document.uri.toString()); }); - test.skip('Cannot open notebook from cell-uri with vscode.open-command', async function () { - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + test('Cannot open notebook from cell-uri with vscode.open-command', async function () { - const document = vscode.window.activeNotebookEditor?.document!; + const document = await openRandomNotebookDocument(); const [cell] = document.getCells(); - await saveAllFilesAndCloseAll(document.uri); + await saveAllFilesAndCloseAll(); assert.strictEqual(vscode.window.activeNotebookEditor, undefined); // BUG is that the editor opener (https://github.com/microsoft/vscode/blob/8e7877bdc442f1e83a7fec51920d82b696139129/src/vs/editor/browser/services/openerService.ts#L69) // removes the fragment if it matches something numeric. For notebooks that's not wanted... await vscode.commands.executeCommand('vscode.open', cell.document.uri); - assert.strictEqual(vscode.window.activeNotebookEditor!.document.uri.toString(), resource.toString()); + assert.strictEqual(vscode.window.activeNotebookEditor!.document.uri.toString(), document.uri.toString()); }); test('#97830, #97764. Support switch to other editor types', async function () { @@ -1137,8 +1099,6 @@ suite('Notebook API tests', function () { await vscode.commands.executeCommand('vscode.openWith', resource, 'default'); assert.strictEqual(vscode.window.activeTextEditor?.document.uri.path, resource.path); - - await closeAllEditors(); }); // open text editor, pin, and then open a notebook @@ -1151,15 +1111,14 @@ suite('Notebook API tests', function () { // now it's dirty, open the resource with notebook editor should open a new one await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - assert.notEqual(vscode.window.activeNotebookEditor, undefined, 'notebook first'); - // assert.notEqual(vscode.window.activeTextEditor, undefined); + assert.notStrictEqual(vscode.window.activeNotebookEditor, undefined, 'notebook first'); + // assert.notStrictEqual(vscode.window.activeTextEditor, undefined); - await closeAllEditors(); }); test('#102411 - untitled notebook creation failed', async function () { await vscode.commands.executeCommand('workbench.action.files.newUntitledFile', { viewType: 'notebookCoreTest' }); - assert.notEqual(vscode.window.activeNotebookEditor, undefined, 'untitled notebook editor is not undefined'); + assert.notStrictEqual(vscode.window.activeNotebookEditor, undefined, 'untitled notebook editor is not undefined'); await closeAllEditors(); }); @@ -1182,26 +1141,26 @@ suite('Notebook API tests', function () { await vscode.workspace.applyEdit(edit); assert.strictEqual(vscode.window.activeNotebookEditor!.document.getCells().length, 3); - assert.notEqual(vscode.window.activeNotebookEditor!.document.cellAt(0).document.getText(), vscode.window.activeNotebookEditor!.document.cellAt(1).document.getText()); + assert.notStrictEqual(vscode.window.activeNotebookEditor!.document.cellAt(0).document.getText(), vscode.window.activeNotebookEditor!.document.cellAt(1).document.getText()); await closeAllEditors(); }); test('#115855 onDidSaveNotebookDocument', async function () { const resource = await createRandomNotebookFile(); - const notebook = await vscode.notebook.openNotebookDocument(resource); + const notebook = await vscode.workspace.openNotebookDocument(resource); const editor = await vscode.window.showNotebookDocument(notebook); - const cellsChangeEvent = asPromise(vscode.notebook.onDidChangeNotebookCells); + const cellsChangeEvent = asPromise(vscode.notebooks.onDidChangeNotebookCells); await editor.edit(editBuilder => { - editBuilder.replaceCells(1, 0, [{ kind: vscode.NotebookCellKind.Code, language: 'javascript', source: 'test 2', outputs: [], metadata: undefined }]); + editBuilder.replaceCells(1, 0, [{ kind: vscode.NotebookCellKind.Code, languageId: 'javascript', value: 'test 2', outputs: [], metadata: undefined }]); }); const cellChangeEventRet = await cellsChangeEvent; assert.strictEqual(cellChangeEventRet.document === notebook, true); assert.strictEqual(cellChangeEventRet.document.isDirty, true); - const saveEvent = asPromise(vscode.notebook.onDidSaveNotebookDocument); + const saveEvent = asPromise(vscode.notebooks.onDidSaveNotebookDocument); await notebook.save(); @@ -1210,6 +1169,9 @@ suite('Notebook API tests', function () { }); test('Output changes are applied once the promise resolves', async function () { + + let called = false; + const verifyOutputSyncKernel = new class extends Kernel { constructor() { @@ -1218,54 +1180,51 @@ suite('Notebook API tests', function () { override async _execute(cells: vscode.NotebookCell[]) { const [cell] = cells; - const task = this.controller.createNotebookCellExecutionTask(cell); + const task = this.controller.createNotebookCellExecution(cell); task.start(); await task.replaceOutput([new vscode.NotebookCellOutput([ - new vscode.NotebookCellOutputItem('text/plain', ['Some output'], undefined) + vscode.NotebookCellOutputItem.text('Some output', 'text/plain') ])]); assert.strictEqual(cell.notebook.cellAt(0).outputs.length, 1); - assert.deepStrictEqual(cell.notebook.cellAt(0).outputs[0].outputs[0].value, ['Some output']); - task.end({}); + assert.deepStrictEqual(new TextDecoder().decode(cell.notebook.cellAt(0).outputs[0].items[0].data), 'Some output'); + task.end(undefined); + called = true; } }; - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - await assertKernel(verifyOutputSyncKernel.controller); + const notebook = await openRandomNotebookDocument(); + await vscode.window.showNotebookDocument(notebook); + await assertKernel(verifyOutputSyncKernel, notebook); await vscode.commands.executeCommand('notebook.cell.execute'); - - await saveAllFilesAndCloseAll(undefined); + assert.strictEqual(called, true); verifyOutputSyncKernel.controller.dispose(); }); - test('latestExecutionSummary', async () => { + test('executionSummary', async () => { const resource = await createRandomNotebookFile(); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); const editor = vscode.window.activeNotebookEditor!; const cell = editor.document.cellAt(0); - assert.strictEqual(cell.latestExecutionSummary?.success, undefined); - assert.strictEqual(cell.latestExecutionSummary?.executionOrder, undefined); + assert.strictEqual(cell.executionSummary?.success, undefined); + assert.strictEqual(cell.executionSummary?.executionOrder, undefined); await vscode.commands.executeCommand('notebook.cell.execute'); assert.strictEqual(cell.outputs.length, 1, 'should execute'); - assert.ok(cell.latestExecutionSummary); - assert.strictEqual(cell.latestExecutionSummary!.success, true); - assert.strictEqual(typeof cell.latestExecutionSummary!.executionOrder, 'number'); + assert.ok(cell.executionSummary); + assert.strictEqual(cell.executionSummary!.success, true); + assert.strictEqual(typeof cell.executionSummary!.executionOrder, 'number'); - await saveAllFilesAndCloseAll(undefined); }); - test('initialize latestExecutionSummary', async () => { - const resource = await createRandomNotebookFile(); - await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); - const editor = vscode.window.activeNotebookEditor!; - const cell = editor.document.cellAt(0); + test('initialize executionSummary', async () => { + + const document = await openRandomNotebookDocument(); + const cell = document.cellAt(0); - assert.strictEqual(cell.latestExecutionSummary?.success, undefined); - assert.strictEqual(cell.latestExecutionSummary?.startTime, 10); - assert.strictEqual(cell.latestExecutionSummary?.endTime, 20); + assert.strictEqual(cell.executionSummary?.success, undefined); + assert.strictEqual(cell.executionSummary?.timing?.startTime, 10); + assert.strictEqual(cell.executionSummary?.timing?.endTime, 20); - await saveAllFilesAndCloseAll(undefined); }); @@ -1273,7 +1232,7 @@ suite('Notebook API tests', function () { const emitter = new vscode.EventEmitter(); const onDidCallProvide = emitter.event; suiteSetup(() => { - vscode.notebook.registerNotebookCellStatusBarItemProvider({ viewType: 'notebookCoreTest' }, { + vscode.notebooks.registerNotebookCellStatusBarItemProvider('notebookCoreTest', { async provideCellStatusBarItems(cell: vscode.NotebookCell, _token: vscode.CancellationToken): Promise { emitter.fire(cell); return []; @@ -1288,7 +1247,7 @@ suite('Notebook API tests', function () { await provideCalled; const edit = new vscode.WorkspaceEdit(); - edit.replaceNotebookCellMetadata(resource, 0, new vscode.NotebookCellMetadata().with({ inputCollapsed: true })); + edit.replaceNotebookCellMetadata(resource, 0, { inputCollapsed: true }); vscode.workspace.applyEdit(edit); await provideCalled; }); diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/quickInput.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/quickInput.test.ts similarity index 85% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/quickInput.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/quickInput.test.ts index 701c947426bc..0b3b4e921023 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/quickInput.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/quickInput.test.ts @@ -216,10 +216,10 @@ function createQuickPick(expected: QuickPickExpected, done: (err?: any) => void, } try { eventIndex++; - assert.equal('active', expected.events.shift(), `onDidChangeActive (event ${eventIndex})`); + assert.strictEqual('active', expected.events.shift(), `onDidChangeActive (event ${eventIndex})`); const expectedItems = expected.activeItems.shift(); - assert.deepEqual(items.map(item => item.label), expectedItems, `onDidChangeActive event items (event ${eventIndex})`); - assert.deepEqual(quickPick.activeItems.map(item => item.label), expectedItems, `onDidChangeActive active items (event ${eventIndex})`); + assert.deepStrictEqual(items.map(item => item.label), expectedItems, `onDidChangeActive event items (event ${eventIndex})`); + assert.deepStrictEqual(quickPick.activeItems.map(item => item.label), expectedItems, `onDidChangeActive active items (event ${eventIndex})`); } catch (err) { done(err); } @@ -231,10 +231,10 @@ function createQuickPick(expected: QuickPickExpected, done: (err?: any) => void, } try { eventIndex++; - assert.equal('selection', expected.events.shift(), `onDidChangeSelection (event ${eventIndex})`); + assert.strictEqual('selection', expected.events.shift(), `onDidChangeSelection (event ${eventIndex})`); const expectedItems = expected.selectionItems.shift(); - assert.deepEqual(items.map(item => item.label), expectedItems, `onDidChangeSelection event items (event ${eventIndex})`); - assert.deepEqual(quickPick.selectedItems.map(item => item.label), expectedItems, `onDidChangeSelection selected items (event ${eventIndex})`); + assert.deepStrictEqual(items.map(item => item.label), expectedItems, `onDidChangeSelection event items (event ${eventIndex})`); + assert.deepStrictEqual(quickPick.selectedItems.map(item => item.label), expectedItems, `onDidChangeSelection selected items (event ${eventIndex})`); } catch (err) { done(err); } @@ -246,11 +246,11 @@ function createQuickPick(expected: QuickPickExpected, done: (err?: any) => void, } try { eventIndex++; - assert.equal('accept', expected.events.shift(), `onDidAccept (event ${eventIndex})`); + assert.strictEqual('accept', expected.events.shift(), `onDidAccept (event ${eventIndex})`); const expectedActive = expected.acceptedItems.active.shift(); - assert.deepEqual(quickPick.activeItems.map(item => item.label), expectedActive, `onDidAccept active items (event ${eventIndex})`); + assert.deepStrictEqual(quickPick.activeItems.map(item => item.label), expectedActive, `onDidAccept active items (event ${eventIndex})`); const expectedSelection = expected.acceptedItems.selection.shift(); - assert.deepEqual(quickPick.selectedItems.map(item => item.label), expectedSelection, `onDidAccept selected items (event ${eventIndex})`); + assert.deepStrictEqual(quickPick.selectedItems.map(item => item.label), expectedSelection, `onDidAccept selected items (event ${eventIndex})`); if (expected.acceptedItems.dispose.shift()) { quickPick.dispose(); } @@ -265,7 +265,7 @@ function createQuickPick(expected: QuickPickExpected, done: (err?: any) => void, return; } try { - assert.equal('hide', expected.events.shift()); + assert.strictEqual('hide', expected.events.shift()); done(); } catch (err) { done(err); diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/rpc.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/rpc.test.ts similarity index 91% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/rpc.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/rpc.test.ts index 2b336f097189..5fdf01fada48 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/rpc.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/rpc.test.ts @@ -90,8 +90,14 @@ suite('vscode', function () { }); test('no rpc, createNotebookEditorDecorationType(...)', function () { - const item = vscode.notebook.createNotebookEditorDecorationType({ top: {} }); + const item = vscode.notebooks.createNotebookEditorDecorationType({ top: {} }); dispo.push(item); assertNoRpcFromEntry([item, 'NotebookEditorDecorationType']); }); + + test('no rpc, createNotebookController(...)', function () { + const ctrl = vscode.notebooks.createNotebookController('foo', 'bar', ''); + dispo.push(ctrl); + assertNoRpcFromEntry([ctrl, 'NotebookController']); + }); }); diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts similarity index 96% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index a23d3e55c73f..da2da9499fcc 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -504,6 +504,41 @@ import { assertNoRpc } from '../utils'; const terminal = window.createTerminal({ name: 'foo', pty }); }); + test('should change terminal name', (done) => { + disposables.push(window.onDidOpenTerminal(term => { + try { + equal(terminal, term); + equal(terminal.name, 'foo'); + } catch (e) { + done(e); + return; + } + disposables.push(window.onDidCloseTerminal(t => { + try { + equal(terminal, t); + equal(terminal.name, 'bar'); + } catch (e) { + done(e); + return; + } + done(); + })); + })); + const changeNameEmitter = new EventEmitter(); + const closeEmitter = new EventEmitter(); + const pty: Pseudoterminal = { + onDidWrite: new EventEmitter().event, + onDidChangeName: changeNameEmitter.event, + onDidClose: closeEmitter.event, + open: () => { + changeNameEmitter.fire('bar'); + closeEmitter.fire(undefined); + }, + close: () => { } + }; + const terminal = window.createTerminal({ name: 'foo', pty }); + }); + test('exitStatus.code should be set to the exit code (undefined)', (done) => { disposables.push(window.onDidOpenTerminal(term => { try { diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/types.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/types.test.ts similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/types.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/types.test.ts diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts similarity index 98% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts index 629fbaace14b..f706b64677f0 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts @@ -17,7 +17,7 @@ function workspaceFile(...segments: string[]) { const testDocument = workspaceFile('bower.json'); -suite.skip('vscode API - webview', () => { +suite('vscode API - webview', () => { const disposables: vscode.Disposable[] = []; function _register(disposable: T) { @@ -400,7 +400,7 @@ suite.skip('vscode API - webview', () => { }); } - test('webviews should transfer ArrayBuffers to and from webviews', async () => { + test.skip('webviews should transfer ArrayBuffers to and from webviews', async () => { const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true, retainContextWhenHidden: true })); const ready = getMessage(webview); webview.webview.html = createHtmlDocumentWithBody(/*html*/` @@ -451,7 +451,7 @@ suite.skip('vscode API - webview', () => { } }); - test('webviews should transfer Typed arrays to and from webviews', async () => { + test.skip('webviews should transfer Typed arrays to and from webviews', async () => { const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true, retainContextWhenHidden: true })); const ready = getMessage(webview); webview.webview.html = createHtmlDocumentWithBody(/*html*/` diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts similarity index 86% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts index c30ab5138373..0a403549ce28 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { workspace, window, commands, ViewColumn, TextEditorViewColumnChangeEvent, Uri, Selection, Position, CancellationTokenSource, TextEditorSelectionChangeKind, QuickPickItem, TextEditor } from 'vscode'; +import { workspace, window, commands, ViewColumn, TextEditorViewColumnChangeEvent, Uri, Selection, Position, CancellationTokenSource, TextEditorSelectionChangeKind, QuickPickItem, TextEditor, StatusBarAlignment } from 'vscode'; import { join } from 'path'; import { closeAllEditors, pathEquals, createRandomFile, assertNoRpc } from '../utils'; @@ -34,20 +34,20 @@ suite('vscode API - window', () => { }); // test('editor, UN-active text editor', () => { - // assert.equal(window.visibleTextEditors.length, 0); + // assert.strictEqual(window.visibleTextEditors.length, 0); // assert.ok(window.activeTextEditor === undefined); // }); test('editor, assign and check view columns', async () => { const doc = await workspace.openTextDocument(join(workspace.rootPath || '', './far.js')); let p1 = window.showTextDocument(doc, ViewColumn.One).then(editor => { - assert.equal(editor.viewColumn, ViewColumn.One); + assert.strictEqual(editor.viewColumn, ViewColumn.One); }); let p2 = window.showTextDocument(doc, ViewColumn.Two).then(editor_1 => { - assert.equal(editor_1.viewColumn, ViewColumn.Two); + assert.strictEqual(editor_1.viewColumn, ViewColumn.Two); }); let p3 = window.showTextDocument(doc, ViewColumn.Three).then(editor_2 => { - assert.equal(editor_2.viewColumn, ViewColumn.Three); + assert.strictEqual(editor_2.viewColumn, ViewColumn.Three); }); return Promise.all([p1, p2, p3]); }); @@ -60,13 +60,13 @@ suite('vscode API - window', () => { const doc = await workspace.openTextDocument(join(workspace.rootPath || '', './far.js')); await window.showTextDocument(doc, ViewColumn.One); - assert.equal(eventCounter, 1); + assert.strictEqual(eventCounter, 1); await window.showTextDocument(doc, ViewColumn.Two); - assert.equal(eventCounter, 2); + assert.strictEqual(eventCounter, 2); await window.showTextDocument(doc, ViewColumn.Three); - assert.equal(eventCounter, 3); + assert.strictEqual(eventCounter, 3); reg.dispose(); }); @@ -138,10 +138,10 @@ suite('vscode API - window', () => { return commands.executeCommand('workbench.action.moveActiveEditorGroupLeft'); }).then(() => { - assert.equal(actualEvents.length, 2); + assert.strictEqual(actualEvents.length, 2); for (const event of actualEvents) { - assert.equal(event.viewColumn, event.textEditor.viewColumn); + assert.strictEqual(event.viewColumn, event.textEditor.viewColumn); } registration1.dispose(); @@ -202,7 +202,7 @@ suite('vscode API - window', () => { assert.ok(window.activeTextEditor); assert.ok(window.activeTextEditor!.document === docB); - assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.Two); + assert.strictEqual(window.activeTextEditor!.viewColumn, ViewColumn.Two); const editor = await window.showTextDocument(docC); assert.ok( @@ -210,7 +210,7 @@ suite('vscode API - window', () => { `wanted fileName:${editor.document.fileName}/viewColumn:${editor.viewColumn} but got fileName:${window.activeTextEditor!.document.fileName}/viewColumn:${window.activeTextEditor!.viewColumn}. a:${docA.fileName}, b:${docB.fileName}, c:${docC.fileName}` ); assert.ok(window.activeTextEditor!.document === docC); - assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.Two); + assert.strictEqual(window.activeTextEditor!.viewColumn, ViewColumn.Two); }); test('showTextDocument ViewColumn.BESIDE', async () => { @@ -225,12 +225,12 @@ suite('vscode API - window', () => { assert.ok(window.activeTextEditor); assert.ok(window.activeTextEditor!.document === docB); - assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.Two); + assert.strictEqual(window.activeTextEditor!.viewColumn, ViewColumn.Two); await window.showTextDocument(docC, ViewColumn.Beside); assert.ok(window.activeTextEditor!.document === docC); - assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.Three); + assert.strictEqual(window.activeTextEditor!.viewColumn, ViewColumn.Three); }); test('showTextDocument ViewColumn is always defined (even when opening > ViewColumn.Nine)', async () => { @@ -260,7 +260,7 @@ suite('vscode API - window', () => { assert.ok(window.activeTextEditor); assert.ok(window.activeTextEditor!.document === doc10); - assert.equal(window.activeTextEditor!.viewColumn, 10); + assert.strictEqual(window.activeTextEditor!.viewColumn, 10); }); test('issue #27408 - showTextDocument & vscode.diff always default to ViewColumn.One', async () => { @@ -275,12 +275,12 @@ suite('vscode API - window', () => { assert.ok(window.activeTextEditor); assert.ok(window.activeTextEditor!.document === docB); - assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.Two); + assert.strictEqual(window.activeTextEditor!.viewColumn, ViewColumn.Two); await window.showTextDocument(docC, ViewColumn.Active); assert.ok(window.activeTextEditor!.document === docC); - assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.Two); + assert.strictEqual(window.activeTextEditor!.viewColumn, ViewColumn.Two); }); test('issue #5362 - Incorrect TextEditor passed by onDidChangeTextEditorSelection', (done) => { @@ -359,7 +359,7 @@ suite('vscode API - window', () => { const p = window.showInputBox(undefined, source.token); source.cancel(); const value = await p; - assert.equal(value, undefined); + assert.strictEqual(value, undefined); }); test('showInputBox - cancel early', async function () { @@ -367,21 +367,21 @@ suite('vscode API - window', () => { source.cancel(); const p = window.showInputBox(undefined, source.token); const value = await p; - assert.equal(value, undefined); + assert.strictEqual(value, undefined); }); test('showInputBox - \'\' on Enter', function () { const p = window.showInputBox(); return Promise.all([ commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem'), - p.then(value => assert.equal(value, '')) + p.then(value => assert.strictEqual(value, '')) ]); }); test('showInputBox - default value on Enter', function () { const p = window.showInputBox({ value: 'farboo' }); return Promise.all([ - p.then(value => assert.equal(value, 'farboo')), + p.then(value => assert.strictEqual(value, 'farboo')), commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem'), ]); }); @@ -390,7 +390,7 @@ suite('vscode API - window', () => { const p = window.showInputBox(); return Promise.all([ commands.executeCommand('workbench.action.closeQuickOpen'), - p.then(value => assert.equal(value, undefined)) + p.then(value => assert.strictEqual(value, undefined)) ]); }); @@ -398,17 +398,17 @@ suite('vscode API - window', () => { const p = window.showInputBox({ value: 'farboo' }); return Promise.all([ commands.executeCommand('workbench.action.closeQuickOpen'), - p.then(value => assert.equal(value, undefined)) + p.then(value => assert.strictEqual(value, undefined)) ]); }); test('showInputBox - value not empty on second try', async function () { const one = window.showInputBox({ value: 'notempty' }); await commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem'); - assert.equal(await one, 'notempty'); + assert.strictEqual(await one, 'notempty'); const two = window.showInputBox({ value: 'notempty' }); await commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem'); - assert.equal(await two, 'notempty'); + assert.strictEqual(await two, 'notempty'); }); test('showQuickPick, accept first', async function () { @@ -417,9 +417,9 @@ suite('vscode API - window', () => { const pick = window.showQuickPick(['eins', 'zwei', 'drei'], { onDidSelectItem: tracker.onDidSelectItem }); - assert.equal(await first, 'eins'); + assert.strictEqual(await first, 'eins'); await commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem'); - assert.equal(await pick, 'eins'); + assert.strictEqual(await pick, 'eins'); return tracker.done(); }); @@ -429,12 +429,12 @@ suite('vscode API - window', () => { const pick = window.showQuickPick(['eins', 'zwei', 'drei'], { onDidSelectItem: tracker.onDidSelectItem }); - assert.equal(await first, 'eins'); + assert.strictEqual(await first, 'eins'); const second = tracker.nextItem(); await commands.executeCommand('workbench.action.quickOpenSelectNext'); - assert.equal(await second, 'zwei'); + assert.strictEqual(await second, 'zwei'); await commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem'); - assert.equal(await pick, 'zwei'); + assert.strictEqual(await pick, 'zwei'); return tracker.done(); }); @@ -457,14 +457,14 @@ suite('vscode API - window', () => { // console.log(`${label}: ${++i}`); await commands.executeCommand('workbench.action.quickOpenSelectNext'); // console.log(`${label}: ${++i}`); - assert.equal(await first, 'eins'); + assert.strictEqual(await first, 'eins'); // console.log(`${label}: ${++i}`); await commands.executeCommand('workbench.action.quickPickManyToggle'); // console.log(`${label}: ${++i}`); const second = new Promise(resolve => resolves.push(resolve)); await commands.executeCommand('workbench.action.quickOpenSelectNext'); // console.log(`${label}: ${++i}`); - assert.equal(await second, 'zwei'); + assert.strictEqual(await second, 'zwei'); // console.log(`${label}: ${++i}`); await commands.executeCommand('workbench.action.quickPickManyToggle'); // console.log(`${label}: ${++i}`); @@ -503,7 +503,7 @@ suite('vscode API - window', () => { const p = window.showQuickPick(['eins', 'zwei', 'drei'], undefined, source.token); source.cancel(); return p.then(value => { - assert.equal(value, undefined); + assert.strictEqual(value, undefined); }); }); @@ -512,7 +512,7 @@ suite('vscode API - window', () => { source.cancel(); const p = window.showQuickPick(['eins', 'zwei', 'drei'], undefined, source.token); return p.then(value => { - assert.equal(value, undefined); + assert.strictEqual(value, undefined); }); }); @@ -522,7 +522,7 @@ suite('vscode API - window', () => { const result = window.showQuickPick(['eins', 'zwei', 'drei'], { ignoreFocusOut: true }).then(result => { source.cancel(); - assert.equal(result, undefined); + assert.strictEqual(result, undefined); }); window.showQuickPick(['eins', 'zwei', 'drei'], undefined, source.token); @@ -533,7 +533,7 @@ suite('vscode API - window', () => { test('showQuickPick, canceled by input', function () { const result = window.showQuickPick(['eins', 'zwei', 'drei'], { ignoreFocusOut: true }).then(result => { - assert.equal(result, undefined); + assert.strictEqual(result, undefined); }); const source = new CancellationTokenSource(); @@ -553,7 +553,7 @@ suite('vscode API - window', () => { const result = window.showQuickPick(data, undefined, source.token); source.cancel(); const value_1 = await result; - assert.equal(value_1, undefined); + assert.strictEqual(value_1, undefined); }); test('showQuickPick, never resolve promise and cancel - #22453', function () { @@ -561,7 +561,7 @@ suite('vscode API - window', () => { const result = window.showQuickPick(new Promise(_resolve => { })); const a = result.then(value => { - assert.equal(value, undefined); + assert.strictEqual(value, undefined); }); const b = commands.executeCommand('workbench.action.closeQuickOpen'); return Promise.all([a, b]); @@ -598,7 +598,7 @@ suite('vscode API - window', () => { await commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem'); await commands.executeCommand('workbench.action.closeQuickOpen'); - assert.equal(await result, undefined); + assert.strictEqual(await result, undefined); }); function createQuickPickTracker() { @@ -627,7 +627,7 @@ suite('vscode API - window', () => { let subscription = window.onDidChangeTextEditorSelection(e => { assert.ok(e.textEditor === editor); - assert.equal(e.kind, TextEditorSelectionChangeKind.Command); + assert.strictEqual(e.kind, TextEditorSelectionChangeKind.Command); subscription.dispose(); resolve(); @@ -638,4 +638,22 @@ suite('vscode API - window', () => { }); }); + + test('createStatusBar', async function () { + const statusBarEntryWithoutId = window.createStatusBarItem(StatusBarAlignment.Left, 100); + assert.strictEqual(statusBarEntryWithoutId.id, 'vscode.vscode-api-tests'); + assert.strictEqual(statusBarEntryWithoutId.alignment, StatusBarAlignment.Left); + assert.strictEqual(statusBarEntryWithoutId.priority, 100); + assert.strictEqual(statusBarEntryWithoutId.name, undefined); + statusBarEntryWithoutId.name = 'Test Name'; + assert.strictEqual(statusBarEntryWithoutId.name, 'Test Name'); + + const statusBarEntryWithId = window.createStatusBarItem('testId', StatusBarAlignment.Right, 200); + assert.strictEqual(statusBarEntryWithId.alignment, StatusBarAlignment.Right); + assert.strictEqual(statusBarEntryWithId.priority, 200); + assert.strictEqual(statusBarEntryWithId.id, 'testId'); + assert.strictEqual(statusBarEntryWithId.name, undefined); + statusBarEntryWithId.name = 'Test Name'; + assert.strictEqual(statusBarEntryWithId.name, 'Test Name'); + }); }); diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/workspace.event.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.event.test.ts similarity index 82% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/workspace.event.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/workspace.event.test.ts index 10ef9563c874..cdb2217512bb 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/workspace.event.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.event.test.ts @@ -35,12 +35,12 @@ suite('vscode API - workspace events', () => { assert.ok(success); assert.ok(onWillCreate); - assert.equal(onWillCreate?.files.length, 1); - assert.equal(onWillCreate?.files[0].toString(), newUri.toString()); + assert.strictEqual(onWillCreate?.files.length, 1); + assert.strictEqual(onWillCreate?.files[0].toString(), newUri.toString()); assert.ok(onDidCreate); - assert.equal(onDidCreate?.files.length, 1); - assert.equal(onDidCreate?.files[0].toString(), newUri.toString()); + assert.strictEqual(onDidCreate?.files.length, 1); + assert.strictEqual(onDidCreate?.files[0].toString(), newUri.toString()); })); test('onWillCreate/onDidCreate, make changes, edit another file', withLogDisabled(async function () { @@ -62,7 +62,7 @@ suite('vscode API - workspace events', () => { const success = await vscode.workspace.applyEdit(edit); assert.ok(success); - assert.equal(baseDoc.getText(), 'HALLO_NEW'); + assert.strictEqual(baseDoc.getText(), 'HALLO_NEW'); })); test('onWillCreate/onDidCreate, make changes, edit new file fails', withLogDisabled(async function () { @@ -83,8 +83,8 @@ suite('vscode API - workspace events', () => { const success = await vscode.workspace.applyEdit(edit); assert.ok(success); - assert.equal((await vscode.workspace.fs.readFile(newUri)).toString(), ''); - assert.equal((await vscode.workspace.openTextDocument(newUri)).getText(), ''); + assert.strictEqual((await vscode.workspace.fs.readFile(newUri)).toString(), ''); + assert.strictEqual((await vscode.workspace.openTextDocument(newUri)).getText(), ''); })); test('onWillDelete/onDidDelete', withLogDisabled(async function () { @@ -104,12 +104,12 @@ suite('vscode API - workspace events', () => { assert.ok(success); assert.ok(onWilldelete); - assert.equal(onWilldelete?.files.length, 1); - assert.equal(onWilldelete?.files[0].toString(), base.toString()); + assert.strictEqual(onWilldelete?.files.length, 1); + assert.strictEqual(onWilldelete?.files[0].toString(), base.toString()); assert.ok(onDiddelete); - assert.equal(onDiddelete?.files.length, 1); - assert.equal(onDiddelete?.files[0].toString(), base.toString()); + assert.strictEqual(onDiddelete?.files.length, 1); + assert.strictEqual(onDiddelete?.files[0].toString(), base.toString()); })); test('onWillDelete/onDidDelete, make changes', withLogDisabled(async function () { @@ -190,14 +190,14 @@ suite('vscode API - workspace events', () => { assert.ok(success); assert.ok(onWillRename); - assert.equal(onWillRename?.files.length, 1); - assert.equal(onWillRename?.files[0].oldUri.toString(), oldUri.toString()); - assert.equal(onWillRename?.files[0].newUri.toString(), newUri.toString()); + assert.strictEqual(onWillRename?.files.length, 1); + assert.strictEqual(onWillRename?.files[0].oldUri.toString(), oldUri.toString()); + assert.strictEqual(onWillRename?.files[0].newUri.toString(), newUri.toString()); assert.ok(onDidRename); - assert.equal(onDidRename?.files.length, 1); - assert.equal(onDidRename?.files[0].oldUri.toString(), oldUri.toString()); - assert.equal(onDidRename?.files[0].newUri.toString(), newUri.toString()); + assert.strictEqual(onDidRename?.files.length, 1); + assert.strictEqual(onDidRename?.files[0].oldUri.toString(), oldUri.toString()); + assert.strictEqual(onDidRename?.files[0].newUri.toString(), newUri.toString()); })); test('onWillRename - make changes (saved file)', withLogDisabled(function () { @@ -244,15 +244,15 @@ suite('vscode API - workspace events', () => { assert.ok(success); assert.ok(onWillRename); - assert.equal(onWillRename?.files.length, 1); - assert.equal(onWillRename?.files[0].oldUri.toString(), oldUri.toString()); - assert.equal(onWillRename?.files[0].newUri.toString(), newUri.toString()); + assert.strictEqual(onWillRename?.files.length, 1); + assert.strictEqual(onWillRename?.files[0].oldUri.toString(), oldUri.toString()); + assert.strictEqual(onWillRename?.files[0].newUri.toString(), newUri.toString()); const newDocument = await vscode.workspace.openTextDocument(newUri); const anotherDocument = await vscode.workspace.openTextDocument(anotherFile); - assert.equal(newDocument.getText(), withDirtyFile ? 'FOOBARBAR' : 'FOOBAR'); - assert.equal(anotherDocument.getText(), 'FARBOO'); + assert.strictEqual(newDocument.getText(), withDirtyFile ? 'FOOBARBAR' : 'FOOBAR'); + assert.strictEqual(anotherDocument.getText(), 'FARBOO'); assert.ok(newDocument.isDirty); assert.ok(anotherDocument.isDirty); diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.ts similarity index 90% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.ts index 193ab54be61d..a59c0f85fc13 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.ts @@ -20,11 +20,11 @@ suite('vscode API - workspace-fs', () => { test('fs.stat', async function () { const stat = await vscode.workspace.fs.stat(root); - assert.equal(stat.type, vscode.FileType.Directory); + assert.strictEqual(stat.type, vscode.FileType.Directory); - assert.equal(typeof stat.size, 'number'); - assert.equal(typeof stat.mtime, 'number'); - assert.equal(typeof stat.ctime, 'number'); + assert.strictEqual(typeof stat.size, 'number'); + assert.strictEqual(typeof stat.mtime, 'number'); + assert.strictEqual(typeof stat.ctime, 'number'); assert.ok(stat.mtime > 0); assert.ok(stat.ctime > 0); @@ -35,8 +35,8 @@ suite('vscode API - workspace-fs', () => { // find far.js const tuple = entries.find(tuple => tuple[0] === 'far.js')!; assert.ok(tuple); - assert.equal(tuple[0], 'far.js'); - assert.equal(tuple[1], vscode.FileType.File); + assert.strictEqual(tuple[0], 'far.js'); + assert.strictEqual(tuple[1], vscode.FileType.File); }); test('fs.stat - bad scheme', async function () { @@ -63,7 +63,7 @@ suite('vscode API - workspace-fs', () => { await vscode.workspace.fs.writeFile(uri, Buffer.from('HELLO')); const stat = await vscode.workspace.fs.stat(uri); - assert.equal(stat.type, vscode.FileType.File); + assert.strictEqual(stat.type, vscode.FileType.File); await vscode.workspace.fs.delete(uri); @@ -129,7 +129,7 @@ suite('vscode API - workspace-fs', () => { assert.ok(false); } catch (e) { assert.ok(e instanceof vscode.FileSystemError); - assert.equal(e.name, vscode.FileSystemError.FileNotFound().name); + assert.strictEqual(e.name, vscode.FileSystemError.FileNotFound().name); } }); @@ -140,7 +140,7 @@ suite('vscode API - workspace-fs', () => { assert.ok(false); } catch (e) { assert.ok(e instanceof vscode.FileSystemError); - assert.equal(e.name, vscode.FileSystemError.Unavailable().name); + assert.strictEqual(e.name, vscode.FileSystemError.Unavailable().name); } }); diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts diff --git a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts similarity index 84% rename from lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts rename to extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts index e60998c24bee..b17ebdbd5c6b 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts @@ -19,17 +19,17 @@ suite('vscode API - workspace', () => { test('MarkdownString', function () { let md = new vscode.MarkdownString(); - assert.equal(md.value, ''); - assert.equal(md.isTrusted, undefined); + assert.strictEqual(md.value, ''); + assert.strictEqual(md.isTrusted, undefined); md = new vscode.MarkdownString('**bold**'); - assert.equal(md.value, '**bold**'); + assert.strictEqual(md.value, '**bold**'); md.appendText('**bold?**'); - assert.equal(md.value, '**bold**\\*\\*bold?\\*\\*'); + assert.strictEqual(md.value, '**bold**\\*\\*bold?\\*\\*'); md.appendMarkdown('**bold**'); - assert.equal(md.value, '**bold**\\*\\*bold?\\*\\***bold**'); + assert.strictEqual(md.value, '**bold**\\*\\*bold?\\*\\***bold**'); }); @@ -49,7 +49,7 @@ suite('vscode API - workspace', () => { test('workspaceFolders', () => { if (vscode.workspace.workspaceFolders) { - assert.equal(vscode.workspace.workspaceFolders.length, 1); + assert.strictEqual(vscode.workspace.workspaceFolders.length, 1); assert.ok(pathEquals(vscode.workspace.workspaceFolders[0].uri.fsPath, join(__dirname, '../../testWorkspace'))); } }); @@ -68,14 +68,14 @@ suite('vscode API - workspace', () => { // not yet there const existing1 = vscode.workspace.textDocuments.find(doc => doc.uri.toString() === uri.toString()); - assert.equal(existing1, undefined); + assert.strictEqual(existing1, undefined); // open and assert its there const doc = await vscode.workspace.openTextDocument(uri); assert.ok(doc); - assert.equal(doc.uri.toString(), uri.toString()); + assert.strictEqual(doc.uri.toString(), uri.toString()); const existing2 = vscode.workspace.textDocuments.find(doc => doc.uri.toString() === uri.toString()); - assert.equal(existing2 === doc, true); + assert.strictEqual(existing2 === doc, true); }); test('openTextDocument, illegal path', () => { @@ -88,7 +88,7 @@ suite('vscode API - workspace', () => { test('openTextDocument, untitled is dirty', async function () { return vscode.workspace.openTextDocument(vscode.workspace.workspaceFolders![0].uri.with({ scheme: 'untitled', path: posix.join(vscode.workspace.workspaceFolders![0].uri.path, 'newfile.txt') })).then(doc => { - assert.equal(doc.uri.scheme, 'untitled'); + assert.strictEqual(doc.uri.scheme, 'untitled'); assert.ok(doc.isDirty); }); }); @@ -96,31 +96,31 @@ suite('vscode API - workspace', () => { test('openTextDocument, untitled with host', function () { const uri = vscode.Uri.parse('untitled://localhost/c%24/Users/jrieken/code/samples/foobar.txt'); return vscode.workspace.openTextDocument(uri).then(doc => { - assert.equal(doc.uri.scheme, 'untitled'); + assert.strictEqual(doc.uri.scheme, 'untitled'); }); }); test('openTextDocument, untitled without path', function () { return vscode.workspace.openTextDocument().then(doc => { - assert.equal(doc.uri.scheme, 'untitled'); + assert.strictEqual(doc.uri.scheme, 'untitled'); assert.ok(doc.isDirty); }); }); test('openTextDocument, untitled without path but language ID', function () { return vscode.workspace.openTextDocument({ language: 'xml' }).then(doc => { - assert.equal(doc.uri.scheme, 'untitled'); - assert.equal(doc.languageId, 'xml'); + assert.strictEqual(doc.uri.scheme, 'untitled'); + assert.strictEqual(doc.languageId, 'xml'); assert.ok(doc.isDirty); }); }); test('openTextDocument, untitled without path but language ID and content', function () { return vscode.workspace.openTextDocument({ language: 'html', content: '

    Hello world!

    ' }).then(doc => { - assert.equal(doc.uri.scheme, 'untitled'); - assert.equal(doc.languageId, 'html'); + assert.strictEqual(doc.uri.scheme, 'untitled'); + assert.strictEqual(doc.languageId, 'html'); assert.ok(doc.isDirty); - assert.equal(doc.getText(), '

    Hello world!

    '); + assert.strictEqual(doc.getText(), '

    Hello world!

    '); }); }); @@ -128,7 +128,7 @@ suite('vscode API - workspace', () => { const path = join(vscode.workspace.rootPath || '', './newfile.txt'); return vscode.workspace.openTextDocument(vscode.Uri.parse('untitled:' + path)).then(doc => { - assert.equal(doc.uri.scheme, 'untitled'); + assert.strictEqual(doc.uri.scheme, 'untitled'); assert.ok(doc.isDirty); let closed: vscode.TextDocument; @@ -137,7 +137,7 @@ suite('vscode API - workspace', () => { return vscode.window.showTextDocument(doc).then(() => { return doc.save().then((didSave: boolean) => { - assert.equal(didSave, true, `FAILED to save${doc.uri.toString()}`); + assert.strictEqual(didSave, true, `FAILED to save${doc.uri.toString()}`); assert.ok(closed === doc); assert.ok(!doc.isDirty); @@ -161,16 +161,16 @@ suite('vscode API - workspace', () => { return Promise.all([ vscode.workspace.openTextDocument(vscode.Uri.parse('sc://auth')).then(doc => { - assert.equal(doc.uri.authority, 'auth'); - assert.equal(doc.uri.path, ''); + assert.strictEqual(doc.uri.authority, 'auth'); + assert.strictEqual(doc.uri.path, ''); }), vscode.workspace.openTextDocument(vscode.Uri.parse('sc:///path')).then(doc => { - assert.equal(doc.uri.authority, ''); - assert.equal(doc.uri.path, '/path'); + assert.strictEqual(doc.uri.authority, ''); + assert.strictEqual(doc.uri.path, '/path'); }), vscode.workspace.openTextDocument(vscode.Uri.parse('sc://auth/path')).then(doc => { - assert.equal(doc.uri.authority, 'auth'); - assert.equal(doc.uri.path, '/path'); + assert.strictEqual(doc.uri.authority, 'auth'); + assert.strictEqual(doc.uri.path, '/path'); }) ]).then(() => { registration.dispose(); @@ -192,21 +192,21 @@ suite('vscode API - workspace', () => { // lower case (actual case) comes first let docOne = await vscode.workspace.openTextDocument(uriOne); - assert.equal(docOne.uri.toString(), uriOne.toString()); + assert.strictEqual(docOne.uri.toString(), uriOne.toString()); let docONE = await vscode.workspace.openTextDocument(uriONE); - assert.equal(docONE === docOne, true); - assert.equal(docONE.uri.toString(), uriOne.toString()); - assert.equal(docONE.uri.toString() !== uriONE.toString(), true); // yep + assert.strictEqual(docONE === docOne, true); + assert.strictEqual(docONE.uri.toString(), uriOne.toString()); + assert.strictEqual(docONE.uri.toString() !== uriONE.toString(), true); // yep // upper case (NOT the actual case) comes first let docTWO = await vscode.workspace.openTextDocument(uriTWO); - assert.equal(docTWO.uri.toString(), uriTWO.toString()); + assert.strictEqual(docTWO.uri.toString(), uriTWO.toString()); let docTwo = await vscode.workspace.openTextDocument(uriTwo); - assert.equal(docTWO === docTwo, true); - assert.equal(docTwo.uri.toString(), uriTWO.toString()); - assert.equal(docTwo.uri.toString() !== uriTwo.toString(), true); // yep + assert.strictEqual(docTWO === docTwo, true); + assert.strictEqual(docTwo.uri.toString(), uriTWO.toString()); + assert.strictEqual(docTwo.uri.toString() !== uriTwo.toString(), true); // yep reg.dispose(); }); @@ -214,17 +214,17 @@ suite('vscode API - workspace', () => { test('eol, read', () => { const a = createRandomFile('foo\nbar\nbar').then(file => { return vscode.workspace.openTextDocument(file).then(doc => { - assert.equal(doc.eol, vscode.EndOfLine.LF); + assert.strictEqual(doc.eol, vscode.EndOfLine.LF); }); }); const b = createRandomFile('foo\nbar\nbar\r\nbaz').then(file => { return vscode.workspace.openTextDocument(file).then(doc => { - assert.equal(doc.eol, vscode.EndOfLine.LF); + assert.strictEqual(doc.eol, vscode.EndOfLine.LF); }); }); const c = createRandomFile('foo\r\nbar\r\nbar').then(file => { return vscode.workspace.openTextDocument(file).then(doc => { - assert.equal(doc.eol, vscode.EndOfLine.CRLF); + assert.strictEqual(doc.eol, vscode.EndOfLine.CRLF); }); }); return Promise.all([a, b, c]); @@ -233,14 +233,14 @@ suite('vscode API - workspace', () => { test('eol, change via editor', () => { return createRandomFile('foo\nbar\nbar').then(file => { return vscode.workspace.openTextDocument(file).then(doc => { - assert.equal(doc.eol, vscode.EndOfLine.LF); + assert.strictEqual(doc.eol, vscode.EndOfLine.LF); return vscode.window.showTextDocument(doc).then(editor => { return editor.edit(builder => builder.setEndOfLine(vscode.EndOfLine.CRLF)); }).then(value => { assert.ok(value); assert.ok(doc.isDirty); - assert.equal(doc.eol, vscode.EndOfLine.CRLF); + assert.strictEqual(doc.eol, vscode.EndOfLine.CRLF); }); }); }); @@ -249,14 +249,14 @@ suite('vscode API - workspace', () => { test('eol, change via applyEdit', () => { return createRandomFile('foo\nbar\nbar').then(file => { return vscode.workspace.openTextDocument(file).then(doc => { - assert.equal(doc.eol, vscode.EndOfLine.LF); + assert.strictEqual(doc.eol, vscode.EndOfLine.LF); const edit = new vscode.WorkspaceEdit(); edit.set(file, [vscode.TextEdit.setEndOfLine(vscode.EndOfLine.CRLF)]); return vscode.workspace.applyEdit(edit).then(value => { assert.ok(value); assert.ok(doc.isDirty); - assert.equal(doc.eol, vscode.EndOfLine.CRLF); + assert.strictEqual(doc.eol, vscode.EndOfLine.CRLF); }); }); }); @@ -271,7 +271,7 @@ suite('vscode API - workspace', () => { const file = await createRandomFile('foo\r\nbar\r\nbar'); const doc = await vscode.workspace.openTextDocument(file); - assert.equal(doc.eol, vscode.EndOfLine.CRLF); + assert.strictEqual(doc.eol, vscode.EndOfLine.CRLF); const edit = new vscode.WorkspaceEdit(); edit.set(file, [vscode.TextEdit.insert(new vscode.Position(0, 0), '-changes-')]); @@ -282,7 +282,7 @@ suite('vscode API - workspace', () => { assert.ok(successSave); assert.ok(called); assert.ok(!doc.isDirty); - assert.equal(doc.eol, vscode.EndOfLine.LF); + assert.strictEqual(doc.eol, vscode.EndOfLine.LF); sub.dispose(); }); @@ -358,10 +358,10 @@ suite('vscode API - workspace', () => { return createRandomFile('foo\nbar\nbar').then(file => { return vscode.workspace.openTextDocument(file).then(doc => { return vscode.window.showTextDocument(doc, { selection: new vscode.Range(new vscode.Position(1, 1), new vscode.Position(1, 2)) }).then(editor => { - assert.equal(editor.selection.start.line, 1); - assert.equal(editor.selection.start.character, 1); - assert.equal(editor.selection.end.line, 1); - assert.equal(editor.selection.end.character, 2); + assert.strictEqual(editor.selection.start.line, 1); + assert.strictEqual(editor.selection.start.character, 1); + assert.strictEqual(editor.selection.end.line, 1); + assert.strictEqual(editor.selection.end.character, 2); }); }); }); @@ -377,9 +377,9 @@ suite('vscode API - workspace', () => { const uri = vscode.Uri.parse('foo://testing/virtual.js'); return vscode.workspace.openTextDocument(uri).then(doc => { - assert.equal(doc.getText(), uri.toString()); - assert.equal(doc.isDirty, false); - assert.equal(doc.uri.toString(), uri.toString()); + assert.strictEqual(doc.getText(), uri.toString()); + assert.strictEqual(doc.isDirty, false); + assert.strictEqual(doc.uri.toString(), uri.toString()); registration.dispose(); }); }); @@ -424,8 +424,8 @@ suite('vscode API - workspace', () => { }); return Promise.all([ - vscode.workspace.openTextDocument(vscode.Uri.parse('foo://foo/bla')).then(doc => { assert.equal(doc.getText(), '1'); }), - vscode.workspace.openTextDocument(vscode.Uri.parse('foo://bar/bla')).then(doc => { assert.equal(doc.getText(), '2'); }) + vscode.workspace.openTextDocument(vscode.Uri.parse('foo://foo/bla')).then(doc => { assert.strictEqual(doc.getText(), '1'); }), + vscode.workspace.openTextDocument(vscode.Uri.parse('foo://bar/bla')).then(doc => { assert.strictEqual(doc.getText(), '2'); }) ]).then(() => { registration1.dispose(); registration2.dispose(); @@ -447,7 +447,7 @@ suite('vscode API - workspace', () => { }); return vscode.workspace.openTextDocument(vscode.Uri.parse('foo://foo/bla')).then(doc => { - assert.equal(doc.getText(), '1'); + assert.strictEqual(doc.getText(), '1'); registration1.dispose(); registration2.dispose(); }); @@ -480,7 +480,7 @@ suite('vscode API - workspace', () => { return vscode.window.showTextDocument(doc).then(editor => { assert.ok(editor.document === doc); - assert.equal(editor.document.getText(), 'I am virtual'); + assert.strictEqual(editor.document.getText(), 'I am virtual'); registration.dispose(); }); }); @@ -502,7 +502,7 @@ suite('vscode API - workspace', () => { let [first, second] = docs; assert.ok(first === second); assert.ok(vscode.workspace.textDocuments.some(doc => doc.uri.toString() === uri.toString())); - assert.equal(callCount, 1); + assert.strictEqual(callCount, 1); registration.dispose(); }); }); @@ -518,8 +518,8 @@ suite('vscode API - workspace', () => { const uri = vscode.Uri.parse('foo:doc/empty'); return vscode.workspace.openTextDocument(uri).then(doc => { - assert.equal(doc.getText(), ''); - assert.equal(doc.uri.toString(), uri.toString()); + assert.strictEqual(doc.getText(), ''); + assert.strictEqual(doc.uri.toString(), uri.toString()); registration.dispose(); }); }); @@ -539,14 +539,14 @@ suite('vscode API - workspace', () => { const uri = vscode.Uri.parse('foo://testing/path3'); const doc = await vscode.workspace.openTextDocument(uri); - assert.equal(callCount, 1); - assert.equal(doc.getText(), 'call0'); + assert.strictEqual(callCount, 1); + assert.strictEqual(doc.getText(), 'call0'); return new Promise(resolve => { let subscription = vscode.workspace.onDidChangeTextDocument(event => { assert.ok(event.document === doc); - assert.equal(event.document.getText(), 'call1'); + assert.strictEqual(event.document.getText(), 'call1'); subscription.dispose(); registration.dispose(); resolve(); @@ -558,36 +558,36 @@ suite('vscode API - workspace', () => { test('findFiles', () => { return vscode.workspace.findFiles('**/image.png').then((res) => { - assert.equal(res.length, 2); - assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'image.png'); + assert.strictEqual(res.length, 2); + assert.strictEqual(basename(vscode.workspace.asRelativePath(res[0])), 'image.png'); }); }); test('findFiles - null exclude', async () => { await vscode.workspace.findFiles('**/file.txt').then((res) => { // search.exclude folder is still searched, files.exclude folder is not - assert.equal(res.length, 1); - assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'file.txt'); + assert.strictEqual(res.length, 1); + assert.strictEqual(basename(vscode.workspace.asRelativePath(res[0])), 'file.txt'); }); await vscode.workspace.findFiles('**/file.txt', null).then((res) => { // search.exclude and files.exclude folders are both searched - assert.equal(res.length, 2); - assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'file.txt'); + assert.strictEqual(res.length, 2); + assert.strictEqual(basename(vscode.workspace.asRelativePath(res[0])), 'file.txt'); }); }); test('findFiles - exclude', () => { return vscode.workspace.findFiles('**/image.png').then((res) => { - assert.equal(res.length, 2); - assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'image.png'); + assert.strictEqual(res.length, 2); + assert.strictEqual(basename(vscode.workspace.asRelativePath(res[0])), 'image.png'); }); }); test('findFiles, exclude', () => { return vscode.workspace.findFiles('**/image.png', '**/sub/**').then((res) => { - assert.equal(res.length, 1); - assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'image.png'); + assert.strictEqual(res.length, 1); + assert.strictEqual(basename(vscode.workspace.asRelativePath(res[0])), 'image.png'); }); }); @@ -598,7 +598,7 @@ suite('vscode API - workspace', () => { source.cancel(); return vscode.workspace.findFiles('*.js', null, 100, token).then((res) => { - assert.deepEqual(res, []); + assert.deepStrictEqual(res, []); }); }); @@ -616,10 +616,10 @@ suite('vscode API - workspace', () => { results.push(result); }); - assert.equal(results.length, 1); + assert.strictEqual(results.length, 1); const match = results[0]; assert(match.preview.text.indexOf('foo') >= 0); - assert.equal(basename(vscode.workspace.asRelativePath(match.uri)), '10linefile.ts'); + assert.strictEqual(basename(vscode.workspace.asRelativePath(match.uri)), '10linefile.ts'); }); test('findTextInFiles, cancellation', async () => { @@ -639,8 +639,8 @@ suite('vscode API - workspace', () => { edit.insert(doc.uri, new vscode.Position(0, 0), new Array(1000).join('Hello World')); let success = await vscode.workspace.applyEdit(edit); - assert.equal(success, true); - assert.equal(doc.isDirty, true); + assert.strictEqual(success, true); + assert.strictEqual(doc.isDirty, true); }); test('applyEdit should fail when editing deleted resource', withLogDisabled(async () => { @@ -651,7 +651,7 @@ suite('vscode API - workspace', () => { edit.insert(resource, new vscode.Position(0, 0), ''); let success = await vscode.workspace.applyEdit(edit); - assert.equal(success, false); + assert.strictEqual(success, false); })); test('applyEdit should fail when renaming deleted resource', withLogDisabled(async () => { @@ -662,7 +662,7 @@ suite('vscode API - workspace', () => { edit.renameFile(resource, resource); let success = await vscode.workspace.applyEdit(edit); - assert.equal(success, false); + assert.strictEqual(success, false); })); test('applyEdit should fail when editing renamed from resource', withLogDisabled(async () => { @@ -673,7 +673,7 @@ suite('vscode API - workspace', () => { edit.insert(resource, new vscode.Position(0, 0), ''); let success = await vscode.workspace.applyEdit(edit); - assert.equal(success, false); + assert.strictEqual(success, false); })); test('applyEdit "edit A -> rename A to B -> edit B"', async () => { @@ -699,8 +699,8 @@ suite('vscode API - workspace', () => { assert.ok(await vscode.workspace.applyEdit(edit)); let doc = await vscode.workspace.openTextDocument(newUri); - assert.equal(doc.getText(), 'AFTERBEFORE'); - assert.equal(doc.isDirty, true); + assert.strictEqual(doc.getText(), 'AFTERBEFORE'); + assert.strictEqual(doc.isDirty, true); } function nameWithUnderscore(uri: vscode.Uri) { @@ -719,7 +719,7 @@ suite('vscode API - workspace', () => { assert.ok(await vscode.workspace.applyEdit(we)); let doc = await vscode.workspace.openTextDocument(newUri); - assert.equal(doc.getText(), 'BarHelloFoo'); + assert.strictEqual(doc.getText(), 'BarHelloFoo'); })); test('WorkspaceEdit: Problem recreating a renamed resource #42634', withLogDisabled(async function () { @@ -737,9 +737,9 @@ suite('vscode API - workspace', () => { assert.ok(await vscode.workspace.applyEdit(we)); let newDoc = await vscode.workspace.openTextDocument(newUri); - assert.equal(newDoc.getText(), 'HelloFoo'); + assert.strictEqual(newDoc.getText(), 'HelloFoo'); let doc = await vscode.workspace.openTextDocument(docUri); - assert.equal(doc.getText(), 'Bar'); + assert.strictEqual(doc.getText(), 'Bar'); })); test('WorkspaceEdit api - after saving a deleted file, it still shows up as deleted. #42667', withLogDisabled(async function () { @@ -783,7 +783,7 @@ suite('vscode API - workspace', () => { let doc = await vscode.workspace.openTextDocument(newUri); assert.ok(doc); - assert.equal(doc.getText(), 'Hello'); + assert.strictEqual(doc.getText(), 'Hello'); }); test('WorkspaceEdit: rename resource followed by edit does not work #42638', withLogDisabled(async function () { @@ -797,7 +797,7 @@ suite('vscode API - workspace', () => { assert.ok(await vscode.workspace.applyEdit(we)); let doc = await vscode.workspace.openTextDocument(newUri); - assert.equal(doc.getText(), 'Hello'); + assert.strictEqual(doc.getText(), 'Hello'); })); test('WorkspaceEdit: create & override', withLogDisabled(async function () { @@ -807,12 +807,12 @@ suite('vscode API - workspace', () => { let we = new vscode.WorkspaceEdit(); we.createFile(docUri); assert.ok(!await vscode.workspace.applyEdit(we)); - assert.equal((await vscode.workspace.openTextDocument(docUri)).getText(), 'before'); + assert.strictEqual((await vscode.workspace.openTextDocument(docUri)).getText(), 'before'); we = new vscode.WorkspaceEdit(); we.createFile(docUri, { overwrite: true }); assert.ok(await vscode.workspace.applyEdit(we)); - assert.equal((await vscode.workspace.openTextDocument(docUri)).getText(), ''); + assert.strictEqual((await vscode.workspace.openTextDocument(docUri)).getText(), ''); })); test('WorkspaceEdit: create & ignoreIfExists', withLogDisabled(async function () { @@ -821,12 +821,12 @@ suite('vscode API - workspace', () => { let we = new vscode.WorkspaceEdit(); we.createFile(docUri, { ignoreIfExists: true }); assert.ok(await vscode.workspace.applyEdit(we)); - assert.equal((await vscode.workspace.openTextDocument(docUri)).getText(), 'before'); + assert.strictEqual((await vscode.workspace.openTextDocument(docUri)).getText(), 'before'); we = new vscode.WorkspaceEdit(); we.createFile(docUri, { overwrite: true, ignoreIfExists: true }); assert.ok(await vscode.workspace.applyEdit(we)); - assert.equal((await vscode.workspace.openTextDocument(docUri)).getText(), ''); + assert.strictEqual((await vscode.workspace.openTextDocument(docUri)).getText(), ''); })); test('WorkspaceEdit: rename & ignoreIfExists', withLogDisabled(async function () { @@ -880,9 +880,9 @@ suite('vscode API - workspace', () => { assert.ok(await vscode.workspace.applyEdit(we)); - assert.equal((await vscode.workspace.openTextDocument(f3)).getText(), 'f3'); - assert.equal((await vscode.workspace.openTextDocument(f2)).getText(), 'f2'); - assert.equal((await vscode.workspace.openTextDocument(f1_)).getText(), 'f1'); + assert.strictEqual((await vscode.workspace.openTextDocument(f3)).getText(), 'f3'); + assert.strictEqual((await vscode.workspace.openTextDocument(f2)).getText(), 'f2'); + assert.strictEqual((await vscode.workspace.openTextDocument(f1_)).getText(), 'f1'); try { await vscode.workspace.fs.stat(f1); assert.ok(false); @@ -932,12 +932,12 @@ suite('vscode API - workspace', () => { assert.ok(await vscode.workspace.applyEdit(we)); const document = await vscode.workspace.openTextDocument(newUri); - assert.equal(document.isDirty, true); + assert.strictEqual(document.isDirty, true); await document.save(); - assert.equal(document.isDirty, false); + assert.strictEqual(document.isDirty, false); - assert.equal(document.getText(), expected); + assert.strictEqual(document.getText(), expected); await delay(10); } @@ -959,7 +959,7 @@ suite('vscode API - workspace', () => { const document = await vscode.workspace.openTextDocument(file1); // const expected = 'import1;import2;'; const expected2 = 'import2;import1;'; - assert.equal(document.getText(), expected2); + assert.strictEqual(document.getText(), expected2); }); test('The api workspace.applyEdit failed for some case of mixing resourceChange and textEdit #80688', async function () { @@ -978,7 +978,7 @@ suite('vscode API - workspace', () => { const document = await vscode.workspace.openTextDocument(file1); const expected = 'import1;import2;'; // const expected2 = 'import2;import1;'; - assert.equal(document.getText(), expected); + assert.strictEqual(document.getText(), expected); }); test('Should send a single FileWillRenameEvent instead of separate events when moving multiple files at once#111867', async function () { @@ -1073,8 +1073,8 @@ suite('vscode API - workspace', () => { { const document = await vscode.workspace.openTextDocument(newFile); await vscode.window.showTextDocument(document); - assert.equal(document.getText(), 'hello2'); - assert.equal(document.isDirty, true); + assert.strictEqual(document.getText(), 'hello2'); + assert.strictEqual(document.isDirty, true); } // undo and show the old document @@ -1082,7 +1082,7 @@ suite('vscode API - workspace', () => { await vscode.commands.executeCommand('undo'); const document = await vscode.workspace.openTextDocument(file); await vscode.window.showTextDocument(document); - assert.equal(document.getText(), 'hello'); + assert.strictEqual(document.getText(), 'hello'); } // redo and show the new document @@ -1090,8 +1090,8 @@ suite('vscode API - workspace', () => { await vscode.commands.executeCommand('redo'); const document = await vscode.workspace.openTextDocument(newFile); await vscode.window.showTextDocument(document); - assert.equal(document.getText(), 'hello2'); - assert.equal(document.isDirty, true); + assert.strictEqual(document.getText(), 'hello2'); + assert.strictEqual(document.isDirty, true); } }); @@ -1111,8 +1111,8 @@ suite('vscode API - workspace', () => { // check the document { - assert.equal(document.getText(), 'hello2\nworld'); - assert.equal(document.isDirty, true); + assert.strictEqual(document.getText(), 'hello2\nworld'); + assert.strictEqual(document.isDirty, true); } // apply no-op edit @@ -1125,8 +1125,8 @@ suite('vscode API - workspace', () => { // undo { await vscode.commands.executeCommand('undo'); - assert.equal(document.getText(), 'hello\nworld'); - assert.equal(document.isDirty, false); + assert.strictEqual(document.getText(), 'hello\nworld'); + assert.strictEqual(document.isDirty, false); } }); }); diff --git a/lib/vscode/extensions/vscode-api-tests/src/typings/ref.d.ts b/extensions/vscode-api-tests/src/typings/ref.d.ts similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/src/typings/ref.d.ts rename to extensions/vscode-api-tests/src/typings/ref.d.ts diff --git a/lib/vscode/extensions/vscode-api-tests/src/utils.ts b/extensions/vscode-api-tests/src/utils.ts similarity index 91% rename from lib/vscode/extensions/vscode-api-tests/src/utils.ts rename to extensions/vscode-api-tests/src/utils.ts index a36b75496267..b346efefce96 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/utils.ts +++ b/extensions/vscode-api-tests/src/utils.ts @@ -137,3 +137,15 @@ export async function asPromise(event: vscode.Event, timeout = vscode.env. }); }); } + +export function testRepeat(n: number, description: string, callback: (this: any) => any): void { + for (let i = 0; i < n; i++) { + test(`${description} (iteration ${i})`, callback); + } +} + +export function suiteRepeat(n: number, description: string, callback: (this: any) => any): void { + for (let i = 0; i < n; i++) { + suite(`${description} (iteration ${i})`, callback); + } +} diff --git a/lib/vscode/extensions/vscode-api-tests/src/workspace-tests/index.ts b/extensions/vscode-api-tests/src/workspace-tests/index.ts similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/src/workspace-tests/index.ts rename to extensions/vscode-api-tests/src/workspace-tests/index.ts diff --git a/lib/vscode/extensions/vscode-api-tests/src/workspace-tests/workspace.test.ts b/extensions/vscode-api-tests/src/workspace-tests/workspace.test.ts similarity index 95% rename from lib/vscode/extensions/vscode-api-tests/src/workspace-tests/workspace.test.ts rename to extensions/vscode-api-tests/src/workspace-tests/workspace.test.ts index 1b4ef88325aa..5721e1ddf1be 100644 --- a/lib/vscode/extensions/vscode-api-tests/src/workspace-tests/workspace.test.ts +++ b/extensions/vscode-api-tests/src/workspace-tests/workspace.test.ts @@ -21,7 +21,7 @@ suite('vscode API - workspace', () => { }); test('workspaceFolders', () => { - assert.equal(vscode.workspace.workspaceFolders!.length, 2); + assert.strictEqual(vscode.workspace.workspaceFolders!.length, 2); assert.ok(pathEquals(vscode.workspace.workspaceFolders![0].uri.fsPath, join(__dirname, '../../testWorkspace'))); assert.ok(pathEquals(vscode.workspace.workspaceFolders![1].uri.fsPath, join(__dirname, '../../testWorkspace2'))); assert.ok(pathEquals(vscode.workspace.workspaceFolders![1].name, 'Test Workspace 2')); diff --git a/lib/vscode/extensions/vscode-api-tests/testWorkspace/.vscode/launch.json b/extensions/vscode-api-tests/testWorkspace/.vscode/launch.json similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testWorkspace/.vscode/launch.json rename to extensions/vscode-api-tests/testWorkspace/.vscode/launch.json diff --git a/lib/vscode/extensions/vscode-api-tests/testWorkspace/.vscode/settings.json b/extensions/vscode-api-tests/testWorkspace/.vscode/settings.json similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testWorkspace/.vscode/settings.json rename to extensions/vscode-api-tests/testWorkspace/.vscode/settings.json diff --git a/lib/vscode/extensions/vscode-api-tests/testWorkspace/10linefile.ts b/extensions/vscode-api-tests/testWorkspace/10linefile.ts similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testWorkspace/10linefile.ts rename to extensions/vscode-api-tests/testWorkspace/10linefile.ts diff --git a/lib/vscode/extensions/vscode-api-tests/testWorkspace/30linefile.ts b/extensions/vscode-api-tests/testWorkspace/30linefile.ts similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testWorkspace/30linefile.ts rename to extensions/vscode-api-tests/testWorkspace/30linefile.ts diff --git a/lib/vscode/extensions/vscode-api-tests/testWorkspace/bower.json b/extensions/vscode-api-tests/testWorkspace/bower.json similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testWorkspace/bower.json rename to extensions/vscode-api-tests/testWorkspace/bower.json diff --git a/lib/vscode/extensions/vscode-api-tests/testWorkspace/debug.js b/extensions/vscode-api-tests/testWorkspace/debug.js similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testWorkspace/debug.js rename to extensions/vscode-api-tests/testWorkspace/debug.js diff --git a/lib/vscode/extensions/vscode-api-tests/testWorkspace/far.js b/extensions/vscode-api-tests/testWorkspace/far.js similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testWorkspace/far.js rename to extensions/vscode-api-tests/testWorkspace/far.js diff --git a/lib/vscode/extensions/vscode-api-tests/testWorkspace/files-exclude/file.txt b/extensions/vscode-api-tests/testWorkspace/files-exclude/file.txt similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testWorkspace/files-exclude/file.txt rename to extensions/vscode-api-tests/testWorkspace/files-exclude/file.txt diff --git a/lib/vscode/extensions/vscode-api-tests/testWorkspace/image%.png b/extensions/vscode-api-tests/testWorkspace/image%.png similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testWorkspace/image%.png rename to extensions/vscode-api-tests/testWorkspace/image%.png diff --git a/lib/vscode/extensions/vscode-api-tests/testWorkspace/image%02.png b/extensions/vscode-api-tests/testWorkspace/image%02.png similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testWorkspace/image%02.png rename to extensions/vscode-api-tests/testWorkspace/image%02.png diff --git a/lib/vscode/extensions/vscode-api-tests/testWorkspace/image.png b/extensions/vscode-api-tests/testWorkspace/image.png similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testWorkspace/image.png rename to extensions/vscode-api-tests/testWorkspace/image.png diff --git a/lib/vscode/extensions/vscode-api-tests/testWorkspace/lorem.txt b/extensions/vscode-api-tests/testWorkspace/lorem.txt similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testWorkspace/lorem.txt rename to extensions/vscode-api-tests/testWorkspace/lorem.txt diff --git a/lib/vscode/extensions/vscode-api-tests/testWorkspace/search-exclude/file.txt b/extensions/vscode-api-tests/testWorkspace/search-exclude/file.txt similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testWorkspace/search-exclude/file.txt rename to extensions/vscode-api-tests/testWorkspace/search-exclude/file.txt diff --git a/lib/vscode/extensions/vscode-api-tests/testWorkspace/simple.txt b/extensions/vscode-api-tests/testWorkspace/simple.txt similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testWorkspace/simple.txt rename to extensions/vscode-api-tests/testWorkspace/simple.txt diff --git a/lib/vscode/extensions/vscode-api-tests/testWorkspace/sub/image.png b/extensions/vscode-api-tests/testWorkspace/sub/image.png similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testWorkspace/sub/image.png rename to extensions/vscode-api-tests/testWorkspace/sub/image.png diff --git a/lib/vscode/extensions/vscode-api-tests/testWorkspace2/.vscode/settings.json b/extensions/vscode-api-tests/testWorkspace2/.vscode/settings.json similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testWorkspace2/.vscode/settings.json rename to extensions/vscode-api-tests/testWorkspace2/.vscode/settings.json diff --git a/lib/vscode/extensions/vscode-api-tests/testWorkspace2/simple.txt b/extensions/vscode-api-tests/testWorkspace2/simple.txt similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testWorkspace2/simple.txt rename to extensions/vscode-api-tests/testWorkspace2/simple.txt diff --git a/lib/vscode/extensions/vscode-api-tests/testworkspace.code-workspace b/extensions/vscode-api-tests/testworkspace.code-workspace similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/testworkspace.code-workspace rename to extensions/vscode-api-tests/testworkspace.code-workspace diff --git a/lib/vscode/extensions/vscode-api-tests/tsconfig.json b/extensions/vscode-api-tests/tsconfig.json similarity index 100% rename from lib/vscode/extensions/vscode-api-tests/tsconfig.json rename to extensions/vscode-api-tests/tsconfig.json diff --git a/lib/vscode/extensions/vscode-api-tests/yarn.lock b/extensions/vscode-api-tests/yarn.lock similarity index 56% rename from lib/vscode/extensions/vscode-api-tests/yarn.lock rename to extensions/vscode-api-tests/yarn.lock index 0e3ca71c654a..b54d6b488365 100644 --- a/lib/vscode/extensions/vscode-api-tests/yarn.lock +++ b/extensions/vscode-api-tests/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.0.tgz#3eb56d13a1de1d347ecb1957c6860c911704bc44" integrity sha512-/Sge3BymXo4lKc31C8OINJgXLaw+7vL1/L1pGiBNpGrBiT8FQiaFpSYV0uhTaG4y78vcMBTMFsWaHDvuD+xGzQ== -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== diff --git a/lib/vscode/extensions/vscode-colorize-tests/.gitignore b/extensions/vscode-colorize-tests/.gitignore similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/.gitignore rename to extensions/vscode-colorize-tests/.gitignore diff --git a/lib/vscode/extensions/vscode-colorize-tests/.vscode/launch.json b/extensions/vscode-colorize-tests/.vscode/launch.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/.vscode/launch.json rename to extensions/vscode-colorize-tests/.vscode/launch.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/.vscode/tasks.json b/extensions/vscode-colorize-tests/.vscode/tasks.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/.vscode/tasks.json rename to extensions/vscode-colorize-tests/.vscode/tasks.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/media/icon.png b/extensions/vscode-colorize-tests/media/icon.png similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/media/icon.png rename to extensions/vscode-colorize-tests/media/icon.png diff --git a/lib/vscode/extensions/vscode-colorize-tests/package.json b/extensions/vscode-colorize-tests/package.json similarity index 97% rename from lib/vscode/extensions/vscode-colorize-tests/package.json rename to extensions/vscode-colorize-tests/package.json index 0ec286b33853..b2ce2e9d9cfa 100644 --- a/lib/vscode/extensions/vscode-colorize-tests/package.json +++ b/extensions/vscode-colorize-tests/package.json @@ -21,7 +21,7 @@ "jsonc-parser": "2.2.1" }, "devDependencies": { - "@types/node": "^12.19.9" + "@types/node": "14.x" }, "contributes": { "semanticTokenTypes": [ diff --git a/lib/vscode/extensions/vscode-colorize-tests/producticons/ElegantIcons.woff b/extensions/vscode-colorize-tests/producticons/ElegantIcons.woff similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/producticons/ElegantIcons.woff rename to extensions/vscode-colorize-tests/producticons/ElegantIcons.woff diff --git a/lib/vscode/extensions/vscode-colorize-tests/producticons/index.html b/extensions/vscode-colorize-tests/producticons/index.html similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/producticons/index.html rename to extensions/vscode-colorize-tests/producticons/index.html diff --git a/lib/vscode/extensions/vscode-colorize-tests/producticons/mit_license.txt b/extensions/vscode-colorize-tests/producticons/mit_license.txt similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/producticons/mit_license.txt rename to extensions/vscode-colorize-tests/producticons/mit_license.txt diff --git a/lib/vscode/extensions/vscode-colorize-tests/producticons/test-product-icon-theme.json b/extensions/vscode-colorize-tests/producticons/test-product-icon-theme.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/producticons/test-product-icon-theme.json rename to extensions/vscode-colorize-tests/producticons/test-product-icon-theme.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/src/colorizer.test.ts b/extensions/vscode-colorize-tests/src/colorizer.test.ts similarity index 93% rename from lib/vscode/extensions/vscode-colorize-tests/src/colorizer.test.ts rename to extensions/vscode-colorize-tests/src/colorizer.test.ts index 9d809409b401..8c4c70fd0b5c 100644 --- a/lib/vscode/extensions/vscode-colorize-tests/src/colorizer.test.ts +++ b/extensions/vscode-colorize-tests/src/colorizer.test.ts @@ -64,7 +64,9 @@ suite('colorization', () => { for (const fixture of fs.readdirSync(fixturesPath)) { test(`colorize: ${fixture}`, function (done) { - assertUnchangedTokens(fixturesPath, resultsPath, fixture, done); + commands.executeCommand('workbench.action.closeAllEditors').then(() => { + assertUnchangedTokens(fixturesPath, resultsPath, fixture, done); + }); }); } }); diff --git a/lib/vscode/extensions/vscode-colorize-tests/src/colorizerTestMain.ts b/extensions/vscode-colorize-tests/src/colorizerTestMain.ts similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/src/colorizerTestMain.ts rename to extensions/vscode-colorize-tests/src/colorizerTestMain.ts diff --git a/lib/vscode/extensions/vscode-colorize-tests/src/index.ts b/extensions/vscode-colorize-tests/src/index.ts similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/src/index.ts rename to extensions/vscode-colorize-tests/src/index.ts diff --git a/lib/vscode/extensions/vscode-colorize-tests/src/typings/ref.d.ts b/extensions/vscode-colorize-tests/src/typings/ref.d.ts similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/src/typings/ref.d.ts rename to extensions/vscode-colorize-tests/src/typings/ref.d.ts diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/12750.html b/extensions/vscode-colorize-tests/test/colorize-fixtures/12750.html similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/12750.html rename to extensions/vscode-colorize-tests/test/colorize-fixtures/12750.html diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/13448.html b/extensions/vscode-colorize-tests/test/colorize-fixtures/13448.html similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/13448.html rename to extensions/vscode-colorize-tests/test/colorize-fixtures/13448.html diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/14119.less b/extensions/vscode-colorize-tests/test/colorize-fixtures/14119.less similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/14119.less rename to extensions/vscode-colorize-tests/test/colorize-fixtures/14119.less diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/25920.html b/extensions/vscode-colorize-tests/test/colorize-fixtures/25920.html similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/25920.html rename to extensions/vscode-colorize-tests/test/colorize-fixtures/25920.html diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/Dockerfile b/extensions/vscode-colorize-tests/test/colorize-fixtures/Dockerfile similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/Dockerfile rename to extensions/vscode-colorize-tests/test/colorize-fixtures/Dockerfile diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/basic.java b/extensions/vscode-colorize-tests/test/colorize-fixtures/basic.java similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/basic.java rename to extensions/vscode-colorize-tests/test/colorize-fixtures/basic.java diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/issue-1550.yaml b/extensions/vscode-colorize-tests/test/colorize-fixtures/issue-1550.yaml similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/issue-1550.yaml rename to extensions/vscode-colorize-tests/test/colorize-fixtures/issue-1550.yaml diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/issue-28354.php b/extensions/vscode-colorize-tests/test/colorize-fixtures/issue-28354.php similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/issue-28354.php rename to extensions/vscode-colorize-tests/test/colorize-fixtures/issue-28354.php diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/issue-4008.yaml b/extensions/vscode-colorize-tests/test/colorize-fixtures/issue-4008.yaml similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/issue-4008.yaml rename to extensions/vscode-colorize-tests/test/colorize-fixtures/issue-4008.yaml diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/issue-6303.yaml b/extensions/vscode-colorize-tests/test/colorize-fixtures/issue-6303.yaml similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/issue-6303.yaml rename to extensions/vscode-colorize-tests/test/colorize-fixtures/issue-6303.yaml diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/issue-76997.php b/extensions/vscode-colorize-tests/test/colorize-fixtures/issue-76997.php similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/issue-76997.php rename to extensions/vscode-colorize-tests/test/colorize-fixtures/issue-76997.php diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/makefile b/extensions/vscode-colorize-tests/test/colorize-fixtures/makefile similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/makefile rename to extensions/vscode-colorize-tests/test/colorize-fixtures/makefile diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-13777.go b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-13777.go similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-13777.go rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-13777.go diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-23630.cpp b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-23630.cpp similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-23630.cpp rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-23630.cpp diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-23850.cpp b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-23850.cpp similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-23850.cpp rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-23850.cpp diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-33886.md b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-33886.md similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-33886.md rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-33886.md diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-4287.pug b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-4287.pug similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-4287.pug rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-4287.pug diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-6611.rs b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-6611.rs similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-6611.rs rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-6611.rs diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-7115.xml b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-7115.xml similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-7115.xml rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-7115.xml diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-78769.cpp b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-78769.cpp similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-78769.cpp rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-78769.cpp diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-80644.cpp b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-80644.cpp similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-80644.cpp rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-80644.cpp diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-brackets.tsx b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-brackets.tsx similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-brackets.tsx rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-brackets.tsx diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-cssvariables.less b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-cssvariables.less similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-cssvariables.less rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-cssvariables.less diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-cssvariables.scss b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-cssvariables.scss similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-cssvariables.scss rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-cssvariables.scss diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-embedding.html b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-embedding.html similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-embedding.html rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-embedding.html diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-freeze-56476.ps1 b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-freeze-56476.ps1 similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-freeze-56476.ps1 rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-freeze-56476.ps1 diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-function-inv.ts b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-function-inv.ts similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-function-inv.ts rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-function-inv.ts diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-issue11.ts b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-issue11.ts similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-issue11.ts rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-issue11.ts diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-issue5431.ts b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-issue5431.ts similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-issue5431.ts rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-issue5431.ts diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-issue5465.ts b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-issue5465.ts similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-issue5465.ts rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-issue5465.ts diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-issue5566.ts b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-issue5566.ts similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-issue5566.ts rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-issue5566.ts diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-jsdoc-multiline-type.ts b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-jsdoc-multiline-type.ts similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-jsdoc-multiline-type.ts rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-jsdoc-multiline-type.ts diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-keywords.ts b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-keywords.ts similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-keywords.ts rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-keywords.ts diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-members.ts b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-members.ts similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-members.ts rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-members.ts diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-object-literals.ts b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-object-literals.ts similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-object-literals.ts rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-object-literals.ts diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-regex.coffee b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-regex.coffee similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-regex.coffee rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-regex.coffee diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-strings.ts b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-strings.ts similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-strings.ts rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-strings.ts diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-this.ts b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-this.ts similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-this.ts rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-this.ts diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-variables.css b/extensions/vscode-colorize-tests/test/colorize-fixtures/test-variables.css similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test-variables.css rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test-variables.css diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.bat b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.bat similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.bat rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.bat diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.c b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.c similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.c rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.c diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.cc b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.cc similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.cc rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.cc diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.clj b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.clj similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.clj rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.clj diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.coffee b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.coffee similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.coffee rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.coffee diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.cpp b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.cpp similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.cpp rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.cpp diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.cs b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.cs similarity index 68% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.cs rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.cs index d4ebb2fe753d..c7098217742c 100644 --- a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.cs +++ b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.cs @@ -13,5 +13,15 @@ static void Main(string[] args) System.Console.WriteLine("Circumference = {0:N2}", circumference); } } + + public void TestMethod() + { + ListField = new List(); + + List localVar; + localVar = new List(); + + List localVar2 = new List(); + } } -} \ No newline at end of file +} diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.cshtml b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.cshtml similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.cshtml rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.cshtml diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.css b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.css similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.css rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.css diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.cu b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.cu similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.cu rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.cu diff --git a/extensions/vscode-colorize-tests/test/colorize-fixtures/test.dart b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.dart new file mode 100644 index 000000000000..e26254197bcd --- /dev/null +++ b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.dart @@ -0,0 +1,19 @@ +// from https://flutter.dev/ + +import 'package:flutter/material.dart'; + +void main() async { + runApp( + MaterialApp( + debugShowCheckedModeBanner: false, + home: Scaffold( + body: MyApp(), + ), + ), + ); +} + +class MyApp extends StatefulWidget { + @override + _MyAppState createState() => _MyAppState(); +} \ No newline at end of file diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.fs b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.fs similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.fs rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.fs diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.go b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.go similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.go rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.go diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.groovy b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.groovy similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.groovy rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.groovy diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.handlebars b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.handlebars similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.handlebars rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.handlebars diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.hbs b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.hbs similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.hbs rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.hbs diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.hlsl b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.hlsl similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.hlsl rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.hlsl diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.html b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.html similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.html rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.html diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.ini b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.ini similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.ini rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.ini diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.jl b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.jl similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.jl rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.jl diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.js b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.js similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.js rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.js diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.json b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.json rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.jsx b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.jsx similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.jsx rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.jsx diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.less b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.less similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.less rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.less diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.log b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.log similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.log rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.log diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.lua b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.lua similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.lua rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.lua diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.m b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.m similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.m rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.m diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.md b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.md similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.md rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.md diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.mm b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.mm similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.mm rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.mm diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.php b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.php similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.php rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.php diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.pl b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.pl similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.pl rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.pl diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.ps1 b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.ps1 similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.ps1 rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.ps1 diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.pug b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.pug similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.pug rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.pug diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.r b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.r similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.r rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.r diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.rb b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.rb similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.rb rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.rb diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.rs b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.rs similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.rs rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.rs diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.scss b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.scss similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.scss rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.scss diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.sh b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.sh similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.sh rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.sh diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.shader b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.shader similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.shader rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.shader diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.sql b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.sql similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.sql rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.sql diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.swift b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.swift similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.swift rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.swift diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.ts b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.ts similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.ts rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.ts diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.vb b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.vb similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.vb rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.vb diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.xml b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.xml similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.xml rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.xml diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.yaml b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.yaml similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test.yaml rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test.yaml diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test2.pl b/extensions/vscode-colorize-tests/test/colorize-fixtures/test2.pl similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test2.pl rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test2.pl diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test6916.js b/extensions/vscode-colorize-tests/test/colorize-fixtures/test6916.js similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/test6916.js rename to extensions/vscode-colorize-tests/test/colorize-fixtures/test6916.js diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/tsconfig_off.json b/extensions/vscode-colorize-tests/test/colorize-fixtures/tsconfig_off.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-fixtures/tsconfig_off.json rename to extensions/vscode-colorize-tests/test/colorize-fixtures/tsconfig_off.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/12750_html.json b/extensions/vscode-colorize-tests/test/colorize-results/12750_html.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/12750_html.json rename to extensions/vscode-colorize-tests/test/colorize-results/12750_html.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/13448_html.json b/extensions/vscode-colorize-tests/test/colorize-results/13448_html.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/13448_html.json rename to extensions/vscode-colorize-tests/test/colorize-results/13448_html.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/14119_less.json b/extensions/vscode-colorize-tests/test/colorize-results/14119_less.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/14119_less.json rename to extensions/vscode-colorize-tests/test/colorize-results/14119_less.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/25920_html.json b/extensions/vscode-colorize-tests/test/colorize-results/25920_html.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/25920_html.json rename to extensions/vscode-colorize-tests/test/colorize-results/25920_html.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/Dockerfile.json b/extensions/vscode-colorize-tests/test/colorize-results/Dockerfile.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/Dockerfile.json rename to extensions/vscode-colorize-tests/test/colorize-results/Dockerfile.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/basic_java.json b/extensions/vscode-colorize-tests/test/colorize-results/basic_java.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/basic_java.json rename to extensions/vscode-colorize-tests/test/colorize-results/basic_java.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/issue-1550_yaml.json b/extensions/vscode-colorize-tests/test/colorize-results/issue-1550_yaml.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/issue-1550_yaml.json rename to extensions/vscode-colorize-tests/test/colorize-results/issue-1550_yaml.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/issue-28354_php.json b/extensions/vscode-colorize-tests/test/colorize-results/issue-28354_php.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/issue-28354_php.json rename to extensions/vscode-colorize-tests/test/colorize-results/issue-28354_php.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/issue-4008_yaml.json b/extensions/vscode-colorize-tests/test/colorize-results/issue-4008_yaml.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/issue-4008_yaml.json rename to extensions/vscode-colorize-tests/test/colorize-results/issue-4008_yaml.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/issue-6303_yaml.json b/extensions/vscode-colorize-tests/test/colorize-results/issue-6303_yaml.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/issue-6303_yaml.json rename to extensions/vscode-colorize-tests/test/colorize-results/issue-6303_yaml.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/issue-76997_php.json b/extensions/vscode-colorize-tests/test/colorize-results/issue-76997_php.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/issue-76997_php.json rename to extensions/vscode-colorize-tests/test/colorize-results/issue-76997_php.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/makefile.json b/extensions/vscode-colorize-tests/test/colorize-results/makefile.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/makefile.json rename to extensions/vscode-colorize-tests/test/colorize-results/makefile.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-13777_go.json b/extensions/vscode-colorize-tests/test/colorize-results/test-13777_go.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-13777_go.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-13777_go.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-23630_cpp.json b/extensions/vscode-colorize-tests/test/colorize-results/test-23630_cpp.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-23630_cpp.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-23630_cpp.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-23850_cpp.json b/extensions/vscode-colorize-tests/test/colorize-results/test-23850_cpp.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-23850_cpp.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-23850_cpp.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-33886_md.json b/extensions/vscode-colorize-tests/test/colorize-results/test-33886_md.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-33886_md.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-33886_md.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-4287_pug.json b/extensions/vscode-colorize-tests/test/colorize-results/test-4287_pug.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-4287_pug.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-4287_pug.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-6611_rs.json b/extensions/vscode-colorize-tests/test/colorize-results/test-6611_rs.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-6611_rs.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-6611_rs.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-7115_xml.json b/extensions/vscode-colorize-tests/test/colorize-results/test-7115_xml.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-7115_xml.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-7115_xml.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-78769_cpp.json b/extensions/vscode-colorize-tests/test/colorize-results/test-78769_cpp.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-78769_cpp.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-78769_cpp.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-80644_cpp.json b/extensions/vscode-colorize-tests/test/colorize-results/test-80644_cpp.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-80644_cpp.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-80644_cpp.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-brackets_tsx.json b/extensions/vscode-colorize-tests/test/colorize-results/test-brackets_tsx.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-brackets_tsx.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-brackets_tsx.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-cssvariables_less.json b/extensions/vscode-colorize-tests/test/colorize-results/test-cssvariables_less.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-cssvariables_less.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-cssvariables_less.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-cssvariables_scss.json b/extensions/vscode-colorize-tests/test/colorize-results/test-cssvariables_scss.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-cssvariables_scss.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-cssvariables_scss.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-embedding_html.json b/extensions/vscode-colorize-tests/test/colorize-results/test-embedding_html.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-embedding_html.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-embedding_html.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-freeze-56476_ps1.json b/extensions/vscode-colorize-tests/test/colorize-results/test-freeze-56476_ps1.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-freeze-56476_ps1.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-freeze-56476_ps1.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-function-inv_ts.json b/extensions/vscode-colorize-tests/test/colorize-results/test-function-inv_ts.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-function-inv_ts.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-function-inv_ts.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-issue11_ts.json b/extensions/vscode-colorize-tests/test/colorize-results/test-issue11_ts.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-issue11_ts.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-issue11_ts.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-issue5431_ts.json b/extensions/vscode-colorize-tests/test/colorize-results/test-issue5431_ts.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-issue5431_ts.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-issue5431_ts.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-issue5465_ts.json b/extensions/vscode-colorize-tests/test/colorize-results/test-issue5465_ts.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-issue5465_ts.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-issue5465_ts.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-issue5566_ts.json b/extensions/vscode-colorize-tests/test/colorize-results/test-issue5566_ts.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-issue5566_ts.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-issue5566_ts.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-jsdoc-multiline-type_ts.json b/extensions/vscode-colorize-tests/test/colorize-results/test-jsdoc-multiline-type_ts.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-jsdoc-multiline-type_ts.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-jsdoc-multiline-type_ts.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-keywords_ts.json b/extensions/vscode-colorize-tests/test/colorize-results/test-keywords_ts.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-keywords_ts.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-keywords_ts.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-members_ts.json b/extensions/vscode-colorize-tests/test/colorize-results/test-members_ts.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-members_ts.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-members_ts.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-object-literals_ts.json b/extensions/vscode-colorize-tests/test/colorize-results/test-object-literals_ts.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-object-literals_ts.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-object-literals_ts.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-regex_coffee.json b/extensions/vscode-colorize-tests/test/colorize-results/test-regex_coffee.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-regex_coffee.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-regex_coffee.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-strings_ts.json b/extensions/vscode-colorize-tests/test/colorize-results/test-strings_ts.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-strings_ts.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-strings_ts.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-this_ts.json b/extensions/vscode-colorize-tests/test/colorize-results/test-this_ts.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-this_ts.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-this_ts.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-variables_css.json b/extensions/vscode-colorize-tests/test/colorize-results/test-variables_css.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test-variables_css.json rename to extensions/vscode-colorize-tests/test/colorize-results/test-variables_css.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test2_pl.json b/extensions/vscode-colorize-tests/test/colorize-results/test2_pl.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test2_pl.json rename to extensions/vscode-colorize-tests/test/colorize-results/test2_pl.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test6916_js.json b/extensions/vscode-colorize-tests/test/colorize-results/test6916_js.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test6916_js.json rename to extensions/vscode-colorize-tests/test/colorize-results/test6916_js.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_bat.json b/extensions/vscode-colorize-tests/test/colorize-results/test_bat.json similarity index 98% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_bat.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_bat.json index eb76b0e1d041..399fd0c22084 100644 --- a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_bat.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_bat.json @@ -100,13 +100,13 @@ }, { "c": "%", - "t": "source.batchfile punctuation.definition.variable.batchfile", + "t": "source.batchfile variable.parameter.batchfile punctuation.definition.variable.batchfile", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "hc_black": "variable: #9CDCFE" } }, { diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_c.json b/extensions/vscode-colorize-tests/test/colorize-results/test_c.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_c.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_c.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_cc.json b/extensions/vscode-colorize-tests/test/colorize-results/test_cc.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_cc.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_cc.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_clj.json b/extensions/vscode-colorize-tests/test/colorize-results/test_clj.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_clj.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_clj.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_coffee.json b/extensions/vscode-colorize-tests/test/colorize-results/test_coffee.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_coffee.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_coffee.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_cpp.json b/extensions/vscode-colorize-tests/test/colorize-results/test_cpp.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_cpp.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_cpp.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_cs.json b/extensions/vscode-colorize-tests/test/colorize-results/test_cs.json similarity index 65% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_cs.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_cs.json index 5893af16e9db..5ebe142cb8f0 100644 --- a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_cs.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_cs.json @@ -1341,6 +1341,743 @@ "hc_black": "default: #FFFFFF" } }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "public", + "t": "source.cs storage.modifier.cs", + "r": { + "dark_plus": "storage.modifier: #569CD6", + "light_plus": "storage.modifier: #0000FF", + "dark_vs": "storage.modifier: #569CD6", + "light_vs": "storage.modifier: #0000FF", + "hc_black": "storage.modifier: #569CD6" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "void", + "t": "source.cs keyword.type.cs", + "r": { + "dark_plus": "keyword: #569CD6", + "light_plus": "keyword: #0000FF", + "dark_vs": "keyword: #569CD6", + "light_vs": "keyword: #0000FF", + "hc_black": "keyword: #569CD6" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "TestMethod", + "t": "source.cs entity.name.function.cs", + "r": { + "dark_plus": "entity.name.function: #DCDCAA", + "light_plus": "entity.name.function: #795E26", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "entity.name.function: #DCDCAA" + } + }, + { + "c": "(", + "t": "source.cs punctuation.parenthesis.open.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ")", + "t": "source.cs punctuation.parenthesis.close.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "{", + "t": "source.cs punctuation.curlybrace.open.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "ListField", + "t": "source.cs variable.other.readwrite.cs", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "=", + "t": "source.cs keyword.operator.assignment.cs", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "new", + "t": "source.cs keyword.other.new.cs", + "r": { + "dark_plus": "keyword: #569CD6", + "light_plus": "keyword: #0000FF", + "dark_vs": "keyword: #569CD6", + "light_vs": "keyword: #0000FF", + "hc_black": "keyword: #569CD6" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "List", + "t": "source.cs storage.type.cs", + "r": { + "dark_plus": "storage.type.cs: #4EC9B0", + "light_plus": "storage.type.cs: #267F99", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type.cs: #4EC9B0" + } + }, + { + "c": "<", + "t": "source.cs punctuation.definition.typeparameters.begin.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "int", + "t": "source.cs keyword.type.cs", + "r": { + "dark_plus": "keyword: #569CD6", + "light_plus": "keyword: #0000FF", + "dark_vs": "keyword: #569CD6", + "light_vs": "keyword: #0000FF", + "hc_black": "keyword: #569CD6" + } + }, + { + "c": ">", + "t": "source.cs punctuation.definition.typeparameters.end.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "(", + "t": "source.cs punctuation.parenthesis.open.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ")", + "t": "source.cs punctuation.parenthesis.close.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.cs punctuation.terminator.statement.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "List", + "t": "source.cs storage.type.cs", + "r": { + "dark_plus": "storage.type.cs: #4EC9B0", + "light_plus": "storage.type.cs: #267F99", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type.cs: #4EC9B0" + } + }, + { + "c": "<", + "t": "source.cs punctuation.definition.typeparameters.begin.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "int", + "t": "source.cs keyword.type.cs", + "r": { + "dark_plus": "keyword: #569CD6", + "light_plus": "keyword: #0000FF", + "dark_vs": "keyword: #569CD6", + "light_vs": "keyword: #0000FF", + "hc_black": "keyword: #569CD6" + } + }, + { + "c": ">", + "t": "source.cs punctuation.definition.typeparameters.end.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "localVar", + "t": "source.cs entity.name.variable.local.cs", + "r": { + "dark_plus": "entity.name.variable: #9CDCFE", + "light_plus": "entity.name.variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.cs punctuation.terminator.statement.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "localVar", + "t": "source.cs variable.other.readwrite.cs", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "=", + "t": "source.cs keyword.operator.assignment.cs", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "new", + "t": "source.cs keyword.other.new.cs", + "r": { + "dark_plus": "keyword: #569CD6", + "light_plus": "keyword: #0000FF", + "dark_vs": "keyword: #569CD6", + "light_vs": "keyword: #0000FF", + "hc_black": "keyword: #569CD6" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "List", + "t": "source.cs storage.type.cs", + "r": { + "dark_plus": "storage.type.cs: #4EC9B0", + "light_plus": "storage.type.cs: #267F99", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type.cs: #4EC9B0" + } + }, + { + "c": "<", + "t": "source.cs punctuation.definition.typeparameters.begin.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "int", + "t": "source.cs keyword.type.cs", + "r": { + "dark_plus": "keyword: #569CD6", + "light_plus": "keyword: #0000FF", + "dark_vs": "keyword: #569CD6", + "light_vs": "keyword: #0000FF", + "hc_black": "keyword: #569CD6" + } + }, + { + "c": ">", + "t": "source.cs punctuation.definition.typeparameters.end.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "(", + "t": "source.cs punctuation.parenthesis.open.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ")", + "t": "source.cs punctuation.parenthesis.close.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.cs punctuation.terminator.statement.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "List", + "t": "source.cs storage.type.cs", + "r": { + "dark_plus": "storage.type.cs: #4EC9B0", + "light_plus": "storage.type.cs: #267F99", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type.cs: #4EC9B0" + } + }, + { + "c": "<", + "t": "source.cs punctuation.definition.typeparameters.begin.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "int", + "t": "source.cs keyword.type.cs", + "r": { + "dark_plus": "keyword: #569CD6", + "light_plus": "keyword: #0000FF", + "dark_vs": "keyword: #569CD6", + "light_vs": "keyword: #0000FF", + "hc_black": "keyword: #569CD6" + } + }, + { + "c": ">", + "t": "source.cs punctuation.definition.typeparameters.end.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "localVar2", + "t": "source.cs entity.name.variable.local.cs", + "r": { + "dark_plus": "entity.name.variable: #9CDCFE", + "light_plus": "entity.name.variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "=", + "t": "source.cs keyword.operator.assignment.cs", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "new", + "t": "source.cs keyword.other.new.cs", + "r": { + "dark_plus": "keyword: #569CD6", + "light_plus": "keyword: #0000FF", + "dark_vs": "keyword: #569CD6", + "light_vs": "keyword: #0000FF", + "hc_black": "keyword: #569CD6" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "List", + "t": "source.cs storage.type.cs", + "r": { + "dark_plus": "storage.type.cs: #4EC9B0", + "light_plus": "storage.type.cs: #267F99", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type.cs: #4EC9B0" + } + }, + { + "c": "<", + "t": "source.cs punctuation.definition.typeparameters.begin.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "int", + "t": "source.cs keyword.type.cs", + "r": { + "dark_plus": "keyword: #569CD6", + "light_plus": "keyword: #0000FF", + "dark_vs": "keyword: #569CD6", + "light_vs": "keyword: #0000FF", + "hc_black": "keyword: #569CD6" + } + }, + { + "c": ">", + "t": "source.cs punctuation.definition.typeparameters.end.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "(", + "t": "source.cs punctuation.parenthesis.open.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ")", + "t": "source.cs punctuation.parenthesis.close.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.cs punctuation.terminator.statement.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "}", + "t": "source.cs punctuation.curlybrace.close.cs", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, { "c": " ", "t": "source.cs", @@ -1374,4 +2111,4 @@ "hc_black": "default: #FFFFFF" } } -] +] \ No newline at end of file diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_cshtml.json b/extensions/vscode-colorize-tests/test/colorize-results/test_cshtml.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_cshtml.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_cshtml.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_css.json b/extensions/vscode-colorize-tests/test/colorize-results/test_css.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_css.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_css.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_cu.json b/extensions/vscode-colorize-tests/test/colorize-results/test_cu.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_cu.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_cu.json diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_dart.json b/extensions/vscode-colorize-tests/test/colorize-results/test_dart.json new file mode 100644 index 000000000000..0d944b2b5a5f --- /dev/null +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_dart.json @@ -0,0 +1,673 @@ +[ + { + "c": "// from https://flutter.dev/", + "t": "source.dart comment.line.double-slash.dart", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "import", + "t": "source.dart meta.declaration.dart keyword.other.import.dart", + "r": { + "dark_plus": "keyword: #569CD6", + "light_plus": "keyword: #0000FF", + "dark_vs": "keyword: #569CD6", + "light_vs": "keyword: #0000FF", + "hc_black": "keyword: #569CD6" + } + }, + { + "c": " ", + "t": "source.dart meta.declaration.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "'package:flutter/material.dart'", + "t": "source.dart meta.declaration.dart string.interpolated.single.dart", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": ";", + "t": "source.dart meta.declaration.dart punctuation.terminator.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "void", + "t": "source.dart storage.type.primitive.dart", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": " ", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "main", + "t": "source.dart entity.name.function.dart", + "r": { + "dark_plus": "entity.name.function: #DCDCAA", + "light_plus": "entity.name.function: #795E26", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "entity.name.function: #DCDCAA" + } + }, + { + "c": "() ", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "async", + "t": "source.dart keyword.control.dart", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + }, + { + "c": " {", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "runApp", + "t": "source.dart entity.name.function.dart", + "r": { + "dark_plus": "entity.name.function: #DCDCAA", + "light_plus": "entity.name.function: #795E26", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "entity.name.function: #DCDCAA" + } + }, + { + "c": "(", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "MaterialApp", + "t": "source.dart support.class.dart", + "r": { + "dark_plus": "support.class: #4EC9B0", + "light_plus": "support.class: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "support.class: #4EC9B0" + } + }, + { + "c": "(", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " debugShowCheckedModeBanner", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ":", + "t": "source.dart keyword.operator.ternary.dart", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "false", + "t": "source.dart constant.language.dart", + "r": { + "dark_plus": "constant.language: #569CD6", + "light_plus": "constant.language: #0000FF", + "dark_vs": "constant.language: #569CD6", + "light_vs": "constant.language: #0000FF", + "hc_black": "constant.language: #569CD6" + } + }, + { + "c": ",", + "t": "source.dart punctuation.comma.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " home", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ":", + "t": "source.dart keyword.operator.ternary.dart", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "Scaffold", + "t": "source.dart support.class.dart", + "r": { + "dark_plus": "support.class: #4EC9B0", + "light_plus": "support.class: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "support.class: #4EC9B0" + } + }, + { + "c": "(", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " body", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ":", + "t": "source.dart keyword.operator.ternary.dart", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "MyApp", + "t": "source.dart support.class.dart", + "r": { + "dark_plus": "support.class: #4EC9B0", + "light_plus": "support.class: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "support.class: #4EC9B0" + } + }, + { + "c": "()", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ",", + "t": "source.dart punctuation.comma.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " )", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ",", + "t": "source.dart punctuation.comma.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " )", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ",", + "t": "source.dart punctuation.comma.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " )", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.dart punctuation.terminator.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "}", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "class", + "t": "source.dart keyword.declaration.dart", + "r": { + "dark_plus": "keyword: #569CD6", + "light_plus": "keyword: #0000FF", + "dark_vs": "keyword: #569CD6", + "light_vs": "keyword: #0000FF", + "hc_black": "keyword: #569CD6" + } + }, + { + "c": " ", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "MyApp", + "t": "source.dart support.class.dart", + "r": { + "dark_plus": "support.class: #4EC9B0", + "light_plus": "support.class: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "support.class: #4EC9B0" + } + }, + { + "c": " ", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "extends", + "t": "source.dart keyword.declaration.dart", + "r": { + "dark_plus": "keyword: #569CD6", + "light_plus": "keyword: #0000FF", + "dark_vs": "keyword: #569CD6", + "light_vs": "keyword: #0000FF", + "hc_black": "keyword: #569CD6" + } + }, + { + "c": " ", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "StatefulWidget", + "t": "source.dart support.class.dart", + "r": { + "dark_plus": "support.class: #4EC9B0", + "light_plus": "support.class: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "support.class: #4EC9B0" + } + }, + { + "c": " {", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "@override", + "t": "source.dart storage.type.annotation.dart", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": " ", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "_MyAppState", + "t": "source.dart support.class.dart", + "r": { + "dark_plus": "support.class: #4EC9B0", + "light_plus": "support.class: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "support.class: #4EC9B0" + } + }, + { + "c": " ", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "createState", + "t": "source.dart entity.name.function.dart", + "r": { + "dark_plus": "entity.name.function: #DCDCAA", + "light_plus": "entity.name.function: #795E26", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "entity.name.function: #DCDCAA" + } + }, + { + "c": "() ", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "=>", + "t": "source.dart keyword.operator.closure.dart", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "_MyAppState", + "t": "source.dart support.class.dart", + "r": { + "dark_plus": "support.class: #4EC9B0", + "light_plus": "support.class: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "support.class: #4EC9B0" + } + }, + { + "c": "()", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.dart punctuation.terminator.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "}", + "t": "source.dart", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + } +] \ No newline at end of file diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_fs.json b/extensions/vscode-colorize-tests/test/colorize-results/test_fs.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_fs.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_fs.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_go.json b/extensions/vscode-colorize-tests/test/colorize-results/test_go.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_go.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_go.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_groovy.json b/extensions/vscode-colorize-tests/test/colorize-results/test_groovy.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_groovy.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_groovy.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_handlebars.json b/extensions/vscode-colorize-tests/test/colorize-results/test_handlebars.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_handlebars.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_handlebars.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_hbs.json b/extensions/vscode-colorize-tests/test/colorize-results/test_hbs.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_hbs.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_hbs.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_hlsl.json b/extensions/vscode-colorize-tests/test/colorize-results/test_hlsl.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_hlsl.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_hlsl.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_html.json b/extensions/vscode-colorize-tests/test/colorize-results/test_html.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_html.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_html.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_ini.json b/extensions/vscode-colorize-tests/test/colorize-results/test_ini.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_ini.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_ini.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_jl.json b/extensions/vscode-colorize-tests/test/colorize-results/test_jl.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_jl.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_jl.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_js.json b/extensions/vscode-colorize-tests/test/colorize-results/test_js.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_js.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_js.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_json.json b/extensions/vscode-colorize-tests/test/colorize-results/test_json.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_json.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_json.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_jsx.json b/extensions/vscode-colorize-tests/test/colorize-results/test_jsx.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_jsx.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_jsx.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_less.json b/extensions/vscode-colorize-tests/test/colorize-results/test_less.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_less.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_less.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_log.json b/extensions/vscode-colorize-tests/test/colorize-results/test_log.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_log.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_log.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_lua.json b/extensions/vscode-colorize-tests/test/colorize-results/test_lua.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_lua.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_lua.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_m.json b/extensions/vscode-colorize-tests/test/colorize-results/test_m.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_m.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_m.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_md.json b/extensions/vscode-colorize-tests/test/colorize-results/test_md.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_md.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_md.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_mm.json b/extensions/vscode-colorize-tests/test/colorize-results/test_mm.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_mm.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_mm.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_php.json b/extensions/vscode-colorize-tests/test/colorize-results/test_php.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_php.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_php.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_pl.json b/extensions/vscode-colorize-tests/test/colorize-results/test_pl.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_pl.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_pl.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_ps1.json b/extensions/vscode-colorize-tests/test/colorize-results/test_ps1.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_ps1.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_ps1.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_pug.json b/extensions/vscode-colorize-tests/test/colorize-results/test_pug.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_pug.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_pug.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_r.json b/extensions/vscode-colorize-tests/test/colorize-results/test_r.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_r.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_r.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_rb.json b/extensions/vscode-colorize-tests/test/colorize-results/test_rb.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_rb.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_rb.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_rs.json b/extensions/vscode-colorize-tests/test/colorize-results/test_rs.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_rs.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_rs.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_scss.json b/extensions/vscode-colorize-tests/test/colorize-results/test_scss.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_scss.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_scss.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_sh.json b/extensions/vscode-colorize-tests/test/colorize-results/test_sh.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_sh.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_sh.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_shader.json b/extensions/vscode-colorize-tests/test/colorize-results/test_shader.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_shader.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_shader.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_sql.json b/extensions/vscode-colorize-tests/test/colorize-results/test_sql.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_sql.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_sql.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_swift.json b/extensions/vscode-colorize-tests/test/colorize-results/test_swift.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_swift.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_swift.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_ts.json b/extensions/vscode-colorize-tests/test/colorize-results/test_ts.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_ts.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_ts.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_vb.json b/extensions/vscode-colorize-tests/test/colorize-results/test_vb.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_vb.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_vb.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_xml.json b/extensions/vscode-colorize-tests/test/colorize-results/test_xml.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_xml.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_xml.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_yaml.json b/extensions/vscode-colorize-tests/test/colorize-results/test_yaml.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/test_yaml.json rename to extensions/vscode-colorize-tests/test/colorize-results/test_yaml.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/tsconfig_off_json.json b/extensions/vscode-colorize-tests/test/colorize-results/tsconfig_off_json.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/colorize-results/tsconfig_off_json.json rename to extensions/vscode-colorize-tests/test/colorize-results/tsconfig_off_json.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/semantic-test/.vscode/settings.json b/extensions/vscode-colorize-tests/test/semantic-test/.vscode/settings.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/semantic-test/.vscode/settings.json rename to extensions/vscode-colorize-tests/test/semantic-test/.vscode/settings.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/test/semantic-test/semantic-test.json b/extensions/vscode-colorize-tests/test/semantic-test/semantic-test.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/test/semantic-test/semantic-test.json rename to extensions/vscode-colorize-tests/test/semantic-test/semantic-test.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/tsconfig.json b/extensions/vscode-colorize-tests/tsconfig.json similarity index 100% rename from lib/vscode/extensions/vscode-colorize-tests/tsconfig.json rename to extensions/vscode-colorize-tests/tsconfig.json diff --git a/lib/vscode/extensions/vscode-colorize-tests/yarn.lock b/extensions/vscode-colorize-tests/yarn.lock similarity index 57% rename from lib/vscode/extensions/vscode-colorize-tests/yarn.lock rename to extensions/vscode-colorize-tests/yarn.lock index a02d17759287..15725cff5029 100644 --- a/lib/vscode/extensions/vscode-colorize-tests/yarn.lock +++ b/extensions/vscode-colorize-tests/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== jsonc-parser@2.2.1: version "2.2.1" diff --git a/lib/vscode/extensions/vscode-custom-editor-tests/.vscodeignore b/extensions/vscode-custom-editor-tests/.vscodeignore similarity index 100% rename from lib/vscode/extensions/vscode-custom-editor-tests/.vscodeignore rename to extensions/vscode-custom-editor-tests/.vscodeignore diff --git a/lib/vscode/extensions/vscode-custom-editor-tests/customEditorMedia/textEditor.js b/extensions/vscode-custom-editor-tests/customEditorMedia/textEditor.js similarity index 100% rename from lib/vscode/extensions/vscode-custom-editor-tests/customEditorMedia/textEditor.js rename to extensions/vscode-custom-editor-tests/customEditorMedia/textEditor.js diff --git a/lib/vscode/extensions/vscode-custom-editor-tests/media/icon.png b/extensions/vscode-custom-editor-tests/media/icon.png similarity index 100% rename from lib/vscode/extensions/vscode-custom-editor-tests/media/icon.png rename to extensions/vscode-custom-editor-tests/media/icon.png diff --git a/lib/vscode/extensions/vscode-custom-editor-tests/package.json b/extensions/vscode-custom-editor-tests/package.json similarity index 97% rename from lib/vscode/extensions/vscode-custom-editor-tests/package.json rename to extensions/vscode-custom-editor-tests/package.json index c718e324bc98..997c3a94da6e 100644 --- a/lib/vscode/extensions/vscode-custom-editor-tests/package.json +++ b/extensions/vscode-custom-editor-tests/package.json @@ -22,7 +22,7 @@ "p-limit": "^3.0.2" }, "devDependencies": { - "@types/node": "^12.19.9", + "@types/node": "14.x", "@types/p-limit": "^2.2.0" }, "contributes": { diff --git a/lib/vscode/extensions/vscode-custom-editor-tests/src/customTextEditor.ts b/extensions/vscode-custom-editor-tests/src/customTextEditor.ts similarity index 100% rename from lib/vscode/extensions/vscode-custom-editor-tests/src/customTextEditor.ts rename to extensions/vscode-custom-editor-tests/src/customTextEditor.ts diff --git a/lib/vscode/extensions/vscode-custom-editor-tests/src/dispose.ts b/extensions/vscode-custom-editor-tests/src/dispose.ts similarity index 100% rename from lib/vscode/extensions/vscode-custom-editor-tests/src/dispose.ts rename to extensions/vscode-custom-editor-tests/src/dispose.ts diff --git a/lib/vscode/extensions/vscode-custom-editor-tests/src/extension.ts b/extensions/vscode-custom-editor-tests/src/extension.ts similarity index 100% rename from lib/vscode/extensions/vscode-custom-editor-tests/src/extension.ts rename to extensions/vscode-custom-editor-tests/src/extension.ts diff --git a/lib/vscode/extensions/vscode-custom-editor-tests/src/test/customEditor.test.ts b/extensions/vscode-custom-editor-tests/src/test/customEditor.test.ts similarity index 92% rename from lib/vscode/extensions/vscode-custom-editor-tests/src/test/customEditor.test.ts rename to extensions/vscode-custom-editor-tests/src/test/customEditor.test.ts index b4725c22de3e..654afb84cd78 100644 --- a/lib/vscode/extensions/vscode-custom-editor-tests/src/test/customEditor.test.ts +++ b/extensions/vscode-custom-editor-tests/src/test/customEditor.test.ts @@ -92,7 +92,7 @@ suite('CustomEditor tests', () => { await vscode.commands.executeCommand(commands.open, testDocument); const { content } = await listener.nextResponse(); - assert.equal(content, startingContent); + assert.strictEqual(content, startingContent); }); test('Should support basic edits', async () => { @@ -107,7 +107,7 @@ suite('CustomEditor tests', () => { const newContent = `basic edit test`; await vscode.commands.executeCommand(Testing.abcEditorTypeCommand, newContent); const { content } = await listener.nextResponse(); - assert.equal(content, newContent); + assert.strictEqual(content, newContent); }); test('Should support single undo', async () => { @@ -123,13 +123,13 @@ suite('CustomEditor tests', () => { { await vscode.commands.executeCommand(Testing.abcEditorTypeCommand, newContent); const { content } = await listener.nextResponse(); - assert.equal(content, newContent); + assert.strictEqual(content, newContent); } await delay(100); { await vscode.commands.executeCommand(commands.undo); const { content } = await listener.nextResponse(); - assert.equal(content, startingContent); + assert.strictEqual(content, startingContent); } }); @@ -148,7 +148,7 @@ suite('CustomEditor tests', () => { for (let i = 0; i < count; ++i) { await vscode.commands.executeCommand(Testing.abcEditorTypeCommand, `${i}`); const { content } = await listener.nextResponse(); - assert.equal(`${i}`, content); + assert.strictEqual(`${i}`, content); } // Then undo them in order @@ -156,14 +156,14 @@ suite('CustomEditor tests', () => { await delay(100); await vscode.commands.executeCommand(commands.undo); const { content } = await listener.nextResponse(); - assert.equal(`${i - 1}`, content); + assert.strictEqual(`${i - 1}`, content); } { await delay(100); await vscode.commands.executeCommand(commands.undo); const { content } = await listener.nextResponse(); - assert.equal(content, startingContent); + assert.strictEqual(content, startingContent); } }); @@ -184,8 +184,8 @@ suite('CustomEditor tests', () => { await vscode.workspace.applyEdit(edit); const response = (await listener.nextResponse()); - assert.equal(response.content, startingContent); - assert.equal(response.source.toString(), newFileName.toString()); + assert.strictEqual(response.content, startingContent); + assert.strictEqual(response.source.toString(), newFileName.toString()); }); test('Should support saving custom editors', async () => { @@ -201,12 +201,12 @@ suite('CustomEditor tests', () => { { await vscode.commands.executeCommand(Testing.abcEditorTypeCommand, newContent); const { content } = await listener.nextResponse(); - assert.equal(content, newContent); + assert.strictEqual(content, newContent); } { await vscode.commands.executeCommand(commands.save); const fileContent = (await fs.promises.readFile(testDocument.fsPath)).toString(); - assert.equal(fileContent, newContent); + assert.strictEqual(fileContent, newContent); } }); @@ -223,18 +223,18 @@ suite('CustomEditor tests', () => { { await vscode.commands.executeCommand(Testing.abcEditorTypeCommand, newContent); const { content } = await listener.nextResponse(); - assert.equal(content, newContent); + assert.strictEqual(content, newContent); } { await vscode.commands.executeCommand(commands.save); const fileContent = (await fs.promises.readFile(testDocument.fsPath)).toString(); - assert.equal(fileContent, newContent); + assert.strictEqual(fileContent, newContent); } await delay(100); { await vscode.commands.executeCommand(commands.undo); const { content } = await listener.nextResponse(); - assert.equal(content, startingContent); + assert.strictEqual(content, startingContent); } }); @@ -244,14 +244,14 @@ suite('CustomEditor tests', () => { const untitledFile = randomFilePath({ root: testWorkspaceRoot, ext: '.abc' }).with({ scheme: 'untitled' }); await vscode.commands.executeCommand(commands.open, untitledFile); - assert.equal((await listener.nextResponse()).content, ''); + assert.strictEqual((await listener.nextResponse()).content, ''); await vscode.commands.executeCommand(Testing.abcEditorTypeCommand, `123`); - assert.equal((await listener.nextResponse()).content, '123'); + assert.strictEqual((await listener.nextResponse()).content, '123'); await vscode.commands.executeCommand(commands.save); const content = await fs.promises.readFile(untitledFile.fsPath); - assert.equal(content.toString(), '123'); + assert.strictEqual(content.toString(), '123'); }); test.skip('When switching away from a non-default custom editors and then back, we should continue using the non-default editor', async () => { diff --git a/lib/vscode/extensions/vscode-custom-editor-tests/src/test/index.ts b/extensions/vscode-custom-editor-tests/src/test/index.ts similarity index 100% rename from lib/vscode/extensions/vscode-custom-editor-tests/src/test/index.ts rename to extensions/vscode-custom-editor-tests/src/test/index.ts diff --git a/lib/vscode/extensions/vscode-custom-editor-tests/src/test/utils.ts b/extensions/vscode-custom-editor-tests/src/test/utils.ts similarity index 100% rename from lib/vscode/extensions/vscode-custom-editor-tests/src/test/utils.ts rename to extensions/vscode-custom-editor-tests/src/test/utils.ts diff --git a/lib/vscode/extensions/vscode-custom-editor-tests/src/typings/ref.d.ts b/extensions/vscode-custom-editor-tests/src/typings/ref.d.ts similarity index 100% rename from lib/vscode/extensions/vscode-custom-editor-tests/src/typings/ref.d.ts rename to extensions/vscode-custom-editor-tests/src/typings/ref.d.ts diff --git a/lib/vscode/extensions/vscode-custom-editor-tests/test-workspace/index.abc b/extensions/vscode-custom-editor-tests/test-workspace/index.abc similarity index 100% rename from lib/vscode/extensions/vscode-custom-editor-tests/test-workspace/index.abc rename to extensions/vscode-custom-editor-tests/test-workspace/index.abc diff --git a/lib/vscode/extensions/vscode-custom-editor-tests/tsconfig.json b/extensions/vscode-custom-editor-tests/tsconfig.json similarity index 100% rename from lib/vscode/extensions/vscode-custom-editor-tests/tsconfig.json rename to extensions/vscode-custom-editor-tests/tsconfig.json diff --git a/lib/vscode/extensions/vscode-custom-editor-tests/yarn.lock b/extensions/vscode-custom-editor-tests/yarn.lock similarity index 77% rename from lib/vscode/extensions/vscode-custom-editor-tests/yarn.lock rename to extensions/vscode-custom-editor-tests/yarn.lock index 29a81a09a498..76cc46da4b7e 100644 --- a/lib/vscode/extensions/vscode-custom-editor-tests/yarn.lock +++ b/extensions/vscode-custom-editor-tests/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== "@types/p-limit@^2.2.0": version "2.2.0" diff --git a/lib/vscode/extensions/vscode-notebook-tests/.vscode/launch.json b/extensions/vscode-notebook-tests/.vscode/launch.json similarity index 100% rename from lib/vscode/extensions/vscode-notebook-tests/.vscode/launch.json rename to extensions/vscode-notebook-tests/.vscode/launch.json diff --git a/lib/vscode/extensions/vscode-notebook-tests/.vscode/tasks.json b/extensions/vscode-notebook-tests/.vscode/tasks.json similarity index 100% rename from lib/vscode/extensions/vscode-notebook-tests/.vscode/tasks.json rename to extensions/vscode-notebook-tests/.vscode/tasks.json diff --git a/lib/vscode/extensions/vscode-notebook-tests/media/icon.png b/extensions/vscode-notebook-tests/media/icon.png similarity index 100% rename from lib/vscode/extensions/vscode-notebook-tests/media/icon.png rename to extensions/vscode-notebook-tests/media/icon.png diff --git a/lib/vscode/extensions/vscode-notebook-tests/package.json b/extensions/vscode-notebook-tests/package.json similarity index 90% rename from lib/vscode/extensions/vscode-notebook-tests/package.json rename to extensions/vscode-notebook-tests/package.json index f1bdd988bee5..cc0264bb1a3a 100644 --- a/lib/vscode/extensions/vscode-notebook-tests/package.json +++ b/extensions/vscode-notebook-tests/package.json @@ -20,7 +20,7 @@ }, "dependencies": {}, "devDependencies": { - "@types/node": "^12.19.9" + "@types/node": "14.x" }, "contributes": { "commands": [ @@ -34,9 +34,9 @@ "icon": "$(debug)" } ], - "notebookProvider": [ + "notebooks": [ { - "viewType": "notebookSmokeTest", + "type": "notebookSmokeTest", "displayName": "Notebook Smoke Test", "selector": [ { @@ -46,7 +46,7 @@ ] } ], - "notebookOutputRenderer": [ + "notebookRenderer": [ { "id": "notebookCoreTestRenderer", "displayName": "Notebook Core Test Renderer", @@ -60,7 +60,7 @@ "notebook/cell/title": [ { "command": "vscode-notebook-tests.debugAction", - "when": "notebookViewType == notebookSmokeTest", + "when": "notebookType == notebookSmokeTest", "group": "inline@1" } ] diff --git a/lib/vscode/extensions/vscode-notebook-tests/src/customRenderer.js b/extensions/vscode-notebook-tests/src/customRenderer.js similarity index 76% rename from lib/vscode/extensions/vscode-notebook-tests/src/customRenderer.js rename to extensions/vscode-notebook-tests/src/customRenderer.js index f23538e38a76..94fd028eee72 100644 --- a/lib/vscode/extensions/vscode-notebook-tests/src/customRenderer.js +++ b/extensions/vscode-notebook-tests/src/customRenderer.js @@ -5,14 +5,7 @@ const vscode = acquireVsCodeApi(); -vscode.postMessage({ - type: 'custom_renderer_initialize', - payload: { - firstMessage: true - } -}); - -const notebook = acquireNotebookRendererApi('notebookCoreTestRenderer'); +const notebook = acquireNotebookRendererApi(); notebook.onDidCreateOutput(({ element, mimeType }) => { const div = document.createElement('div'); diff --git a/lib/vscode/extensions/vscode-notebook-tests/src/extension.ts b/extensions/vscode-notebook-tests/src/extension.ts similarity index 77% rename from lib/vscode/extensions/vscode-notebook-tests/src/extension.ts rename to extensions/vscode-notebook-tests/src/extension.ts index ff0b4981d508..7160f07c1a10 100644 --- a/lib/vscode/extensions/vscode-notebook-tests/src/extension.ts +++ b/extensions/vscode-notebook-tests/src/extension.ts @@ -20,24 +20,24 @@ export function activate(context: vscode.ExtensionContext): any { await vscode.commands.executeCommand('vscode.open', vscode.Uri.file(notebookPath)); })); - context.subscriptions.push(vscode.notebook.registerNotebookContentProvider('notebookSmokeTest', { + context.subscriptions.push(vscode.workspace.registerNotebookContentProvider('notebookSmokeTest', { openNotebook: async (_resource: vscode.Uri) => { const dto: vscode.NotebookData = { - metadata: new vscode.NotebookDocumentMetadata(), + metadata: {}, cells: [ { - source: 'code()', - language: 'typescript', + value: 'code()', + languageId: 'typescript', kind: vscode.NotebookCellKind.Code, outputs: [], - metadata: new vscode.NotebookCellMetadata().with({ custom: { testCellMetadata: 123 } }) + metadata: { custom: { testCellMetadata: 123 } } }, { - source: 'Markdown Cell', - language: 'markdown', - kind: vscode.NotebookCellKind.Markdown, + value: 'Markdown Cell', + languageId: 'markdown', + kind: vscode.NotebookCellKind.Markup, outputs: [], - metadata: new vscode.NotebookCellMetadata().with({ custom: { testCellMetadata: 123 } }) + metadata: { custom: { testCellMetadata: 123 } } } ] }; @@ -58,7 +58,7 @@ export function activate(context: vscode.ExtensionContext): any { } })); - const controller = vscode.notebook.createNotebookController( + const controller = vscode.notebooks.createNotebookController( 'notebookSmokeTest', 'notebookSmokeTest', 'notebookSmokeTest' @@ -66,12 +66,12 @@ export function activate(context: vscode.ExtensionContext): any { controller.executeHandler = (cells) => { for (const cell of cells) { - const task = controller.createNotebookCellExecutionTask(cell); + const task = controller.createNotebookCellExecution(cell); task.start(); task.replaceOutput([new vscode.NotebookCellOutput([ - new vscode.NotebookCellOutputItem('text/html', ['test output'], undefined) + vscode.NotebookCellOutputItem.text('test output', 'text/html') ])]); - task.end({ success: true }); + task.end(true); } }; diff --git a/lib/vscode/extensions/vscode-notebook-tests/src/index.ts b/extensions/vscode-notebook-tests/src/index.ts similarity index 100% rename from lib/vscode/extensions/vscode-notebook-tests/src/index.ts rename to extensions/vscode-notebook-tests/src/index.ts diff --git a/lib/vscode/extensions/vscode-notebook-tests/src/typings/ref.d.ts b/extensions/vscode-notebook-tests/src/typings/ref.d.ts similarity index 100% rename from lib/vscode/extensions/vscode-notebook-tests/src/typings/ref.d.ts rename to extensions/vscode-notebook-tests/src/typings/ref.d.ts diff --git a/lib/vscode/extensions/vscode-notebook-tests/src/utils.ts b/extensions/vscode-notebook-tests/src/utils.ts similarity index 100% rename from lib/vscode/extensions/vscode-notebook-tests/src/utils.ts rename to extensions/vscode-notebook-tests/src/utils.ts diff --git a/lib/vscode/extensions/vscode-notebook-tests/test/customRenderer.vsctestnb b/extensions/vscode-notebook-tests/test/customRenderer.vsctestnb similarity index 100% rename from lib/vscode/extensions/vscode-notebook-tests/test/customRenderer.vsctestnb rename to extensions/vscode-notebook-tests/test/customRenderer.vsctestnb diff --git a/lib/vscode/extensions/vscode-notebook-tests/test/empty.vsctestnb b/extensions/vscode-notebook-tests/test/empty.vsctestnb similarity index 100% rename from lib/vscode/extensions/vscode-notebook-tests/test/empty.vsctestnb rename to extensions/vscode-notebook-tests/test/empty.vsctestnb diff --git a/lib/vscode/extensions/vscode-notebook-tests/test/first.vsctestnb b/extensions/vscode-notebook-tests/test/first.vsctestnb similarity index 100% rename from lib/vscode/extensions/vscode-notebook-tests/test/first.vsctestnb rename to extensions/vscode-notebook-tests/test/first.vsctestnb diff --git a/lib/vscode/extensions/vscode-notebook-tests/test/second.vsctestnb b/extensions/vscode-notebook-tests/test/second.vsctestnb similarity index 100% rename from lib/vscode/extensions/vscode-notebook-tests/test/second.vsctestnb rename to extensions/vscode-notebook-tests/test/second.vsctestnb diff --git a/lib/vscode/extensions/vscode-notebook-tests/tsconfig.json b/extensions/vscode-notebook-tests/tsconfig.json similarity index 100% rename from lib/vscode/extensions/vscode-notebook-tests/tsconfig.json rename to extensions/vscode-notebook-tests/tsconfig.json diff --git a/extensions/vscode-notebook-tests/yarn.lock b/extensions/vscode-notebook-tests/yarn.lock new file mode 100644 index 000000000000..995b2c2f8b32 --- /dev/null +++ b/extensions/vscode-notebook-tests/yarn.lock @@ -0,0 +1,8 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== diff --git a/lib/vscode/extensions/vscode-test-resolver/.gitignore b/extensions/vscode-test-resolver/.gitignore similarity index 100% rename from lib/vscode/extensions/vscode-test-resolver/.gitignore rename to extensions/vscode-test-resolver/.gitignore diff --git a/lib/vscode/extensions/vscode-test-resolver/.vscode/launch.json b/extensions/vscode-test-resolver/.vscode/launch.json similarity index 100% rename from lib/vscode/extensions/vscode-test-resolver/.vscode/launch.json rename to extensions/vscode-test-resolver/.vscode/launch.json diff --git a/lib/vscode/extensions/vscode-test-resolver/.vscodeignore b/extensions/vscode-test-resolver/.vscodeignore similarity index 100% rename from lib/vscode/extensions/vscode-test-resolver/.vscodeignore rename to extensions/vscode-test-resolver/.vscodeignore diff --git a/lib/vscode/extensions/vscode-test-resolver/media/icon.png b/extensions/vscode-test-resolver/media/icon.png similarity index 100% rename from lib/vscode/extensions/vscode-test-resolver/media/icon.png rename to extensions/vscode-test-resolver/media/icon.png diff --git a/lib/vscode/extensions/vscode-test-resolver/package.json b/extensions/vscode-test-resolver/package.json similarity index 95% rename from lib/vscode/extensions/vscode-test-resolver/package.json rename to extensions/vscode-test-resolver/package.json index 2256c0473594..9aa252ea5110 100644 --- a/lib/vscode/extensions/vscode-test-resolver/package.json +++ b/extensions/vscode-test-resolver/package.json @@ -27,7 +27,13 @@ ], "main": "./out/extension", "devDependencies": { - "@types/node": "^12.19.9" + "@types/node": "14.x" + }, + "capabilities": { + "untrustedWorkspaces": { + "supported": true + }, + "virtualWorkspaces": true }, "contributes": { "resourceLabelFormatters": [ @@ -83,7 +89,7 @@ "statusBar/remoteIndicator": [ { "command": "vscode-testresolver.newWindow", - "when": "!remoteName", + "when": "!remoteName && !virtualWorkspace", "group": "remote_90_test_1_local@2" }, { diff --git a/lib/vscode/extensions/vscode-test-resolver/scripts/terminateProcess.sh b/extensions/vscode-test-resolver/scripts/terminateProcess.sh similarity index 100% rename from lib/vscode/extensions/vscode-test-resolver/scripts/terminateProcess.sh rename to extensions/vscode-test-resolver/scripts/terminateProcess.sh diff --git a/lib/vscode/extensions/vscode-test-resolver/src/download.ts b/extensions/vscode-test-resolver/src/download.ts similarity index 100% rename from lib/vscode/extensions/vscode-test-resolver/src/download.ts rename to extensions/vscode-test-resolver/src/download.ts diff --git a/lib/vscode/extensions/vscode-test-resolver/src/extension.ts b/extensions/vscode-test-resolver/src/extension.ts similarity index 97% rename from lib/vscode/extensions/vscode-test-resolver/src/extension.ts rename to extensions/vscode-test-resolver/src/extension.ts index c338957146bf..78301260ea7f 100644 --- a/lib/vscode/extensions/vscode-test-resolver/src/extension.ts +++ b/extensions/vscode-test-resolver/src/extension.ts @@ -52,7 +52,7 @@ export function activate(context: vscode.ExtensionContext) { const match = lastProgressLine.match(/Extension host agent listening on (\d+)/); if (match) { isResolved = true; - res(new vscode.ResolvedAuthority('localhost', parseInt(match[1], 10))); // success! + res(new vscode.ResolvedAuthority('127.0.0.1', parseInt(match[1], 10))); // success! } lastProgressLine = ''; } else if (chr === CharCode.Backspace) { @@ -200,7 +200,7 @@ export function activate(context: vscode.ExtensionContext) { } }); }); - proxyServer.listen(0, () => { + proxyServer.listen(0, '127.0.0.1', () => { const port = (proxyServer.address()).port; outputChannel.appendLine(`Going through proxy at port ${port}`); const r: vscode.ResolverResult = new vscode.ResolvedAuthority('127.0.0.1', port); @@ -216,6 +216,9 @@ export function activate(context: vscode.ExtensionContext) { } const authorityResolverDisposable = vscode.workspace.registerRemoteAuthorityResolver('test', { + async getCanonicalURI(uri: vscode.Uri): Promise { + return vscode.Uri.file(uri.path); + }, resolve(_authority: string): Thenable { return vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, @@ -265,7 +268,7 @@ export function activate(context: vscode.ExtensionContext) { const port = Number.parseInt(result); vscode.workspace.openTunnel({ remoteAddress: { - host: 'localhost', + host: '127.0.0.1', port: port }, localAddressPort: port + 1 @@ -403,10 +406,10 @@ async function tunnelFactory(tunnelOptions: vscode.TunnelOptions, tunnelCreation if (localPort < 1024 && process.platform !== 'win32') { localPort = 0; } - proxyServer.listen(localPort, () => { + proxyServer.listen(localPort, '127.0.0.1', () => { const localPort = (proxyServer.address()).port; outputChannel.appendLine(`New test resolver tunnel service: Remote ${tunnelOptions.remoteAddress.port} -> local ${localPort}`); - const tunnel = newTunnel({ host: 'localhost', port: localPort }); + const tunnel = newTunnel({ host: '127.0.0.1', port: localPort }); tunnel.onDidDispose(() => proxyServer.close()); res(tunnel); }); @@ -420,8 +423,8 @@ function runHTTPTestServer(port: number): vscode.Disposable { res.end(`Hello, World from test server running on port ${port}!`); }); remoteServers.push(port); - server.listen(port); - const message = `Opened HTTP server on http://localhost:${port}`; + server.listen(port, '127.0.0.1'); + const message = `Opened HTTP server on http://127.0.0.1:${port}`; console.log(message); outputChannel.appendLine(message); return { diff --git a/lib/vscode/extensions/vscode-test-resolver/src/typings/ref.d.ts b/extensions/vscode-test-resolver/src/typings/ref.d.ts similarity index 100% rename from lib/vscode/extensions/vscode-test-resolver/src/typings/ref.d.ts rename to extensions/vscode-test-resolver/src/typings/ref.d.ts diff --git a/lib/vscode/extensions/vscode-test-resolver/src/util/processes.ts b/extensions/vscode-test-resolver/src/util/processes.ts similarity index 100% rename from lib/vscode/extensions/vscode-test-resolver/src/util/processes.ts rename to extensions/vscode-test-resolver/src/util/processes.ts diff --git a/lib/vscode/extensions/vscode-test-resolver/tsconfig.json b/extensions/vscode-test-resolver/tsconfig.json similarity index 100% rename from lib/vscode/extensions/vscode-test-resolver/tsconfig.json rename to extensions/vscode-test-resolver/tsconfig.json diff --git a/extensions/vscode-test-resolver/yarn.lock b/extensions/vscode-test-resolver/yarn.lock new file mode 100644 index 000000000000..995b2c2f8b32 --- /dev/null +++ b/extensions/vscode-test-resolver/yarn.lock @@ -0,0 +1,8 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/node@14.x": + version "14.14.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" + integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== diff --git a/lib/vscode/extensions/xml/.vscodeignore b/extensions/xml/.vscodeignore similarity index 100% rename from lib/vscode/extensions/xml/.vscodeignore rename to extensions/xml/.vscodeignore diff --git a/lib/vscode/extensions/xml/cgmanifest.json b/extensions/xml/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/xml/cgmanifest.json rename to extensions/xml/cgmanifest.json diff --git a/lib/vscode/extensions/xml/package.json b/extensions/xml/package.json similarity index 100% rename from lib/vscode/extensions/xml/package.json rename to extensions/xml/package.json diff --git a/lib/vscode/extensions/xml/package.nls.json b/extensions/xml/package.nls.json similarity index 100% rename from lib/vscode/extensions/xml/package.nls.json rename to extensions/xml/package.nls.json diff --git a/lib/vscode/extensions/xml/syntaxes/xml.tmLanguage.json b/extensions/xml/syntaxes/xml.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/xml/syntaxes/xml.tmLanguage.json rename to extensions/xml/syntaxes/xml.tmLanguage.json diff --git a/lib/vscode/extensions/xml/syntaxes/xsl.tmLanguage.json b/extensions/xml/syntaxes/xsl.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/xml/syntaxes/xsl.tmLanguage.json rename to extensions/xml/syntaxes/xsl.tmLanguage.json diff --git a/lib/vscode/extensions/xml/xml.language-configuration.json b/extensions/xml/xml.language-configuration.json similarity index 100% rename from lib/vscode/extensions/xml/xml.language-configuration.json rename to extensions/xml/xml.language-configuration.json diff --git a/lib/vscode/extensions/xml/xsl.language-configuration.json b/extensions/xml/xsl.language-configuration.json similarity index 100% rename from lib/vscode/extensions/xml/xsl.language-configuration.json rename to extensions/xml/xsl.language-configuration.json diff --git a/lib/vscode/extensions/xml/yarn.lock b/extensions/xml/yarn.lock similarity index 100% rename from lib/vscode/extensions/xml/yarn.lock rename to extensions/xml/yarn.lock diff --git a/lib/vscode/extensions/yaml/.vscodeignore b/extensions/yaml/.vscodeignore similarity index 100% rename from lib/vscode/extensions/yaml/.vscodeignore rename to extensions/yaml/.vscodeignore diff --git a/lib/vscode/extensions/yaml/cgmanifest.json b/extensions/yaml/cgmanifest.json similarity index 100% rename from lib/vscode/extensions/yaml/cgmanifest.json rename to extensions/yaml/cgmanifest.json diff --git a/lib/vscode/extensions/yaml/language-configuration.json b/extensions/yaml/language-configuration.json similarity index 100% rename from lib/vscode/extensions/yaml/language-configuration.json rename to extensions/yaml/language-configuration.json diff --git a/lib/vscode/extensions/yaml/package.json b/extensions/yaml/package.json similarity index 100% rename from lib/vscode/extensions/yaml/package.json rename to extensions/yaml/package.json diff --git a/lib/vscode/extensions/yaml/package.nls.json b/extensions/yaml/package.nls.json similarity index 100% rename from lib/vscode/extensions/yaml/package.nls.json rename to extensions/yaml/package.nls.json diff --git a/lib/vscode/extensions/yaml/syntaxes/yaml.tmLanguage.json b/extensions/yaml/syntaxes/yaml.tmLanguage.json similarity index 100% rename from lib/vscode/extensions/yaml/syntaxes/yaml.tmLanguage.json rename to extensions/yaml/syntaxes/yaml.tmLanguage.json diff --git a/lib/vscode/extensions/yaml/yarn.lock b/extensions/yaml/yarn.lock similarity index 100% rename from lib/vscode/extensions/yaml/yarn.lock rename to extensions/yaml/yarn.lock diff --git a/lib/vscode/extensions/yarn.lock b/extensions/yarn.lock similarity index 88% rename from lib/vscode/extensions/yarn.lock rename to extensions/yarn.lock index 067a5ebba64c..78b52f40dfb9 100644 --- a/lib/vscode/extensions/yarn.lock +++ b/extensions/yarn.lock @@ -24,10 +24,10 @@ fast-plist@0.1.2: resolved "https://registry.yarnpkg.com/fast-plist/-/fast-plist-0.1.2.tgz#a45aff345196006d406ca6cdcd05f69051ef35b8" integrity sha1-pFr/NFGWAG1AbKbNzQX2kFHvNbg= -typescript@4.2.4: - version "4.2.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" - integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== +typescript@4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805" + integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw== vscode-grammar-updater@^1.0.3: version "1.0.3" diff --git a/lib/vscode/gulpfile.js b/gulpfile.js similarity index 100% rename from lib/vscode/gulpfile.js rename to gulpfile.js diff --git a/install.sh b/install.sh deleted file mode 100755 index a3e0df08c685..000000000000 --- a/install.sh +++ /dev/null @@ -1,577 +0,0 @@ -#!/bin/sh -set -eu - -# code-server's automatic install script. -# See https://github.com/cdr/code-server/blob/main/docs/install.md - -usage() { - arg0="$0" - if [ "$0" = sh ]; then - arg0="curl -fsSL https://code-server.dev/install.sh | sh -s --" - else - not_curl_usage="The latest script is available at https://code-server.dev/install.sh -" - fi - - cath < - Sets the prefix used by standalone release archives. Defaults to ~/.local - The release is unarchived into ~/.local/lib/code-server-X.X.X - and the binary symlinked into ~/.local/bin/code-server - To install system wide pass ---prefix=/usr/local - - --rsh - Specifies the remote shell for remote installation. Defaults to ssh. - -- For Debian, Ubuntu and Raspbian it will install the latest deb package. -- For Fedora, CentOS, RHEL and openSUSE it will install the latest rpm package. -- For Arch Linux it will install the AUR package. -- For any unrecognized Linux operating system it will install the latest standalone - release into ~/.local - -- For macOS it will install the Homebrew package. - - If Homebrew is not installed it will install the latest standalone release - into ~/.local - -- For FreeBSD, it will install the npm package with yarn or npm. - -- If ran on an architecture with no releases, it will install the - npm package with yarn or npm. - - We only have releases for amd64 and arm64 presently. - - The npm package builds the native modules on postinstall. - -It will cache all downloaded assets into ~/.cache/code-server - -More installation docs are at https://github.com/cdr/code-server/blob/main/docs/install.md -EOF -} - -echo_latest_version() { - # https://gist.github.com/lukechilds/a83e1d7127b78fef38c2914c4ececc3c#gistcomment-2758860 - version="$(curl -fsSLI -o /dev/null -w "%{url_effective}" https://github.com/cdr/code-server/releases/latest)" - version="${version#https://github.com/cdr/code-server/releases/tag/}" - version="${version#v}" - echo "$version" -} - -echo_npm_postinstall() { - echoh - cath < macos -# - freebsd -> freebsd -# - ubuntu, raspbian, debian ... -> debian -# - amzn, centos, rhel, fedora, ... -> fedora -# - opensuse-{leap,tumbleweed} -> opensuse -# - alpine -> alpine -# - arch -> arch -# -# Inspired by https://github.com/docker/docker-install/blob/26ff363bcf3b3f5a00498ac43694bf1c7d9ce16c/install.sh#L111-L120. -distro() { - if [ "$OS" = "macos" ] || [ "$OS" = "freebsd" ]; then - echo "$OS" - return - fi - - if [ -f /etc/os-release ]; then - ( - . /etc/os-release - if [ "${ID_LIKE-}" ]; then - for id_like in $ID_LIKE; do - case "$id_like" in debian | fedora | opensuse) - echo "$id_like" - return - ;; - esac - done - fi - - echo "$ID" - ) - return - fi -} - -# os_name prints a pretty human readable name for the OS/Distro. -distro_name() { - if [ "$(uname)" = "Darwin" ]; then - echo "macOS v$(sw_vers -productVersion)" - return - fi - - if [ -f /etc/os-release ]; then - ( - . /etc/os-release - echo "$PRETTY_NAME" - ) - return - fi - - # Prints something like: Linux 4.19.0-9-amd64 - uname -sr -} - -arch() { - case "$(uname -m)" in - aarch64) - echo arm64 - ;; - x86_64) - echo amd64 - ;; - amd64) # FreeBSD. - echo amd64 - ;; - esac -} - -command_exists() { - command -v "$@" >/dev/null -} - -sh_c() { - echoh "+ $*" - if [ ! "${DRY_RUN-}" ]; then - sh -c "$*" - fi -} - -sudo_sh_c() { - if [ "$(id -u)" = 0 ]; then - sh_c "$@" - elif command_exists sudo; then - sh_c "sudo $*" - elif command_exists su; then - sh_c "su - -c '$*'" - else - echoh - echoerr "This script needs to run the following command as root." - echoerr " $*" - echoerr "Please install sudo or su." - exit 1 - fi -} - -echo_cache_dir() { - if [ "${XDG_CACHE_HOME-}" ]; then - echo "$XDG_CACHE_HOME/code-server" - elif [ "${HOME-}" ]; then - echo "$HOME/.cache/code-server" - else - echo "/tmp/code-server-cache" - fi -} - -echoh() { - echo "$@" | humanpath -} - -cath() { - humanpath -} - -echoerr() { - echoh "$@" >&2 -} - -# humanpath replaces all occurrences of " $HOME" with " ~" -# and all occurrences of '"$HOME' with the literal '"$HOME'. -humanpath() { - sed "s# $HOME# ~#g; s#\"$HOME#\"\$HOME#g" -} - -# We need to make sure we exit with a non zero exit if the command fails. -# /bin/sh does not support -o pipefail unfortunately. -prefix() { - PREFIX="$1" - shift - fifo="$(mktemp -d)/fifo" - mkfifo "$fifo" - sed -e "s#^#$PREFIX: #" "$fifo" & - "$@" >"$fifo" 2>&1 -} - -main "$@" diff --git a/lib/vscode/.devcontainer/README.md b/lib/vscode/.devcontainer/README.md deleted file mode 100644 index 8262d411570b..000000000000 --- a/lib/vscode/.devcontainer/README.md +++ /dev/null @@ -1,100 +0,0 @@ -# Code - OSS Development Container - -This repository includes configuration for a development container for working with Code - OSS in an isolated local container or using [GitHub Codespaces](https://github.com/features/codespaces). - -> **Tip:** The default VNC password is `vscode`. The VNC server runs on port `5901` with a web client at `6080`. For better performance, we recommend using a [VNC Viewer](https://www.realvnc.com/en/connect/download/viewer/). Applications like the macOS Screen Sharing app will not perform as well. - -## Quick start - local - -1. Install Docker Desktop or Docker for Linux on your local machine. (See [docs](https://aka.ms/vscode-remote/containers/getting-started) for additional details.) - -2. **Important**: Docker needs at least **4 Cores and 6 GB of RAM (8 GB recommended)** to run full build. If you on macOS, or using the old Hyper-V engine for Windows, update these values for Docker Desktop by right-clicking on the Docker status bar item, going to **Preferences/Settings > Resources > Advanced**. - - > **Note:** The [Resource Monitor](https://marketplace.visualstudio.com/items?itemName=mutantdino.resourcemonitor) extension is included in the container so you can keep an eye on CPU/Memory in the status bar. - -3. Install [Visual Studio Code Stable](https://code.visualstudio.com/) or [Insiders](https://code.visualstudio.com/insiders/) and the [Remote - Containers](https://aka.ms/vscode-remote/download/containers) extension. - - ![Image of Remote - Containers extension](https://microsoft.github.io/vscode-remote-release/images/remote-containers-extn.png) - - > Note that the Remote - Containers extension requires the Visual Studio Code distribution of Code - OSS. See the [FAQ](https://aka.ms/vscode-remote/faq/license) for details. - -4. Press Ctrl/Cmd + Shift + P and select **Remote-Containers: Clone Repository in Container Volume...**. - - > **Tip:** While you can use your local source tree instead, operations like `yarn install` can be slow on macOS or using the Hyper-V engine on Windows. We recommend the "clone repository in container" approach instead since it uses "named volume" rather than the local filesystem. - -5. Type `https://github.com/microsoft/vscode` (or a branch or PR URL) in the input box and press Enter. - -6. After the container is running, open a web browser and go to [http://localhost:6080](http://localhost:6080) or use a [VNC Viewer](https://www.realvnc.com/en/connect/download/viewer/) to connect to `localhost:5901` and enter `vscode` as the password. - -Anything you start in VS Code or the integrated terminal will appear here. - -Next: **[Try it out!](#try-it)** - -## Quick start - GitHub Codespaces - -> **IMPORTANT:** You need to use a "Standard" sized codespace or larger (4-core, 8GB) since VS Code needs 6GB of RAM to compile. This is now the default for GitHub Codespaces, but do not downgrade to "Basic" unless you do not intend to compile. - -1. From the [microsoft/vscode GitHub repository](https://github.com/microsoft/vscode), click on the **Code** dropdown, select **Open with Codespaces**, and the **New codespace** - - > Note that you will not see these options if you are not in the beta yet. - -2. After the codespace is up and running in your browser, press F1 and select **Ports: Focus on Ports View**. - -3. You should see port `6080` under **Forwarded Ports**. Select the line and click on the globe icon to open it in a browser tab. - - > If you do not see port `6080`, press F1, select **Forward a Port** and enter port `6080`. - -4. In the new tab, you should see noVNC. Click **Connect** and enter `vscode` as the password. - -Anything you start in VS Code or the integrated terminal will appear here. - -Next: **[Try it out!](#try-it)** - -### Using VS Code with GitHub Codespaces - -You will likely see better performance when accessing the codespace you created from VS Code since you can use a[VNC Viewer](https://www.realvnc.com/en/connect/download/viewer/). Here's how to do it. - -1. [Create a codespace](#quick-start---github-codespaces) if you have not already. - -2. Set up [VS Code for use with GitHub Codespaces](https://docs.github.com/github/developing-online-with-codespaces/using-codespaces-in-visual-studio-code) - -3. After the VS Code is up and running, press F1, choose **Codespaces: Connect to Codespace**, and select the codespace you created. - -4. After you've connected to the codespace, use a [VNC Viewer](https://www.realvnc.com/en/connect/download/viewer/) to connect to `localhost:5901` and enter `vscode` as the password. - -5. Anything you start in VS Code or the integrated terminal will appear here. - -Next: **[Try it out!](#try-it)** - -## Try it! - -This container uses the [Fluxbox](http://fluxbox.org/) window manager to keep things lean. **Right-click on the desktop** to see menu options. It works with GNOME and GTK applications, so other tools can be installed if needed. - -Note you can also set the resolution from the command line by typing `set-resolution`. - -To start working with Code - OSS, follow these steps: - -1. In your local VS Code, open a terminal (Ctrl/Cmd + Shift + \`) and type the following commands: - - ```bash - yarn install - bash scripts/code.sh - ``` - - Note that a previous run of `yarn install` will already be cached, so this step should simply pick up any recent differences. - -2. After the build is complete, open a web browser or a [VNC Viewer](https://www.realvnc.com/en/connect/download/viewer/) to the desktop environnement as described in the quick start and enter `vscode` as the password. - -3. You should now see Code - OSS! - -Next, let's try debugging. - -1. Shut down Code - OSS by clicking the box in the upper right corner of the Code - OSS window through your browser or VNC viewer. - -2. Go to your local VS Code client, and use Run / Debug view to launch the **VS Code** configuration. (Typically the default, so you can likely just press F5). - - > **Note:** If launching times out, you can increase the value of `timeout` in the "VS Code", "Attach Main Process", "Attach Extension Host", and "Attach to Shared Process" configurations in [launch.json](../.vscode/launch.json). However, running `scripts/code.sh` first will set up Electron which will usually solve timeout issues. - -3. After a bit, Code - OSS will appear with the debugger attached! - -Enjoy! diff --git a/lib/vscode/.editorconfig b/lib/vscode/.editorconfig deleted file mode 100644 index e7e99b5bcb52..000000000000 --- a/lib/vscode/.editorconfig +++ /dev/null @@ -1,15 +0,0 @@ -# EditorConfig is awesome: https://EditorConfig.org - -# top-most EditorConfig file -root = true - -# Tab indentation -[*] -indent_style = tab -trim_trailing_whitespace = true - -# The indent size used in the `package.json` file cannot be changed -# https://github.com/npm/npm/pull/3180#issuecomment-16336516 -[{*.yml,*.yaml,package.json}] -indent_style = space -indent_size = 2 diff --git a/lib/vscode/.gitattributes b/lib/vscode/.gitattributes deleted file mode 100644 index 5a817c30b6d7..000000000000 --- a/lib/vscode/.gitattributes +++ /dev/null @@ -1,10 +0,0 @@ -* text=auto - -LICENSE.txt eol=crlf -ThirdPartyNotices.txt eol=crlf - -*.bat eol=crlf -*.cmd eol=crlf -*.ps1 eol=lf -*.sh eol=lf -*.rtf -text \ No newline at end of file diff --git a/lib/vscode/.github/ISSUE_TEMPLATE/config.yml b/lib/vscode/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 51e7f3660431..000000000000 --- a/lib/vscode/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,5 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: Question - url: https://stackoverflow.com/questions/tagged/visual-studio-code - about: Please ask and answer questions here. diff --git a/lib/vscode/.gitignore b/lib/vscode/.gitignore deleted file mode 100644 index c53681396d35..000000000000 --- a/lib/vscode/.gitignore +++ /dev/null @@ -1,18 +0,0 @@ -.DS_Store -.cache -npm-debug.log -Thumbs.db -node_modules/ -.build/ -extensions/**/dist/ -/out*/ -/extensions/**/out/ -# src/vs/server NOTE@coder: So our code isn't ignored. -resources/server -build/node_modules -coverage/ -test_data/ -test-results/ -yarn-error.log -vscode.lsif -vscode.db diff --git a/lib/vscode/LICENSE.txt b/lib/vscode/LICENSE.txt deleted file mode 100644 index 0ac28ee234d2..000000000000 --- a/lib/vscode/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2015 - present Microsoft Corporation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/lib/vscode/README.md b/lib/vscode/README.md deleted file mode 100644 index 0a9a62d9b7f3..000000000000 --- a/lib/vscode/README.md +++ /dev/null @@ -1,75 +0,0 @@ -# Visual Studio Code - Open Source ("Code - OSS") -[![Feature Requests](https://img.shields.io/github/issues/microsoft/vscode/feature-request.svg)](https://github.com/microsoft/vscode/issues?q=is%3Aopen+is%3Aissue+label%3Afeature-request+sort%3Areactions-%2B1-desc) -[![Bugs](https://img.shields.io/github/issues/microsoft/vscode/bug.svg)](https://github.com/microsoft/vscode/issues?utf8=✓&q=is%3Aissue+is%3Aopen+label%3Abug) -[![Gitter](https://img.shields.io/badge/chat-on%20gitter-yellow.svg)](https://gitter.im/Microsoft/vscode) - -## The Repository - -This repository ("`Code - OSS`") is where we (Microsoft) develop the [Visual Studio Code](https://code.visualstudio.com) product together with the community. Not only do we work on code and issues here, we also publish our [roadmap](https://github.com/microsoft/vscode/wiki/Roadmap), [monthly iteration plans](https://github.com/microsoft/vscode/wiki/Iteration-Plans), and our [endgame plans](https://github.com/microsoft/vscode/wiki/Running-the-Endgame). This source code is available to everyone under the standard [MIT license](https://github.com/microsoft/vscode/blob/main/LICENSE.txt). - -## Visual Studio Code - -

    - VS Code in action -

    - -[Visual Studio Code](https://code.visualstudio.com) is a distribution of the `Code - OSS` repository with Microsoft specific customizations released under a traditional [Microsoft product license](https://code.visualstudio.com/License/). - -[Visual Studio Code](https://code.visualstudio.com) combines the simplicity of a code editor with what developers need for their core edit-build-debug cycle. It provides comprehensive code editing, navigation, and understanding support along with lightweight debugging, a rich extensibility model, and lightweight integration with existing tools. - -Visual Studio Code is updated monthly with new features and bug fixes. You can download it for Windows, macOS, and Linux on [Visual Studio Code's website](https://code.visualstudio.com/Download). To get the latest releases every day, install the [Insiders build](https://code.visualstudio.com/insiders). - -## Contributing - -There are many ways in which you can participate in the project, for example: - -* [Submit bugs and feature requests](https://github.com/microsoft/vscode/issues), and help us verify as they are checked in -* Review [source code changes](https://github.com/microsoft/vscode/pulls) -* Review the [documentation](https://github.com/microsoft/vscode-docs) and make pull requests for anything from typos to new content - -If you are interested in fixing issues and contributing directly to the code base, -please see the document [How to Contribute](https://github.com/microsoft/vscode/wiki/How-to-Contribute), which covers the following: - -* [How to build and run from source](https://github.com/microsoft/vscode/wiki/How-to-Contribute) -* [The development workflow, including debugging and running tests](https://github.com/microsoft/vscode/wiki/How-to-Contribute#debugging) -* [Coding guidelines](https://github.com/microsoft/vscode/wiki/Coding-Guidelines) -* [Submitting pull requests](https://github.com/microsoft/vscode/wiki/How-to-Contribute#pull-requests) -* [Finding an issue to work on](https://github.com/microsoft/vscode/wiki/How-to-Contribute#where-to-contribute) -* [Contributing to translations](https://aka.ms/vscodeloc) - -## Feedback - -* Ask a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/vscode) -* [Request a new feature](CONTRIBUTING.md) -* Upvote [popular feature requests](https://github.com/microsoft/vscode/issues?q=is%3Aopen+is%3Aissue+label%3Afeature-request+sort%3Areactions-%2B1-desc) -* [File an issue](https://github.com/microsoft/vscode/issues) -* Follow [@code](https://twitter.com/code) and let us know what you think! - -See our [wiki](https://github.com/microsoft/vscode/wiki/Feedback-Channels) for a description of each of these channels and information on some other available community-driven channels. - -## Related Projects - -Many of the core components and extensions to VS Code live in their own repositories on GitHub. For example, the [node debug adapter](https://github.com/microsoft/vscode-node-debug) and the [mono debug adapter](https://github.com/microsoft/vscode-mono-debug) have their own repositories. For a complete list, please visit the [Related Projects](https://github.com/microsoft/vscode/wiki/Related-Projects) page on our [wiki](https://github.com/microsoft/vscode/wiki). - -## Bundled Extensions - -VS Code includes a set of built-in extensions located in the [extensions](extensions) folder, including grammars and snippets for many languages. Extensions that provide rich language support (code completion, Go to Definition) for a language have the suffix `language-features`. For example, the `json` extension provides coloring for `JSON` and the `json-language-features` provides rich language support for `JSON`. - -## Development Container - -This repository includes a Visual Studio Code Remote - Containers / Codespaces development container. - -- For [Remote - Containers](https://aka.ms/vscode-remote/download/containers), use the **Remote-Containers: Open Repository in Container...** command which creates a Docker volume for better disk I/O on macOS and Windows. -- For Codespaces, install the [Visual Studio Codespaces](https://aka.ms/vscs-ext-vscode) extension in VS Code, and use the **Codespaces: Create New Codespace** command. - -Docker / the Codespace should have at least **4 Cores and 6 GB of RAM (8 GB recommended)** to run full build. See the [development container README](.devcontainer/README.md) for more information. - -## Code of Conduct - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. - -## License - -Copyright (c) Microsoft Corporation. All rights reserved. - -Licensed under the [MIT](LICENSE.txt) license. diff --git a/lib/vscode/ThirdPartyNotices.txt b/lib/vscode/ThirdPartyNotices.txt deleted file mode 100644 index e30e71ee4a21..000000000000 --- a/lib/vscode/ThirdPartyNotices.txt +++ /dev/null @@ -1,2853 +0,0 @@ -microsoft-vscode - -THIRD-PARTY SOFTWARE NOTICES AND INFORMATION -Do Not Translate or Localize - -This project incorporates components from the projects listed below. The original copyright notices and the licenses under which Microsoft received such components are set forth below. Microsoft reserves all rights not expressly granted herein, whether by implication, estoppel or otherwise. - -1. JuliaEditorSupport/atom-language-julia version 0.21.0 (https://github.com/JuliaEditorSupport/atom-language-julia) -2. atom/language-clojure version 0.22.7 (https://github.com/atom/language-clojure) -3. atom/language-coffee-script version 0.49.3 (https://github.com/atom/language-coffee-script) -4. atom/language-css version 0.44.4 (https://github.com/atom/language-css) -5. atom/language-java version 0.32.1 (https://github.com/atom/language-java) -6. atom/language-sass version 0.61.4 (https://github.com/atom/language-sass) -7. atom/language-shellscript version 0.26.0 (https://github.com/atom/language-shellscript) -8. atom/language-xml version 0.35.2 (https://github.com/atom/language-xml) -9. better-go-syntax version 1.0.0 (https://github.com/jeff-hykin/better-go-syntax/ ) -10. Colorsublime-Themes version 0.1.0 (https://github.com/Colorsublime/Colorsublime-Themes) -11. daaain/Handlebars version 1.8.0 (https://github.com/daaain/Handlebars) -12. davidrios/pug-tmbundle (https://github.com/davidrios/pug-tmbundle) -13. definitelytyped (https://github.com/DefinitelyTyped/DefinitelyTyped) -14. demyte/language-cshtml version 0.3.0 (https://github.com/demyte/language-cshtml) -15. Document Object Model version 4.0.0 (https://www.w3.org/DOM/) -16. dotnet/csharp-tmLanguage version 0.1.0 (https://github.com/dotnet/csharp-tmLanguage) -17. expand-abbreviation version 0.5.8 (https://github.com/emmetio/expand-abbreviation) -18. fadeevab/make.tmbundle (https://github.com/fadeevab/make.tmbundle) -19. freebroccolo/atom-language-swift (https://github.com/freebroccolo/atom-language-swift) -20. HTML 5.1 W3C Working Draft version 08 October 2015 (http://www.w3.org/TR/2015/WD-html51-20151008/) -21. Ikuyadeu/vscode-R version 1.3.0 (https://github.com/Ikuyadeu/vscode-R) -22. insane version 2.6.2 (https://github.com/bevacqua/insane) -23. Ionic documentation version 1.2.4 (https://github.com/ionic-team/ionic-site) -24. ionide/ionide-fsgrammar (https://github.com/ionide/ionide-fsgrammar) -25. jeff-hykin/cpp-textmate-grammar version 1.12.11 (https://github.com/jeff-hykin/cpp-textmate-grammar) -26. jeff-hykin/cpp-textmate-grammar version 1.15.5 (https://github.com/jeff-hykin/cpp-textmate-grammar) -27. js-beautify version 1.6.8 (https://github.com/beautify-web/js-beautify) -28. Jxck/assert version 1.0.0 (https://github.com/Jxck/assert) -29. language-docker (https://github.com/moby/moby) -30. language-less version 0.34.2 (https://github.com/atom/language-less) -31. language-php version 0.46.0 (https://github.com/atom/language-php) -32. MagicStack/MagicPython version 1.1.1 (https://github.com/MagicStack/MagicPython) -33. marked version 1.1.0 (https://github.com/markedjs/marked) -34. mdn-data version 1.1.12 (https://github.com/mdn/data) -35. microsoft/TypeScript-TmLanguage version 0.0.1 (https://github.com/microsoft/TypeScript-TmLanguage) -36. microsoft/vscode-JSON.tmLanguage (https://github.com/microsoft/vscode-JSON.tmLanguage) -37. microsoft/vscode-markdown-tm-grammar version 1.0.0 (https://github.com/microsoft/vscode-markdown-tm-grammar) -38. microsoft/vscode-mssql version 1.9.0 (https://github.com/microsoft/vscode-mssql) -39. mmims/language-batchfile version 0.7.5 (https://github.com/mmims/language-batchfile) -40. NVIDIA/cuda-cpp-grammar (https://github.com/NVIDIA/cuda-cpp-grammar) -41. PowerShell/EditorSyntax version 1.0.0 (https://github.com/PowerShell/EditorSyntax) -42. rust-syntax version 0.4.3 (https://github.com/dustypomerleau/rust-syntax) -43. seti-ui version 0.1.0 (https://github.com/jesseweed/seti-ui) -44. shaders-tmLanguage version 0.1.0 (https://github.com/tgjones/shaders-tmLanguage) -45. textmate/asp.vb.net.tmbundle (https://github.com/textmate/asp.vb.net.tmbundle) -46. textmate/c.tmbundle (https://github.com/textmate/c.tmbundle) -47. textmate/diff.tmbundle (https://github.com/textmate/diff.tmbundle) -48. textmate/git.tmbundle (https://github.com/textmate/git.tmbundle) -49. textmate/groovy.tmbundle (https://github.com/textmate/groovy.tmbundle) -50. textmate/html.tmbundle (https://github.com/textmate/html.tmbundle) -51. textmate/ini.tmbundle (https://github.com/textmate/ini.tmbundle) -52. textmate/javascript.tmbundle (https://github.com/textmate/javascript.tmbundle) -53. textmate/lua.tmbundle (https://github.com/textmate/lua.tmbundle) -54. textmate/markdown.tmbundle (https://github.com/textmate/markdown.tmbundle) -55. textmate/perl.tmbundle (https://github.com/textmate/perl.tmbundle) -56. textmate/ruby.tmbundle (https://github.com/textmate/ruby.tmbundle) -57. textmate/yaml.tmbundle (https://github.com/textmate/yaml.tmbundle) -58. TypeScript-TmLanguage version 0.1.8 (https://github.com/microsoft/TypeScript-TmLanguage) -59. TypeScript-TmLanguage version 1.0.0 (https://github.com/microsoft/TypeScript-TmLanguage) -60. Unicode version 12.0.0 (https://home.unicode.org/) -61. vscode-codicons version 0.0.14 (https://github.com/microsoft/vscode-codicons) -62. vscode-logfile-highlighter version 2.11.0 (https://github.com/emilast/vscode-logfile-highlighter) -63. vscode-swift version 0.0.1 (https://github.com/owensd/vscode-swift) -64. Web Background Synchronization (https://github.com/WICG/background-sync) - - -%% JuliaEditorSupport/atom-language-julia NOTICES AND INFORMATION BEGIN HERE -========================================= -The atom-language-julia package is licensed under the MIT "Expat" License: - -> Copyright (c) 2015 -> -> Permission is hereby granted, free of charge, to any person obtaining -> a copy of this software and associated documentation files (the -> "Software"), to deal in the Software without restriction, including -> without limitation the rights to use, copy, modify, merge, publish, -> distribute, sublicense, and/or sell copies of the Software, and to -> permit persons to whom the Software is furnished to do so, subject to -> the following conditions: -> -> The above copyright notice and this permission notice shall be -> included in all copies or substantial portions of the Software. -> -> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -> IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -> CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -> TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -> SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF JuliaEditorSupport/atom-language-julia NOTICES AND INFORMATION - -%% atom/language-clojure NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) 2014 GitHub Inc. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -This package was derived from a TextMate bundle located at -https://github.com/mmcgrana/textmate-clojure and distributed under the -following license, located in `LICENSE.md`: - -The MIT License (MIT) - -Copyright (c) 2010- Mark McGranaghan - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -========================================= -END OF atom/language-clojure NOTICES AND INFORMATION - -%% atom/language-coffee-script NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2014 GitHub Inc. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -This package was derived from a TextMate bundle located at -https://github.com/jashkenas/coffee-script-tmbundle and distributed under the -following license, located in `LICENSE`: - -Copyright (c) 2009-2014 Jeremy Ashkenas - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF atom/language-coffee-script NOTICES AND INFORMATION - -%% atom/language-css NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) 2014 GitHub Inc. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------------------------- - -This package was derived from a TextMate bundle located at -https://github.com/textmate/css.tmbundle and distributed under the following -license, located in `README.mdown`: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. -========================================= -END OF atom/language-css NOTICES AND INFORMATION - -%% atom/language-java NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2014 GitHub Inc. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -This package was derived from a TextMate bundle located at -https://github.com/textmate/java.tmbundle and distributed under the following -license, located in `README.mdown`: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. -========================================= -END OF atom/language-java NOTICES AND INFORMATION - -%% atom/language-sass NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2014 GitHub Inc. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -This package was derived from a TextMate bundle located at -https://github.com/alexsancho/Sass.tmbundle and distributed under the following -license, located in `LICENSE.md`: - -Copyright (c) 2012 Alex Sancho, http://alexsancho.name/ - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF atom/language-sass NOTICES AND INFORMATION - -%% atom/language-shellscript NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2014 GitHub Inc. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -This package was derived from a TextMate bundle located at -https://github.com/textmate/shellscript.tmbundle and distributed under the -following license, located in `README.mdown`: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. -========================================= -END OF atom/language-shellscript NOTICES AND INFORMATION - -%% atom/language-xml NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2014 GitHub Inc. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -This package was derived from a TextMate bundle located at -https://github.com/textmate/xml.tmbundle and distributed under the following -license, located in `README.mdown`: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. -========================================= -END OF atom/language-xml NOTICES AND INFORMATION - -%% better-go-syntax NOTICES AND INFORMATION BEGIN HERE -========================================= -MIT License - -Copyright (c) 2019 Jeff Hykin - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -========================================= -END OF better-go-syntax NOTICES AND INFORMATION - -%% Colorsublime-Themes NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) 2015 Colorsublime.com - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -========================================= -END OF Colorsublime-Themes NOTICES AND INFORMATION - -%% daaain/Handlebars NOTICES AND INFORMATION BEGIN HERE -========================================= --- Credits - -Adapted from the great sublime-text-handlebars package by Nicholas Westlake. - -Thanks a lot to all the generous contributors (in alphabetical order): @bittersweetryan, @bradcliffe, @calumbrodie, @duncanbeevers, @hlvnst, @jonschlinkert, @Krutius, @samselikoff, @utkarshkukreti, @zeppelin - --- License - -(The MIT License) - -Copyright (c) daaain/Handlebars project authors - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF daaain/Handlebars NOTICES AND INFORMATION - -%% davidrios/pug-tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2016 David Rios - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF davidrios/pug-tmbundle NOTICES AND INFORMATION - -%% definitelytyped NOTICES AND INFORMATION BEGIN HERE -========================================= -This project is licensed under the MIT license. -Copyrights are respective of each contributor listed at the beginning of each definition file. - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF definitelytyped NOTICES AND INFORMATION - -%% demyte/language-cshtml NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2014 James Summerton - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF demyte/language-cshtml NOTICES AND INFORMATION - -%% Document Object Model NOTICES AND INFORMATION BEGIN HERE -========================================= -W3C License -This work is being provided by the copyright holders under the following license. -By obtaining and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions. -Permission to copy, modify, and distribute this work, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following -on ALL copies of the work or portions thereof, including modifications: -* The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. -* Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the W3C Software and Document Short Notice should be included. -* Notice of any changes or modifications, through a copyright statement on the new code or document such as "This software or document includes material copied from or derived -from Document Object Model. Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang)." -Disclaimers -THIS WORK IS PROVIDED "AS IS - AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR -FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. -COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. -The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the work without specific, written prior permission. -Title to copyright in this work will at all times remain with copyright holders. -========================================= -END OF Document Object Model NOTICES AND INFORMATION - -%% dotnet/csharp-tmLanguage NOTICES AND INFORMATION BEGIN HERE -========================================= -MIT License - -Copyright (c) 2016 .NET Foundation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -========================================= -END OF dotnet/csharp-tmLanguage NOTICES AND INFORMATION - -%% expand-abbreviation NOTICES AND INFORMATION BEGIN HERE -========================================= -MIT License - -Copyright (c) 2017 Emmet.io - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -========================================= -END OF expand-abbreviation NOTICES AND INFORMATION - -%% fadeevab/make.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) textmate-make.tmbundle project authors - -If not otherwise specified (see below), files in this repository fall under the following license: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. - -An exception is made for files in readable text which contain their own license information, -or files where an accompanying file exists (in the same directory) with a "-license" suffix added -to the base-name name of the original file, and an extension of txt, html, or similar. For example -"tidy" is accompanied by "tidy-license.txt". -========================================= -END OF fadeevab/make.tmbundle NOTICES AND INFORMATION - -%% freebroccolo/atom-language-swift NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2014 Darin Morrison - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF freebroccolo/atom-language-swift NOTICES AND INFORMATION - -%% HTML 5.1 W3C Working Draft NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang). This software or document includes material copied -from or derived from HTML 5.1 W3C Working Draft (http://www.w3.org/TR/2015/WD-html51-20151008/.) - -THIS DOCUMENT IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT -NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE CONTENTS OF -THE DOCUMENT ARE SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF SUCH CONTENTS WILL NOT INFRINGE ANY THIRD PARTY -PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. - -COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE -DOCUMENT OR THE PERFORMANCE OR IMPLEMENTATION OF THE CONTENTS THEREOF. - -The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to this document or its contents -without specific, written prior permission. Title to copyright in this document will at all times remain with copyright holders. -========================================= -END OF HTML 5.1 W3C Working Draft NOTICES AND INFORMATION - -%% Ikuyadeu/vscode-R NOTICES AND INFORMATION BEGIN HERE -========================================= -MIT License - -Copyright (c) 2019 Yuki Ueda - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -========================================= -END OF Ikuyadeu/vscode-R NOTICES AND INFORMATION - -%% insane NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright © 2015 Nicolas Bevacqua - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF insane NOTICES AND INFORMATION - -%% Ionic documentation NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright Drifty Co. http://drifty.com/. - -Apache License - -Version 2.0, January 2004 - -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of this License; and - -You must cause any modified files to carry prominent notices stating that You changed the files; and - -You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - -If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS -========================================= -END OF Ionic documentation NOTICES AND INFORMATION - -%% ionide/ionide-fsgrammar NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2015 Krzysztof Cieslak - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -========================================= -END OF ionide/ionide-fsgrammar NOTICES AND INFORMATION - -%% jeff-hykin/cpp-textmate-grammar NOTICES AND INFORMATION BEGIN HERE -========================================= -MIT License - -Copyright (c) 2019 Jeff Hykin - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -========================================= -END OF jeff-hykin/cpp-textmate-grammar NOTICES AND INFORMATION - -%% js-beautify NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors. - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF js-beautify NOTICES AND INFORMATION - -%% Jxck/assert NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2011 Jxck - -Originally from node.js (http://nodejs.org) -Copyright Joyent, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF Jxck/assert NOTICES AND INFORMATION - -%% language-docker NOTICES AND INFORMATION BEGIN HERE -========================================= -Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2013-2018 Docker, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -========================================= -END OF language-docker NOTICES AND INFORMATION - -%% language-less NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2014 GitHub Inc. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -This package was derived from a TextMate bundle located at -https://github.com/textmate/less.tmbundle and distributed under the following -license, located in `LICENSE.md`: - -Copyright (c) 2010 Scott Kyle and Rasmus Andersson - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -========================================= -END OF language-less NOTICES AND INFORMATION - -%% language-php NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2014 GitHub Inc. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -This package was derived from a TextMate bundle located at -https://github.com/textmate/php.tmbundle and distributed under the following -license, located in `README.mdown`: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. -========================================= -END OF language-php NOTICES AND INFORMATION - -%% MagicStack/MagicPython NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License - -Copyright (c) 2015-present MagicStack Inc. http://magic.io - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -========================================= -END OF MagicStack/MagicPython NOTICES AND INFORMATION - -%% marked NOTICES AND INFORMATION BEGIN HERE -========================================= -information - -## Contribution License Agreement - -If you contribute code to this project, you are implicitly allowing your code -to be distributed under the MIT license. You are also implicitly verifying that -all code is your original work. `` - -## Marked - -Copyright (c) 2018+, MarkedJS (https://github.com/markedjs/) -Copyright (c) 2011-2018, Christopher Jeffrey (https://github.com/chjj/) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -## Markdown - -Copyright © 2004, John Gruber -http://daringfireball.net/ -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -* Neither the name "Markdown" nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -This software is provided by the copyright holders and contributors "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright owner or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. -========================================= -END OF marked NOTICES AND INFORMATION - -%% mdn-data NOTICES AND INFORMATION BEGIN HERE -========================================= -Mozilla Public License Version 2.0 - -Copyright (c) 2018 Mozilla Corporation - -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. -========================================= -END OF mdn-data NOTICES AND INFORMATION - -%% microsoft/TypeScript-TmLanguage NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) Microsoft Corporation -All rights reserved. - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -========================================= -END OF microsoft/TypeScript-TmLanguage NOTICES AND INFORMATION - -%% microsoft/vscode-JSON.tmLanguage NOTICES AND INFORMATION BEGIN HERE -========================================= -vscode-JSON.tmLanguage - -Copyright (c) Microsoft Corporation - -All rights reserved. - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated -documentation files (the ""Software""), to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, -and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF microsoft/vscode-JSON.tmLanguage NOTICES AND INFORMATION - -%% microsoft/vscode-markdown-tm-grammar NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) Microsoft 2018 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -========================================= -END OF microsoft/vscode-markdown-tm-grammar NOTICES AND INFORMATION - -%% microsoft/vscode-mssql NOTICES AND INFORMATION BEGIN HERE -========================================= ------------------------------------------- START OF LICENSE ----------------------------------------- -vscode-mssql -Copyright (c) Microsoft Corporation -All rights reserved. -MIT License -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -Copyright (c) 2016 Microsoft -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------ END OF LICENSE ----------------------------------------- -========================================= -END OF microsoft/vscode-mssql NOTICES AND INFORMATION - -%% mmims/language-batchfile NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2021 Michael Mims - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -========================================= -END OF mmims/language-batchfile NOTICES AND INFORMATION - -%% NVIDIA/cuda-cpp-grammar NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright 2021 NVIDIA Corporation - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF NVIDIA/cuda-cpp-grammar NOTICES AND INFORMATION - -%% PowerShell/EditorSyntax NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) Microsoft Corporation - -All rights reserved. - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -========================================= -END OF PowerShell/EditorSyntax NOTICES AND INFORMATION - -%% rust-syntax NOTICES AND INFORMATION BEGIN HERE -========================================= -MIT License - -Copyright (c) 2020 Dustin Pomerleau - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -========================================= -END OF rust-syntax NOTICES AND INFORMATION - -%% seti-ui NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) 2014 Jesse Weed - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF seti-ui NOTICES AND INFORMATION - -%% shaders-tmLanguage NOTICES AND INFORMATION BEGIN HERE -========================================= -MIT License - -Copyright (c) 2017 Tim Jones - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -========================================= -END OF shaders-tmLanguage NOTICES AND INFORMATION - -%% textmate/asp.vb.net.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) textmate-asp.vb.net.tmbundle project authors - -If not otherwise specified (see below), files in this folder fall under the following license: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. - -An exception is made for files in readable text which contain their own license information, -or files where an accompanying file exists (in the same directory) with a "-license" suffix added -to the base-name name of the original file, and an extension of txt, html, or similar. For example -"tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/asp.vb.net.tmbundle NOTICES AND INFORMATION - -%% textmate/c.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) textmate-c.tmbundle authors - -If not otherwise specified (see below), files in this repository fall under the following license: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. - -An exception is made for files in readable text which contain their own license information, -or files where an accompanying file exists (in the same directory) with a "-license" suffix added -to the base-name name of the original file, and an extension of txt, html, or similar. For example -"tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/c.tmbundle NOTICES AND INFORMATION - -%% textmate/diff.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) textmate-diff.tmbundle project authors - -If not otherwise specified (see below), files in this repository fall under the following license: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. - -An exception is made for files in readable text which contain their own license information, -or files where an accompanying file exists (in the same directory) with a "-license" suffix added -to the base-name name of the original file, and an extension of txt, html, or similar. For example -"tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/diff.tmbundle NOTICES AND INFORMATION - -%% textmate/git.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2008 Tim Harper - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the" -Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF textmate/git.tmbundle NOTICES AND INFORMATION - -%% textmate/groovy.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) textmate-groovy.tmbundle project authors - -If not otherwise specified (see below), files in this repository fall under the following license: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. - -An exception is made for files in readable text which contain their own license information, -or files where an accompanying file exists (in the same directory) with a "-license" suffix added -to the base-name name of the original file, and an extension of txt, html, or similar. For example -"tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/groovy.tmbundle NOTICES AND INFORMATION - -%% textmate/html.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) textmate-html.tmbundle project authors - -If not otherwise specified (see below), files in this repository fall under the following license: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. - -An exception is made for files in readable text which contain their own license information, -or files where an accompanying file exists (in the same directory) with a "-license" suffix added -to the base-name name of the original file, and an extension of txt, html, or similar. For example -"tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/html.tmbundle NOTICES AND INFORMATION - -%% textmate/ini.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) textmate-ini.tmbundle project authors - -If not otherwise specified (see below), files in this folder fall under the following license: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. - -An exception is made for files in readable text which contain their own license information, -or files where an accompanying file exists (in the same directory) with a "-license" suffix added -to the base-name name of the original file, and an extension of txt, html, or similar. For example -"tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/ini.tmbundle NOTICES AND INFORMATION - -%% textmate/javascript.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) textmate-javascript.tmbundle project authors - -If not otherwise specified (see below), files in this repository fall under the following license: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. - -An exception is made for files in readable text which contain their own license information, -or files where an accompanying file exists (in the same directory) with a "-license" suffix added -to the base-name name of the original file, and an extension of txt, html, or similar. For example -"tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/javascript.tmbundle NOTICES AND INFORMATION - -%% textmate/lua.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) textmate-lua.tmbundle project authors - -If not otherwise specified (see below), files in this repository fall under the following license: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. - -An exception is made for files in readable text which contain their own license information, -or files where an accompanying file exists (in the same directory) with a "-license" suffix added -to the base-name name of the original file, and an extension of txt, html, or similar. For example -"tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/lua.tmbundle NOTICES AND INFORMATION - -%% textmate/markdown.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) markdown.tmbundle authors - -If not otherwise specified (see below), files in this repository fall under the following license: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. - -An exception is made for files in readable text which contain their own license information, -or files where an accompanying file exists (in the same directory) with a "-license" suffix added -to the base-name name of the original file, and an extension of txt, html, or similar. For example -"tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/markdown.tmbundle NOTICES AND INFORMATION - -%% textmate/perl.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) textmate-perl.tmbundle project authors - -If not otherwise specified (see below), files in this repository fall under the following license: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. - -An exception is made for files in readable text which contain their own license information, -or files where an accompanying file exists (in the same directory) with a "-license" suffix added -to the base-name name of the original file, and an extension of txt, html, or similar. For example -"tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/perl.tmbundle NOTICES AND INFORMATION - -%% textmate/ruby.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) textmate-ruby.tmbundle project authors - -If not otherwise specified (see below), files in this folder fall under the following license: - -Permission to copy, use, modify, sell and distribute this -software is granted. This software is provided "as is" without -express or implied warranty, and with no claim as to its -suitability for any purpose. - -An exception is made for files in readable text which contain their own license information, -or files where an accompanying file exists (in the same directory) with a "-license" suffix added -to the base-name name of the original file, and an extension of txt, html, or similar. For example -"tidy" is accompanied by "tidy-license.txt". -========================================= -END OF textmate/ruby.tmbundle NOTICES AND INFORMATION - -%% textmate/yaml.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) 2015 FichteFoll - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF textmate/yaml.tmbundle NOTICES AND INFORMATION - -%% TypeScript-TmLanguage NOTICES AND INFORMATION BEGIN HERE -========================================= -Copyright (c) Microsoft Corporation -All rights reserved. - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -========================================= -END OF TypeScript-TmLanguage NOTICES AND INFORMATION - -%% Unicode NOTICES AND INFORMATION BEGIN HERE -========================================= -Unicode Data Files include all data files under the directories -http://www.unicode.org/Public/, http://www.unicode.org/reports/, -http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and -http://www.unicode.org/utility/trac/browser/. - -Unicode Data Files do not include PDF online code charts under the -directory http://www.unicode.org/Public/. - -Software includes any source code published in the Unicode Standard -or under the directories -http://www.unicode.org/Public/, http://www.unicode.org/reports/, -http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and -http://www.unicode.org/utility/trac/browser/. - -NOTICE TO USER: Carefully read the following legal agreement. -BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S -DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), -YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE -TERMS AND CONDITIONS OF THIS AGREEMENT. -IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE -THE DATA FILES OR SOFTWARE. - -COPYRIGHT AND PERMISSION NOTICE - -Copyright (c) 1991-2017 Unicode, Inc. All rights reserved. -Distributed under the Terms of Use in http://www.unicode.org/copyright.html. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Unicode data files and any associated documentation -(the "Data Files") or Unicode software and any associated documentation -(the "Software") to deal in the Data Files or Software -without restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, and/or sell copies of -the Data Files or Software, and to permit persons to whom the Data Files -or Software are furnished to do so, provided that either -(a) this copyright and permission notice appear with all copies -of the Data Files or Software, or -(b) this copyright and permission notice appear in associated -Documentation. - -THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT OF THIRD PARTY RIGHTS. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS -NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL -DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, -DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THE DATA FILES OR SOFTWARE. - -Except as contained in this notice, the name of a copyright holder -shall not be used in advertising or otherwise to promote the sale, -use or other dealings in these Data Files or Software without prior -written authorization of the copyright holder. -========================================= -END OF Unicode NOTICES AND INFORMATION - -%% vscode-codicons NOTICES AND INFORMATION BEGIN HERE -========================================= -Attribution 4.0 International - -======================================================================= - -Creative Commons Corporation ("Creative Commons") is not a law firm and -does not provide legal services or legal advice. Distribution of -Creative Commons public licenses does not create a lawyer-client or -other relationship. Creative Commons makes its licenses and related -information available on an "as-is" basis. Creative Commons gives no -warranties regarding its licenses, any material licensed under their -terms and conditions, or any related information. Creative Commons -disclaims all liability for damages resulting from their use to the -fullest extent possible. - -Using Creative Commons Public Licenses - -Creative Commons public licenses provide a standard set of terms and -conditions that creators and other rights holders may use to share -original works of authorship and other material subject to copyright -and certain other rights specified in the public license below. The -following considerations are for informational purposes only, are not -exhaustive, and do not form part of our licenses. - - Considerations for licensors: Our public licenses are - intended for use by those authorized to give the public - permission to use material in ways otherwise restricted by - copyright and certain other rights. Our licenses are - irrevocable. Licensors should read and understand the terms - and conditions of the license they choose before applying it. - Licensors should also secure all rights necessary before - applying our licenses so that the public can reuse the - material as expected. Licensors should clearly mark any - material not subject to the license. This includes other CC- - licensed material, or material used under an exception or - limitation to copyright. More considerations for licensors: - wiki.creativecommons.org/Considerations_for_licensors - - Considerations for the public: By using one of our public - licenses, a licensor grants the public permission to use the - licensed material under specified terms and conditions. If - the licensor's permission is not necessary for any reason--for - example, because of any applicable exception or limitation to - copyright--then that use is not regulated by the license. Our - licenses grant only permissions under copyright and certain - other rights that a licensor has authority to grant. Use of - the licensed material may still be restricted for other - reasons, including because others have copyright or other - rights in the material. A licensor may make special requests, - such as asking that all changes be marked or described. - Although not required by our licenses, you are encouraged to - respect those requests where reasonable. More_considerations - for the public: - wiki.creativecommons.org/Considerations_for_licensees - -======================================================================= - -Creative Commons Attribution 4.0 International Public License - -By exercising the Licensed Rights (defined below), You accept and agree -to be bound by the terms and conditions of this Creative Commons -Attribution 4.0 International Public License ("Public License"). To the -extent this Public License may be interpreted as a contract, You are -granted the Licensed Rights in consideration of Your acceptance of -these terms and conditions, and the Licensor grants You such rights in -consideration of benefits the Licensor receives from making the -Licensed Material available under these terms and conditions. - - -Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - d. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - e. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - f. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - g. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - h. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - i. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - j. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - k. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - -Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part; and - - b. produce, reproduce, and Share Adapted Material. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties. - - -Section 3 -- License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the -following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - 4. If You Share Adapted Material You produce, the Adapter's - License You apply must not prevent recipients of the Adapted - Material from complying with this Public License. - - -Section 4 -- Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that -apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material; and - - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not -replace Your obligations under this Public License where the Licensed -Rights include other Copyright and Similar Rights. - - -Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - -Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - -Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - -Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. - - -======================================================================= - -Creative Commons is not a party to its public -licenses. Notwithstanding, Creative Commons may elect to apply one of -its public licenses to material it publishes and in those instances -will be considered the "Licensor." The text of the Creative Commons -public licenses is dedicated to the public domain under the CC0 Public -Domain Dedication. Except for the limited purpose of indicating that -material is shared under a Creative Commons public license or as -otherwise permitted by the Creative Commons policies published at -creativecommons.org/policies, Creative Commons does not authorize the -use of the trademark "Creative Commons" or any other trademark or logo -of Creative Commons without its prior written consent including, -without limitation, in connection with any unauthorized modifications -to any of its public licenses or any other arrangements, -understandings, or agreements concerning use of licensed material. For -the avoidance of doubt, this paragraph does not form part of the -public licenses. - -Creative Commons may be contacted at creativecommons.org. -========================================= -END OF vscode-codicons NOTICES AND INFORMATION - -%% vscode-logfile-highlighter NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2015 emilast - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -========================================= -END OF vscode-logfile-highlighter NOTICES AND INFORMATION - -%% vscode-swift NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2015 David Owens II - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF vscode-swift NOTICES AND INFORMATION - -%% Web Background Synchronization NOTICES AND INFORMATION BEGIN HERE -========================================= -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -========================================= -END OF Web Background Synchronization NOTICES AND INFORMATION \ No newline at end of file diff --git a/lib/vscode/build/azure-pipelines/common/createAsset.js b/lib/vscode/build/azure-pipelines/common/createAsset.js deleted file mode 100644 index 3038ff62b825..000000000000 --- a/lib/vscode/build/azure-pipelines/common/createAsset.js +++ /dev/null @@ -1,94 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; -Object.defineProperty(exports, "__esModule", { value: true }); -const fs = require("fs"); -const crypto = require("crypto"); -const azure = require("azure-storage"); -const mime = require("mime"); -const cosmos_1 = require("@azure/cosmos"); -const retry_1 = require("./retry"); -if (process.argv.length !== 6) { - console.error('Usage: node createAsset.js PLATFORM TYPE NAME FILE'); - process.exit(-1); -} -function hashStream(hashName, stream) { - return new Promise((c, e) => { - const shasum = crypto.createHash(hashName); - stream - .on('data', shasum.update.bind(shasum)) - .on('error', e) - .on('close', () => c(shasum.digest('hex'))); - }); -} -async function doesAssetExist(blobService, quality, blobName) { - const existsResult = await new Promise((c, e) => blobService.doesBlobExist(quality, blobName, (err, r) => err ? e(err) : c(r))); - return existsResult.exists; -} -async function uploadBlob(blobService, quality, blobName, filePath, fileName) { - const blobOptions = { - contentSettings: { - contentType: mime.lookup(filePath), - contentDisposition: `attachment; filename="${fileName}"`, - cacheControl: 'max-age=31536000, public' - } - }; - await new Promise((c, e) => blobService.createBlockBlobFromLocalFile(quality, blobName, filePath, blobOptions, err => err ? e(err) : c())); -} -function getEnv(name) { - const result = process.env[name]; - if (typeof result === 'undefined') { - throw new Error('Missing env: ' + name); - } - return result; -} -async function main() { - const [, , platform, type, fileName, filePath] = process.argv; - const quality = getEnv('VSCODE_QUALITY'); - const commit = getEnv('BUILD_SOURCEVERSION'); - console.log('Creating asset...'); - const stat = await new Promise((c, e) => fs.stat(filePath, (err, stat) => err ? e(err) : c(stat))); - const size = stat.size; - console.log('Size:', size); - const stream = fs.createReadStream(filePath); - const [sha1hash, sha256hash] = await Promise.all([hashStream('sha1', stream), hashStream('sha256', stream)]); - console.log('SHA1:', sha1hash); - console.log('SHA256:', sha256hash); - const blobName = commit + '/' + fileName; - const storageAccount = process.env['AZURE_STORAGE_ACCOUNT_2']; - const blobService = azure.createBlobService(storageAccount, process.env['AZURE_STORAGE_ACCESS_KEY_2']) - .withFilter(new azure.ExponentialRetryPolicyFilter(20)); - const blobExists = await doesAssetExist(blobService, quality, blobName); - if (blobExists) { - console.log(`Blob ${quality}, ${blobName} already exists, not publishing again.`); - return; - } - console.log('Uploading blobs to Azure storage...'); - await uploadBlob(blobService, quality, blobName, filePath, fileName); - console.log('Blobs successfully uploaded.'); - const asset = { - platform, - type, - url: `${process.env['AZURE_CDN_URL']}/${quality}/${blobName}`, - hash: sha1hash, - sha256hash, - size - }; - // Remove this if we ever need to rollback fast updates for windows - if (/win32/.test(platform)) { - asset.supportsFastUpdate = true; - } - console.log('Asset:', JSON.stringify(asset, null, ' ')); - const client = new cosmos_1.CosmosClient({ endpoint: process.env['AZURE_DOCUMENTDB_ENDPOINT'], key: process.env['AZURE_DOCUMENTDB_MASTERKEY'] }); - const scripts = client.database('builds').container(quality).scripts; - await retry_1.retry(() => scripts.storedProcedure('createAsset').execute('', [commit, asset, true])); -} -main().then(() => { - console.log('Asset successfully created'); - process.exit(0); -}, err => { - console.error(err); - process.exit(1); -}); diff --git a/lib/vscode/build/azure-pipelines/common/sync-mooncake.js b/lib/vscode/build/azure-pipelines/common/sync-mooncake.js deleted file mode 100644 index 1f3354226519..000000000000 --- a/lib/vscode/build/azure-pipelines/common/sync-mooncake.js +++ /dev/null @@ -1,87 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; -Object.defineProperty(exports, "__esModule", { value: true }); -const url = require("url"); -const azure = require("azure-storage"); -const mime = require("mime"); -const cosmos_1 = require("@azure/cosmos"); -const retry_1 = require("./retry"); -function log(...args) { - console.log(...[`[${new Date().toISOString()}]`, ...args]); -} -function error(...args) { - console.error(...[`[${new Date().toISOString()}]`, ...args]); -} -if (process.argv.length < 3) { - error('Usage: node sync-mooncake.js '); - process.exit(-1); -} -async function sync(commit, quality) { - log(`Synchronizing Mooncake assets for ${quality}, ${commit}...`); - const client = new cosmos_1.CosmosClient({ endpoint: process.env['AZURE_DOCUMENTDB_ENDPOINT'], key: process.env['AZURE_DOCUMENTDB_MASTERKEY'] }); - const container = client.database('builds').container(quality); - const query = `SELECT TOP 1 * FROM c WHERE c.id = "${commit}"`; - const res = await container.items.query(query, {}).fetchAll(); - if (res.resources.length !== 1) { - throw new Error(`No builds found for ${commit}`); - } - const build = res.resources[0]; - log(`Found build for ${commit}, with ${build.assets.length} assets`); - const storageAccount = process.env['AZURE_STORAGE_ACCOUNT_2']; - const blobService = azure.createBlobService(storageAccount, process.env['AZURE_STORAGE_ACCESS_KEY_2']) - .withFilter(new azure.ExponentialRetryPolicyFilter(20)); - const mooncakeBlobService = azure.createBlobService(storageAccount, process.env['MOONCAKE_STORAGE_ACCESS_KEY'], `${storageAccount}.blob.core.chinacloudapi.cn`) - .withFilter(new azure.ExponentialRetryPolicyFilter(20)); - // mooncake is fussy and far away, this is needed! - blobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000; - mooncakeBlobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000; - for (const asset of build.assets) { - try { - const blobPath = url.parse(asset.url).path; - if (!blobPath) { - throw new Error(`Failed to parse URL: ${asset.url}`); - } - const blobName = blobPath.replace(/^\/\w+\//, ''); - log(`Found ${blobName}`); - if (asset.mooncakeUrl) { - log(` Already in Mooncake ✔️`); - continue; - } - const readStream = blobService.createReadStream(quality, blobName, undefined); - const blobOptions = { - contentSettings: { - contentType: mime.lookup(blobPath), - cacheControl: 'max-age=31536000, public' - } - }; - const writeStream = mooncakeBlobService.createWriteStreamToBlockBlob(quality, blobName, blobOptions, undefined); - log(` Uploading to Mooncake...`); - await new Promise((c, e) => readStream.pipe(writeStream).on('finish', c).on('error', e)); - log(` Updating build in DB...`); - const mooncakeUrl = `${process.env['MOONCAKE_CDN_URL']}${blobPath}`; - await retry_1.retry(() => container.scripts.storedProcedure('setAssetMooncakeUrl') - .execute('', [commit, asset.platform, asset.type, mooncakeUrl])); - log(` Done ✔️`); - } - catch (err) { - error(err); - } - } - log(`All done ✔️`); -} -function main() { - const commit = process.env['BUILD_SOURCEVERSION']; - if (!commit) { - error('Skipping publish due to missing BUILD_SOURCEVERSION'); - return; - } - const quality = process.argv[2]; - sync(commit, quality).catch(err => { - error(err); - process.exit(1); - }); -} -main(); diff --git a/lib/vscode/build/azure-pipelines/common/sync-mooncake.ts b/lib/vscode/build/azure-pipelines/common/sync-mooncake.ts deleted file mode 100644 index 4ffe7a8f15bb..000000000000 --- a/lib/vscode/build/azure-pipelines/common/sync-mooncake.ts +++ /dev/null @@ -1,131 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -import * as url from 'url'; -import * as azure from 'azure-storage'; -import * as mime from 'mime'; -import { CosmosClient } from '@azure/cosmos'; -import { retry } from './retry'; - -function log(...args: any[]) { - console.log(...[`[${new Date().toISOString()}]`, ...args]); -} - -function error(...args: any[]) { - console.error(...[`[${new Date().toISOString()}]`, ...args]); -} - -if (process.argv.length < 3) { - error('Usage: node sync-mooncake.js '); - process.exit(-1); -} - -interface Build { - assets: Asset[]; -} - -interface Asset { - platform: string; - type: string; - url: string; - mooncakeUrl: string; - hash: string; - sha256hash: string; - size: number; - supportsFastUpdate?: boolean; -} - -async function sync(commit: string, quality: string): Promise { - log(`Synchronizing Mooncake assets for ${quality}, ${commit}...`); - - const client = new CosmosClient({ endpoint: process.env['AZURE_DOCUMENTDB_ENDPOINT']!, key: process.env['AZURE_DOCUMENTDB_MASTERKEY'] }); - const container = client.database('builds').container(quality); - - const query = `SELECT TOP 1 * FROM c WHERE c.id = "${commit}"`; - const res = await container.items.query(query, {}).fetchAll(); - - if (res.resources.length !== 1) { - throw new Error(`No builds found for ${commit}`); - } - - const build = res.resources[0]; - - log(`Found build for ${commit}, with ${build.assets.length} assets`); - - const storageAccount = process.env['AZURE_STORAGE_ACCOUNT_2']!; - - const blobService = azure.createBlobService(storageAccount, process.env['AZURE_STORAGE_ACCESS_KEY_2']!) - .withFilter(new azure.ExponentialRetryPolicyFilter(20)); - - const mooncakeBlobService = azure.createBlobService(storageAccount, process.env['MOONCAKE_STORAGE_ACCESS_KEY']!, `${storageAccount}.blob.core.chinacloudapi.cn`) - .withFilter(new azure.ExponentialRetryPolicyFilter(20)); - - // mooncake is fussy and far away, this is needed! - blobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000; - mooncakeBlobService.defaultClientRequestTimeoutInMs = 10 * 60 * 1000; - - for (const asset of build.assets) { - try { - const blobPath = url.parse(asset.url).path; - - if (!blobPath) { - throw new Error(`Failed to parse URL: ${asset.url}`); - } - - const blobName = blobPath.replace(/^\/\w+\//, ''); - - log(`Found ${blobName}`); - - if (asset.mooncakeUrl) { - log(` Already in Mooncake ✔️`); - continue; - } - - const readStream = blobService.createReadStream(quality, blobName, undefined!); - const blobOptions: azure.BlobService.CreateBlockBlobRequestOptions = { - contentSettings: { - contentType: mime.lookup(blobPath), - cacheControl: 'max-age=31536000, public' - } - }; - - const writeStream = mooncakeBlobService.createWriteStreamToBlockBlob(quality, blobName, blobOptions, undefined); - - log(` Uploading to Mooncake...`); - await new Promise((c, e) => readStream.pipe(writeStream).on('finish', c).on('error', e)); - - log(` Updating build in DB...`); - const mooncakeUrl = `${process.env['MOONCAKE_CDN_URL']}${blobPath}`; - await retry(() => container.scripts.storedProcedure('setAssetMooncakeUrl') - .execute('', [commit, asset.platform, asset.type, mooncakeUrl])); - - log(` Done ✔️`); - } catch (err) { - error(err); - } - } - - log(`All done ✔️`); -} - -function main(): void { - const commit = process.env['BUILD_SOURCEVERSION']; - - if (!commit) { - error('Skipping publish due to missing BUILD_SOURCEVERSION'); - return; - } - - const quality = process.argv[2]; - - sync(commit, quality).catch(err => { - error(err); - process.exit(1); - }); -} - -main(); diff --git a/lib/vscode/build/azure-pipelines/darwin/publish-server.sh b/lib/vscode/build/azure-pipelines/darwin/publish-server.sh deleted file mode 100755 index 72a85942d5a5..000000000000 --- a/lib/vscode/build/azure-pipelines/darwin/publish-server.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -set -e - -if [ "$VSCODE_ARCH" == "x64" ]; then - # package Remote Extension Host - pushd .. && mv vscode-reh-darwin vscode-server-darwin && zip -Xry vscode-server-darwin.zip vscode-server-darwin && popd - - # publish Remote Extension Host - node build/azure-pipelines/common/createAsset.js \ - server-darwin \ - archive-unsigned \ - "vscode-server-darwin.zip" \ - ../vscode-server-darwin.zip -fi diff --git a/lib/vscode/build/azure-pipelines/linux/alpine/publish.sh b/lib/vscode/build/azure-pipelines/linux/alpine/publish.sh deleted file mode 100755 index 2f5647d1ea36..000000000000 --- a/lib/vscode/build/azure-pipelines/linux/alpine/publish.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -set -e -REPO="$(pwd)" -ROOT="$REPO/.." - -PLATFORM_LINUX="linux-alpine" - -# Publish Remote Extension Host -LEGACY_SERVER_BUILD_NAME="vscode-reh-$PLATFORM_LINUX" -SERVER_BUILD_NAME="vscode-server-$PLATFORM_LINUX" -SERVER_TARBALL_FILENAME="vscode-server-$PLATFORM_LINUX.tar.gz" -SERVER_TARBALL_PATH="$ROOT/$SERVER_TARBALL_FILENAME" - -rm -rf $ROOT/vscode-server-*.tar.* -(cd $ROOT && mv $LEGACY_SERVER_BUILD_NAME $SERVER_BUILD_NAME && tar --owner=0 --group=0 -czf $SERVER_TARBALL_PATH $SERVER_BUILD_NAME) - -node build/azure-pipelines/common/createAsset.js "server-$PLATFORM_LINUX" archive-unsigned "$SERVER_TARBALL_FILENAME" "$SERVER_TARBALL_PATH" - -# Publish Remote Extension Host (Web) -LEGACY_SERVER_BUILD_NAME="vscode-reh-web-$PLATFORM_LINUX" -SERVER_BUILD_NAME="vscode-server-$PLATFORM_LINUX-web" -SERVER_TARBALL_FILENAME="vscode-server-$PLATFORM_LINUX-web.tar.gz" -SERVER_TARBALL_PATH="$ROOT/$SERVER_TARBALL_FILENAME" - -rm -rf $ROOT/vscode-server-*-web.tar.* -(cd $ROOT && mv $LEGACY_SERVER_BUILD_NAME $SERVER_BUILD_NAME && tar --owner=0 --group=0 -czf $SERVER_TARBALL_PATH $SERVER_BUILD_NAME) - -node build/azure-pipelines/common/createAsset.js "server-$PLATFORM_LINUX-web" archive-unsigned "$SERVER_TARBALL_FILENAME" "$SERVER_TARBALL_PATH" diff --git a/lib/vscode/build/azure-pipelines/sync-mooncake.yml b/lib/vscode/build/azure-pipelines/sync-mooncake.yml deleted file mode 100644 index 6e379754f2f8..000000000000 --- a/lib/vscode/build/azure-pipelines/sync-mooncake.yml +++ /dev/null @@ -1,24 +0,0 @@ -steps: - - task: NodeTool@0 - inputs: - versionSpec: "14.x" - - - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - inputs: - versionSpec: "1.x" - - - task: AzureKeyVault@1 - displayName: "Azure Key Vault: Get Secrets" - inputs: - azureSubscription: "vscode-builds-subscription" - KeyVaultName: vscode - - - script: | - set -e - - (cd build ; yarn) - - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - MOONCAKE_STORAGE_ACCESS_KEY="$(vscode-mooncake-storage-key)" \ - node build/azure-pipelines/common/sync-mooncake.js "$VSCODE_QUALITY" diff --git a/lib/vscode/build/azure-pipelines/web/publish.sh b/lib/vscode/build/azure-pipelines/web/publish.sh deleted file mode 100755 index 827edc2661bf..000000000000 --- a/lib/vscode/build/azure-pipelines/web/publish.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash -set -e -REPO="$(pwd)" -ROOT="$REPO/.." - -# Publish Web Client -WEB_BUILD_NAME="vscode-web" -WEB_TARBALL_FILENAME="vscode-web.tar.gz" -WEB_TARBALL_PATH="$ROOT/$WEB_TARBALL_FILENAME" - -rm -rf $ROOT/vscode-web.tar.* - -(cd $ROOT && tar --owner=0 --group=0 -czf $WEB_TARBALL_PATH $WEB_BUILD_NAME) - -node build/azure-pipelines/common/createAsset.js web-standalone archive-unsigned "$WEB_TARBALL_FILENAME" "$WEB_TARBALL_PATH" diff --git a/lib/vscode/build/lib/i18n.js b/lib/vscode/build/lib/i18n.js deleted file mode 100644 index 50ec3f3f45a0..000000000000 --- a/lib/vscode/build/lib/i18n.js +++ /dev/null @@ -1,1204 +0,0 @@ -"use strict"; -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.prepareIslFiles = exports.prepareI18nPackFiles = exports.pullI18nPackFiles = exports.prepareI18nFiles = exports.pullSetupXlfFiles = exports.pullCoreAndExtensionsXlfFiles = exports.findObsoleteResources = exports.pushXlfFiles = exports.createXlfFilesForIsl = exports.createXlfFilesForExtensions = exports.createXlfFilesForCoreBundle = exports.getResource = exports.processNlsFiles = exports.Limiter = exports.XLF = exports.Line = exports.externalExtensionsWithTranslations = exports.extraLanguages = exports.defaultLanguages = void 0; -const path = require("path"); -const fs = require("fs"); -const event_stream_1 = require("event-stream"); -const File = require("vinyl"); -const Is = require("is"); -const xml2js = require("xml2js"); -const glob = require("glob"); -const https = require("https"); -const gulp = require("gulp"); -const fancyLog = require("fancy-log"); -const ansiColors = require("ansi-colors"); -const iconv = require("iconv-lite-umd"); -const NUMBER_OF_CONCURRENT_DOWNLOADS = 4; -function log(message, ...rest) { - fancyLog(ansiColors.green('[i18n]'), message, ...rest); -} -exports.defaultLanguages = [ - { id: 'zh-tw', folderName: 'cht', translationId: 'zh-hant' }, - { id: 'zh-cn', folderName: 'chs', translationId: 'zh-hans' }, - { id: 'ja', folderName: 'jpn' }, - { id: 'ko', folderName: 'kor' }, - { id: 'de', folderName: 'deu' }, - { id: 'fr', folderName: 'fra' }, - { id: 'es', folderName: 'esn' }, - { id: 'ru', folderName: 'rus' }, - { id: 'it', folderName: 'ita' } -]; -// languages requested by the community to non-stable builds -exports.extraLanguages = [ - { id: 'pt-br', folderName: 'ptb' }, - { id: 'hu', folderName: 'hun' }, - { id: 'tr', folderName: 'trk' } -]; -// non built-in extensions also that are transifex and need to be part of the language packs -exports.externalExtensionsWithTranslations = { - 'vscode-chrome-debug': 'msjsdiag.debugger-for-chrome', - 'vscode-node-debug': 'ms-vscode.node-debug', - 'vscode-node-debug2': 'ms-vscode.node-debug2' -}; -var LocalizeInfo; -(function (LocalizeInfo) { - function is(value) { - let candidate = value; - return Is.defined(candidate) && Is.string(candidate.key) && (Is.undef(candidate.comment) || (Is.array(candidate.comment) && candidate.comment.every(element => Is.string(element)))); - } - LocalizeInfo.is = is; -})(LocalizeInfo || (LocalizeInfo = {})); -var BundledFormat; -(function (BundledFormat) { - function is(value) { - if (Is.undef(value)) { - return false; - } - let candidate = value; - let length = Object.keys(value).length; - return length === 3 && Is.defined(candidate.keys) && Is.defined(candidate.messages) && Is.defined(candidate.bundles); - } - BundledFormat.is = is; -})(BundledFormat || (BundledFormat = {})); -var PackageJsonFormat; -(function (PackageJsonFormat) { - function is(value) { - if (Is.undef(value) || !Is.object(value)) { - return false; - } - return Object.keys(value).every(key => { - let element = value[key]; - return Is.string(element) || (Is.object(element) && Is.defined(element.message) && Is.defined(element.comment)); - }); - } - PackageJsonFormat.is = is; -})(PackageJsonFormat || (PackageJsonFormat = {})); -class Line { - constructor(indent = 0) { - this.buffer = []; - if (indent > 0) { - this.buffer.push(new Array(indent + 1).join(' ')); - } - } - append(value) { - this.buffer.push(value); - return this; - } - toString() { - return this.buffer.join(''); - } -} -exports.Line = Line; -class TextModel { - constructor(contents) { - this._lines = contents.split(/\r\n|\r|\n/); - } - get lines() { - return this._lines; - } -} -class XLF { - constructor(project) { - this.project = project; - this.buffer = []; - this.files = Object.create(null); - this.numberOfMessages = 0; - } - toString() { - this.appendHeader(); - for (let file in this.files) { - this.appendNewLine(``, 2); - for (let item of this.files[file]) { - this.addStringItem(file, item); - } - this.appendNewLine('', 2); - } - this.appendFooter(); - return this.buffer.join('\r\n'); - } - addFile(original, keys, messages) { - if (keys.length === 0) { - console.log('No keys in ' + original); - return; - } - if (keys.length !== messages.length) { - throw new Error(`Unmatching keys(${keys.length}) and messages(${messages.length}).`); - } - this.numberOfMessages += keys.length; - this.files[original] = []; - let existingKeys = new Set(); - for (let i = 0; i < keys.length; i++) { - let key = keys[i]; - let realKey; - let comment; - if (Is.string(key)) { - realKey = key; - comment = undefined; - } - else if (LocalizeInfo.is(key)) { - realKey = key.key; - if (key.comment && key.comment.length > 0) { - comment = key.comment.map(comment => encodeEntities(comment)).join('\r\n'); - } - } - if (!realKey || existingKeys.has(realKey)) { - continue; - } - existingKeys.add(realKey); - let message = encodeEntities(messages[i]); - this.files[original].push({ id: realKey, message: message, comment: comment }); - } - } - addStringItem(file, item) { - if (!item.id || item.message === undefined || item.message === null) { - throw new Error(`No item ID or value specified: ${JSON.stringify(item)}. File: ${file}`); - } - if (item.message.length === 0) { - log(`Item with id ${item.id} in file ${file} has an empty message.`); - } - this.appendNewLine(``, 4); - this.appendNewLine(`${item.message}`, 6); - if (item.comment) { - this.appendNewLine(`${item.comment}`, 6); - } - this.appendNewLine('', 4); - } - appendHeader() { - this.appendNewLine('', 0); - this.appendNewLine('', 0); - } - appendFooter() { - this.appendNewLine('', 0); - } - appendNewLine(content, indent) { - let line = new Line(indent); - line.append(content); - this.buffer.push(line.toString()); - } -} -exports.XLF = XLF; -XLF.parsePseudo = function (xlfString) { - return new Promise((resolve) => { - let parser = new xml2js.Parser(); - let files = []; - parser.parseString(xlfString, function (_err, result) { - const fileNodes = result['xliff']['file']; - fileNodes.forEach(file => { - const originalFilePath = file.$.original; - const messages = {}; - const transUnits = file.body[0]['trans-unit']; - if (transUnits) { - transUnits.forEach((unit) => { - const key = unit.$.id; - const val = pseudify(unit.source[0]['_'].toString()); - if (key && val) { - messages[key] = decodeEntities(val); - } - }); - files.push({ messages: messages, originalFilePath: originalFilePath, language: 'ps' }); - } - }); - resolve(files); - }); - }); -}; -XLF.parse = function (xlfString) { - return new Promise((resolve, reject) => { - let parser = new xml2js.Parser(); - let files = []; - parser.parseString(xlfString, function (err, result) { - if (err) { - reject(new Error(`XLF parsing error: Failed to parse XLIFF string. ${err}`)); - } - const fileNodes = result['xliff']['file']; - if (!fileNodes) { - reject(new Error(`XLF parsing error: XLIFF file does not contain "xliff" or "file" node(s) required for parsing.`)); - } - fileNodes.forEach((file) => { - const originalFilePath = file.$.original; - if (!originalFilePath) { - reject(new Error(`XLF parsing error: XLIFF file node does not contain original attribute to determine the original location of the resource file.`)); - } - let language = file.$['target-language']; - if (!language) { - reject(new Error(`XLF parsing error: XLIFF file node does not contain target-language attribute to determine translated language.`)); - } - const messages = {}; - const transUnits = file.body[0]['trans-unit']; - if (transUnits) { - transUnits.forEach((unit) => { - const key = unit.$.id; - if (!unit.target) { - return; // No translation available - } - let val = unit.target[0]; - if (typeof val !== 'string') { - // We allow empty source values so support them for translations as well. - val = val._ ? val._ : ''; - } - if (!key) { - reject(new Error(`XLF parsing error: trans-unit ${JSON.stringify(unit, undefined, 0)} defined in file ${originalFilePath} is missing the ID attribute.`)); - return; - } - messages[key] = decodeEntities(val); - }); - files.push({ messages: messages, originalFilePath: originalFilePath, language: language.toLowerCase() }); - } - }); - resolve(files); - }); - }); -}; -class Limiter { - constructor(maxDegreeOfParalellism) { - this.maxDegreeOfParalellism = maxDegreeOfParalellism; - this.outstandingPromises = []; - this.runningPromises = 0; - } - queue(factory) { - return new Promise((c, e) => { - this.outstandingPromises.push({ factory, c, e }); - this.consume(); - }); - } - consume() { - while (this.outstandingPromises.length && this.runningPromises < this.maxDegreeOfParalellism) { - const iLimitedTask = this.outstandingPromises.shift(); - this.runningPromises++; - const promise = iLimitedTask.factory(); - promise.then(iLimitedTask.c).catch(iLimitedTask.e); - promise.then(() => this.consumed()).catch(() => this.consumed()); - } - } - consumed() { - this.runningPromises--; - this.consume(); - } -} -exports.Limiter = Limiter; -function sortLanguages(languages) { - return languages.sort((a, b) => { - return a.id < b.id ? -1 : (a.id > b.id ? 1 : 0); - }); -} -function stripComments(content) { - /** - * First capturing group matches double quoted string - * Second matches single quotes string - * Third matches block comments - * Fourth matches line comments - */ - const regexp = /("(?:[^\\\"]*(?:\\.)?)*")|('(?:[^\\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g; - let result = content.replace(regexp, (match, _m1, _m2, m3, m4) => { - // Only one of m1, m2, m3, m4 matches - if (m3) { - // A block comment. Replace with nothing - return ''; - } - else if (m4) { - // A line comment. If it ends in \r?\n then keep it. - let length = m4.length; - if (length > 2 && m4[length - 1] === '\n') { - return m4[length - 2] === '\r' ? '\r\n' : '\n'; - } - else { - return ''; - } - } - else { - // We match a string - return match; - } - }); - return result; -} -function escapeCharacters(value) { - const result = []; - for (let i = 0; i < value.length; i++) { - const ch = value.charAt(i); - switch (ch) { - case '\'': - result.push('\\\''); - break; - case '"': - result.push('\\"'); - break; - case '\\': - result.push('\\\\'); - break; - case '\n': - result.push('\\n'); - break; - case '\r': - result.push('\\r'); - break; - case '\t': - result.push('\\t'); - break; - case '\b': - result.push('\\b'); - break; - case '\f': - result.push('\\f'); - break; - default: - result.push(ch); - } - } - return result.join(''); -} -function processCoreBundleFormat(fileHeader, languages, json, emitter) { - let keysSection = json.keys; - let messageSection = json.messages; - let bundleSection = json.bundles; - let statistics = Object.create(null); - let defaultMessages = Object.create(null); - let modules = Object.keys(keysSection); - modules.forEach((module) => { - let keys = keysSection[module]; - let messages = messageSection[module]; - if (!messages || keys.length !== messages.length) { - emitter.emit('error', `Message for module ${module} corrupted. Mismatch in number of keys and messages.`); - return; - } - let messageMap = Object.create(null); - defaultMessages[module] = messageMap; - keys.map((key, i) => { - if (typeof key === 'string') { - messageMap[key] = messages[i]; - } - else { - messageMap[key.key] = messages[i]; - } - }); - }); - let languageDirectory = path.join(__dirname, '..', '..', '..', 'vscode-loc', 'i18n'); - if (!fs.existsSync(languageDirectory)) { - log(`No VS Code localization repository found. Looking at ${languageDirectory}`); - log(`To bundle translations please check out the vscode-loc repository as a sibling of the vscode repository.`); - } - let sortedLanguages = sortLanguages(languages); - sortedLanguages.forEach((language) => { - if (process.env['VSCODE_BUILD_VERBOSE']) { - log(`Generating nls bundles for: ${language.id}`); - } - statistics[language.id] = 0; - let localizedModules = Object.create(null); - let languageFolderName = language.translationId || language.id; - let i18nFile = path.join(languageDirectory, `vscode-language-pack-${languageFolderName}`, 'translations', 'main.i18n.json'); - let allMessages; - if (fs.existsSync(i18nFile)) { - let content = stripComments(fs.readFileSync(i18nFile, 'utf8')); - allMessages = JSON.parse(content); - } - modules.forEach((module) => { - let order = keysSection[module]; - let moduleMessage; - if (allMessages) { - moduleMessage = allMessages.contents[module]; - } - if (!moduleMessage) { - if (process.env['VSCODE_BUILD_VERBOSE']) { - log(`No localized messages found for module ${module}. Using default messages.`); - } - moduleMessage = defaultMessages[module]; - statistics[language.id] = statistics[language.id] + Object.keys(moduleMessage).length; - } - let localizedMessages = []; - order.forEach((keyInfo) => { - let key = null; - if (typeof keyInfo === 'string') { - key = keyInfo; - } - else { - key = keyInfo.key; - } - let message = moduleMessage[key]; - if (!message) { - if (process.env['VSCODE_BUILD_VERBOSE']) { - log(`No localized message found for key ${key} in module ${module}. Using default message.`); - } - message = defaultMessages[module][key]; - statistics[language.id] = statistics[language.id] + 1; - } - localizedMessages.push(message); - }); - localizedModules[module] = localizedMessages; - }); - Object.keys(bundleSection).forEach((bundle) => { - let modules = bundleSection[bundle]; - let contents = [ - fileHeader, - `define("${bundle}.nls.${language.id}", {` - ]; - modules.forEach((module, index) => { - contents.push(`\t"${module}": [`); - let messages = localizedModules[module]; - if (!messages) { - emitter.emit('error', `Didn't find messages for module ${module}.`); - return; - } - messages.forEach((message, index) => { - contents.push(`\t\t"${escapeCharacters(message)}${index < messages.length ? '",' : '"'}`); - }); - contents.push(index < modules.length - 1 ? '\t],' : '\t]'); - }); - contents.push('});'); - emitter.queue(new File({ path: bundle + '.nls.' + language.id + '.js', contents: Buffer.from(contents.join('\n'), 'utf-8') })); - }); - }); - Object.keys(statistics).forEach(key => { - let value = statistics[key]; - log(`${key} has ${value} untranslated strings.`); - }); - sortedLanguages.forEach(language => { - let stats = statistics[language.id]; - if (Is.undef(stats)) { - log(`\tNo translations found for language ${language.id}. Using default language instead.`); - } - }); -} -function processNlsFiles(opts) { - return event_stream_1.through(function (file) { - let fileName = path.basename(file.path); - if (fileName === 'nls.metadata.json') { - let json = null; - if (file.isBuffer()) { - json = JSON.parse(file.contents.toString('utf8')); - } - else { - this.emit('error', `Failed to read component file: ${file.relative}`); - return; - } - if (BundledFormat.is(json)) { - processCoreBundleFormat(opts.fileHeader, opts.languages, json, this); - } - } - this.queue(file); - }); -} -exports.processNlsFiles = processNlsFiles; -const editorProject = 'vscode-editor', workbenchProject = 'vscode-workbench', extensionsProject = 'vscode-extensions', setupProject = 'vscode-setup'; -function getResource(sourceFile) { - let resource; - if (/^vs\/platform/.test(sourceFile)) { - return { name: 'vs/platform', project: editorProject }; - } - else if (/^vs\/editor\/contrib/.test(sourceFile)) { - return { name: 'vs/editor/contrib', project: editorProject }; - } - else if (/^vs\/editor/.test(sourceFile)) { - return { name: 'vs/editor', project: editorProject }; - } - else if (/^vs\/base/.test(sourceFile)) { - return { name: 'vs/base', project: editorProject }; - } - else if (/^vs\/code/.test(sourceFile)) { - return { name: 'vs/code', project: workbenchProject }; - } - else if (/^vs\/workbench\/contrib/.test(sourceFile)) { - resource = sourceFile.split('/', 4).join('/'); - return { name: resource, project: workbenchProject }; - } - else if (/^vs\/workbench\/services/.test(sourceFile)) { - resource = sourceFile.split('/', 4).join('/'); - return { name: resource, project: workbenchProject }; - } - else if (/^vs\/workbench/.test(sourceFile)) { - return { name: 'vs/workbench', project: workbenchProject }; - } - throw new Error(`Could not identify the XLF bundle for ${sourceFile}`); -} -exports.getResource = getResource; -function createXlfFilesForCoreBundle() { - return event_stream_1.through(function (file) { - const basename = path.basename(file.path); - if (basename === 'nls.metadata.json') { - if (file.isBuffer()) { - const xlfs = Object.create(null); - const json = JSON.parse(file.contents.toString('utf8')); - for (let coreModule in json.keys) { - const projectResource = getResource(coreModule); - const resource = projectResource.name; - const project = projectResource.project; - const keys = json.keys[coreModule]; - const messages = json.messages[coreModule]; - if (keys.length !== messages.length) { - this.emit('error', `There is a mismatch between keys and messages in ${file.relative} for module ${coreModule}`); - return; - } - else { - let xlf = xlfs[resource]; - if (!xlf) { - xlf = new XLF(project); - xlfs[resource] = xlf; - } - xlf.addFile(`src/${coreModule}`, keys, messages); - } - } - for (let resource in xlfs) { - const xlf = xlfs[resource]; - const filePath = `${xlf.project}/${resource.replace(/\//g, '_')}.xlf`; - const xlfFile = new File({ - path: filePath, - contents: Buffer.from(xlf.toString(), 'utf8') - }); - this.queue(xlfFile); - } - } - else { - this.emit('error', new Error(`File ${file.relative} is not using a buffer content`)); - return; - } - } - else { - this.emit('error', new Error(`File ${file.relative} is not a core meta data file.`)); - return; - } - }); -} -exports.createXlfFilesForCoreBundle = createXlfFilesForCoreBundle; -function createXlfFilesForExtensions() { - let counter = 0; - let folderStreamEnded = false; - let folderStreamEndEmitted = false; - return event_stream_1.through(function (extensionFolder) { - const folderStream = this; - const stat = fs.statSync(extensionFolder.path); - if (!stat.isDirectory()) { - return; - } - let extensionName = path.basename(extensionFolder.path); - if (extensionName === 'node_modules') { - return; - } - counter++; - let _xlf; - function getXlf() { - if (!_xlf) { - _xlf = new XLF(extensionsProject); - } - return _xlf; - } - gulp.src([`.build/extensions/${extensionName}/package.nls.json`, `.build/extensions/${extensionName}/**/nls.metadata.json`], { allowEmpty: true }).pipe(event_stream_1.through(function (file) { - if (file.isBuffer()) { - const buffer = file.contents; - const basename = path.basename(file.path); - if (basename === 'package.nls.json') { - const json = JSON.parse(buffer.toString('utf8')); - const keys = Object.keys(json); - const messages = keys.map((key) => { - const value = json[key]; - if (Is.string(value)) { - return value; - } - else if (value) { - return value.message; - } - else { - return `Unknown message for key: ${key}`; - } - }); - getXlf().addFile(`extensions/${extensionName}/package`, keys, messages); - } - else if (basename === 'nls.metadata.json') { - const json = JSON.parse(buffer.toString('utf8')); - const relPath = path.relative(`.build/extensions/${extensionName}`, path.dirname(file.path)); - for (let file in json) { - const fileContent = json[file]; - getXlf().addFile(`extensions/${extensionName}/${relPath}/${file}`, fileContent.keys, fileContent.messages); - } - } - else { - this.emit('error', new Error(`${file.path} is not a valid extension nls file`)); - return; - } - } - }, function () { - if (_xlf) { - let xlfFile = new File({ - path: path.join(extensionsProject, extensionName + '.xlf'), - contents: Buffer.from(_xlf.toString(), 'utf8') - }); - folderStream.queue(xlfFile); - } - this.queue(null); - counter--; - if (counter === 0 && folderStreamEnded && !folderStreamEndEmitted) { - folderStreamEndEmitted = true; - folderStream.queue(null); - } - })); - }, function () { - folderStreamEnded = true; - if (counter === 0) { - folderStreamEndEmitted = true; - this.queue(null); - } - }); -} -exports.createXlfFilesForExtensions = createXlfFilesForExtensions; -function createXlfFilesForIsl() { - return event_stream_1.through(function (file) { - let projectName, resourceFile; - if (path.basename(file.path) === 'Default.isl') { - projectName = setupProject; - resourceFile = 'setup_default.xlf'; - } - else { - projectName = workbenchProject; - resourceFile = 'setup_messages.xlf'; - } - let xlf = new XLF(projectName), keys = [], messages = []; - let model = new TextModel(file.contents.toString()); - let inMessageSection = false; - model.lines.forEach(line => { - if (line.length === 0) { - return; - } - let firstChar = line.charAt(0); - switch (firstChar) { - case ';': - // Comment line; - return; - case '[': - inMessageSection = '[Messages]' === line || '[CustomMessages]' === line; - return; - } - if (!inMessageSection) { - return; - } - let sections = line.split('='); - if (sections.length !== 2) { - throw new Error(`Badly formatted message found: ${line}`); - } - else { - let key = sections[0]; - let value = sections[1]; - if (key.length > 0 && value.length > 0) { - keys.push(key); - messages.push(value); - } - } - }); - const originalPath = file.path.substring(file.cwd.length + 1, file.path.split('.')[0].length).replace(/\\/g, '/'); - xlf.addFile(originalPath, keys, messages); - // Emit only upon all ISL files combined into single XLF instance - const newFilePath = path.join(projectName, resourceFile); - const xlfFile = new File({ path: newFilePath, contents: Buffer.from(xlf.toString(), 'utf-8') }); - this.queue(xlfFile); - }); -} -exports.createXlfFilesForIsl = createXlfFilesForIsl; -function pushXlfFiles(apiHostname, username, password) { - let tryGetPromises = []; - let updateCreatePromises = []; - return event_stream_1.through(function (file) { - const project = path.dirname(file.relative); - const fileName = path.basename(file.path); - const slug = fileName.substr(0, fileName.length - '.xlf'.length); - const credentials = `${username}:${password}`; - // Check if resource already exists, if not, then create it. - let promise = tryGetResource(project, slug, apiHostname, credentials); - tryGetPromises.push(promise); - promise.then(exists => { - if (exists) { - promise = updateResource(project, slug, file, apiHostname, credentials); - } - else { - promise = createResource(project, slug, file, apiHostname, credentials); - } - updateCreatePromises.push(promise); - }); - }, function () { - // End the pipe only after all the communication with Transifex API happened - Promise.all(tryGetPromises).then(() => { - Promise.all(updateCreatePromises).then(() => { - this.queue(null); - }).catch((reason) => { throw new Error(reason); }); - }).catch((reason) => { throw new Error(reason); }); - }); -} -exports.pushXlfFiles = pushXlfFiles; -function getAllResources(project, apiHostname, username, password) { - return new Promise((resolve, reject) => { - const credentials = `${username}:${password}`; - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resources`, - auth: credentials, - method: 'GET' - }; - const request = https.request(options, (res) => { - let buffer = []; - res.on('data', (chunk) => buffer.push(chunk)); - res.on('end', () => { - if (res.statusCode === 200) { - let json = JSON.parse(Buffer.concat(buffer).toString()); - if (Array.isArray(json)) { - resolve(json.map(o => o.slug)); - return; - } - reject(`Unexpected data format. Response code: ${res.statusCode}.`); - } - else { - reject(`No resources in ${project} returned no data. Response code: ${res.statusCode}.`); - } - }); - }); - request.on('error', (err) => { - reject(`Failed to query resources in ${project} with the following error: ${err}. ${options.path}`); - }); - request.end(); - }); -} -function findObsoleteResources(apiHostname, username, password) { - let resourcesByProject = Object.create(null); - resourcesByProject[extensionsProject] = [].concat(exports.externalExtensionsWithTranslations); // clone - return event_stream_1.through(function (file) { - const project = path.dirname(file.relative); - const fileName = path.basename(file.path); - const slug = fileName.substr(0, fileName.length - '.xlf'.length); - let slugs = resourcesByProject[project]; - if (!slugs) { - resourcesByProject[project] = slugs = []; - } - slugs.push(slug); - this.push(file); - }, function () { - const json = JSON.parse(fs.readFileSync('./build/lib/i18n.resources.json', 'utf8')); - let i18Resources = [...json.editor, ...json.workbench].map((r) => r.project + '/' + r.name.replace(/\//g, '_')); - let extractedResources = []; - for (let project of [workbenchProject, editorProject]) { - for (let resource of resourcesByProject[project]) { - if (resource !== 'setup_messages') { - extractedResources.push(project + '/' + resource); - } - } - } - if (i18Resources.length !== extractedResources.length) { - console.log(`[i18n] Obsolete resources in file 'build/lib/i18n.resources.json': JSON.stringify(${i18Resources.filter(p => extractedResources.indexOf(p) === -1)})`); - console.log(`[i18n] Missing resources in file 'build/lib/i18n.resources.json': JSON.stringify(${extractedResources.filter(p => i18Resources.indexOf(p) === -1)})`); - } - let promises = []; - for (let project in resourcesByProject) { - promises.push(getAllResources(project, apiHostname, username, password).then(resources => { - let expectedResources = resourcesByProject[project]; - let unusedResources = resources.filter(resource => resource && expectedResources.indexOf(resource) === -1); - if (unusedResources.length) { - console.log(`[transifex] Obsolete resources in project '${project}': ${unusedResources.join(', ')}`); - } - })); - } - return Promise.all(promises).then(_ => { - this.push(null); - }).catch((reason) => { throw new Error(reason); }); - }); -} -exports.findObsoleteResources = findObsoleteResources; -function tryGetResource(project, slug, apiHostname, credentials) { - return new Promise((resolve, reject) => { - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/?details`, - auth: credentials, - method: 'GET' - }; - const request = https.request(options, (response) => { - if (response.statusCode === 404) { - resolve(false); - } - else if (response.statusCode === 200) { - resolve(true); - } - else { - reject(`Failed to query resource ${project}/${slug}. Response: ${response.statusCode} ${response.statusMessage}`); - } - }); - request.on('error', (err) => { - reject(`Failed to get ${project}/${slug} on Transifex: ${err}`); - }); - request.end(); - }); -} -function createResource(project, slug, xlfFile, apiHostname, credentials) { - return new Promise((_resolve, reject) => { - const data = JSON.stringify({ - 'content': xlfFile.contents.toString(), - 'name': slug, - 'slug': slug, - 'i18n_type': 'XLIFF' - }); - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resources`, - headers: { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(data) - }, - auth: credentials, - method: 'POST' - }; - let request = https.request(options, (res) => { - if (res.statusCode === 201) { - log(`Resource ${project}/${slug} successfully created on Transifex.`); - } - else { - reject(`Something went wrong in the request creating ${slug} in ${project}. ${res.statusCode}`); - } - }); - request.on('error', (err) => { - reject(`Failed to create ${project}/${slug} on Transifex: ${err}`); - }); - request.write(data); - request.end(); - }); -} -/** - * The following link provides information about how Transifex handles updates of a resource file: - * https://dev.befoolish.co/tx-docs/public/projects/updating-content#what-happens-when-you-update-files - */ -function updateResource(project, slug, xlfFile, apiHostname, credentials) { - return new Promise((resolve, reject) => { - const data = JSON.stringify({ content: xlfFile.contents.toString() }); - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/content`, - headers: { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(data) - }, - auth: credentials, - method: 'PUT' - }; - let request = https.request(options, (res) => { - if (res.statusCode === 200) { - res.setEncoding('utf8'); - let responseBuffer = ''; - res.on('data', function (chunk) { - responseBuffer += chunk; - }); - res.on('end', () => { - const response = JSON.parse(responseBuffer); - log(`Resource ${project}/${slug} successfully updated on Transifex. Strings added: ${response.strings_added}, updated: ${response.strings_added}, deleted: ${response.strings_added}`); - resolve(); - }); - } - else { - reject(`Something went wrong in the request updating ${slug} in ${project}. ${res.statusCode}`); - } - }); - request.on('error', (err) => { - reject(`Failed to update ${project}/${slug} on Transifex: ${err}`); - }); - request.write(data); - request.end(); - }); -} -// cache resources -let _coreAndExtensionResources; -function pullCoreAndExtensionsXlfFiles(apiHostname, username, password, language, externalExtensions) { - if (!_coreAndExtensionResources) { - _coreAndExtensionResources = []; - // editor and workbench - const json = JSON.parse(fs.readFileSync('./build/lib/i18n.resources.json', 'utf8')); - _coreAndExtensionResources.push(...json.editor); - _coreAndExtensionResources.push(...json.workbench); - // extensions - let extensionsToLocalize = Object.create(null); - glob.sync('.build/extensions/**/*.nls.json').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); - glob.sync('.build/extensions/*/node_modules/vscode-nls').forEach(extension => extensionsToLocalize[extension.split('/')[2]] = true); - Object.keys(extensionsToLocalize).forEach(extension => { - _coreAndExtensionResources.push({ name: extension, project: extensionsProject }); - }); - if (externalExtensions) { - for (let resourceName in externalExtensions) { - _coreAndExtensionResources.push({ name: resourceName, project: extensionsProject }); - } - } - } - return pullXlfFiles(apiHostname, username, password, language, _coreAndExtensionResources); -} -exports.pullCoreAndExtensionsXlfFiles = pullCoreAndExtensionsXlfFiles; -function pullSetupXlfFiles(apiHostname, username, password, language, includeDefault) { - let setupResources = [{ name: 'setup_messages', project: workbenchProject }]; - if (includeDefault) { - setupResources.push({ name: 'setup_default', project: setupProject }); - } - return pullXlfFiles(apiHostname, username, password, language, setupResources); -} -exports.pullSetupXlfFiles = pullSetupXlfFiles; -function pullXlfFiles(apiHostname, username, password, language, resources) { - const credentials = `${username}:${password}`; - let expectedTranslationsCount = resources.length; - let translationsRetrieved = 0, called = false; - return event_stream_1.readable(function (_count, callback) { - // Mark end of stream when all resources were retrieved - if (translationsRetrieved === expectedTranslationsCount) { - return this.emit('end'); - } - if (!called) { - called = true; - const stream = this; - resources.map(function (resource) { - retrieveResource(language, resource, apiHostname, credentials).then((file) => { - if (file) { - stream.emit('data', file); - } - translationsRetrieved++; - }).catch(error => { throw new Error(error); }); - }); - } - callback(); - }); -} -const limiter = new Limiter(NUMBER_OF_CONCURRENT_DOWNLOADS); -function retrieveResource(language, resource, apiHostname, credentials) { - return limiter.queue(() => new Promise((resolve, reject) => { - const slug = resource.name.replace(/\//g, '_'); - const project = resource.project; - let transifexLanguageId = language.id === 'ps' ? 'en' : language.translationId || language.id; - const options = { - hostname: apiHostname, - path: `/api/2/project/${project}/resource/${slug}/translation/${transifexLanguageId}?file&mode=onlyreviewed`, - auth: credentials, - port: 443, - method: 'GET' - }; - console.log('[transifex] Fetching ' + options.path); - let request = https.request(options, (res) => { - let xlfBuffer = []; - res.on('data', (chunk) => xlfBuffer.push(chunk)); - res.on('end', () => { - if (res.statusCode === 200) { - resolve(new File({ contents: Buffer.concat(xlfBuffer), path: `${project}/${slug}.xlf` })); - } - else if (res.statusCode === 404) { - console.log(`[transifex] ${slug} in ${project} returned no data.`); - resolve(null); - } - else { - reject(`${slug} in ${project} returned no data. Response code: ${res.statusCode}.`); - } - }); - }); - request.on('error', (err) => { - reject(`Failed to query resource ${slug} with the following error: ${err}. ${options.path}`); - }); - request.end(); - })); -} -function prepareI18nFiles() { - let parsePromises = []; - return event_stream_1.through(function (xlf) { - let stream = this; - let parsePromise = XLF.parse(xlf.contents.toString()); - parsePromises.push(parsePromise); - parsePromise.then(resolvedFiles => { - resolvedFiles.forEach(file => { - let translatedFile = createI18nFile(file.originalFilePath, file.messages); - stream.queue(translatedFile); - }); - }); - }, function () { - Promise.all(parsePromises) - .then(() => { this.queue(null); }) - .catch(reason => { throw new Error(reason); }); - }); -} -exports.prepareI18nFiles = prepareI18nFiles; -function createI18nFile(originalFilePath, messages) { - let result = Object.create(null); - result[''] = [ - '--------------------------------------------------------------------------------------------', - 'Copyright (c) Microsoft Corporation. All rights reserved.', - 'Licensed under the MIT License. See License.txt in the project root for license information.', - '--------------------------------------------------------------------------------------------', - 'Do not edit this file. It is machine generated.' - ]; - for (let key of Object.keys(messages)) { - result[key] = messages[key]; - } - let content = JSON.stringify(result, null, '\t'); - if (process.platform === 'win32') { - content = content.replace(/\n/g, '\r\n'); - } - return new File({ - path: path.join(originalFilePath + '.i18n.json'), - contents: Buffer.from(content, 'utf8') - }); -} -const i18nPackVersion = '1.0.0'; -function pullI18nPackFiles(apiHostname, username, password, language, resultingTranslationPaths) { - return pullCoreAndExtensionsXlfFiles(apiHostname, username, password, language, exports.externalExtensionsWithTranslations) - .pipe(prepareI18nPackFiles(exports.externalExtensionsWithTranslations, resultingTranslationPaths, language.id === 'ps')); -} -exports.pullI18nPackFiles = pullI18nPackFiles; -function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths, pseudo = false) { - let parsePromises = []; - let mainPack = { version: i18nPackVersion, contents: {} }; - let extensionsPacks = {}; - let errors = []; - return event_stream_1.through(function (xlf) { - let project = path.basename(path.dirname(xlf.relative)); - let resource = path.basename(xlf.relative, '.xlf'); - let contents = xlf.contents.toString(); - let parsePromise = pseudo ? XLF.parsePseudo(contents) : XLF.parse(contents); - parsePromises.push(parsePromise); - parsePromise.then(resolvedFiles => { - resolvedFiles.forEach(file => { - const path = file.originalFilePath; - const firstSlash = path.indexOf('/'); - if (project === extensionsProject) { - let extPack = extensionsPacks[resource]; - if (!extPack) { - extPack = extensionsPacks[resource] = { version: i18nPackVersion, contents: {} }; - } - const externalId = externalExtensions[resource]; - if (!externalId) { // internal extension: remove 'extensions/extensionId/' segnent - const secondSlash = path.indexOf('/', firstSlash + 1); - extPack.contents[path.substr(secondSlash + 1)] = file.messages; - } - else { - extPack.contents[path] = file.messages; - } - } - else { - mainPack.contents[path.substr(firstSlash + 1)] = file.messages; - } - }); - }).catch(reason => { - errors.push(reason); - }); - }, function () { - Promise.all(parsePromises) - .then(() => { - if (errors.length > 0) { - throw errors; - } - const translatedMainFile = createI18nFile('./main', mainPack); - resultingTranslationPaths.push({ id: 'vscode', resourceName: 'main.i18n.json' }); - this.queue(translatedMainFile); - for (let extension in extensionsPacks) { - const translatedExtFile = createI18nFile(`extensions/${extension}`, extensionsPacks[extension]); - this.queue(translatedExtFile); - const externalExtensionId = externalExtensions[extension]; - if (externalExtensionId) { - resultingTranslationPaths.push({ id: externalExtensionId, resourceName: `extensions/${extension}.i18n.json` }); - } - else { - resultingTranslationPaths.push({ id: `vscode.${extension}`, resourceName: `extensions/${extension}.i18n.json` }); - } - } - this.queue(null); - }) - .catch((reason) => { - this.emit('error', reason); - }); - }); -} -exports.prepareI18nPackFiles = prepareI18nPackFiles; -function prepareIslFiles(language, innoSetupConfig) { - let parsePromises = []; - return event_stream_1.through(function (xlf) { - let stream = this; - let parsePromise = XLF.parse(xlf.contents.toString()); - parsePromises.push(parsePromise); - parsePromise.then(resolvedFiles => { - resolvedFiles.forEach(file => { - if (path.basename(file.originalFilePath) === 'Default' && !innoSetupConfig.defaultInfo) { - return; - } - let translatedFile = createIslFile(file.originalFilePath, file.messages, language, innoSetupConfig); - stream.queue(translatedFile); - }); - }).catch(reason => { - this.emit('error', reason); - }); - }, function () { - Promise.all(parsePromises) - .then(() => { this.queue(null); }) - .catch(reason => { - this.emit('error', reason); - }); - }); -} -exports.prepareIslFiles = prepareIslFiles; -function createIslFile(originalFilePath, messages, language, innoSetup) { - let content = []; - let originalContent; - if (path.basename(originalFilePath) === 'Default') { - originalContent = new TextModel(fs.readFileSync(originalFilePath + '.isl', 'utf8')); - } - else { - originalContent = new TextModel(fs.readFileSync(originalFilePath + '.en.isl', 'utf8')); - } - originalContent.lines.forEach(line => { - if (line.length > 0) { - let firstChar = line.charAt(0); - if (firstChar === '[' || firstChar === ';') { - content.push(line); - } - else { - let sections = line.split('='); - let key = sections[0]; - let translated = line; - if (key) { - if (key === 'LanguageName') { - translated = `${key}=${innoSetup.defaultInfo.name}`; - } - else if (key === 'LanguageID') { - translated = `${key}=${innoSetup.defaultInfo.id}`; - } - else if (key === 'LanguageCodePage') { - translated = `${key}=${innoSetup.codePage.substr(2)}`; - } - else { - let translatedMessage = messages[key]; - if (translatedMessage) { - translated = `${key}=${translatedMessage}`; - } - } - } - content.push(translated); - } - } - }); - const basename = path.basename(originalFilePath); - const filePath = `${basename}.${language.id}.isl`; - const encoded = iconv.encode(Buffer.from(content.join('\r\n'), 'utf8').toString(), innoSetup.codePage); - return new File({ - path: filePath, - contents: Buffer.from(encoded), - }); -} -function encodeEntities(value) { - let result = []; - for (let i = 0; i < value.length; i++) { - let ch = value[i]; - switch (ch) { - case '<': - result.push('<'); - break; - case '>': - result.push('>'); - break; - case '&': - result.push('&'); - break; - default: - result.push(ch); - } - } - return result.join(''); -} -function decodeEntities(value) { - return value.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'); -} -function pseudify(message) { - return '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D'; -} diff --git a/lib/vscode/build/npm/update-localization-extension.js b/lib/vscode/build/npm/update-localization-extension.js deleted file mode 100644 index b1656dc88f44..000000000000 --- a/lib/vscode/build/npm/update-localization-extension.js +++ /dev/null @@ -1,132 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -let i18n = require("../lib/i18n"); - -let fs = require("fs"); -let path = require("path"); - -let gulp = require('gulp'); -let vfs = require("vinyl-fs"); -let rimraf = require('rimraf'); -let minimist = require('minimist'); - -function update(options) { - let idOrPath = options._; - if (!idOrPath) { - throw new Error('Argument must be the location of the localization extension.'); - } - let transifex = options.transifex; - let location = options.location; - if (transifex === true && location !== undefined) { - throw new Error('Either --transifex or --location can be specified, but not both.'); - } - if (!transifex && !location) { - transifex = true; - } - if (location !== undefined && !fs.existsSync(location)) { - throw new Error(`${location} doesn't exist.`); - } - let locExtFolder = idOrPath; - if (/^\w{2}(-\w+)?$/.test(idOrPath)) { - locExtFolder = path.join('..', 'vscode-loc', 'i18n', `vscode-language-pack-${idOrPath}`); - } - let locExtStat = fs.statSync(locExtFolder); - if (!locExtStat || !locExtStat.isDirectory) { - throw new Error('No directory found at ' + idOrPath); - } - let packageJSON = JSON.parse(fs.readFileSync(path.join(locExtFolder, 'package.json')).toString()); - let contributes = packageJSON['contributes']; - if (!contributes) { - throw new Error('The extension must define a "localizations" contribution in the "package.json"'); - } - let localizations = contributes['localizations']; - if (!localizations) { - throw new Error('The extension must define a "localizations" contribution of type array in the "package.json"'); - } - - localizations.forEach(function (localization) { - if (!localization.languageId || !localization.languageName || !localization.localizedLanguageName) { - throw new Error('Each localization contribution must define "languageId", "languageName" and "localizedLanguageName" properties.'); - } - let server = localization.server || 'www.transifex.com'; - let userName = localization.userName || 'api'; - let apiToken = process.env.TRANSIFEX_API_TOKEN; - let languageId = localization.transifexId || localization.languageId; - let translationDataFolder = path.join(locExtFolder, 'translations'); - if (languageId === "zh-cn") { - languageId = "zh-hans"; - } - if (languageId === "zh-tw") { - languageId = "zh-hant"; - } - if (fs.existsSync(translationDataFolder) && fs.existsSync(path.join(translationDataFolder, 'main.i18n.json'))) { - console.log('Clearing \'' + translationDataFolder + '\'...'); - rimraf.sync(translationDataFolder); - } - - if (transifex) { - console.log(`Downloading translations for ${languageId} to '${translationDataFolder}' ...`); - let translationPaths = []; - i18n.pullI18nPackFiles(server, userName, apiToken, { id: languageId }, translationPaths) - .on('error', (error) => { - console.log(`Error occurred while importing translations:`); - translationPaths = undefined; - if (Array.isArray(error)) { - error.forEach(console.log); - } else if (error) { - console.log(error); - } else { - console.log('Unknown error'); - } - }) - .pipe(vfs.dest(translationDataFolder)) - .on('end', function () { - if (translationPaths !== undefined) { - localization.translations = []; - for (let tp of translationPaths) { - localization.translations.push({ id: tp.id, path: `./translations/${tp.resourceName}`}); - } - fs.writeFileSync(path.join(locExtFolder, 'package.json'), JSON.stringify(packageJSON, null, '\t')); - } - }); - } else { - console.log(`Importing translations for ${languageId} form '${location}' to '${translationDataFolder}' ...`); - let translationPaths = []; - gulp.src(path.join(location, languageId, '**', '*.xlf')) - .pipe(i18n.prepareI18nPackFiles(i18n.externalExtensionsWithTranslations, translationPaths, languageId === 'ps')) - .on('error', (error) => { - console.log(`Error occurred while importing translations:`); - translationPaths = undefined; - if (Array.isArray(error)) { - error.forEach(console.log); - } else if (error) { - console.log(error); - } else { - console.log('Unknown error'); - } - }) - .pipe(vfs.dest(translationDataFolder)) - .on('end', function () { - if (translationPaths !== undefined) { - localization.translations = []; - for (let tp of translationPaths) { - localization.translations.push({ id: tp.id, path: `./translations/${tp.resourceName}`}); - } - fs.writeFileSync(path.join(locExtFolder, 'package.json'), JSON.stringify(packageJSON, null, '\t')); - } - }); - } - }); -} -if (path.basename(process.argv[1]) === 'update-localization-extension.js') { - var options = minimist(process.argv.slice(2), { - boolean: 'transifex', - string: 'location' - }); - update(options); -} diff --git a/lib/vscode/coder.js b/lib/vscode/coder.js deleted file mode 100644 index cbc448059531..000000000000 --- a/lib/vscode/coder.js +++ /dev/null @@ -1,63 +0,0 @@ -// This must be ran from VS Code's root. -const gulp = require("gulp"); -const path = require("path"); -const _ = require("underscore"); -const buildfile = require("./src/buildfile"); -const common = require("./build/lib/optimize"); -const util = require("./build/lib/util"); - -const vscodeEntryPoints = _.flatten([ - buildfile.entrypoint("vs/workbench/workbench.web.api"), - buildfile.entrypoint("vs/server/entry"), - buildfile.base, - buildfile.workbenchWeb, - buildfile.workerExtensionHost, - buildfile.workerNotebook, - buildfile.keyboardMaps, - buildfile.entrypoint("vs/platform/files/node/watcher/unix/watcherApp"), - buildfile.entrypoint("vs/platform/files/node/watcher/nsfw/watcherApp"), - buildfile.entrypoint("vs/workbench/services/extensions/node/extensionHostProcess"), -]); - -const vscodeResources = [ - "out-build/vs/server/fork.js", - "!out-build/vs/server/doc/**", - "out-build/vs/workbench/services/extensions/worker/extensionHostWorkerMain.js", - "out-build/bootstrap.js", - "out-build/bootstrap-fork.js", - "out-build/bootstrap-amd.js", - 'out-build/bootstrap-node.js', - "out-build/paths.js", - 'out-build/vs/**/*.{svg,png,html,ttf,jpg}', - "!out-build/vs/code/browser/workbench/*.html", - '!out-build/vs/code/electron-browser/**', - "out-build/vs/base/common/performance.js", - "out-build/vs/base/node/languagePacks.js", - 'out-build/vs/base/browser/ui/codicons/codicon/**', - "out-build/vs/workbench/browser/media/*-theme.css", - "out-build/vs/workbench/contrib/debug/**/*.json", - "out-build/vs/workbench/contrib/externalTerminal/**/*.scpt", - "out-build/vs/workbench/contrib/webview/browser/pre/*.js", - "out-build/vs/**/markdown.css", - "out-build/vs/workbench/contrib/tasks/**/*.json", - "out-build/vs/platform/files/**/*.md", - "!**/test/**" -]; - -gulp.task("optimize", gulp.series( - util.rimraf("out-vscode"), - common.optimizeTask({ - src: "out-build", - entryPoints: vscodeEntryPoints, - resources: vscodeResources, - loaderConfig: common.loaderConfig(), - out: "out-vscode", - inlineAmdImages: true, - bundleInfo: undefined - }), -)); - -gulp.task("minify", gulp.series( - util.rimraf("out-vscode-min"), - common.minifyTask("out-vscode") -)); diff --git a/lib/vscode/extensions/github-authentication/src/extension.ts b/lib/vscode/extensions/github-authentication/src/extension.ts deleted file mode 100644 index 253f3aec579e..000000000000 --- a/lib/vscode/extensions/github-authentication/src/extension.ts +++ /dev/null @@ -1,91 +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 vscode from 'vscode'; -import { GitHubAuthenticationProvider, onDidChangeSessions } from './github'; -import { uriHandler } from './githubServer'; -import Logger from './common/logger'; -import TelemetryReporter from 'vscode-extension-telemetry'; -import { createExperimentationService, ExperimentationTelemetry } from './experimentationService'; - -export async function activate(context: vscode.ExtensionContext) { - const { name, version, aiKey } = require('../package.json') as { name: string, version: string, aiKey: string }; - const telemetryReporter = new ExperimentationTelemetry(new TelemetryReporter(name, version, aiKey)); - - const experimentationService = await createExperimentationService(context, telemetryReporter); - await experimentationService.initialFetch; - - context.subscriptions.push(vscode.window.registerUriHandler(uriHandler)); - const loginService = new GitHubAuthenticationProvider(context, telemetryReporter); - - await loginService.initialize(context); - - context.subscriptions.push(vscode.commands.registerCommand('github.provide-token', () => { - return loginService.manuallyProvideToken(); - })); - - context.subscriptions.push(vscode.authentication.registerAuthenticationProvider('github', 'GitHub', { - onDidChangeSessions: onDidChangeSessions.event, - getSessions: (scopes?: string[]) => loginService.getSessions(scopes), - createSession: async (scopeList: string[]) => { - try { - /* __GDPR__ - "login" : { } - */ - telemetryReporter.sendTelemetryEvent('login'); - - const session = await loginService.createSession(scopeList.sort().join(' ')); - Logger.info('Login success!'); - onDidChangeSessions.fire({ added: [session], removed: [], changed: [] }); - return session; - } catch (e) { - // If login was cancelled, do not notify user. - if (e.message === 'Cancelled') { - /* __GDPR__ - "loginCancelled" : { } - */ - telemetryReporter.sendTelemetryEvent('loginCancelled'); - throw e; - } - - /* __GDPR__ - "loginFailed" : { } - */ - telemetryReporter.sendTelemetryEvent('loginFailed'); - - vscode.window.showErrorMessage(`Sign in failed: ${e}`); - Logger.error(e); - throw e; - } - }, - removeSession: async (id: string) => { - try { - /* __GDPR__ - "logout" : { } - */ - telemetryReporter.sendTelemetryEvent('logout'); - - const session = await loginService.removeSession(id); - if (session) { - onDidChangeSessions.fire({ added: [], removed: [session], changed: [] }); - } - } catch (e) { - /* __GDPR__ - "logoutFailed" : { } - */ - telemetryReporter.sendTelemetryEvent('logoutFailed'); - - vscode.window.showErrorMessage(`Sign out failed: ${e}`); - Logger.error(e); - throw e; - } - } - }, { supportsMultipleAccounts: false })); - - return; -} - -// this method is called when your extension is deactivated -export function deactivate() { } diff --git a/lib/vscode/extensions/jake/yarn.lock b/lib/vscode/extensions/jake/yarn.lock deleted file mode 100644 index 687f15f481e5..000000000000 --- a/lib/vscode/extensions/jake/yarn.lock +++ /dev/null @@ -1,13 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== - -vscode-nls@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" - integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== diff --git a/lib/vscode/extensions/markdown-language-features/notebook/index.ts b/lib/vscode/extensions/markdown-language-features/notebook/index.ts deleted file mode 100644 index 1d7c65233447..000000000000 --- a/lib/vscode/extensions/markdown-language-features/notebook/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -const MarkdownIt = require('markdown-it'); - -export async function activate(ctx: { - dependencies: ReadonlyArray<{ entrypoint: string }> -}) { - let markdownIt = new MarkdownIt({ - html: true - }); - - // Should we load the deps before this point? - // Also could we await inside `renderMarkup`? - await Promise.all(ctx.dependencies.map(async (dep) => { - try { - const api = await import(dep.entrypoint); - if (api?.extendMarkdownIt) { - markdownIt = api.extendMarkdownIt(markdownIt); - } - } catch (e) { - console.error('Could not load markdown entryPoint', e); - } - })); - - return { - renderMarkup: (context: { element: HTMLElement, content: string }) => { - const rendered = markdownIt.render(context.content); - context.element.innerHTML = rendered; - - // Insert styles into markdown preview shadow dom so that they are applied - for (const markdownStyleNode of document.getElementsByClassName('markdown-style')) { - context.element.appendChild(markdownStyleNode.cloneNode(true)); - } - } - }; -} diff --git a/lib/vscode/extensions/markdown-language-features/src/util/resources.ts b/lib/vscode/extensions/markdown-language-features/src/util/resources.ts deleted file mode 100644 index 063c410b39ee..000000000000 --- a/lib/vscode/extensions/markdown-language-features/src/util/resources.ts +++ /dev/null @@ -1,33 +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 vscode from 'vscode'; - -export interface WebviewResourceProvider { - asWebviewUri(resource: vscode.Uri): vscode.Uri; - - readonly cspSource: string; -} - -export function normalizeResource( - base: vscode.Uri, - resource: vscode.Uri -): vscode.Uri { - // If we have a windows path and are loading a workspace with an authority, - // make sure we use a unc path with an explicit localhost authority. - // - // Otherwise, the `` rule will insert the authority into the resolved resource - // URI incorrectly. - if (base.authority && !resource.authority) { - const driveMatch = resource.path.match(/^\/(\w):\//); - if (driveMatch) { - return vscode.Uri.file(`\\\\localhost\\${driveMatch[1]}$\\${resource.fsPath.replace(/^\w:\\/, '')}`).with({ - fragment: resource.fragment, - query: resource.query - }); - } - } - return resource; -} diff --git a/lib/vscode/extensions/merge-conflict/yarn.lock b/lib/vscode/extensions/merge-conflict/yarn.lock deleted file mode 100644 index 687f15f481e5..000000000000 --- a/lib/vscode/extensions/merge-conflict/yarn.lock +++ /dev/null @@ -1,13 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== - -vscode-nls@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" - integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== diff --git a/lib/vscode/extensions/php/syntaxes/html.tmLanguage.json b/lib/vscode/extensions/php/syntaxes/html.tmLanguage.json deleted file mode 100644 index 4bf15294159f..000000000000 --- a/lib/vscode/extensions/php/syntaxes/html.tmLanguage.json +++ /dev/null @@ -1,189 +0,0 @@ -{ - "information_for_contributors": [ - "This file has been converted from https://github.com/atom/language-php/blob/master/grammars/html.cson", - "If you want to provide a fix or improvement, please create a pull request against the original repository.", - "Once accepted there, we are happy to receive an update request." - ], - "version": "https://github.com/atom/language-php/commit/b6c5e83016b52311cdc622c2579462861ee91587", - "name": "PHP", - "scopeName": "text.html.php", - "injections": { - "L:source.php string.quoted.single.sql.php source.sql.embedded.php": { - "patterns": [ - { - "match": "(#)(\\\\'|[^'])*(?='|$)", - "name": "comment.line.number-sign.sql", - "captures": { - "1": { - "name": "punctuation.definition.comment.sql" - } - } - }, - { - "match": "(--)(\\\\'|[^'])*(?='|$)", - "name": "comment.line.double-dash.sql", - "captures": { - "1": { - "name": "punctuation.definition.comment.sql" - } - } - }, - { - "match": "\\\\[\\\\'`\"]", - "name": "constant.character.escape.php" - }, - { - "match": "\"(?=((\\\\\")|[^\"'])*('|$))", - "name": "string.quoted.double.unclosed.sql" - } - ] - }, - "L:source.php string.quoted.double.sql.php source.sql.embedded.php": { - "patterns": [ - { - "match": "(#)(\\\\\"|[^\"])*(?=\"|$)", - "name": "comment.line.number-sign.sql", - "captures": { - "1": { - "name": "punctuation.definition.comment.sql" - } - } - }, - { - "match": "(--)(\\\\\"|[^\"])*(?=\"|$)", - "name": "comment.line.double-dash.sql", - "captures": { - "1": { - "name": "punctuation.definition.comment.sql" - } - } - }, - { - "match": "\\\\[\\\\'`\"]", - "name": "constant.character.escape.php" - }, - { - "match": "(')([^'\\\\]*)(')", - "name": "string.quoted.single.sql", - "captures": { - "1": { - "name": "punctuation.definition.string.begin.sql" - }, - "2": { - "patterns": [ - { - "include": "source.php#interpolation_double_quoted" - } - ] - }, - "3": { - "name": "punctuation.definition.string.end.sql" - } - } - }, - { - "match": "(`)([^`\\\\]*)(`)", - "name": "string.quoted.other.backtick.sql", - "captures": { - "1": { - "name": "punctuation.definition.string.begin.sql" - }, - "2": { - "patterns": [ - { - "include": "source.php#interpolation_double_quoted" - } - ] - }, - "3": { - "name": "punctuation.definition.string.end.sql" - } - } - }, - { - "match": "'(?=((\\\\')|[^'\"])*(\"|$))", - "name": "string.quoted.single.unclosed.sql" - }, - { - "include": "source.php#interpolation_double_quoted" - } - ] - }, - "text.html.php - (meta.embedded | meta.tag), L:((text.html.php meta.tag) - (meta.embedded.block.php | meta.embedded.line.php)), L:(source.js - (meta.embedded.block.php | meta.embedded.line.php)), L:(source.css - (meta.embedded.block.php | meta.embedded.line.php))": { - "patterns": [ - { - "include": "#php-tag" - } - ] - } - }, - "patterns": [ - { - "begin": "\\A#!", - "beginCaptures": { - "0": { - "name": "punctuation.definition.comment.php" - } - }, - "end": "$", - "name": "comment.line.shebang.php" - }, - { - "include": "text.html.derivative" - } - ], - "repository": { - "php-tag": { - "patterns": [ - { - "begin": "<\\?(?i:php|=)?(?![^?]*\\?>)", - "beginCaptures": { - "0": { - "name": "punctuation.section.embedded.begin.php" - } - }, - "end": "(\\?)>", - "endCaptures": { - "0": { - "name": "punctuation.section.embedded.end.php" - }, - "1": { - "name": "source.php" - } - }, - "name": "meta.embedded.block.php", - "contentName": "source.php", - "patterns": [ - { - "include": "source.php" - } - ] - }, - { - "begin": "<\\?(?i:php|=)?", - "beginCaptures": { - "0": { - "name": "punctuation.section.embedded.begin.php" - } - }, - "end": "(\\?)>", - "endCaptures": { - "0": { - "name": "punctuation.section.embedded.end.php" - }, - "1": { - "name": "source.php" - } - }, - "name": "meta.embedded.line.php", - "contentName": "source.php", - "patterns": [ - { - "include": "source.php" - } - ] - } - ] - } - } -} \ No newline at end of file diff --git a/lib/vscode/extensions/theme-seti/CONTRIBUTING.md b/lib/vscode/extensions/theme-seti/CONTRIBUTING.md deleted file mode 100644 index 888829ff0042..000000000000 --- a/lib/vscode/extensions/theme-seti/CONTRIBUTING.md +++ /dev/null @@ -1,32 +0,0 @@ -# theme-seti - -This is an icon theme that uses the icons from [`seti-ui`](https://github.com/jesseweed/seti-ui). - -## Updating icons - -There is script that can be used to update icons, [./build/update-icon-theme.js](build/update-icon-theme.js). - -To run this script, run `npm run update` from the `theme-seti` directory. - -This can be run in one of two ways: looking at a local copy of `seti-ui` for icons, or getting them straight from GitHub. - -If you want to run it from a local copy of `seti-ui`, first clone [`seti-ui`](https://github.com/jesseweed/seti-ui) to the folder next to your `vscode` repo (from the `theme-seti` directory, `../../`). -Then, inside the `set-ui` directory, run `npm install` followed by `npm run prepublishOnly`. This will generate updated icons. - -If you want to download the icons straight from GitHub, change the `FROM_DISK` variable to `false` inside of `update-icon-theme.js`. - -### Languages not shipped with `vscode` - -Languages that are not shipped with `vscode` must be added to the `nonBuiltInLanguages` object inside of `update-icon-theme.js`. - -These should match [the file mapping in `seti-ui`](https://github.com/jesseweed/seti-ui/blob/master/styles/components/icons/mapping.less). - -Please try and keep this list in alphabetical order! Thank you. - -## Previewing icons - -There is a [`./icons/preview.html`](./icons/preview.html) file that can be opened to see all of the icons included in the theme. -Note that to view this, it needs to be hosted by a web server. - -When updating icons, it is always a good idea to make sure that they work properly by looking at this page. -When submitting a PR that updates these icons, a screenshot of the preview page should accompany it. diff --git a/lib/vscode/extensions/theme-seti/icons/seti.woff b/lib/vscode/extensions/theme-seti/icons/seti.woff deleted file mode 100644 index 928e91b30c12227c806b9be7c01e14df4c47aba8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36472 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 diff --git a/lib/vscode/extensions/vscode-notebook-tests/yarn.lock b/lib/vscode/extensions/vscode-notebook-tests/yarn.lock deleted file mode 100644 index e03bdd573eab..000000000000 --- a/lib/vscode/extensions/vscode-notebook-tests/yarn.lock +++ /dev/null @@ -1,8 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== diff --git a/lib/vscode/extensions/vscode-test-resolver/yarn.lock b/lib/vscode/extensions/vscode-test-resolver/yarn.lock deleted file mode 100644 index e03bdd573eab..000000000000 --- a/lib/vscode/extensions/vscode-test-resolver/yarn.lock +++ /dev/null @@ -1,8 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@types/node@^12.19.9": - version "12.19.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.19.9.tgz#990ad687ad8b26ef6dcc34a4f69c33d40c95b679" - integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q== diff --git a/lib/vscode/package.json b/lib/vscode/package.json deleted file mode 100644 index 73d8584c9d66..000000000000 --- a/lib/vscode/package.json +++ /dev/null @@ -1,227 +0,0 @@ -{ - "name": "code-oss-dev", - "version": "1.56.0", - "distro": "3d76109d9437bda93a3f337625de2833149ca724", - "author": { - "name": "Microsoft Corporation" - }, - "license": "MIT", - "main": "./out/main", - "private": true, - "scripts": { - "test": "mocha", - "test-browser": "node test/unit/browser/index.js", - "preinstall": "node build/npm/preinstall.js", - "postinstall": "node build/npm/postinstall.js", - "compile": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js compile", - "watch": "npm-run-all -lp watch-client watch-extensions watch-extension-media", - "watchd": "deemon yarn watch", - "watch-webd": "deemon yarn watch-web", - "kill-watchd": "deemon --kill yarn watch", - "kill-watch-webd": "deemon --kill yarn watch-web", - "restart-watchd": "deemon --restart yarn watch", - "restart-watch-webd": "deemon --restart yarn watch-web", - "watch-client": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js watch-client", - "watch-clientd": "deemon yarn watch-client", - "kill-watch-clientd": "deemon --kill yarn watch-client", - "watch-extensions": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js watch-extensions", - "watch-extension-media": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js watch-extension-media", - "watch-extensionsd": "deemon yarn watch-extensions", - "kill-watch-extensionsd": "deemon --kill yarn watch-extensions", - "watch-extension-mediad": "deemon yarn watch-extension-media", - "kill-watch-extension-mediad": "deemon --kill yarn watch-extension-media", - "mocha": "mocha test/unit/node/all.js --delay", - "precommit": "node build/hygiene.js", - "gulp": "node --max_old_space_size=8192 ./node_modules/gulp/bin/gulp.js", - "electron": "node build/lib/electron", - "7z": "7z", - "update-grammars": "node build/npm/update-all-grammars.js", - "update-localization-extension": "node build/npm/update-localization-extension.js", - "smoketest": "cd test/smoke && yarn compile && node test/index.js", - "smoketest-no-compile": "cd test/smoke && node test/index.js", - "download-builtin-extensions": "node build/lib/builtInExtensions.js", - "download-builtin-extensions-cg": "node build/lib/builtInExtensionsCG.js", - "monaco-compile-check": "tsc -p src/tsconfig.monaco.json --noEmit", - "tsec-compile-check": "node node_modules/tsec/bin/tsec -p src/tsconfig.tsec.json", - "valid-layers-check": "node build/lib/layersChecker.js", - "update-distro": "node build/npm/update-distro.js", - "web": "node resources/web/code-web.js", - "compile-web": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js compile-web", - "watch-web": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js watch-web", - "eslint": "node build/eslint", - "playwright-install": "node build/azure-pipelines/common/installPlaywright.js", - "compile-build": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js compile-build", - "compile-extensions-build": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js compile-extensions-build", - "minify-vscode": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js minify-vscode", - "minify-vscode-reh": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js minify-vscode-reh", - "minify-vscode-reh-web": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js minify-vscode-reh-web", - "hygiene": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js hygiene", - "core-ci": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js core-ci", - "extensions-ci": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js extensions-ci" - }, - "dependencies_comment": "Move rimraf to dependencies because it is used in the postinstall script.", - "dependencies": { - "@coder/logger": "^1.1.16", - "applicationinsights": "1.0.8", - "chokidar": "3.5.1", - "graceful-fs": "4.2.3", - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.3", - "iconv-lite-umd": "0.6.8", - "jschardet": "2.3.0", - "minimist": "^1.2.5", - "native-is-elevated": "0.4.3", - "native-watchdog": "1.3.0", - "node-pty": "0.10.1", - "nsfw": "2.1.2", - "proxy-agent": "^4.0.1", - "proxy-from-env": "^1.1.0", - "spdlog": "^0.11.1", - "sudo-prompt": "9.2.1", - "tas-client-umd": "0.1.4", - "v8-inspect-profiler": "^0.0.20", - "vscode-oniguruma": "1.3.1", - "vscode-proxy-agent": "^0.11.0", - "vscode-regexpp": "^3.1.0", - "vscode-ripgrep": "^1.11.3", - "vscode-sqlite3": "4.0.11", - "vscode-textmate": "5.2.0", - "xterm": "4.12.0-beta.26", - "xterm-addon-search": "0.9.0-beta.2", - "xterm-addon-unicode11": "0.3.0-beta.5", - "xterm-addon-webgl": "0.11.0-beta.8", - "yauzl": "^2.9.2", - "yazl": "^2.4.3" - }, - "devDependencies_comment": "set gulp-rename to ~1.2.0 (instead of ^1.2.0), build breaks on 1.4.4", - "devDependencies": { - "7zip": "0.0.6", - "@types/applicationinsights": "0.20.0", - "@types/chokidar": "2.1.3", - "@types/cookie": "^0.3.3", - "@types/copy-webpack-plugin": "^6.0.3", - "@types/cssnano": "^4.0.0", - "@types/debug": "4.1.5", - "@types/graceful-fs": "4.1.2", - "@types/gulp-postcss": "^8.0.0", - "@types/http-proxy-agent": "^2.0.1", - "@types/minimist": "^1.2.1", - "@types/mocha": "^8.2.0", - "@types/node": "^14.14.37", - "@types/sinon": "^1.16.36", - "@types/trusted-types": "^1.0.6", - "@types/vscode-windows-registry": "^1.0.0", - "@types/webpack": "^4.41.25", - "@types/wicg-file-system-access": "^2020.9.1", - "@types/windows-foreground-love": "^0.3.0", - "@types/windows-mutex": "^0.4.0", - "@types/windows-process-tree": "^0.2.0", - "@types/winreg": "^1.2.30", - "@types/yauzl": "^2.9.1", - "@types/yazl": "^2.4.2", - "@typescript-eslint/eslint-plugin": "3.2.0", - "@typescript-eslint/parser": "^3.3.0", - "ansi-colors": "^3.2.3", - "asar": "^3.0.3", - "chromium-pickle-js": "^0.2.0", - "copy-webpack-plugin": "^6.0.3", - "cson-parser": "^1.3.3", - "css-loader": "^3.2.0", - "cssnano": "^4.1.11", - "debounce": "^1.0.0", - "deemon": "^1.4.0", - "eslint": "6.8.0", - "eslint-plugin-jsdoc": "^19.1.0", - "event-stream": "3.3.4", - "fancy-log": "^1.3.3", - "fast-plist": "0.1.2", - "file-loader": "^4.2.0", - "glob": "^5.0.13", - "gulp": "^4.0.0", - "gulp-atom-electron": "^1.30.1", - "gulp-azure-storage": "^0.11.1", - "gulp-bom": "^3.0.0", - "gulp-buffer": "0.0.2", - "gulp-concat": "^2.6.1", - "gulp-eslint": "^5.0.0", - "gulp-filter": "^5.1.0", - "gulp-flatmap": "^1.0.2", - "gulp-gunzip": "^1.0.0", - "gulp-gzip": "^1.4.2", - "gulp-json-editor": "^2.5.0", - "gulp-plumber": "^1.2.0", - "gulp-postcss": "^9.0.0", - "gulp-remote-retry-src": "^0.6.0", - "gulp-rename": "~1.2.0", - "gulp-replace": "^0.5.4", - "gulp-shell": "^0.6.5", - "gulp-sourcemaps": "^3.0.0", - "gulp-tsb": "4.0.6", - "gulp-untar": "^0.0.7", - "gulp-vinyl-zip": "^2.1.2", - "husky": "^0.13.1", - "innosetup": "6.0.5", - "is": "^3.1.0", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.0", - "jsdom-no-contextify": "^3.1.0", - "lazy.js": "^0.4.2", - "merge-options": "^1.0.1", - "mime": "^1.4.1", - "minimatch": "^3.0.4", - "minimist": "^1.2.5", - "mkdirp": "^1.0.4", - "mocha": "^8.2.1", - "mocha-junit-reporter": "^2.0.0", - "mocha-multi-reporters": "^1.5.1", - "npm-run-all": "^4.1.5", - "opn": "^6.0.0", - "optimist": "0.3.5", - "p-all": "^1.0.0", - "playwright": "1.8.0", - "pump": "^1.0.1", - "queue": "3.0.6", - "rcedit": "^1.1.0", - "request": "^2.85.0", - "rimraf": "^3.0.2", - "sinon": "^1.17.2", - "source-map": "0.6.1", - "source-map-support": "^0.3.2", - "style-loader": "^1.0.0", - "ts-loader": "^6.2.1", - "tsec": "0.1.4", - "typescript": "^4.3.0-dev.20210426", - "typescript-formatter": "7.1.0", - "underscore": "^1.8.2", - "vinyl": "^2.0.0", - "vinyl-fs": "^3.0.0", - "vscode-debugprotocol": "1.47.0", - "vscode-nls-dev": "^3.3.1", - "vscode-telemetry-extractor": "^1.7.0", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.12", - "webpack-stream": "^5.2.1", - "xml2js": "^0.4.17", - "yaserver": "^0.2.0" - }, - "repository": { - "type": "git", - "url": "https://github.com/microsoft/vscode.git" - }, - "bugs": { - "url": "https://github.com/microsoft/vscode/issues" - }, - "optionalDependencies": { - "vscode-windows-registry": "1.0.3", - "windows-foreground-love": "0.2.0", - "windows-mutex": "0.3.0", - "windows-process-tree": "0.3.0" - }, - "resolutions": { - "elliptic": "^6.5.3", - "nwmatcher": "^1.4.4" - } -} diff --git a/lib/vscode/src/typings/electron.d.ts b/lib/vscode/src/typings/electron.d.ts deleted file mode 100644 index d093c27fc464..000000000000 --- a/lib/vscode/src/typings/electron.d.ts +++ /dev/null @@ -1,16051 +0,0 @@ -// Type definitions for Electron 12.0.5 -// Project: http://electronjs.org/ -// Definitions by: The Electron Team -// Definitions: https://github.com/electron/electron-typescript-definitions - -/// - -type GlobalEvent = Event & { returnValue: any }; - -declare namespace Electron { - const NodeEventEmitter: typeof import('events').EventEmitter; - - class Accelerator extends String { - - } - interface App extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/app - - /** - * Emitted when Chrome's accessibility support changes. This event fires when - * assistive technologies, such as screen readers, are enabled or disabled. See - * https://www.chromium.org/developers/design-documents/accessibility for more - * details. - * - * @platform darwin,win32 - */ - on(event: 'accessibility-support-changed', listener: (event: Event, - /** - * `true` when Chrome's accessibility support is enabled, `false` otherwise. - */ - accessibilitySupportEnabled: boolean) => void): this; - once(event: 'accessibility-support-changed', listener: (event: Event, - /** - * `true` when Chrome's accessibility support is enabled, `false` otherwise. - */ - accessibilitySupportEnabled: boolean) => void): this; - addListener(event: 'accessibility-support-changed', listener: (event: Event, - /** - * `true` when Chrome's accessibility support is enabled, `false` otherwise. - */ - accessibilitySupportEnabled: boolean) => void): this; - removeListener(event: 'accessibility-support-changed', listener: (event: Event, - /** - * `true` when Chrome's accessibility support is enabled, `false` otherwise. - */ - accessibilitySupportEnabled: boolean) => void): this; - /** - * Emitted when the application is activated. Various actions can trigger this - * event, such as launching the application for the first time, attempting to - * re-launch the application when it's already running, or clicking on the - * application's dock or taskbar icon. - * - * @platform darwin - */ - on(event: 'activate', listener: (event: Event, - hasVisibleWindows: boolean) => void): this; - once(event: 'activate', listener: (event: Event, - hasVisibleWindows: boolean) => void): this; - addListener(event: 'activate', listener: (event: Event, - hasVisibleWindows: boolean) => void): this; - removeListener(event: 'activate', listener: (event: Event, - hasVisibleWindows: boolean) => void): this; - /** - * Emitted during Handoff after an activity from this device was successfully - * resumed on another one. - * - * @platform darwin - */ - on(event: 'activity-was-continued', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity. - */ - userInfo: unknown) => void): this; - once(event: 'activity-was-continued', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity. - */ - userInfo: unknown) => void): this; - addListener(event: 'activity-was-continued', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity. - */ - userInfo: unknown) => void): this; - removeListener(event: 'activity-was-continued', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity. - */ - userInfo: unknown) => void): this; - /** - * Emitted before the application starts closing its windows. Calling - * `event.preventDefault()` will prevent the default behavior, which is terminating - * the application. - * - * **Note:** If application quit was initiated by `autoUpdater.quitAndInstall()`, - * then `before-quit` is emitted *after* emitting `close` event on all windows and - * closing them. - * - * **Note:** On Windows, this event will not be emitted if the app is closed due to - * a shutdown/restart of the system or a user logout. - */ - on(event: 'before-quit', listener: (event: Event) => void): this; - once(event: 'before-quit', listener: (event: Event) => void): this; - addListener(event: 'before-quit', listener: (event: Event) => void): this; - removeListener(event: 'before-quit', listener: (event: Event) => void): this; - /** - * Emitted when a browserWindow gets blurred. - */ - on(event: 'browser-window-blur', listener: (event: Event, - window: BrowserWindow) => void): this; - once(event: 'browser-window-blur', listener: (event: Event, - window: BrowserWindow) => void): this; - addListener(event: 'browser-window-blur', listener: (event: Event, - window: BrowserWindow) => void): this; - removeListener(event: 'browser-window-blur', listener: (event: Event, - window: BrowserWindow) => void): this; - /** - * Emitted when a new browserWindow is created. - */ - on(event: 'browser-window-created', listener: (event: Event, - window: BrowserWindow) => void): this; - once(event: 'browser-window-created', listener: (event: Event, - window: BrowserWindow) => void): this; - addListener(event: 'browser-window-created', listener: (event: Event, - window: BrowserWindow) => void): this; - removeListener(event: 'browser-window-created', listener: (event: Event, - window: BrowserWindow) => void): this; - /** - * Emitted when a browserWindow gets focused. - */ - on(event: 'browser-window-focus', listener: (event: Event, - window: BrowserWindow) => void): this; - once(event: 'browser-window-focus', listener: (event: Event, - window: BrowserWindow) => void): this; - addListener(event: 'browser-window-focus', listener: (event: Event, - window: BrowserWindow) => void): this; - removeListener(event: 'browser-window-focus', listener: (event: Event, - window: BrowserWindow) => void): this; - /** - * Emitted when failed to verify the `certificate` for `url`, to trust the - * certificate you should prevent the default behavior with - * `event.preventDefault()` and call `callback(true)`. - */ - on(event: 'certificate-error', listener: (event: Event, - webContents: WebContents, - url: string, - /** - * The error code - */ - error: string, - certificate: Certificate, - callback: (isTrusted: boolean) => void) => void): this; - once(event: 'certificate-error', listener: (event: Event, - webContents: WebContents, - url: string, - /** - * The error code - */ - error: string, - certificate: Certificate, - callback: (isTrusted: boolean) => void) => void): this; - addListener(event: 'certificate-error', listener: (event: Event, - webContents: WebContents, - url: string, - /** - * The error code - */ - error: string, - certificate: Certificate, - callback: (isTrusted: boolean) => void) => void): this; - removeListener(event: 'certificate-error', listener: (event: Event, - webContents: WebContents, - url: string, - /** - * The error code - */ - error: string, - certificate: Certificate, - callback: (isTrusted: boolean) => void) => void): this; - /** - * Emitted when the child process unexpectedly disappears. This is normally because - * it was crashed or killed. It does not include renderer processes. - */ - on(event: 'child-process-gone', listener: (event: Event, - details: Details) => void): this; - once(event: 'child-process-gone', listener: (event: Event, - details: Details) => void): this; - addListener(event: 'child-process-gone', listener: (event: Event, - details: Details) => void): this; - removeListener(event: 'child-process-gone', listener: (event: Event, - details: Details) => void): this; - /** - * Emitted during Handoff when an activity from a different device wants to be - * resumed. You should call `event.preventDefault()` if you want to handle this - * event. - * - * A user activity can be continued only in an app that has the same developer Team - * ID as the activity's source app and that supports the activity's type. Supported - * activity types are specified in the app's `Info.plist` under the - * `NSUserActivityTypes` key. - * - * @platform darwin - */ - on(event: 'continue-activity', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity on another device. - */ - userInfo: unknown) => void): this; - once(event: 'continue-activity', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity on another device. - */ - userInfo: unknown) => void): this; - addListener(event: 'continue-activity', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity on another device. - */ - userInfo: unknown) => void): this; - removeListener(event: 'continue-activity', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity on another device. - */ - userInfo: unknown) => void): this; - /** - * Emitted during Handoff when an activity from a different device fails to be - * resumed. - * - * @platform darwin - */ - on(event: 'continue-activity-error', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * A string with the error's localized description. - */ - error: string) => void): this; - once(event: 'continue-activity-error', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * A string with the error's localized description. - */ - error: string) => void): this; - addListener(event: 'continue-activity-error', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * A string with the error's localized description. - */ - error: string) => void): this; - removeListener(event: 'continue-activity-error', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * A string with the error's localized description. - */ - error: string) => void): this; - /** - * Emitted when `desktopCapturer.getSources()` is called in the renderer process of - * `webContents`. Calling `event.preventDefault()` will make it return empty - * sources. - */ - on(event: 'desktop-capturer-get-sources', listener: (event: Event, - webContents: WebContents) => void): this; - once(event: 'desktop-capturer-get-sources', listener: (event: Event, - webContents: WebContents) => void): this; - addListener(event: 'desktop-capturer-get-sources', listener: (event: Event, - webContents: WebContents) => void): this; - removeListener(event: 'desktop-capturer-get-sources', listener: (event: Event, - webContents: WebContents) => void): this; - /** - * Emitted when mac application become active. Difference from `activate` event is - * that `did-become-active` is emitted every time the app becomes active, not only - * when Dock icon is clicked or application is re-launched. - * - * @platform darwin - */ - on(event: 'did-become-active', listener: (event: Event) => void): this; - once(event: 'did-become-active', listener: (event: Event) => void): this; - addListener(event: 'did-become-active', listener: (event: Event) => void): this; - removeListener(event: 'did-become-active', listener: (event: Event) => void): this; - /** - * Emitted whenever there is a GPU info update. - */ - on(event: 'gpu-info-update', listener: Function): this; - once(event: 'gpu-info-update', listener: Function): this; - addListener(event: 'gpu-info-update', listener: Function): this; - removeListener(event: 'gpu-info-update', listener: Function): this; - /** - * Emitted when the GPU process crashes or is killed. - * - * **Deprecated:** This event is superceded by the `child-process-gone` event which - * contains more information about why the child process disappeared. It isn't - * always because it crashed. The `killed` boolean can be replaced by checking - * `reason === 'killed'` when you switch to that event. - * - * @deprecated - */ - on(event: 'gpu-process-crashed', listener: (event: Event, - killed: boolean) => void): this; - once(event: 'gpu-process-crashed', listener: (event: Event, - killed: boolean) => void): this; - addListener(event: 'gpu-process-crashed', listener: (event: Event, - killed: boolean) => void): this; - removeListener(event: 'gpu-process-crashed', listener: (event: Event, - killed: boolean) => void): this; - /** - * Emitted when `webContents` wants to do basic auth. - * - * The default behavior is to cancel all authentications. To override this you - * should prevent the default behavior with `event.preventDefault()` and call - * `callback(username, password)` with the credentials. - * - * If `callback` is called without a username or password, the authentication - * request will be cancelled and the authentication error will be returned to the - * page. - */ - on(event: 'login', listener: (event: Event, - webContents: WebContents, - authenticationResponseDetails: AuthenticationResponseDetails, - authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - once(event: 'login', listener: (event: Event, - webContents: WebContents, - authenticationResponseDetails: AuthenticationResponseDetails, - authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - addListener(event: 'login', listener: (event: Event, - webContents: WebContents, - authenticationResponseDetails: AuthenticationResponseDetails, - authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - removeListener(event: 'login', listener: (event: Event, - webContents: WebContents, - authenticationResponseDetails: AuthenticationResponseDetails, - authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - /** - * Emitted when the user clicks the native macOS new tab button. The new tab button - * is only visible if the current `BrowserWindow` has a `tabbingIdentifier` - * - * @platform darwin - */ - on(event: 'new-window-for-tab', listener: (event: Event) => void): this; - once(event: 'new-window-for-tab', listener: (event: Event) => void): this; - addListener(event: 'new-window-for-tab', listener: (event: Event) => void): this; - removeListener(event: 'new-window-for-tab', listener: (event: Event) => void): this; - /** - * Emitted when the user wants to open a file with the application. The `open-file` - * event is usually emitted when the application is already open and the OS wants - * to reuse the application to open the file. `open-file` is also emitted when a - * file is dropped onto the dock and the application is not yet running. Make sure - * to listen for the `open-file` event very early in your application startup to - * handle this case (even before the `ready` event is emitted). - * - * You should call `event.preventDefault()` if you want to handle this event. - * - * On Windows, you have to parse `process.argv` (in the main process) to get the - * filepath. - * - * @platform darwin - */ - on(event: 'open-file', listener: (event: Event, - path: string) => void): this; - once(event: 'open-file', listener: (event: Event, - path: string) => void): this; - addListener(event: 'open-file', listener: (event: Event, - path: string) => void): this; - removeListener(event: 'open-file', listener: (event: Event, - path: string) => void): this; - /** - * Emitted when the user wants to open a URL with the application. Your - * application's `Info.plist` file must define the URL scheme within the - * `CFBundleURLTypes` key, and set `NSPrincipalClass` to `AtomApplication`. - * -You should call `event.preventDefault()` if you want to handle this event. - * - * @platform darwin - */ - on(event: 'open-url', listener: (event: Event, - url: string) => void): this; - once(event: 'open-url', listener: (event: Event, - url: string) => void): this; - addListener(event: 'open-url', listener: (event: Event, - url: string) => void): this; - removeListener(event: 'open-url', listener: (event: Event, - url: string) => void): this; - /** - * Emitted when the application is quitting. - * - * **Note:** On Windows, this event will not be emitted if the app is closed due to - * a shutdown/restart of the system or a user logout. - */ - on(event: 'quit', listener: (event: Event, - exitCode: number) => void): this; - once(event: 'quit', listener: (event: Event, - exitCode: number) => void): this; - addListener(event: 'quit', listener: (event: Event, - exitCode: number) => void): this; - removeListener(event: 'quit', listener: (event: Event, - exitCode: number) => void): this; - /** - * Emitted once, when Electron has finished initializing. On macOS, `launchInfo` - * holds the `userInfo` of the `NSUserNotification` or information from - * `UNNotificationResponse` that was used to open the application, if it was - * launched from Notification Center. You can also call `app.isReady()` to check if - * this event has already fired and `app.whenReady()` to get a Promise that is - * fulfilled when Electron is initialized. - */ - on(event: 'ready', listener: (event: Event, - launchInfo: (Record) | (NotificationResponse)) => void): this; - once(event: 'ready', listener: (event: Event, - launchInfo: (Record) | (NotificationResponse)) => void): this; - addListener(event: 'ready', listener: (event: Event, - launchInfo: (Record) | (NotificationResponse)) => void): this; - removeListener(event: 'ready', listener: (event: Event, - launchInfo: (Record) | (NotificationResponse)) => void): this; - /** - * Emitted when `remote.getBuiltin()` is called in the renderer process of - * `webContents`. Calling `event.preventDefault()` will prevent the module from - * being returned. Custom value can be returned by setting `event.returnValue`. - * - * @deprecated - */ - on(event: 'remote-get-builtin', listener: (event: Event, - webContents: WebContents, - moduleName: string) => void): this; - once(event: 'remote-get-builtin', listener: (event: Event, - webContents: WebContents, - moduleName: string) => void): this; - addListener(event: 'remote-get-builtin', listener: (event: Event, - webContents: WebContents, - moduleName: string) => void): this; - removeListener(event: 'remote-get-builtin', listener: (event: Event, - webContents: WebContents, - moduleName: string) => void): this; - /** - * Emitted when `remote.getCurrentWebContents()` is called in the renderer process - * of `webContents`. Calling `event.preventDefault()` will prevent the object from - * being returned. Custom value can be returned by setting `event.returnValue`. - * - * @deprecated - */ - on(event: 'remote-get-current-web-contents', listener: (event: Event, - webContents: WebContents) => void): this; - once(event: 'remote-get-current-web-contents', listener: (event: Event, - webContents: WebContents) => void): this; - addListener(event: 'remote-get-current-web-contents', listener: (event: Event, - webContents: WebContents) => void): this; - removeListener(event: 'remote-get-current-web-contents', listener: (event: Event, - webContents: WebContents) => void): this; - /** - * Emitted when `remote.getCurrentWindow()` is called in the renderer process of - * `webContents`. Calling `event.preventDefault()` will prevent the object from - * being returned. Custom value can be returned by setting `event.returnValue`. - * - * @deprecated - */ - on(event: 'remote-get-current-window', listener: (event: Event, - webContents: WebContents) => void): this; - once(event: 'remote-get-current-window', listener: (event: Event, - webContents: WebContents) => void): this; - addListener(event: 'remote-get-current-window', listener: (event: Event, - webContents: WebContents) => void): this; - removeListener(event: 'remote-get-current-window', listener: (event: Event, - webContents: WebContents) => void): this; - /** - * Emitted when `remote.getGlobal()` is called in the renderer process of - * `webContents`. Calling `event.preventDefault()` will prevent the global from - * being returned. Custom value can be returned by setting `event.returnValue`. - * - * @deprecated - */ - on(event: 'remote-get-global', listener: (event: Event, - webContents: WebContents, - globalName: string) => void): this; - once(event: 'remote-get-global', listener: (event: Event, - webContents: WebContents, - globalName: string) => void): this; - addListener(event: 'remote-get-global', listener: (event: Event, - webContents: WebContents, - globalName: string) => void): this; - removeListener(event: 'remote-get-global', listener: (event: Event, - webContents: WebContents, - globalName: string) => void): this; - /** - * Emitted when `remote.require()` is called in the renderer process of - * `webContents`. Calling `event.preventDefault()` will prevent the module from - * being returned. Custom value can be returned by setting `event.returnValue`. - * - * @deprecated - */ - on(event: 'remote-require', listener: (event: Event, - webContents: WebContents, - moduleName: string) => void): this; - once(event: 'remote-require', listener: (event: Event, - webContents: WebContents, - moduleName: string) => void): this; - addListener(event: 'remote-require', listener: (event: Event, - webContents: WebContents, - moduleName: string) => void): this; - removeListener(event: 'remote-require', listener: (event: Event, - webContents: WebContents, - moduleName: string) => void): this; - /** - * Emitted when the renderer process unexpectedly disappears. This is normally - * because it was crashed or killed. - */ - on(event: 'render-process-gone', listener: (event: Event, - webContents: WebContents, - details: RenderProcessGoneDetails) => void): this; - once(event: 'render-process-gone', listener: (event: Event, - webContents: WebContents, - details: RenderProcessGoneDetails) => void): this; - addListener(event: 'render-process-gone', listener: (event: Event, - webContents: WebContents, - details: RenderProcessGoneDetails) => void): this; - removeListener(event: 'render-process-gone', listener: (event: Event, - webContents: WebContents, - details: RenderProcessGoneDetails) => void): this; - /** - * Emitted when the renderer process of `webContents` crashes or is killed. - * - * **Deprecated:** This event is superceded by the `render-process-gone` event - * which contains more information about why the render process disappeared. It - * isn't always because it crashed. The `killed` boolean can be replaced by - * checking `reason === 'killed'` when you switch to that event. - * - * @deprecated - */ - on(event: 'renderer-process-crashed', listener: (event: Event, - webContents: WebContents, - killed: boolean) => void): this; - once(event: 'renderer-process-crashed', listener: (event: Event, - webContents: WebContents, - killed: boolean) => void): this; - addListener(event: 'renderer-process-crashed', listener: (event: Event, - webContents: WebContents, - killed: boolean) => void): this; - removeListener(event: 'renderer-process-crashed', listener: (event: Event, - webContents: WebContents, - killed: boolean) => void): this; - /** - * This event will be emitted inside the primary instance of your application when - * a second instance has been executed and calls `app.requestSingleInstanceLock()`. - * - * `argv` is an Array of the second instance's command line arguments, and - * `workingDirectory` is its current working directory. Usually applications - * respond to this by making their primary window focused and non-minimized. - * - * **Note:** If the second instance is started by a different user than the first, - * the `argv` array will not include the arguments. - * - * This event is guaranteed to be emitted after the `ready` event of `app` gets - * emitted. - * - * **Note:** Extra command line arguments might be added by Chromium, such as - * `--original-process-start-time`. - */ - on(event: 'second-instance', listener: (event: Event, - /** - * An array of the second instance's command line arguments - */ - argv: string[], - /** - * The second instance's working directory - */ - workingDirectory: string) => void): this; - once(event: 'second-instance', listener: (event: Event, - /** - * An array of the second instance's command line arguments - */ - argv: string[], - /** - * The second instance's working directory - */ - workingDirectory: string) => void): this; - addListener(event: 'second-instance', listener: (event: Event, - /** - * An array of the second instance's command line arguments - */ - argv: string[], - /** - * The second instance's working directory - */ - workingDirectory: string) => void): this; - removeListener(event: 'second-instance', listener: (event: Event, - /** - * An array of the second instance's command line arguments - */ - argv: string[], - /** - * The second instance's working directory - */ - workingDirectory: string) => void): this; - /** - * Emitted when a client certificate is requested. - * - * The `url` corresponds to the navigation entry requesting the client certificate - * and `callback` can be called with an entry filtered from the list. Using - * `event.preventDefault()` prevents the application from using the first - * certificate from the store. - */ - on(event: 'select-client-certificate', listener: (event: Event, - webContents: WebContents, - url: string, - certificateList: Certificate[], - callback: (certificate?: Certificate) => void) => void): this; - once(event: 'select-client-certificate', listener: (event: Event, - webContents: WebContents, - url: string, - certificateList: Certificate[], - callback: (certificate?: Certificate) => void) => void): this; - addListener(event: 'select-client-certificate', listener: (event: Event, - webContents: WebContents, - url: string, - certificateList: Certificate[], - callback: (certificate?: Certificate) => void) => void): this; - removeListener(event: 'select-client-certificate', listener: (event: Event, - webContents: WebContents, - url: string, - certificateList: Certificate[], - callback: (certificate?: Certificate) => void) => void): this; - /** - * Emitted when Electron has created a new `session`. - */ - on(event: 'session-created', listener: (session: Session) => void): this; - once(event: 'session-created', listener: (session: Session) => void): this; - addListener(event: 'session-created', listener: (session: Session) => void): this; - removeListener(event: 'session-created', listener: (session: Session) => void): this; - /** - * Emitted when Handoff is about to be resumed on another device. If you need to - * update the state to be transferred, you should call `event.preventDefault()` - * immediately, construct a new `userInfo` dictionary and call - * `app.updateCurrentActivity()` in a timely manner. Otherwise, the operation will - * fail and `continue-activity-error` will be called. - * - * @platform darwin - */ - on(event: 'update-activity-state', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity. - */ - userInfo: unknown) => void): this; - once(event: 'update-activity-state', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity. - */ - userInfo: unknown) => void): this; - addListener(event: 'update-activity-state', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity. - */ - userInfo: unknown) => void): this; - removeListener(event: 'update-activity-state', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string, - /** - * Contains app-specific state stored by the activity. - */ - userInfo: unknown) => void): this; - /** - * Emitted when a new webContents is created. - */ - on(event: 'web-contents-created', listener: (event: Event, - webContents: WebContents) => void): this; - once(event: 'web-contents-created', listener: (event: Event, - webContents: WebContents) => void): this; - addListener(event: 'web-contents-created', listener: (event: Event, - webContents: WebContents) => void): this; - removeListener(event: 'web-contents-created', listener: (event: Event, - webContents: WebContents) => void): this; - /** - * Emitted during Handoff before an activity from a different device wants to be - * resumed. You should call `event.preventDefault()` if you want to handle this - * event. - * - * @platform darwin - */ - on(event: 'will-continue-activity', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string) => void): this; - once(event: 'will-continue-activity', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string) => void): this; - addListener(event: 'will-continue-activity', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string) => void): this; - removeListener(event: 'will-continue-activity', listener: (event: Event, - /** - * A string identifying the activity. Maps to `NSUserActivity.activityType`. - */ - type: string) => void): this; - /** - * Emitted when the application has finished basic startup. On Windows and Linux, - * the `will-finish-launching` event is the same as the `ready` event; on macOS, - * this event represents the `applicationWillFinishLaunching` notification of - * `NSApplication`. You would usually set up listeners for the `open-file` and - * `open-url` events here, and start the crash reporter and auto updater. - * -In most cases, you should do everything in the `ready` event handler. - */ - on(event: 'will-finish-launching', listener: Function): this; - once(event: 'will-finish-launching', listener: Function): this; - addListener(event: 'will-finish-launching', listener: Function): this; - removeListener(event: 'will-finish-launching', listener: Function): this; - /** - * Emitted when all windows have been closed and the application will quit. Calling - * `event.preventDefault()` will prevent the default behavior, which is terminating - * the application. - * - * See the description of the `window-all-closed` event for the differences between - * the `will-quit` and `window-all-closed` events. - * - * **Note:** On Windows, this event will not be emitted if the app is closed due to - * a shutdown/restart of the system or a user logout. - */ - on(event: 'will-quit', listener: (event: Event) => void): this; - once(event: 'will-quit', listener: (event: Event) => void): this; - addListener(event: 'will-quit', listener: (event: Event) => void): this; - removeListener(event: 'will-quit', listener: (event: Event) => void): this; - /** - * Emitted when all windows have been closed. - * - * If you do not subscribe to this event and all windows are closed, the default - * behavior is to quit the app; however, if you subscribe, you control whether the - * app quits or not. If the user pressed `Cmd + Q`, or the developer called - * `app.quit()`, Electron will first try to close all the windows and then emit the - * `will-quit` event, and in this case the `window-all-closed` event would not be - * emitted. - */ - on(event: 'window-all-closed', listener: Function): this; - once(event: 'window-all-closed', listener: Function): this; - addListener(event: 'window-all-closed', listener: Function): this; - removeListener(event: 'window-all-closed', listener: Function): this; - /** - * Adds `path` to the recent documents list. - * - * This list is managed by the OS. On Windows, you can visit the list from the task - * bar, and on macOS, you can visit it from dock menu. - * - * @platform darwin,win32 - */ - addRecentDocument(path: string): void; - /** - * Clears the recent documents list. - * - * @platform darwin,win32 - */ - clearRecentDocuments(): void; - /** - * By default, Chromium disables 3D APIs (e.g. WebGL) until restart on a per domain - * basis if the GPU processes crashes too frequently. This function disables that - * behavior. - -This method can only be called before app is ready. - */ - disableDomainBlockingFor3DAPIs(): void; - /** - * Disables hardware acceleration for current app. - * -This method can only be called before app is ready. - */ - disableHardwareAcceleration(): void; - /** - * Enables full sandbox mode on the app. This means that all renderers will be - * launched sandboxed, regardless of the value of the `sandbox` flag in - * WebPreferences. - -This method can only be called before app is ready. - */ - enableSandbox(): void; - /** - * Exits immediately with `exitCode`. `exitCode` defaults to 0. - * - * All windows will be closed immediately without asking the user, and the - * `before-quit` and `will-quit` events will not be emitted. - */ - exit(exitCode?: number): void; - /** - * On Linux, focuses on the first visible window. On macOS, makes the application - * the active app. On Windows, focuses on the application's first window. - * -You should seek to use the `steal` option as sparingly as possible. - */ - focus(options?: FocusOptions): void; - /** - * Resolve with an object containing the following: - * - * * `icon` NativeImage - the display icon of the app handling the protocol. - * * `path` String - installation path of the app handling the protocol. - * * `name` String - display name of the app handling the protocol. - * - * This method returns a promise that contains the application name, icon and path - * of the default handler for the protocol (aka URI scheme) of a URL. - * - * @platform darwin,win32 - */ - getApplicationInfoForProtocol(url: string): Promise; - /** - * Name of the application handling the protocol, or an empty string if there is no - * handler. For instance, if Electron is the default handler of the URL, this could - * be `Electron` on Windows and Mac. However, don't rely on the precise format - * which is not guaranteed to remain unchanged. Expect a different format on Linux, - * possibly with a `.desktop` suffix. - * - * This method returns the application name of the default handler for the protocol - * (aka URI scheme) of a URL. - */ - getApplicationNameForProtocol(url: string): string; - /** - * Array of `ProcessMetric` objects that correspond to memory and CPU usage - * statistics of all the processes associated with the app. - */ - getAppMetrics(): ProcessMetric[]; - /** - * The current application directory. - */ - getAppPath(): string; - /** - * The current value displayed in the counter badge. - * - * @platform linux,darwin - */ - getBadgeCount(): number; - /** - * The type of the currently running activity. - * - * @platform darwin - */ - getCurrentActivityType(): string; - /** - * fulfilled with the app's icon, which is a NativeImage. - * - * Fetches a path's associated icon. - * - * On _Windows_, there a 2 kinds of icons: - * - * * Icons associated with certain file extensions, like `.mp3`, `.png`, etc. - * * Icons inside the file itself, like `.exe`, `.dll`, `.ico`. - * - * On _Linux_ and _macOS_, icons depend on the application associated with file - * mime type. - */ - getFileIcon(path: string, options?: FileIconOptions): Promise; - /** - * The Graphics Feature Status from `chrome://gpu/`. - * - * **Note:** This information is only usable after the `gpu-info-update` event is - * emitted. - */ - getGPUFeatureStatus(): GPUFeatureStatus; - /** - * For `infoType` equal to `complete`: Promise is fulfilled with `Object` - * containing all the GPU Information as in chromium's GPUInfo object. This - * includes the version and driver information that's shown on `chrome://gpu` page. - * - * For `infoType` equal to `basic`: Promise is fulfilled with `Object` containing - * fewer attributes than when requested with `complete`. Here's an example of basic - * response: - * - * Using `basic` should be preferred if only basic information like `vendorId` or - * `driverId` is needed. - */ - getGPUInfo(infoType: 'basic' | 'complete'): Promise; - /** - * * `minItems` Integer - The minimum number of items that will be shown in the - * Jump List (for a more detailed description of this value see the MSDN docs). - * * `removedItems` JumpListItem[] - Array of `JumpListItem` objects that - * correspond to items that the user has explicitly removed from custom categories - * in the Jump List. These items must not be re-added to the Jump List in the - * **next** call to `app.setJumpList()`, Windows will not display any custom - * category that contains any of the removed items. - * - * @platform win32 - */ - getJumpListSettings(): JumpListSettings; - /** - * The current application locale. Possible return values are documented here. - * - * To set the locale, you'll want to use a command line switch at app startup, - * which may be found here. - * - * **Note:** When distributing your packaged app, you have to also ship the - * `locales` folder. - * - * **Note:** On Windows, you have to call it after the `ready` events gets emitted. - */ - getLocale(): string; - /** - * User operating system's locale two-letter ISO 3166 country code. The value is - * taken from native OS APIs. - * -**Note:** When unable to detect locale country code, it returns empty string. - */ - getLocaleCountryCode(): string; - /** - * If you provided `path` and `args` options to `app.setLoginItemSettings`, then - * you need to pass the same arguments here for `openAtLogin` to be set correctly. - * - * - * * `openAtLogin` Boolean - `true` if the app is set to open at login. - * * `openAsHidden` Boolean _macOS_ - `true` if the app is set to open as hidden at - * login. This setting is not available on MAS builds. - * * `wasOpenedAtLogin` Boolean _macOS_ - `true` if the app was opened at login - * automatically. This setting is not available on MAS builds. - * * `wasOpenedAsHidden` Boolean _macOS_ - `true` if the app was opened as a hidden - * login item. This indicates that the app should not open any windows at startup. - * This setting is not available on MAS builds. - * * `restoreState` Boolean _macOS_ - `true` if the app was opened as a login item - * that should restore the state from the previous session. This indicates that the - * app should restore the windows that were open the last time the app was closed. - * This setting is not available on MAS builds. - * * `executableWillLaunchAtLogin` Boolean _Windows_ - `true` if app is set to open - * at login and its run key is not deactivated. This differs from `openAtLogin` as - * it ignores the `args` option, this property will be true if the given executable - * would be launched at login with **any** arguments. - * * `launchItems` Object[] _Windows_ - * * `name` String _Windows_ - name value of a registry entry. - * * `path` String _Windows_ - The executable to an app that corresponds to a - * registry entry. - * * `args` String[] _Windows_ - the command-line arguments to pass to the - * executable. - * * `scope` String _Windows_ - one of `user` or `machine`. Indicates whether the - * registry entry is under `HKEY_CURRENT USER` or `HKEY_LOCAL_MACHINE`. - * * `enabled` Boolean _Windows_ - `true` if the app registry key is startup - * approved and therefore shows as `enabled` in Task Manager and Windows settings. - * - * @platform darwin,win32 - */ - getLoginItemSettings(options?: LoginItemSettingsOptions): LoginItemSettings; - /** - * The current application's name, which is the name in the application's - * `package.json` file. - * - * Usually the `name` field of `package.json` is a short lowercase name, according - * to the npm modules spec. You should usually also specify a `productName` field, - * which is your application's full capitalized name, and which will be preferred - * over `name` by Electron. - */ - getName(): string; - /** - * A path to a special directory or file associated with `name`. On failure, an - * `Error` is thrown. - * - * If `app.getPath('logs')` is called without called `app.setAppLogsPath()` being - * called first, a default log directory will be created equivalent to calling - * `app.setAppLogsPath()` without a `path` parameter. - */ - getPath(name: 'home' | 'appData' | 'userData' | 'cache' | 'temp' | 'exe' | 'module' | 'desktop' | 'documents' | 'downloads' | 'music' | 'pictures' | 'videos' | 'recent' | 'logs' | 'crashDumps'): string; - /** - * The version of the loaded application. If no version is found in the - * application's `package.json` file, the version of the current bundle or - * executable is returned. - */ - getVersion(): string; - /** - * This method returns whether or not this instance of your app is currently - * holding the single instance lock. You can request the lock with - * `app.requestSingleInstanceLock()` and release with - * `app.releaseSingleInstanceLock()` - */ - hasSingleInstanceLock(): boolean; - /** - * Hides all application windows without minimizing them. - * - * @platform darwin - */ - hide(): void; - /** - * Imports the certificate in pkcs12 format into the platform certificate store. - * `callback` is called with the `result` of import operation, a value of `0` - * indicates success while any other value indicates failure according to Chromium - * net_error_list. - * - * @platform linux - */ - importCertificate(options: ImportCertificateOptions, callback: (result: number) => void): void; - /** - * Invalidates the current Handoff user activity. - * - * @platform darwin - */ - invalidateCurrentActivity(): void; - /** - * `true` if Chrome's accessibility support is enabled, `false` otherwise. This API - * will return `true` if the use of assistive technologies, such as screen readers, - * has been detected. See - * https://www.chromium.org/developers/design-documents/accessibility for more - * details. - * - * @platform darwin,win32 - */ - isAccessibilitySupportEnabled(): boolean; - /** - * Whether the current executable is the default handler for a protocol (aka URI - * scheme). - * - * **Note:** On macOS, you can use this method to check if the app has been - * registered as the default protocol handler for a protocol. You can also verify - * this by checking `~/Library/Preferences/com.apple.LaunchServices.plist` on the - * macOS machine. Please refer to Apple's documentation for details. - * - * The API uses the Windows Registry and `LSCopyDefaultHandlerForURLScheme` - * internally. - */ - isDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; - /** - * whether or not the current OS version allows for native emoji pickers. - */ - isEmojiPanelSupported(): boolean; - /** - * Whether the application is currently running from the systems Application - * folder. Use in combination with `app.moveToApplicationsFolder()` - * - * @platform darwin - */ - isInApplicationsFolder(): boolean; - /** - * `true` if Electron has finished initializing, `false` otherwise. See also - * `app.whenReady()`. - */ - isReady(): boolean; - /** - * whether `Secure Keyboard Entry` is enabled. - * -By default this API will return `false`. - * - * @platform darwin - */ - isSecureKeyboardEntryEnabled(): boolean; - /** - * Whether the current desktop environment is Unity launcher. - * - * @platform linux - */ - isUnityRunning(): boolean; - /** - * Whether the move was successful. Please note that if the move is successful, - * your application will quit and relaunch. - * - * No confirmation dialog will be presented by default. If you wish to allow the - * user to confirm the operation, you may do so using the `dialog` API. - * - * **NOTE:** This method throws errors if anything other than the user causes the - * move to fail. For instance if the user cancels the authorization dialog, this - * method returns false. If we fail to perform the copy, then this method will - * throw an error. The message in the error should be informative and tell you - * exactly what went wrong. - * - * By default, if an app of the same name as the one being moved exists in the - * Applications directory and is _not_ running, the existing app will be trashed - * and the active app moved into its place. If it _is_ running, the pre-existing - * running app will assume focus and the previously active app will quit itself. - * This behavior can be changed by providing the optional conflict handler, where - * the boolean returned by the handler determines whether or not the move conflict - * is resolved with default behavior. i.e. returning `false` will ensure no - * further action is taken, returning `true` will result in the default behavior - * and the method continuing. - * - * For example: - * - * Would mean that if an app already exists in the user directory, if the user - * chooses to 'Continue Move' then the function would continue with its default - * behavior and the existing app will be trashed and the active app moved into its - * place. - * - * @platform darwin - */ - moveToApplicationsFolder(options?: MoveToApplicationsFolderOptions): boolean; - /** - * Try to close all windows. The `before-quit` event will be emitted first. If all - * windows are successfully closed, the `will-quit` event will be emitted and by - * default the application will terminate. - * - * This method guarantees that all `beforeunload` and `unload` event handlers are - * correctly executed. It is possible that a window cancels the quitting by - * returning `false` in the `beforeunload` event handler. - */ - quit(): void; - /** - * Relaunches the app when current instance exits. - * - * By default, the new instance will use the same working directory and command - * line arguments with current instance. When `args` is specified, the `args` will - * be passed as command line arguments instead. When `execPath` is specified, the - * `execPath` will be executed for relaunch instead of current app. - * - * Note that this method does not quit the app when executed, you have to call - * `app.quit` or `app.exit` after calling `app.relaunch` to make the app restart. - * - * When `app.relaunch` is called for multiple times, multiple instances will be - * started after current instance exited. - * - * An example of restarting current instance immediately and adding a new command - * line argument to the new instance: - */ - relaunch(options?: RelaunchOptions): void; - /** - * Releases all locks that were created by `requestSingleInstanceLock`. This will - * allow multiple instances of the application to once again run side by side. - */ - releaseSingleInstanceLock(): void; - /** - * Whether the call succeeded. - * - * This method checks if the current executable as the default handler for a - * protocol (aka URI scheme). If so, it will remove the app as the default handler. - * - * @platform darwin,win32 - */ - removeAsDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; - /** - * The return value of this method indicates whether or not this instance of your - * application successfully obtained the lock. If it failed to obtain the lock, - * you can assume that another instance of your application is already running with - * the lock and exit immediately. - * - * I.e. This method returns `true` if your process is the primary instance of your - * application and your app should continue loading. It returns `false` if your - * process should immediately quit as it has sent its parameters to another - * instance that has already acquired the lock. - * - * On macOS, the system enforces single instance automatically when users try to - * open a second instance of your app in Finder, and the `open-file` and `open-url` - * events will be emitted for that. However when users start your app in command - * line, the system's single instance mechanism will be bypassed, and you have to - * use this method to ensure single instance. - * - * An example of activating the window of primary instance when a second instance - * starts: - */ - requestSingleInstanceLock(): boolean; - /** - * Marks the current Handoff user activity as inactive without invalidating it. - * - * @platform darwin - */ - resignCurrentActivity(): void; - /** - * Set the about panel options. This will override the values defined in the app's - * `.plist` file on macOS. See the Apple docs for more details. On Linux, values - * must be set in order to be shown; there are no defaults. - * - * If you do not set `credits` but still wish to surface them in your app, AppKit - * will look for a file named "Credits.html", "Credits.rtf", and "Credits.rtfd", in - * that order, in the bundle returned by the NSBundle class method main. The first - * file found is used, and if none is found, the info area is left blank. See Apple - * documentation for more information. - */ - setAboutPanelOptions(options: AboutPanelOptionsOptions): void; - /** - * Manually enables Chrome's accessibility support, allowing to expose - * accessibility switch to users in application settings. See Chromium's - * accessibility docs for more details. Disabled by default. - * - * This API must be called after the `ready` event is emitted. - * - * **Note:** Rendering accessibility tree can significantly affect the performance - * of your app. It should not be enabled by default. - * - * @platform darwin,win32 - */ - setAccessibilitySupportEnabled(enabled: boolean): void; - /** - * Sets the activation policy for a given app. - * - * Activation policy types: - * - * * 'regular' - The application is an ordinary app that appears in the Dock and - * may have a user interface. - * * 'accessory' - The application doesn’t appear in the Dock and doesn’t have a - * menu bar, but it may be activated programmatically or by clicking on one of its - * windows. - * * 'prohibited' - The application doesn’t appear in the Dock and may not create - * windows or be activated. - * - * @platform darwin - */ - setActivationPolicy(policy: 'regular' | 'accessory' | 'prohibited'): void; - /** - * Sets or creates a directory your app's logs which can then be manipulated with - * `app.getPath()` or `app.setPath(pathName, newPath)`. - * - * Calling `app.setAppLogsPath()` without a `path` parameter will result in this - * directory being set to `~/Library/Logs/YourAppName` on _macOS_, and inside the - * `userData` directory on _Linux_ and _Windows_. - */ - setAppLogsPath(path?: string): void; - /** - * Changes the Application User Model ID to `id`. - * - * @platform win32 - */ - setAppUserModelId(id: string): void; - /** - * Whether the call succeeded. - * - * Sets the current executable as the default handler for a protocol (aka URI - * scheme). It allows you to integrate your app deeper into the operating system. - * Once registered, all links with `your-protocol://` will be opened with the - * current executable. The whole link, including protocol, will be passed to your - * application as a parameter. - * - * **Note:** On macOS, you can only register protocols that have been added to your - * app's `info.plist`, which cannot be modified at runtime. However, you can change - * the file during build time via Electron Forge, Electron Packager, or by editing - * `info.plist` with a text editor. Please refer to Apple's documentation for - * details. - * - * **Note:** In a Windows Store environment (when packaged as an `appx`) this API - * will return `true` for all calls but the registry key it sets won't be - * accessible by other applications. In order to register your Windows Store - * application as a default protocol handler you must declare the protocol in your - * manifest. - * - * The API uses the Windows Registry and `LSSetDefaultHandlerForURLScheme` - * internally. - */ - setAsDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; - /** - * Whether the call succeeded. - * - * Sets the counter badge for current app. Setting the count to `0` will hide the - * badge. - * - * On macOS, it shows on the dock icon. On Linux, it only works for Unity launcher. - * - * **Note:** Unity launcher requires the existence of a `.desktop` file to work, - * for more information please read Desktop Environment Integration. - * - * @platform linux,darwin - */ - setBadgeCount(count?: number): boolean; - /** - * Sets or removes a custom Jump List for the application, and returns one of the - * following strings: - * - * * `ok` - Nothing went wrong. - * * `error` - One or more errors occurred, enable runtime logging to figure out - * the likely cause. - * * `invalidSeparatorError` - An attempt was made to add a separator to a custom - * category in the Jump List. Separators are only allowed in the standard `Tasks` - * category. - * * `fileTypeRegistrationError` - An attempt was made to add a file link to the - * Jump List for a file type the app isn't registered to handle. - * * `customCategoryAccessDeniedError` - Custom categories can't be added to the - * Jump List due to user privacy or group policy settings. - * - * If `categories` is `null` the previously set custom Jump List (if any) will be - * replaced by the standard Jump List for the app (managed by Windows). - * - * **Note:** If a `JumpListCategory` object has neither the `type` nor the `name` - * property set then its `type` is assumed to be `tasks`. If the `name` property is - * set but the `type` property is omitted then the `type` is assumed to be - * `custom`. - * - * **Note:** Users can remove items from custom categories, and Windows will not - * allow a removed item to be added back into a custom category until **after** the - * next successful call to `app.setJumpList(categories)`. Any attempt to re-add a - * removed item to a custom category earlier than that will result in the entire - * custom category being omitted from the Jump List. The list of removed items can - * be obtained using `app.getJumpListSettings()`. - * - * **Note:** The maximum length of a Jump List item's `description` property is 260 - * characters. Beyond this limit, the item will not be added to the Jump List, nor - * will it be displayed. - * -Here's a very simple example of creating a custom Jump List: - * - * @platform win32 - */ - setJumpList(categories: (JumpListCategory[]) | (null)): void; - /** - * To work with Electron's `autoUpdater` on Windows, which uses Squirrel, you'll - * want to set the launch path to Update.exe, and pass arguments that specify your - * application name. For example: - * - * @platform darwin,win32 - */ - setLoginItemSettings(settings: Settings): void; - /** - * Overrides the current application's name. - * - * **Note:** This function overrides the name used internally by Electron; it does - * not affect the name that the OS uses. - */ - setName(name: string): void; - /** - * Overrides the `path` to a special directory or file associated with `name`. If - * the path specifies a directory that does not exist, an `Error` is thrown. In - * that case, the directory should be created with `fs.mkdirSync` or similar. - * - * You can only override paths of a `name` defined in `app.getPath`. - * - * By default, web pages' cookies and caches will be stored under the `userData` - * directory. If you want to change this location, you have to override the - * `userData` path before the `ready` event of the `app` module is emitted. - */ - setPath(name: string, path: string): void; - /** - * Set the `Secure Keyboard Entry` is enabled in your application. - * - * By using this API, important information such as password and other sensitive - * information can be prevented from being intercepted by other processes. - * - * See Apple's documentation for more details. - * - * **Note:** Enable `Secure Keyboard Entry` only when it is needed and disable it - * when it is no longer needed. - * - * @platform darwin - */ - setSecureKeyboardEntryEnabled(enabled: boolean): void; - /** - * Creates an `NSUserActivity` and sets it as the current activity. The activity is - * eligible for Handoff to another device afterward. - * - * @platform darwin - */ - setUserActivity(type: string, userInfo: any, webpageURL?: string): void; - /** - * Adds `tasks` to the Tasks category of the Jump List on Windows. - * - * `tasks` is an array of `Task` objects. - * - * Whether the call succeeded. - * - * **Note:** If you'd like to customize the Jump List even more use - * `app.setJumpList(categories)` instead. - * - * @platform win32 - */ - setUserTasks(tasks: Task[]): boolean; - /** - * Shows application windows after they were hidden. Does not automatically focus - * them. - * - * @platform darwin - */ - show(): void; - /** - * Show the app's about panel options. These options can be overridden with - * `app.setAboutPanelOptions(options)`. - */ - showAboutPanel(): void; - /** - * Show the platform's native emoji picker. - * - * @platform darwin,win32 - */ - showEmojiPanel(): void; - /** - * This function **must** be called once you have finished accessing the security - * scoped file. If you do not remember to stop accessing the bookmark, kernel - * resources will be leaked and your app will lose its ability to reach outside the - * sandbox completely, until your app is restarted. - * - * Start accessing a security scoped resource. With this method Electron - * applications that are packaged for the Mac App Store may reach outside their - * sandbox to access files chosen by the user. See Apple's documentation for a - * description of how this system works. - * - * @platform mas - */ - startAccessingSecurityScopedResource(bookmarkData: string): Function; - /** - * Updates the current activity if its type matches `type`, merging the entries - * from `userInfo` into its current `userInfo` dictionary. - * - * @platform darwin - */ - updateCurrentActivity(type: string, userInfo: any): void; - /** - * fulfilled when Electron is initialized. May be used as a convenient alternative - * to checking `app.isReady()` and subscribing to the `ready` event if the app is - * not ready yet. - */ - whenReady(): Promise; - /** - * A `Boolean` property that's `true` if Chrome's accessibility support is enabled, - * `false` otherwise. This property will be `true` if the use of assistive - * technologies, such as screen readers, has been detected. Setting this property - * to `true` manually enables Chrome's accessibility support, allowing developers - * to expose accessibility switch to users in application settings. - * - * See Chromium's accessibility docs for more details. Disabled by default. - * - * This API must be called after the `ready` event is emitted. - * - * **Note:** Rendering accessibility tree can significantly affect the performance - * of your app. It should not be enabled by default. - * - * @platform darwin,win32 - */ - accessibilitySupportEnabled: boolean; - /** - * A `Boolean` which when `true` disables the overrides that Electron has in place - * to ensure renderer processes are restarted on every navigation. The current - * default value for this property is `true`. - * - * The intention is for these overrides to become disabled by default and then at - * some point in the future this property will be removed. This property impacts - * which native modules you can use in the renderer process. For more information - * on the direction Electron is going with renderer process restarts and usage of - * native modules in the renderer process please check out this Tracking Issue. - */ - allowRendererProcessReuse: boolean; - /** - * A `Menu | null` property that returns `Menu` if one has been set and `null` - * otherwise. Users can pass a Menu to set this property. - */ - applicationMenu: (Menu) | (null); - /** - * An `Integer` property that returns the badge count for current app. Setting the - * count to `0` will hide the badge. - * - * On macOS, setting this with any nonzero integer shows on the dock icon. On - * Linux, this property only works for Unity launcher. - * - * **Note:** Unity launcher requires the existence of a `.desktop` file to work, - * for more information please read Desktop Environment Integration. - * - * **Note:** On macOS, you need to ensure that your application has the permission - * to display notifications for this property to take effect. - * - * @platform linux,darwin - */ - badgeCount: number; - /** - * A `CommandLine` object that allows you to read and manipulate the command line - * arguments that Chromium uses. - * - */ - readonly commandLine: CommandLine; - /** - * A `Dock` `| undefined` object that allows you to perform actions on your app - * icon in the user's dock on macOS. - * - * @platform darwin - */ - readonly dock: Dock; - /** - * A `Boolean` property that returns `true` if the app is packaged, `false` - * otherwise. For many apps, this property can be used to distinguish development - * and production environments. - * - */ - readonly isPackaged: boolean; - /** - * A `String` property that indicates the current application's name, which is the - * name in the application's `package.json` file. - * - * Usually the `name` field of `package.json` is a short lowercase name, according - * to the npm modules spec. You should usually also specify a `productName` field, - * which is your application's full capitalized name, and which will be preferred - * over `name` by Electron. - */ - name: string; - /** - * A `Boolean` which when `true` indicates that the app is currently running under - * the Rosetta Translator Environment. - * - * You can use this property to prompt users to download the arm64 version of your - * application when they are running the x64 version under Rosetta incorrectly. - * - * @platform darwin - */ - readonly runningUnderRosettaTranslation: boolean; - /** - * A `String` which is the user agent string Electron will use as a global - * fallback. - * - * This is the user agent that will be used when no user agent is set at the - * `webContents` or `session` level. It is useful for ensuring that your entire - * app has the same user agent. Set to a custom value as early as possible in your - * app's initialization to ensure that your overridden value is used. - */ - userAgentFallback: string; - } - - interface AutoUpdater extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/auto-updater - - /** - * This event is emitted after a user calls `quitAndInstall()`. - * - * When this API is called, the `before-quit` event is not emitted before all - * windows are closed. As a result you should listen to this event if you wish to - * perform actions before the windows are closed while a process is quitting, as - * well as listening to `before-quit`. - */ - on(event: 'before-quit-for-update', listener: Function): this; - once(event: 'before-quit-for-update', listener: Function): this; - addListener(event: 'before-quit-for-update', listener: Function): this; - removeListener(event: 'before-quit-for-update', listener: Function): this; - /** - * Emitted when checking if an update has started. - */ - on(event: 'checking-for-update', listener: Function): this; - once(event: 'checking-for-update', listener: Function): this; - addListener(event: 'checking-for-update', listener: Function): this; - removeListener(event: 'checking-for-update', listener: Function): this; - /** - * Emitted when there is an error while updating. - */ - on(event: 'error', listener: (error: Error) => void): this; - once(event: 'error', listener: (error: Error) => void): this; - addListener(event: 'error', listener: (error: Error) => void): this; - removeListener(event: 'error', listener: (error: Error) => void): this; - /** - * Emitted when there is an available update. The update is downloaded - * automatically. - */ - on(event: 'update-available', listener: Function): this; - once(event: 'update-available', listener: Function): this; - addListener(event: 'update-available', listener: Function): this; - removeListener(event: 'update-available', listener: Function): this; - /** - * Emitted when an update has been downloaded. - * - * On Windows only `releaseName` is available. - * - * **Note:** It is not strictly necessary to handle this event. A successfully - * downloaded update will still be applied the next time the application starts. - */ - on(event: 'update-downloaded', listener: (event: Event, - releaseNotes: string, - releaseName: string, - releaseDate: Date, - updateURL: string) => void): this; - once(event: 'update-downloaded', listener: (event: Event, - releaseNotes: string, - releaseName: string, - releaseDate: Date, - updateURL: string) => void): this; - addListener(event: 'update-downloaded', listener: (event: Event, - releaseNotes: string, - releaseName: string, - releaseDate: Date, - updateURL: string) => void): this; - removeListener(event: 'update-downloaded', listener: (event: Event, - releaseNotes: string, - releaseName: string, - releaseDate: Date, - updateURL: string) => void): this; - /** - * Emitted when there is no available update. - */ - on(event: 'update-not-available', listener: Function): this; - once(event: 'update-not-available', listener: Function): this; - addListener(event: 'update-not-available', listener: Function): this; - removeListener(event: 'update-not-available', listener: Function): this; - /** - * Asks the server whether there is an update. You must call `setFeedURL` before - * using this API. - */ - checkForUpdates(): void; - /** - * The current update feed URL. - */ - getFeedURL(): string; - /** - * Restarts the app and installs the update after it has been downloaded. It should - * only be called after `update-downloaded` has been emitted. - * - * Under the hood calling `autoUpdater.quitAndInstall()` will close all application - * windows first, and automatically call `app.quit()` after all windows have been - * closed. - * - * **Note:** It is not strictly necessary to call this function to apply an update, - * as a successfully downloaded update will always be applied the next time the - * application starts. - */ - quitAndInstall(): void; - /** - * Sets the `url` and initialize the auto updater. - */ - setFeedURL(options: FeedURLOptions): void; - } - - interface BluetoothDevice { - - // Docs: https://electronjs.org/docs/api/structures/bluetooth-device - - deviceId: string; - deviceName: string; - } - - class BrowserView { - - // Docs: https://electronjs.org/docs/api/browser-view - - /** - * BrowserView - */ - constructor(options?: BrowserViewConstructorOptions); - /** - * The `bounds` of this BrowserView instance as `Object`. - * - * @experimental - */ - getBounds(): Rectangle; - setAutoResize(options: AutoResizeOptions): void; - setBackgroundColor(color: string): void; - /** - * Resizes and moves the view to the supplied bounds relative to the window. - * - * @experimental - */ - setBounds(bounds: Rectangle): void; - webContents: WebContents; - } - - class BrowserWindow extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/browser-window - - /** - * Emitted when the window is set or unset to show always on top of other windows. - */ - on(event: 'always-on-top-changed', listener: (event: Event, - isAlwaysOnTop: boolean) => void): this; - once(event: 'always-on-top-changed', listener: (event: Event, - isAlwaysOnTop: boolean) => void): this; - addListener(event: 'always-on-top-changed', listener: (event: Event, - isAlwaysOnTop: boolean) => void): this; - removeListener(event: 'always-on-top-changed', listener: (event: Event, - isAlwaysOnTop: boolean) => void): this; - /** - * Emitted when an App Command is invoked. These are typically related to keyboard - * media keys or browser commands, as well as the "Back" button built into some - * mice on Windows. - * - * Commands are lowercased, underscores are replaced with hyphens, and the - * `APPCOMMAND_` prefix is stripped off. e.g. `APPCOMMAND_BROWSER_BACKWARD` is - * emitted as `browser-backward`. - * - * The following app commands are explicitly supported on Linux: - * -* `browser-backward` -* `browser-forward` - * - * @platform win32,linux - */ - on(event: 'app-command', listener: (event: Event, - command: string) => void): this; - once(event: 'app-command', listener: (event: Event, - command: string) => void): this; - addListener(event: 'app-command', listener: (event: Event, - command: string) => void): this; - removeListener(event: 'app-command', listener: (event: Event, - command: string) => void): this; - /** - * Emitted when the window loses focus. - */ - on(event: 'blur', listener: Function): this; - once(event: 'blur', listener: Function): this; - addListener(event: 'blur', listener: Function): this; - removeListener(event: 'blur', listener: Function): this; - /** - * Emitted when the window is going to be closed. It's emitted before the - * `beforeunload` and `unload` event of the DOM. Calling `event.preventDefault()` - * will cancel the close. - * - * Usually you would want to use the `beforeunload` handler to decide whether the - * window should be closed, which will also be called when the window is reloaded. - * In Electron, returning any value other than `undefined` would cancel the close. - * For example: - * - * _**Note**: There is a subtle difference between the behaviors of - * `window.onbeforeunload = handler` and `window.addEventListener('beforeunload', - * handler)`. It is recommended to always set the `event.returnValue` explicitly, - * instead of only returning a value, as the former works more consistently within - * Electron._ - */ - on(event: 'close', listener: (event: Event) => void): this; - once(event: 'close', listener: (event: Event) => void): this; - addListener(event: 'close', listener: (event: Event) => void): this; - removeListener(event: 'close', listener: (event: Event) => void): this; - /** - * Emitted when the window is closed. After you have received this event you should - * remove the reference to the window and avoid using it any more. - */ - on(event: 'closed', listener: Function): this; - once(event: 'closed', listener: Function): this; - addListener(event: 'closed', listener: Function): this; - removeListener(event: 'closed', listener: Function): this; - /** - * Emitted when the window enters a full-screen state. - */ - on(event: 'enter-full-screen', listener: Function): this; - once(event: 'enter-full-screen', listener: Function): this; - addListener(event: 'enter-full-screen', listener: Function): this; - removeListener(event: 'enter-full-screen', listener: Function): this; - /** - * Emitted when the window enters a full-screen state triggered by HTML API. - */ - on(event: 'enter-html-full-screen', listener: Function): this; - once(event: 'enter-html-full-screen', listener: Function): this; - addListener(event: 'enter-html-full-screen', listener: Function): this; - removeListener(event: 'enter-html-full-screen', listener: Function): this; - /** - * Emitted when the window gains focus. - */ - on(event: 'focus', listener: Function): this; - once(event: 'focus', listener: Function): this; - addListener(event: 'focus', listener: Function): this; - removeListener(event: 'focus', listener: Function): this; - /** - * Emitted when the window is hidden. - */ - on(event: 'hide', listener: Function): this; - once(event: 'hide', listener: Function): this; - addListener(event: 'hide', listener: Function): this; - removeListener(event: 'hide', listener: Function): this; - /** - * Emitted when the window leaves a full-screen state. - */ - on(event: 'leave-full-screen', listener: Function): this; - once(event: 'leave-full-screen', listener: Function): this; - addListener(event: 'leave-full-screen', listener: Function): this; - removeListener(event: 'leave-full-screen', listener: Function): this; - /** - * Emitted when the window leaves a full-screen state triggered by HTML API. - */ - on(event: 'leave-html-full-screen', listener: Function): this; - once(event: 'leave-html-full-screen', listener: Function): this; - addListener(event: 'leave-html-full-screen', listener: Function): this; - removeListener(event: 'leave-html-full-screen', listener: Function): this; - /** - * Emitted when window is maximized. - */ - on(event: 'maximize', listener: Function): this; - once(event: 'maximize', listener: Function): this; - addListener(event: 'maximize', listener: Function): this; - removeListener(event: 'maximize', listener: Function): this; - /** - * Emitted when the window is minimized. - */ - on(event: 'minimize', listener: Function): this; - once(event: 'minimize', listener: Function): this; - addListener(event: 'minimize', listener: Function): this; - removeListener(event: 'minimize', listener: Function): this; - /** - * Emitted when the window is being moved to a new position. - */ - on(event: 'move', listener: Function): this; - once(event: 'move', listener: Function): this; - addListener(event: 'move', listener: Function): this; - removeListener(event: 'move', listener: Function): this; - /** - * Emitted once when the window is moved to a new position. - * -__Note__: On macOS this event is an alias of `move`. - * - * @platform darwin,win32 - */ - on(event: 'moved', listener: Function): this; - once(event: 'moved', listener: Function): this; - addListener(event: 'moved', listener: Function): this; - removeListener(event: 'moved', listener: Function): this; - /** - * Emitted when the native new tab button is clicked. - * - * @platform darwin - */ - on(event: 'new-window-for-tab', listener: Function): this; - once(event: 'new-window-for-tab', listener: Function): this; - addListener(event: 'new-window-for-tab', listener: Function): this; - removeListener(event: 'new-window-for-tab', listener: Function): this; - /** - * Emitted when the document changed its title, calling `event.preventDefault()` - * will prevent the native window's title from changing. `explicitSet` is false - * when title is synthesized from file URL. - */ - on(event: 'page-title-updated', listener: (event: Event, - title: string, - explicitSet: boolean) => void): this; - once(event: 'page-title-updated', listener: (event: Event, - title: string, - explicitSet: boolean) => void): this; - addListener(event: 'page-title-updated', listener: (event: Event, - title: string, - explicitSet: boolean) => void): this; - removeListener(event: 'page-title-updated', listener: (event: Event, - title: string, - explicitSet: boolean) => void): this; - /** - * Emitted when the web page has been rendered (while not being shown) and window - * can be displayed without a visual flash. - * - * Please note that using this event implies that the renderer will be considered - * "visible" and paint even though `show` is false. This event will never fire if - * you use `paintWhenInitiallyHidden: false` - */ - on(event: 'ready-to-show', listener: Function): this; - once(event: 'ready-to-show', listener: Function): this; - addListener(event: 'ready-to-show', listener: Function): this; - removeListener(event: 'ready-to-show', listener: Function): this; - /** - * Emitted after the window has been resized. - */ - on(event: 'resize', listener: Function): this; - once(event: 'resize', listener: Function): this; - addListener(event: 'resize', listener: Function): this; - removeListener(event: 'resize', listener: Function): this; - /** - * Emitted once when the window has finished being resized. - * - * This is usually emitted when the window has been resized manually. On macOS, - * resizing the window with `setBounds`/`setSize` and setting the `animate` - * parameter to `true` will also emit this event once resizing has finished. - * - * @platform darwin,win32 - */ - on(event: 'resized', listener: Function): this; - once(event: 'resized', listener: Function): this; - addListener(event: 'resized', listener: Function): this; - removeListener(event: 'resized', listener: Function): this; - /** - * Emitted when the unresponsive web page becomes responsive again. - */ - on(event: 'responsive', listener: Function): this; - once(event: 'responsive', listener: Function): this; - addListener(event: 'responsive', listener: Function): this; - removeListener(event: 'responsive', listener: Function): this; - /** - * Emitted when the window is restored from a minimized state. - */ - on(event: 'restore', listener: Function): this; - once(event: 'restore', listener: Function): this; - addListener(event: 'restore', listener: Function): this; - removeListener(event: 'restore', listener: Function): this; - /** - * Emitted on trackpad rotation gesture. Continually emitted until rotation gesture - * is ended. The `rotation` value on each emission is the angle in degrees rotated - * since the last emission. The last emitted event upon a rotation gesture will - * always be of value `0`. Counter-clockwise rotation values are positive, while - * clockwise ones are negative. - * - * @platform darwin - */ - on(event: 'rotate-gesture', listener: (event: Event, - rotation: number) => void): this; - once(event: 'rotate-gesture', listener: (event: Event, - rotation: number) => void): this; - addListener(event: 'rotate-gesture', listener: (event: Event, - rotation: number) => void): this; - removeListener(event: 'rotate-gesture', listener: (event: Event, - rotation: number) => void): this; - /** - * Emitted when scroll wheel event phase has begun. - * - * @platform darwin - */ - on(event: 'scroll-touch-begin', listener: Function): this; - once(event: 'scroll-touch-begin', listener: Function): this; - addListener(event: 'scroll-touch-begin', listener: Function): this; - removeListener(event: 'scroll-touch-begin', listener: Function): this; - /** - * Emitted when scroll wheel event phase filed upon reaching the edge of element. - * - * @platform darwin - */ - on(event: 'scroll-touch-edge', listener: Function): this; - once(event: 'scroll-touch-edge', listener: Function): this; - addListener(event: 'scroll-touch-edge', listener: Function): this; - removeListener(event: 'scroll-touch-edge', listener: Function): this; - /** - * Emitted when scroll wheel event phase has ended. - * - * @platform darwin - */ - on(event: 'scroll-touch-end', listener: Function): this; - once(event: 'scroll-touch-end', listener: Function): this; - addListener(event: 'scroll-touch-end', listener: Function): this; - removeListener(event: 'scroll-touch-end', listener: Function): this; - /** - * Emitted when window session is going to end due to force shutdown or machine - * restart or session log off. - * - * @platform win32 - */ - on(event: 'session-end', listener: Function): this; - once(event: 'session-end', listener: Function): this; - addListener(event: 'session-end', listener: Function): this; - removeListener(event: 'session-end', listener: Function): this; - /** - * Emitted when the window opens a sheet. - * - * @platform darwin - */ - on(event: 'sheet-begin', listener: Function): this; - once(event: 'sheet-begin', listener: Function): this; - addListener(event: 'sheet-begin', listener: Function): this; - removeListener(event: 'sheet-begin', listener: Function): this; - /** - * Emitted when the window has closed a sheet. - * - * @platform darwin - */ - on(event: 'sheet-end', listener: Function): this; - once(event: 'sheet-end', listener: Function): this; - addListener(event: 'sheet-end', listener: Function): this; - removeListener(event: 'sheet-end', listener: Function): this; - /** - * Emitted when the window is shown. - */ - on(event: 'show', listener: Function): this; - once(event: 'show', listener: Function): this; - addListener(event: 'show', listener: Function): this; - removeListener(event: 'show', listener: Function): this; - /** - * Emitted on 3-finger swipe. Possible directions are `up`, `right`, `down`, - * `left`. - * - * The method underlying this event is built to handle older macOS-style trackpad - * swiping, where the content on the screen doesn't move with the swipe. Most macOS - * trackpads are not configured to allow this kind of swiping anymore, so in order - * for it to emit properly the 'Swipe between pages' preference in `System - * Preferences > Trackpad > More Gestures` must be set to 'Swipe with two or three - * fingers'. - * - * @platform darwin - */ - on(event: 'swipe', listener: (event: Event, - direction: string) => void): this; - once(event: 'swipe', listener: (event: Event, - direction: string) => void): this; - addListener(event: 'swipe', listener: (event: Event, - direction: string) => void): this; - removeListener(event: 'swipe', listener: (event: Event, - direction: string) => void): this; - /** - * Emitted when the system context menu is triggered on the window, this is - * normally only triggered when the user right clicks on the non-client area of - * your window. This is the window titlebar or any area you have declared as - * `-webkit-app-region: drag` in a frameless window. - * -Calling `event.preventDefault()` will prevent the menu from being displayed. - * - * @platform win32 - */ - on(event: 'system-context-menu', listener: (event: Event, - /** - * The screen coordinates the context menu was triggered at - */ - point: Point) => void): this; - once(event: 'system-context-menu', listener: (event: Event, - /** - * The screen coordinates the context menu was triggered at - */ - point: Point) => void): this; - addListener(event: 'system-context-menu', listener: (event: Event, - /** - * The screen coordinates the context menu was triggered at - */ - point: Point) => void): this; - removeListener(event: 'system-context-menu', listener: (event: Event, - /** - * The screen coordinates the context menu was triggered at - */ - point: Point) => void): this; - /** - * Emitted when the window exits from a maximized state. - */ - on(event: 'unmaximize', listener: Function): this; - once(event: 'unmaximize', listener: Function): this; - addListener(event: 'unmaximize', listener: Function): this; - removeListener(event: 'unmaximize', listener: Function): this; - /** - * Emitted when the web page becomes unresponsive. - */ - on(event: 'unresponsive', listener: Function): this; - once(event: 'unresponsive', listener: Function): this; - addListener(event: 'unresponsive', listener: Function): this; - removeListener(event: 'unresponsive', listener: Function): this; - /** - * Emitted before the window is moved. On Windows, calling `event.preventDefault()` - * will prevent the window from being moved. - * - * Note that this is only emitted when the window is being resized manually. - * Resizing the window with `setBounds`/`setSize` will not emit this event. - * - * @platform darwin,win32 - */ - on(event: 'will-move', listener: (event: Event, - /** - * Location the window is being moved to. - */ - newBounds: Rectangle) => void): this; - once(event: 'will-move', listener: (event: Event, - /** - * Location the window is being moved to. - */ - newBounds: Rectangle) => void): this; - addListener(event: 'will-move', listener: (event: Event, - /** - * Location the window is being moved to. - */ - newBounds: Rectangle) => void): this; - removeListener(event: 'will-move', listener: (event: Event, - /** - * Location the window is being moved to. - */ - newBounds: Rectangle) => void): this; - /** - * Emitted before the window is resized. Calling `event.preventDefault()` will - * prevent the window from being resized. - * - * Note that this is only emitted when the window is being resized manually. - * Resizing the window with `setBounds`/`setSize` will not emit this event. - * - * @platform darwin,win32 - */ - on(event: 'will-resize', listener: (event: Event, - /** - * Size the window is being resized to. - */ - newBounds: Rectangle) => void): this; - once(event: 'will-resize', listener: (event: Event, - /** - * Size the window is being resized to. - */ - newBounds: Rectangle) => void): this; - addListener(event: 'will-resize', listener: (event: Event, - /** - * Size the window is being resized to. - */ - newBounds: Rectangle) => void): this; - removeListener(event: 'will-resize', listener: (event: Event, - /** - * Size the window is being resized to. - */ - newBounds: Rectangle) => void): this; - /** - * BrowserWindow - */ - constructor(options?: BrowserWindowConstructorOptions); - /** - * Adds DevTools extension located at `path`, and returns extension's name. - * - * The extension will be remembered so you only need to call this API once, this - * API is not for programming use. If you try to add an extension that has already - * been loaded, this method will not return and instead log a warning to the - * console. - * - * The method will also not return if the extension's manifest is missing or - * incomplete. - * - * **Note:** This API cannot be called before the `ready` event of the `app` module - * is emitted. - * -**Note:** This method is deprecated. Instead, use `ses.loadExtension(path)`. - * - * @deprecated - */ - static addDevToolsExtension(path: string): void; - /** - * Adds Chrome extension located at `path`, and returns extension's name. - * - * The method will also not return if the extension's manifest is missing or - * incomplete. - * - * **Note:** This API cannot be called before the `ready` event of the `app` module - * is emitted. - * -**Note:** This method is deprecated. Instead, use `ses.loadExtension(path)`. - * - * @deprecated - */ - static addExtension(path: string): void; - /** - * The window that owns the given `browserView`. If the given view is not attached - * to any window, returns `null`. - */ - static fromBrowserView(browserView: BrowserView): (BrowserWindow) | (null); - /** - * The window with the given `id`. - */ - static fromId(id: number): (BrowserWindow) | (null); - /** - * The window that owns the given `webContents` or `null` if the contents are not - * owned by a window. - */ - static fromWebContents(webContents: WebContents): (BrowserWindow) | (null); - /** - * An array of all opened browser windows. - */ - static getAllWindows(): BrowserWindow[]; - /** - * The keys are the extension names and each value is an Object containing `name` - * and `version` properties. - * - * To check if a DevTools extension is installed you can run the following: - * - * **Note:** This API cannot be called before the `ready` event of the `app` module - * is emitted. - * -**Note:** This method is deprecated. Instead, use `ses.getAllExtensions()`. - * - * @deprecated - */ - static getDevToolsExtensions(): Record; - /** - * The keys are the extension names and each value is an Object containing `name` - * and `version` properties. - * - * **Note:** This API cannot be called before the `ready` event of the `app` module - * is emitted. - * -**Note:** This method is deprecated. Instead, use `ses.getAllExtensions()`. - * - * @deprecated - */ - static getExtensions(): Record; - /** - * The window that is focused in this application, otherwise returns `null`. - */ - static getFocusedWindow(): (BrowserWindow) | (null); - /** - * Remove a DevTools extension by name. - * - * **Note:** This API cannot be called before the `ready` event of the `app` module - * is emitted. - * - * **Note:** This method is deprecated. Instead, use - * `ses.removeExtension(extension_id)`. - * - * @deprecated - */ - static removeDevToolsExtension(name: string): void; - /** - * Remove a Chrome extension by name. - * - * **Note:** This API cannot be called before the `ready` event of the `app` module - * is emitted. - * - * **Note:** This method is deprecated. Instead, use - * `ses.removeExtension(extension_id)`. - * - * @deprecated - */ - static removeExtension(name: string): void; - /** - * Replacement API for setBrowserView supporting work with multi browser views. - * - * @experimental - */ - addBrowserView(browserView: BrowserView): void; - /** - * Adds a window as a tab on this window, after the tab for the window instance. - * - * @platform darwin - */ - addTabbedWindow(browserWindow: BrowserWindow): void; - /** - * Removes focus from the window. - */ - blur(): void; - blurWebView(): void; - /** - * Resolves with a NativeImage - * - * Captures a snapshot of the page within `rect`. Omitting `rect` will capture the - * whole visible page. If the page is not visible, `rect` may be empty. - */ - capturePage(rect?: Rectangle): Promise; - /** - * Moves window to the center of the screen. - */ - center(): void; - /** - * Try to close the window. This has the same effect as a user manually clicking - * the close button of the window. The web page may cancel the close though. See - * the close event. - */ - close(): void; - /** - * Closes the currently open Quick Look panel. - * - * @platform darwin - */ - closeFilePreview(): void; - /** - * Force closing the window, the `unload` and `beforeunload` event won't be emitted - * for the web page, and `close` event will also not be emitted for this window, - * but it guarantees the `closed` event will be emitted. - */ - destroy(): void; - /** - * Starts or stops flashing the window to attract user's attention. - */ - flashFrame(flag: boolean): void; - /** - * Focuses on the window. - */ - focus(): void; - focusOnWebView(): void; - /** - * Gets the background color of the window. See Setting `backgroundColor`. - */ - getBackgroundColor(): string; - /** - * The `bounds` of the window as `Object`. - */ - getBounds(): Rectangle; - /** - * The `BrowserView` attached to `win`. Returns `null` if one is not attached. - * Throws an error if multiple `BrowserView`s are attached. - * - * @experimental - */ - getBrowserView(): (BrowserView) | (null); - /** - * an array of all BrowserViews that have been attached with `addBrowserView` or - * `setBrowserView`. - * - * **Note:** The BrowserView API is currently experimental and may change or be - * removed in future Electron releases. - * - * @experimental - */ - getBrowserViews(): BrowserView[]; - /** - * All child windows. - */ - getChildWindows(): BrowserWindow[]; - /** - * The `bounds` of the window's client area as `Object`. - */ - getContentBounds(): Rectangle; - /** - * Contains the window's client area's width and height. - */ - getContentSize(): number[]; - /** - * Contains the window's maximum width and height. - */ - getMaximumSize(): number[]; - /** - * Window id in the format of DesktopCapturerSource's id. For example - * "window:1234:0". - * - * More precisely the format is `window:id:other_id` where `id` is `HWND` on - * Windows, `CGWindowID` (`uint64_t`) on macOS and `Window` (`unsigned long`) on - * Linux. `other_id` is used to identify web contents (tabs) so within the same top - * level window. - */ - getMediaSourceId(): string; - /** - * Contains the window's minimum width and height. - */ - getMinimumSize(): number[]; - /** - * The platform-specific handle of the window. - * - * The native type of the handle is `HWND` on Windows, `NSView*` on macOS, and - * `Window` (`unsigned long`) on Linux. - */ - getNativeWindowHandle(): Buffer; - /** - * Contains the window bounds of the normal state - * - * **Note:** whatever the current state of the window : maximized, minimized or in - * fullscreen, this function always returns the position and size of the window in - * normal state. In normal state, getBounds and getNormalBounds returns the same - * `Rectangle`. - */ - getNormalBounds(): Rectangle; - /** - * between 0.0 (fully transparent) and 1.0 (fully opaque). On Linux, always returns - * 1. - */ - getOpacity(): number; - /** - * The parent window. - */ - getParentWindow(): BrowserWindow; - /** - * Contains the window's current position. - */ - getPosition(): number[]; - /** - * The pathname of the file the window represents. - * - * @platform darwin - */ - getRepresentedFilename(): string; - /** - * Contains the window's width and height. - */ - getSize(): number[]; - /** - * The title of the native window. - * - * **Note:** The title of the web page can be different from the title of the - * native window. - */ - getTitle(): string; - /** - * The current position for the traffic light buttons. Can only be used with - * `titleBarStyle` set to `hidden`. - * - * @platform darwin - */ - getTrafficLightPosition(): Point; - /** - * Whether the window has a shadow. - */ - hasShadow(): boolean; - /** - * Hides the window. - */ - hide(): void; - /** - * Hooks a windows message. The `callback` is called when the message is received - * in the WndProc. - * - * @platform win32 - */ - hookWindowMessage(message: number, callback: (wParam: any, lParam: any) => void): void; - /** - * Whether the window is always on top of other windows. - */ - isAlwaysOnTop(): boolean; - /** - * Whether the window can be manually closed by user. - * -On Linux always returns `true`. - * - * @platform darwin,win32 - */ - isClosable(): boolean; - /** - * Whether the window is destroyed. - */ - isDestroyed(): boolean; - /** - * Whether the window's document has been edited. - * - * @platform darwin - */ - isDocumentEdited(): boolean; - /** - * whether the window is enabled. - */ - isEnabled(): boolean; - /** - * Whether the window is focused. - */ - isFocused(): boolean; - /** - * Whether the window is in fullscreen mode. - */ - isFullScreen(): boolean; - /** - * Whether the maximize/zoom window button toggles fullscreen mode or maximizes the - * window. - */ - isFullScreenable(): boolean; - /** - * Whether the window is in kiosk mode. - */ - isKiosk(): boolean; - /** - * Whether the window can be manually maximized by user. - * -On Linux always returns `true`. - * - * @platform darwin,win32 - */ - isMaximizable(): boolean; - /** - * Whether the window is maximized. - */ - isMaximized(): boolean; - /** - * Whether menu bar automatically hides itself. - */ - isMenuBarAutoHide(): boolean; - /** - * Whether the menu bar is visible. - */ - isMenuBarVisible(): boolean; - /** - * Whether the window can be manually minimized by the user. - * -On Linux always returns `true`. - * - * @platform darwin,win32 - */ - isMinimizable(): boolean; - /** - * Whether the window is minimized. - */ - isMinimized(): boolean; - /** - * Whether current window is a modal window. - */ - isModal(): boolean; - /** - * Whether the window can be moved by user. - -On Linux always returns `true`. - * - * @platform darwin,win32 - */ - isMovable(): boolean; - /** - * Whether the window is in normal state (not maximized, not minimized, not in - * fullscreen mode). - */ - isNormal(): boolean; - /** - * Whether the window can be manually resized by the user. - */ - isResizable(): boolean; - /** - * Whether the window is in simple (pre-Lion) fullscreen mode. - * - * @platform darwin - */ - isSimpleFullScreen(): boolean; - /** - * Whether the window is in Windows 10 tablet mode. - * - * Since Windows 10 users can use their PC as tablet, under this mode apps can - * choose to optimize their UI for tablets, such as enlarging the titlebar and - * hiding titlebar buttons. - * - * This API returns whether the window is in tablet mode, and the `resize` event - * can be be used to listen to changes to tablet mode. - * - * @platform win32 - */ - isTabletMode(): boolean; - /** - * Whether the window is visible to the user. - */ - isVisible(): boolean; - /** - * Whether the window is visible on all workspaces. - * -**Note:** This API always returns false on Windows. - */ - isVisibleOnAllWorkspaces(): boolean; - /** - * `true` or `false` depending on whether the message is hooked. - * - * @platform win32 - */ - isWindowMessageHooked(message: number): boolean; - /** - * the promise will resolve when the page has finished loading (see - * `did-finish-load`), and rejects if the page fails to load (see `did-fail-load`). - * - * Same as `webContents.loadFile`, `filePath` should be a path to an HTML file - * relative to the root of your application. See the `webContents` docs for more - * information. - */ - loadFile(filePath: string, options?: LoadFileOptions): Promise; - /** - * the promise will resolve when the page has finished loading (see - * `did-finish-load`), and rejects if the page fails to load (see `did-fail-load`). - * - * Same as `webContents.loadURL(url[, options])`. - * - * The `url` can be a remote address (e.g. `http://`) or a path to a local HTML - * file using the `file://` protocol. - * - * To ensure that file URLs are properly formatted, it is recommended to use Node's - * `url.format` method: - * - * You can load a URL using a `POST` request with URL-encoded data by doing the - * following: - */ - loadURL(url: string, options?: LoadURLOptions): Promise; - /** - * Maximizes the window. This will also show (but not focus) the window if it isn't - * being displayed already. - */ - maximize(): void; - /** - * Merges all windows into one window with multiple tabs when native tabs are - * enabled and there is more than one open window. - * - * @platform darwin - */ - mergeAllWindows(): void; - /** - * Minimizes the window. On some platforms the minimized window will be shown in - * the Dock. - */ - minimize(): void; - /** - * Moves window above the source window in the sense of z-order. If the - * `mediaSourceId` is not of type window or if the window does not exist then this - * method throws an error. - */ - moveAbove(mediaSourceId: string): void; - /** - * Moves the current tab into a new window if native tabs are enabled and there is - * more than one tab in the current window. - * - * @platform darwin - */ - moveTabToNewWindow(): void; - /** - * Moves window to top(z-order) regardless of focus - */ - moveTop(): void; - /** - * Uses Quick Look to preview a file at a given path. - * - * @platform darwin - */ - previewFile(path: string, displayName?: string): void; - /** - * Same as `webContents.reload`. - */ - reload(): void; - removeBrowserView(browserView: BrowserView): void; - /** - * Remove the window's menu bar. - * - * @platform linux,win32 - */ - removeMenu(): void; - /** - * Restores the window from minimized state to its previous state. - */ - restore(): void; - /** - * Selects the next tab when native tabs are enabled and there are other tabs in - * the window. - * - * @platform darwin - */ - selectNextTab(): void; - /** - * Selects the previous tab when native tabs are enabled and there are other tabs - * in the window. - * - * @platform darwin - */ - selectPreviousTab(): void; - /** - * Sets whether the window should show always on top of other windows. After - * setting this, the window is still a normal window, not a toolbox window which - * can not be focused on. - */ - setAlwaysOnTop(flag: boolean, level?: 'normal' | 'floating' | 'torn-off-menu' | 'modal-panel' | 'main-menu' | 'status' | 'pop-up-menu' | 'screen-saver', relativeLevel?: number): void; - /** - * Sets the properties for the window's taskbar button. - * - * **Note:** `relaunchCommand` and `relaunchDisplayName` must always be set - * together. If one of those properties is not set, then neither will be used. - * - * @platform win32 - */ - setAppDetails(options: AppDetailsOptions): void; - /** - * This will make a window maintain an aspect ratio. The extra size allows a - * developer to have space, specified in pixels, not included within the aspect - * ratio calculations. This API already takes into account the difference between a - * window's size and its content size. - * - * Consider a normal window with an HD video player and associated controls. - * Perhaps there are 15 pixels of controls on the left edge, 25 pixels of controls - * on the right edge and 50 pixels of controls below the player. In order to - * maintain a 16:9 aspect ratio (standard aspect ratio for HD @1920x1080) within - * the player itself we would call this function with arguments of 16/9 and { - * width: 40, height: 50 }. The second argument doesn't care where the extra width - * and height are within the content view--only that they exist. Sum any extra - * width and height areas you have within the overall content view. - * - * The aspect ratio is not respected when window is resized programmingly with APIs - * like `win.setSize`. - */ - setAspectRatio(aspectRatio: number, extraSize?: Size): void; - /** - * Controls whether to hide cursor when typing. - * - * @platform darwin - */ - setAutoHideCursor(autoHide: boolean): void; - /** - * Sets whether the window menu bar should hide itself automatically. Once set the - * menu bar will only show when users press the single `Alt` key. - * - * If the menu bar is already visible, calling `setAutoHideMenuBar(true)` won't - * hide it immediately. - */ - setAutoHideMenuBar(hide: boolean): void; - /** - * Sets the background color of the window. See Setting `backgroundColor`. - */ - setBackgroundColor(backgroundColor: string): void; - /** - * Resizes and moves the window to the supplied bounds. Any properties that are not - * supplied will default to their current values. - */ - setBounds(bounds: Partial, animate?: boolean): void; - setBrowserView(browserView: (BrowserView) | (null)): void; - /** - * Sets whether the window can be manually closed by user. On Linux does nothing. - * - * @platform darwin,win32 - */ - setClosable(closable: boolean): void; - /** - * Resizes and moves the window's client area (e.g. the web page) to the supplied - * bounds. - */ - setContentBounds(bounds: Rectangle, animate?: boolean): void; - /** - * Prevents the window contents from being captured by other apps. - * - * On macOS it sets the NSWindow's sharingType to NSWindowSharingNone. On Windows - * it calls SetWindowDisplayAffinity with `WDA_EXCLUDEFROMCAPTURE`. For Windows 10 - * version 2004 and up the window will be removed from capture entirely, older - * Windows versions behave as if `WDA_MONITOR` is applied capturing a black window. - * - * @platform darwin,win32 - */ - setContentProtection(enable: boolean): void; - /** - * Resizes the window's client area (e.g. the web page) to `width` and `height`. - */ - setContentSize(width: number, height: number, animate?: boolean): void; - /** - * Specifies whether the window’s document has been edited, and the icon in title - * bar will become gray when set to `true`. - * - * @platform darwin - */ - setDocumentEdited(edited: boolean): void; - /** - * Disable or enable the window. - */ - setEnabled(enable: boolean): void; - /** - * Changes whether the window can be focused. - * -On macOS it does not remove the focus from the window. - * - * @platform darwin,win32 - */ - setFocusable(focusable: boolean): void; - /** - * Sets whether the window should be in fullscreen mode. - */ - setFullScreen(flag: boolean): void; - /** - * Sets whether the maximize/zoom window button toggles fullscreen mode or - * maximizes the window. - */ - setFullScreenable(fullscreenable: boolean): void; - /** - * Sets whether the window should have a shadow. - */ - setHasShadow(hasShadow: boolean): void; - /** - * Changes window icon. - * - * @platform win32,linux - */ - setIcon(icon: (NativeImage) | (string)): void; - /** - * Makes the window ignore all mouse events. - * - * All mouse events happened in this window will be passed to the window below this - * window, but if this window has focus, it will still receive keyboard events. - */ - setIgnoreMouseEvents(ignore: boolean, options?: IgnoreMouseEventsOptions): void; - /** - * Enters or leaves kiosk mode. - */ - setKiosk(flag: boolean): void; - /** - * Sets whether the window can be manually maximized by user. On Linux does - * nothing. - * - * @platform darwin,win32 - */ - setMaximizable(maximizable: boolean): void; - /** - * Sets the maximum size of window to `width` and `height`. - */ - setMaximumSize(width: number, height: number): void; - /** - * Sets the `menu` as the window's menu bar. - * - * @platform linux,win32 - */ - setMenu(menu: (Menu) | (null)): void; - /** - * Sets whether the menu bar should be visible. If the menu bar is auto-hide, users - * can still bring up the menu bar by pressing the single `Alt` key. - * - * @platform win32,linux - */ - setMenuBarVisibility(visible: boolean): void; - /** - * Sets whether the window can be manually minimized by user. On Linux does - * nothing. - * - * @platform darwin,win32 - */ - setMinimizable(minimizable: boolean): void; - /** - * Sets the minimum size of window to `width` and `height`. - */ - setMinimumSize(width: number, height: number): void; - /** - * Sets whether the window can be moved by user. On Linux does nothing. - * - * @platform darwin,win32 - */ - setMovable(movable: boolean): void; - /** - * Sets the opacity of the window. On Linux, does nothing. Out of bound number - * values are clamped to the [0, 1] range. - * - * @platform win32,darwin - */ - setOpacity(opacity: number): void; - /** - * Sets a 16 x 16 pixel overlay onto the current taskbar icon, usually used to - * convey some sort of application status or to passively notify the user. - * - * @platform win32 - */ - setOverlayIcon(overlay: (NativeImage) | (null), description: string): void; - /** - * Sets `parent` as current window's parent window, passing `null` will turn - * current window into a top-level window. - */ - setParentWindow(parent: (BrowserWindow) | (null)): void; - /** - * Moves window to `x` and `y`. - */ - setPosition(x: number, y: number, animate?: boolean): void; - /** - * Sets progress value in progress bar. Valid range is [0, 1.0]. - * - * Remove progress bar when progress < 0; Change to indeterminate mode when - * progress > 1. - * - * On Linux platform, only supports Unity desktop environment, you need to specify - * the `*.desktop` file name to `desktopName` field in `package.json`. By default, - * it will assume `{app.name}.desktop`. - * - * On Windows, a mode can be passed. Accepted values are `none`, `normal`, - * `indeterminate`, `error`, and `paused`. If you call `setProgressBar` without a - * mode set (but with a value within the valid range), `normal` will be assumed. - */ - setProgressBar(progress: number, options?: ProgressBarOptions): void; - /** - * Sets the pathname of the file the window represents, and the icon of the file - * will show in window's title bar. - * - * @platform darwin - */ - setRepresentedFilename(filename: string): void; - /** - * Sets whether the window can be manually resized by the user. - */ - setResizable(resizable: boolean): void; - /** - * Setting a window shape determines the area within the window where the system - * permits drawing and user interaction. Outside of the given region, no pixels - * will be drawn and no mouse events will be registered. Mouse events outside of - * the region will not be received by that window, but will fall through to - * whatever is behind the window. - * - * @experimental - * @platform win32,linux - */ - setShape(rects: Rectangle[]): void; - /** - * Changes the attachment point for sheets on macOS. By default, sheets are - * attached just below the window frame, but you may want to display them beneath a - * HTML-rendered toolbar. For example: - * - * @platform darwin - */ - setSheetOffset(offsetY: number, offsetX?: number): void; - /** - * Enters or leaves simple fullscreen mode. - * - * Simple fullscreen mode emulates the native fullscreen behavior found in versions - * of macOS prior to Lion (10.7). - * - * @platform darwin - */ - setSimpleFullScreen(flag: boolean): void; - /** - * Resizes the window to `width` and `height`. If `width` or `height` are below any - * set minimum size constraints the window will snap to its minimum size. - */ - setSize(width: number, height: number, animate?: boolean): void; - /** - * Makes the window not show in the taskbar. - */ - setSkipTaskbar(skip: boolean): void; - /** - * Whether the buttons were added successfully - * - * Add a thumbnail toolbar with a specified set of buttons to the thumbnail image - * of a window in a taskbar button layout. Returns a `Boolean` object indicates - * whether the thumbnail has been added successfully. - * - * The number of buttons in thumbnail toolbar should be no greater than 7 due to - * the limited room. Once you setup the thumbnail toolbar, the toolbar cannot be - * removed due to the platform's limitation. But you can call the API with an empty - * array to clean the buttons. - * - * The `buttons` is an array of `Button` objects: - * - * * `Button` Object - * * `icon` NativeImage - The icon showing in thumbnail toolbar. - * * `click` Function - * * `tooltip` String (optional) - The text of the button's tooltip. - * * `flags` String[] (optional) - Control specific states and behaviors of the - * button. By default, it is `['enabled']`. - * - * The `flags` is an array that can include following `String`s: - * - * * `enabled` - The button is active and available to the user. - * * `disabled` - The button is disabled. It is present, but has a visual state - * indicating it will not respond to user action. - * * `dismissonclick` - When the button is clicked, the thumbnail window closes - * immediately. - * * `nobackground` - Do not draw a button border, use only the image. - * * `hidden` - The button is not shown to the user. - * * `noninteractive` - The button is enabled but not interactive; no pressed - * button state is drawn. This value is intended for instances where the button is - * used in a notification. - * - * @platform win32 - */ - setThumbarButtons(buttons: ThumbarButton[]): boolean; - /** - * Sets the region of the window to show as the thumbnail image displayed when - * hovering over the window in the taskbar. You can reset the thumbnail to be the - * entire window by specifying an empty region: `{ x: 0, y: 0, width: 0, height: 0 - * }`. - * - * @platform win32 - */ - setThumbnailClip(region: Rectangle): void; - /** - * Sets the toolTip that is displayed when hovering over the window thumbnail in - * the taskbar. - * - * @platform win32 - */ - setThumbnailToolTip(toolTip: string): void; - /** - * Changes the title of native window to `title`. - */ - setTitle(title: string): void; - /** - * Raises `browserView` above other `BrowserView`s attached to `win`. Throws an - * error if `browserView` is not attached to `win`. - * - * @experimental - */ - setTopBrowserView(browserView: BrowserView): void; - /** - * Sets the touchBar layout for the current window. Specifying `null` or - * `undefined` clears the touch bar. This method only has an effect if the machine - * has a touch bar and is running on macOS 10.12.1+. - * - * **Note:** The TouchBar API is currently experimental and may change or be - * removed in future Electron releases. - * - * @platform darwin - */ - setTouchBar(touchBar: (TouchBar) | (null)): void; - /** - * Set a custom position for the traffic light buttons. Can only be used with - * `titleBarStyle` set to `hidden`. - * - * @platform darwin - */ - setTrafficLightPosition(position: Point): void; - /** - * Adds a vibrancy effect to the browser window. Passing `null` or an empty string - * will remove the vibrancy effect on the window. - * - * Note that `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` - * have been deprecated and will be removed in an upcoming version of macOS. - * - * @platform darwin - */ - setVibrancy(type: (('appearance-based' | 'light' | 'dark' | 'titlebar' | 'selection' | 'menu' | 'popover' | 'sidebar' | 'medium-light' | 'ultra-dark' | 'header' | 'sheet' | 'window' | 'hud' | 'fullscreen-ui' | 'tooltip' | 'content' | 'under-window' | 'under-page')) | (null)): void; - /** - * Sets whether the window should be visible on all workspaces. - * -**Note:** This API does nothing on Windows. - */ - setVisibleOnAllWorkspaces(visible: boolean, options?: VisibleOnAllWorkspacesOptions): void; - /** - * Sets whether the window traffic light buttons should be visible. - * -This cannot be called when `titleBarStyle` is set to `customButtonsOnHover`. - * - * @platform darwin - */ - setWindowButtonVisibility(visible: boolean): void; - /** - * Shows and gives focus to the window. - */ - show(): void; - /** - * Same as `webContents.showDefinitionForSelection()`. - * - * @platform darwin - */ - showDefinitionForSelection(): void; - /** - * Shows the window but doesn't focus on it. - */ - showInactive(): void; - /** - * Toggles the visibility of the tab bar if native tabs are enabled and there is - * only one tab in the current window. - * - * @platform darwin - */ - toggleTabBar(): void; - /** - * Unhooks all of the window messages. - * - * @platform win32 - */ - unhookAllWindowMessages(): void; - /** - * Unhook the window message. - * - * @platform win32 - */ - unhookWindowMessage(message: number): void; - /** - * Unmaximizes the window. - */ - unmaximize(): void; - accessibleTitle: string; - autoHideMenuBar: boolean; - closable: boolean; - documentEdited: boolean; - excludedFromShownWindowsMenu: boolean; - fullScreen: boolean; - fullScreenable: boolean; - readonly id: number; - kiosk: boolean; - maximizable: boolean; - menuBarVisible: boolean; - minimizable: boolean; - movable: boolean; - representedFilename: string; - resizable: boolean; - shadow: boolean; - simpleFullScreen: boolean; - title: string; - visibleOnAllWorkspaces: boolean; - readonly webContents: WebContents; - } - - class BrowserWindowProxy { - - // Docs: https://electronjs.org/docs/api/browser-window-proxy - - /** - * Removes focus from the child window. - */ - blur(): void; - /** - * Forcefully closes the child window without calling its unload event. - */ - close(): void; - /** - * Evaluates the code in the child window. - */ - eval(code: string): void; - /** - * Focuses the child window (brings the window to front). - */ - focus(): void; - /** - * Sends a message to the child window with the specified origin or `*` for no - * origin preference. - * - * In addition to these methods, the child window implements `window.opener` object - * with no properties and a single method. - */ - postMessage(message: any, targetOrigin: string): void; - /** - * Invokes the print dialog on the child window. - */ - print(): void; - closed: boolean; - } - - interface Certificate { - - // Docs: https://electronjs.org/docs/api/structures/certificate - - /** - * PEM encoded data - */ - data: string; - /** - * Fingerprint of the certificate - */ - fingerprint: string; - /** - * Issuer principal - */ - issuer: CertificatePrincipal; - /** - * Issuer certificate (if not self-signed) - */ - issuerCert: Certificate; - /** - * Issuer's Common Name - */ - issuerName: string; - /** - * Hex value represented string - */ - serialNumber: string; - /** - * Subject principal - */ - subject: CertificatePrincipal; - /** - * Subject's Common Name - */ - subjectName: string; - /** - * End date of the certificate being valid in seconds - */ - validExpiry: number; - /** - * Start date of the certificate being valid in seconds - */ - validStart: number; - } - - interface CertificatePrincipal { - - // Docs: https://electronjs.org/docs/api/structures/certificate-principal - - /** - * Common Name. - */ - commonName: string; - /** - * Country or region. - */ - country: string; - /** - * Locality. - */ - locality: string; - /** - * Organization names. - */ - organizations: string[]; - /** - * Organization Unit names. - */ - organizationUnits: string[]; - /** - * State or province. - */ - state: string; - } - - class ClientRequest extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/client-request - - /** - * Emitted when the `request` is aborted. The `abort` event will not be fired if - * the `request` is already closed. - */ - on(event: 'abort', listener: Function): this; - once(event: 'abort', listener: Function): this; - addListener(event: 'abort', listener: Function): this; - removeListener(event: 'abort', listener: Function): this; - /** - * Emitted as the last event in the HTTP request-response transaction. The `close` - * event indicates that no more events will be emitted on either the `request` or - * `response` objects. - */ - on(event: 'close', listener: Function): this; - once(event: 'close', listener: Function): this; - addListener(event: 'close', listener: Function): this; - removeListener(event: 'close', listener: Function): this; - /** - * Emitted when the `net` module fails to issue a network request. Typically when - * the `request` object emits an `error` event, a `close` event will subsequently - * follow and no response object will be provided. - */ - on(event: 'error', listener: ( - /** - * an error object providing some information about the failure. - */ - error: Error) => void): this; - once(event: 'error', listener: ( - /** - * an error object providing some information about the failure. - */ - error: Error) => void): this; - addListener(event: 'error', listener: ( - /** - * an error object providing some information about the failure. - */ - error: Error) => void): this; - removeListener(event: 'error', listener: ( - /** - * an error object providing some information about the failure. - */ - error: Error) => void): this; - /** - * Emitted just after the last chunk of the `request`'s data has been written into - * the `request` object. - */ - on(event: 'finish', listener: Function): this; - once(event: 'finish', listener: Function): this; - addListener(event: 'finish', listener: Function): this; - removeListener(event: 'finish', listener: Function): this; - /** - * Emitted when an authenticating proxy is asking for user credentials. - * - * The `callback` function is expected to be called back with user credentials: - * - * * `username` String - * * `password` String - * - * Providing empty credentials will cancel the request and report an authentication - * error on the response object: - */ - on(event: 'login', listener: (authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - once(event: 'login', listener: (authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - addListener(event: 'login', listener: (authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - removeListener(event: 'login', listener: (authInfo: AuthInfo, - callback: (username?: string, password?: string) => void) => void): this; - /** - * Emitted when the server returns a redirect response (e.g. 301 Moved - * Permanently). Calling `request.followRedirect` will continue with the - * redirection. If this event is handled, `request.followRedirect` must be called - * **synchronously**, otherwise the request will be cancelled. - */ - on(event: 'redirect', listener: (statusCode: number, - method: string, - redirectUrl: string, - responseHeaders: Record) => void): this; - once(event: 'redirect', listener: (statusCode: number, - method: string, - redirectUrl: string, - responseHeaders: Record) => void): this; - addListener(event: 'redirect', listener: (statusCode: number, - method: string, - redirectUrl: string, - responseHeaders: Record) => void): this; - removeListener(event: 'redirect', listener: (statusCode: number, - method: string, - redirectUrl: string, - responseHeaders: Record) => void): this; - on(event: 'response', listener: ( - /** - * An object representing the HTTP response message. - */ - response: IncomingMessage) => void): this; - once(event: 'response', listener: ( - /** - * An object representing the HTTP response message. - */ - response: IncomingMessage) => void): this; - addListener(event: 'response', listener: ( - /** - * An object representing the HTTP response message. - */ - response: IncomingMessage) => void): this; - removeListener(event: 'response', listener: ( - /** - * An object representing the HTTP response message. - */ - response: IncomingMessage) => void): this; - /** - * ClientRequest - */ - constructor(options: (ClientRequestConstructorOptions) | (string)); - /** - * Cancels an ongoing HTTP transaction. If the request has already emitted the - * `close` event, the abort operation will have no effect. Otherwise an ongoing - * event will emit `abort` and `close` events. Additionally, if there is an ongoing - * response object,it will emit the `aborted` event. - */ - abort(): void; - /** - * Sends the last chunk of the request data. Subsequent write or end operations - * will not be allowed. The `finish` event is emitted just after the end operation. - */ - end(chunk?: (string) | (Buffer), encoding?: string, callback?: () => void): void; - /** - * Continues any pending redirection. Can only be called during a `'redirect'` - * event. - */ - followRedirect(): void; - /** - * The value of a previously set extra header name. - */ - getHeader(name: string): string; - /** - * * `active` Boolean - Whether the request is currently active. If this is false - * no other properties will be set - * * `started` Boolean - Whether the upload has started. If this is false both - * `current` and `total` will be set to 0. - * * `current` Integer - The number of bytes that have been uploaded so far - * * `total` Integer - The number of bytes that will be uploaded this request - * - * You can use this method in conjunction with `POST` requests to get the progress - * of a file upload or other data transfer. - */ - getUploadProgress(): UploadProgress; - /** - * Removes a previously set extra header name. This method can be called only - * before first write. Trying to call it after the first write will throw an error. - */ - removeHeader(name: string): void; - /** - * Adds an extra HTTP header. The header name will be issued as-is without - * lowercasing. It can be called only before first write. Calling this method after - * the first write will throw an error. If the passed value is not a `String`, its - * `toString()` method will be called to obtain the final value. - * - * Certain headers are restricted from being set by apps. These headers are listed - * below. More information on restricted headers can be found in Chromium's header - * utils. - * - * * `Content-Length` - * * `Host` - * * `Trailer` or `Te` - * * `Upgrade` - * * `Cookie2` - * * `Keep-Alive` - * * `Transfer-Encoding` - * - * Additionally, setting the `Connection` header to the value `upgrade` is also - * disallowed. - */ - setHeader(name: string, value: string): void; - /** - * `callback` is essentially a dummy function introduced in the purpose of keeping - * similarity with the Node.js API. It is called asynchronously in the next tick - * after `chunk` content have been delivered to the Chromium networking layer. - * Contrary to the Node.js implementation, it is not guaranteed that `chunk` - * content have been flushed on the wire before `callback` is called. - * - * Adds a chunk of data to the request body. The first write operation may cause - * the request headers to be issued on the wire. After the first write operation, - * it is not allowed to add or remove a custom header. - */ - write(chunk: (string) | (Buffer), encoding?: string, callback?: () => void): void; - chunkedEncoding: boolean; - } - - interface Clipboard { - - // Docs: https://electronjs.org/docs/api/clipboard - - /** - * An array of supported formats for the clipboard `type`. - */ - availableFormats(type?: 'selection' | 'clipboard'): string[]; - /** - * Clears the clipboard content. - */ - clear(type?: 'selection' | 'clipboard'): void; - /** - * Whether the clipboard supports the specified `format`. - * - * @experimental - */ - has(format: string, type?: 'selection' | 'clipboard'): boolean; - /** - * Reads `format` type from the clipboard. - * - * @experimental - */ - read(format: string): string; - /** - * * `title` String - * * `url` String - * - * Returns an Object containing `title` and `url` keys representing the bookmark in - * the clipboard. The `title` and `url` values will be empty strings when the - * bookmark is unavailable. - * - * @platform darwin,win32 - */ - readBookmark(): ReadBookmark; - /** - * Reads `format` type from the clipboard. - * - * @experimental - */ - readBuffer(format: string): Buffer; - /** - * The text on the find pasteboard, which is the pasteboard that holds information - * about the current state of the active application’s find panel. - * - * This method uses synchronous IPC when called from the renderer process. The - * cached value is reread from the find pasteboard whenever the application is - * activated. - * - * @platform darwin - */ - readFindText(): string; - /** - * The content in the clipboard as markup. - */ - readHTML(type?: 'selection' | 'clipboard'): string; - /** - * The image content in the clipboard. - */ - readImage(type?: 'selection' | 'clipboard'): NativeImage; - /** - * The content in the clipboard as RTF. - */ - readRTF(type?: 'selection' | 'clipboard'): string; - /** - * The content in the clipboard as plain text. - */ - readText(type?: 'selection' | 'clipboard'): string; - /** - * Writes `data` to the clipboard. - */ - write(data: Data, type?: 'selection' | 'clipboard'): void; - /** - * Writes the `title` and `url` into the clipboard as a bookmark. - * - * **Note:** Most apps on Windows don't support pasting bookmarks into them so you - * can use `clipboard.write` to write both a bookmark and fallback text to the - * clipboard. - * - * @platform darwin,win32 - */ - writeBookmark(title: string, url: string, type?: 'selection' | 'clipboard'): void; - /** - * Writes the `buffer` into the clipboard as `format`. - * - * @experimental - */ - writeBuffer(format: string, buffer: Buffer, type?: 'selection' | 'clipboard'): void; - /** - * Writes the `text` into the find pasteboard (the pasteboard that holds - * information about the current state of the active application’s find panel) as - * plain text. This method uses synchronous IPC when called from the renderer - * process. - * - * @platform darwin - */ - writeFindText(text: string): void; - /** - * Writes `markup` to the clipboard. - */ - writeHTML(markup: string, type?: 'selection' | 'clipboard'): void; - /** - * Writes `image` to the clipboard. - */ - writeImage(image: NativeImage, type?: 'selection' | 'clipboard'): void; - /** - * Writes the `text` into the clipboard in RTF. - */ - writeRTF(text: string, type?: 'selection' | 'clipboard'): void; - /** - * Writes the `text` into the clipboard as plain text. - */ - writeText(text: string, type?: 'selection' | 'clipboard'): void; - } - - class CommandLine { - - // Docs: https://electronjs.org/docs/api/command-line - - /** - * Append an argument to Chromium's command line. The argument will be quoted - * correctly. Switches will precede arguments regardless of appending order. - * - * If you're appending an argument like `--switch=value`, consider using - * `appendSwitch('switch', 'value')` instead. - * - * **Note:** This will not affect `process.argv`. The intended usage of this - * function is to control Chromium's behavior. - */ - appendArgument(value: string): void; - /** - * Append a switch (with optional `value`) to Chromium's command line. - * - * **Note:** This will not affect `process.argv`. The intended usage of this - * function is to control Chromium's behavior. - */ - appendSwitch(the_switch: string, value?: string): void; - /** - * The command-line switch value. - * - * **Note:** When the switch is not present or has no value, it returns empty - * string. - */ - getSwitchValue(the_switch: string): string; - /** - * Whether the command-line switch is present. - */ - hasSwitch(the_switch: string): boolean; - } - - interface ContentTracing { - - // Docs: https://electronjs.org/docs/api/content-tracing - - /** - * resolves with an array of category groups once all child processes have - * acknowledged the `getCategories` request - * - * Get a set of category groups. The category groups can change as new code paths - * are reached. See also the list of built-in tracing categories. - * - * > **NOTE:** Electron adds a non-default tracing category called `"electron"`. - * This category can be used to capture Electron-specific tracing events. - */ - getCategories(): Promise; - /** - * Resolves with an object containing the `value` and `percentage` of trace buffer - * maximum usage - * - * * `value` Number - * * `percentage` Number - * - * Get the maximum usage across processes of trace buffer as a percentage of the - * full state. - */ - getTraceBufferUsage(): Promise; - /** - * resolved once all child processes have acknowledged the `startRecording` - * request. - * - * Start recording on all processes. - * - * Recording begins immediately locally and asynchronously on child processes as - * soon as they receive the EnableRecording request. - * - * If a recording is already running, the promise will be immediately resolved, as - * only one trace operation can be in progress at a time. - */ - startRecording(options: (TraceConfig) | (TraceCategoriesAndOptions)): Promise; - /** - * resolves with a path to a file that contains the traced data once all child - * processes have acknowledged the `stopRecording` request - * - * Stop recording on all processes. - * - * Child processes typically cache trace data and only rarely flush and send trace - * data back to the main process. This helps to minimize the runtime overhead of - * tracing since sending trace data over IPC can be an expensive operation. So, to - * end tracing, Chromium asynchronously asks all child processes to flush any - * pending trace data. - * - * Trace data will be written into `resultFilePath`. If `resultFilePath` is empty - * or not provided, trace data will be written to a temporary file, and the path - * will be returned in the promise. - */ - stopRecording(resultFilePath?: string): Promise; - } - - interface ContextBridge { - - // Docs: https://electronjs.org/docs/api/context-bridge - - exposeInMainWorld(apiKey: string, api: any): void; - } - - interface Cookie { - - // Docs: https://electronjs.org/docs/api/structures/cookie - - /** - * The domain of the cookie; this will be normalized with a preceding dot so that - * it's also valid for subdomains. - */ - domain?: string; - /** - * The expiration date of the cookie as the number of seconds since the UNIX epoch. - * Not provided for session cookies. - */ - expirationDate?: number; - /** - * Whether the cookie is a host-only cookie; this will only be `true` if no domain - * was passed. - */ - hostOnly?: boolean; - /** - * Whether the cookie is marked as HTTP only. - */ - httpOnly?: boolean; - /** - * The name of the cookie. - */ - name: string; - /** - * The path of the cookie. - */ - path?: string; - /** - * The Same Site policy applied to this cookie. Can be `unspecified`, - * `no_restriction`, `lax` or `strict`. - */ - sameSite: ('unspecified' | 'no_restriction' | 'lax' | 'strict'); - /** - * Whether the cookie is marked as secure. - */ - secure?: boolean; - /** - * Whether the cookie is a session cookie or a persistent cookie with an expiration - * date. - */ - session?: boolean; - /** - * The value of the cookie. - */ - value: string; - } - - class Cookies extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/cookies - - /** - * Emitted when a cookie is changed because it was added, edited, removed, or - * expired. - */ - on(event: 'changed', listener: (event: Event, - /** - * The cookie that was changed. - */ - cookie: Cookie, - /** - * The cause of the change with one of the following values: - */ - cause: ('explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'), - /** - * `true` if the cookie was removed, `false` otherwise. - */ - removed: boolean) => void): this; - once(event: 'changed', listener: (event: Event, - /** - * The cookie that was changed. - */ - cookie: Cookie, - /** - * The cause of the change with one of the following values: - */ - cause: ('explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'), - /** - * `true` if the cookie was removed, `false` otherwise. - */ - removed: boolean) => void): this; - addListener(event: 'changed', listener: (event: Event, - /** - * The cookie that was changed. - */ - cookie: Cookie, - /** - * The cause of the change with one of the following values: - */ - cause: ('explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'), - /** - * `true` if the cookie was removed, `false` otherwise. - */ - removed: boolean) => void): this; - removeListener(event: 'changed', listener: (event: Event, - /** - * The cookie that was changed. - */ - cookie: Cookie, - /** - * The cause of the change with one of the following values: - */ - cause: ('explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'), - /** - * `true` if the cookie was removed, `false` otherwise. - */ - removed: boolean) => void): this; - /** - * A promise which resolves when the cookie store has been flushed - * -Writes any unwritten cookies data to disk. - */ - flushStore(): Promise; - /** - * A promise which resolves an array of cookie objects. - * - * Sends a request to get all cookies matching `filter`, and resolves a promise - * with the response. - */ - get(filter: CookiesGetFilter): Promise; - /** - * A promise which resolves when the cookie has been removed - * -Removes the cookies matching `url` and `name` - */ - remove(url: string, name: string): Promise; - /** - * A promise which resolves when the cookie has been set - * -Sets a cookie with `details`. - */ - set(details: CookiesSetDetails): Promise; - } - - interface CPUUsage { - - // Docs: https://electronjs.org/docs/api/structures/cpu-usage - - /** - * The number of average idle CPU wakeups per second since the last call to - * getCPUUsage. First call returns 0. Will always return 0 on Windows. - */ - idleWakeupsPerSecond: number; - /** - * Percentage of CPU used since the last call to getCPUUsage. First call returns 0. - */ - percentCPUUsage: number; - } - - interface CrashReport { - - // Docs: https://electronjs.org/docs/api/structures/crash-report - - date: Date; - id: string; - } - - interface CrashReporter { - - // Docs: https://electronjs.org/docs/api/crash-reporter - - /** - * Set an extra parameter to be sent with the crash report. The values specified - * here will be sent in addition to any values set via the `extra` option when - * `start` was called. - * - * Parameters added in this fashion (or via the `extra` parameter to - * `crashReporter.start`) are specific to the calling process. Adding extra - * parameters in the main process will not cause those parameters to be sent along - * with crashes from renderer or other child processes. Similarly, adding extra - * parameters in a renderer process will not result in those parameters being sent - * with crashes that occur in other renderer processes or in the main process. - * - * **Note:** Parameters have limits on the length of the keys and values. Key names - * must be no longer than 39 bytes, and values must be no longer than 20320 bytes. - * Keys with names longer than the maximum will be silently ignored. Key values - * longer than the maximum length will be truncated. - * - * **Note:** On linux values that are longer than 127 bytes will be chunked into - * multiple keys, each 127 bytes in length. E.g. `addExtraParameter('foo', - * 'a'.repeat(130))` will result in two chunked keys `foo__1` and `foo__2`, the - * first will contain the first 127 bytes and the second will contain the remaining - * 3 bytes. On your crash reporting backend you should stitch together keys in - * this format. - */ - addExtraParameter(key: string, value: string): void; - /** - * The date and ID of the last crash report. Only crash reports that have been - * uploaded will be returned; even if a crash report is present on disk it will not - * be returned until it is uploaded. In the case that there are no uploaded - * reports, `null` is returned. - * -**Note:** This method is only available in the main process. - */ - getLastCrashReport(): CrashReport; - /** - * The current 'extra' parameters of the crash reporter. - */ - getParameters(): Record; - /** - * Returns all uploaded crash reports. Each report contains the date and uploaded - * ID. - -**Note:** This method is only available in the main process. - */ - getUploadedReports(): CrashReport[]; - /** - * Whether reports should be submitted to the server. Set through the `start` - * method or `setUploadToServer`. - * -**Note:** This method is only available in the main process. - */ - getUploadToServer(): boolean; - /** - * Remove an extra parameter from the current set of parameters. Future crashes - * will not include this parameter. - */ - removeExtraParameter(key: string): void; - /** - * This would normally be controlled by user preferences. This has no effect if - * called before `start` is called. - * -**Note:** This method is only available in the main process. - */ - setUploadToServer(uploadToServer: boolean): void; - /** - * This method must be called before using any other `crashReporter` APIs. Once - * initialized this way, the crashpad handler collects crashes from all - * subsequently created processes. The crash reporter cannot be disabled once - * started. - * - * This method should be called as early as possible in app startup, preferably - * before `app.on('ready')`. If the crash reporter is not initialized at the time a - * renderer process is created, then that renderer process will not be monitored by - * the crash reporter. - * - * **Note:** You can test out the crash reporter by generating a crash using - * `process.crash()`. - * - * **Note:** If you need to send additional/updated `extra` parameters after your - * first call `start` you can call `addExtraParameter`. - * - * **Note:** Parameters passed in `extra`, `globalExtra` or set with - * `addExtraParameter` have limits on the length of the keys and values. Key names - * must be at most 39 bytes long, and values must be no longer than 127 bytes. Keys - * with names longer than the maximum will be silently ignored. Key values longer - * than the maximum length will be truncated. - * -**Note:** This method is only available in the main process. - */ - start(options: CrashReporterStartOptions): void; - } - - interface CustomScheme { - - // Docs: https://electronjs.org/docs/api/structures/custom-scheme - - privileges?: Privileges; - /** - * Custom schemes to be registered with options. - */ - scheme: string; - } - - class Debugger extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/debugger - - /** - * Emitted when the debugging session is terminated. This happens either when - * `webContents` is closed or devtools is invoked for the attached `webContents`. - */ - on(event: 'detach', listener: (event: Event, - /** - * Reason for detaching debugger. - */ - reason: string) => void): this; - once(event: 'detach', listener: (event: Event, - /** - * Reason for detaching debugger. - */ - reason: string) => void): this; - addListener(event: 'detach', listener: (event: Event, - /** - * Reason for detaching debugger. - */ - reason: string) => void): this; - removeListener(event: 'detach', listener: (event: Event, - /** - * Reason for detaching debugger. - */ - reason: string) => void): this; - /** - * Emitted whenever the debugging target issues an instrumentation event. - */ - on(event: 'message', listener: (event: Event, - /** - * Method name. - */ - method: string, - /** - * Event parameters defined by the 'parameters' attribute in the remote debugging - * protocol. - */ - params: any, - /** - * Unique identifier of attached debugging session, will match the value sent from - * `debugger.sendCommand`. - */ - sessionId: string) => void): this; - once(event: 'message', listener: (event: Event, - /** - * Method name. - */ - method: string, - /** - * Event parameters defined by the 'parameters' attribute in the remote debugging - * protocol. - */ - params: any, - /** - * Unique identifier of attached debugging session, will match the value sent from - * `debugger.sendCommand`. - */ - sessionId: string) => void): this; - addListener(event: 'message', listener: (event: Event, - /** - * Method name. - */ - method: string, - /** - * Event parameters defined by the 'parameters' attribute in the remote debugging - * protocol. - */ - params: any, - /** - * Unique identifier of attached debugging session, will match the value sent from - * `debugger.sendCommand`. - */ - sessionId: string) => void): this; - removeListener(event: 'message', listener: (event: Event, - /** - * Method name. - */ - method: string, - /** - * Event parameters defined by the 'parameters' attribute in the remote debugging - * protocol. - */ - params: any, - /** - * Unique identifier of attached debugging session, will match the value sent from - * `debugger.sendCommand`. - */ - sessionId: string) => void): this; - /** - * Attaches the debugger to the `webContents`. - */ - attach(protocolVersion?: string): void; - /** - * Detaches the debugger from the `webContents`. - */ - detach(): void; - /** - * Whether a debugger is attached to the `webContents`. - */ - isAttached(): boolean; - /** - * A promise that resolves with the response defined by the 'returns' attribute of - * the command description in the remote debugging protocol or is rejected - * indicating the failure of the command. - * -Send given command to the debugging target. - */ - sendCommand(method: string, commandParams?: any, sessionId?: string): Promise; - } - - interface DesktopCapturer { - - // Docs: https://electronjs.org/docs/api/desktop-capturer - - /** - * Resolves with an array of `DesktopCapturerSource` objects, each - * `DesktopCapturerSource` represents a screen or an individual window that can be - * captured. - * - * **Note** Capturing the screen contents requires user consent on macOS 10.15 - * Catalina or higher, which can detected by - * `systemPreferences.getMediaAccessStatus`. - */ - getSources(options: SourcesOptions): Promise; - } - - interface DesktopCapturerSource { - - // Docs: https://electronjs.org/docs/api/structures/desktop-capturer-source - - /** - * An icon image of the application that owns the window or null if the source has - * a type screen. The size of the icon is not known in advance and depends on what - * the application provides. - */ - appIcon: NativeImage; - /** - * A unique identifier that will correspond to the `id` of the matching Display - * returned by the Screen API. On some platforms, this is equivalent to the `XX` - * portion of the `id` field above and on others it will differ. It will be an - * empty string if not available. - */ - display_id: string; - /** - * The identifier of a window or screen that can be used as a `chromeMediaSourceId` - * constraint when calling [`navigator.webkitGetUserMedia`]. The format of the - * identifier will be `window:XX` or `screen:XX`, where `XX` is a random generated - * number. - */ - id: string; - /** - * A screen source will be named either `Entire Screen` or `Screen `, while - * the name of a window source will match the window title. - */ - name: string; - /** - * A thumbnail image. **Note:** There is no guarantee that the size of the - * thumbnail is the same as the `thumbnailSize` specified in the `options` passed - * to `desktopCapturer.getSources`. The actual size depends on the scale of the - * screen or window. - */ - thumbnail: NativeImage; - } - - interface Dialog { - - // Docs: https://electronjs.org/docs/api/dialog - - /** - * resolves when the certificate trust dialog is shown. - * - * On macOS, this displays a modal dialog that shows a message and certificate - * information, and gives the user the option of trusting/importing the - * certificate. If you provide a `browserWindow` argument the dialog will be - * attached to the parent window, making it modal. - * - * On Windows the options are more limited, due to the Win32 APIs used: - * - * * The `message` argument is not used, as the OS provides its own confirmation - * dialog. - * * The `browserWindow` argument is ignored since it is not possible to make this - * confirmation dialog modal. - * - * @platform darwin,win32 - */ - showCertificateTrustDialog(browserWindow: BrowserWindow, options: CertificateTrustDialogOptions): Promise; - /** - * resolves when the certificate trust dialog is shown. - * - * On macOS, this displays a modal dialog that shows a message and certificate - * information, and gives the user the option of trusting/importing the - * certificate. If you provide a `browserWindow` argument the dialog will be - * attached to the parent window, making it modal. - * - * On Windows the options are more limited, due to the Win32 APIs used: - * - * * The `message` argument is not used, as the OS provides its own confirmation - * dialog. - * * The `browserWindow` argument is ignored since it is not possible to make this - * confirmation dialog modal. - * - * @platform darwin,win32 - */ - showCertificateTrustDialog(options: CertificateTrustDialogOptions): Promise; - /** - * Displays a modal dialog that shows an error message. - * - * This API can be called safely before the `ready` event the `app` module emits, - * it is usually used to report errors in early stage of startup. If called before - * the app `ready`event on Linux, the message will be emitted to stderr, and no GUI - * dialog will appear. - */ - showErrorBox(title: string, content: string): void; - /** - * resolves with a promise containing the following properties: - * - * * `response` Number - The index of the clicked button. - * * `checkboxChecked` Boolean - The checked state of the checkbox if - * `checkboxLabel` was set. Otherwise `false`. - * - * Shows a message box. - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - */ - showMessageBox(browserWindow: BrowserWindow, options: MessageBoxOptions): Promise; - /** - * resolves with a promise containing the following properties: - * - * * `response` Number - The index of the clicked button. - * * `checkboxChecked` Boolean - The checked state of the checkbox if - * `checkboxLabel` was set. Otherwise `false`. - * - * Shows a message box. - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - */ - showMessageBox(options: MessageBoxOptions): Promise; - /** - * the index of the clicked button. - * - * Shows a message box, it will block the process until the message box is closed. - * It returns the index of the clicked button. - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. If `browserWindow` is not shown dialog will not be - * attached to it. In such case it will be displayed as an independent window. - */ - showMessageBoxSync(browserWindow: BrowserWindow, options: MessageBoxSyncOptions): number; - /** - * the index of the clicked button. - * - * Shows a message box, it will block the process until the message box is closed. - * It returns the index of the clicked button. - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. If `browserWindow` is not shown dialog will not be - * attached to it. In such case it will be displayed as an independent window. - */ - showMessageBoxSync(options: MessageBoxSyncOptions): number; - /** - * Resolve with an object containing the following: - * - * * `canceled` Boolean - whether or not the dialog was canceled. - * * `filePaths` String[] - An array of file paths chosen by the user. If the - * dialog is cancelled this will be an empty array. - * * `bookmarks` String[] (optional) _macOS_ _mas_ - An array matching the - * `filePaths` array of base64 encoded strings which contains security scoped - * bookmark data. `securityScopedBookmarks` must be enabled for this to be - * populated. (For return values, see table here.) - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - * - * The `filters` specifies an array of file types that can be displayed or selected - * when you want to limit the user to a specific type. For example: - * - * The `extensions` array should contain extensions without wildcards or dots (e.g. - * `'png'` is good but `'.png'` and `'*.png'` are bad). To show all files, use the - * `'*'` wildcard (no other wildcard is supported). - * - * **Note:** On Windows and Linux an open dialog can not be both a file selector - * and a directory selector, so if you set `properties` to `['openFile', - * 'openDirectory']` on these platforms, a directory selector will be shown. - */ - showOpenDialog(browserWindow: BrowserWindow, options: OpenDialogOptions): Promise; - /** - * Resolve with an object containing the following: - * - * * `canceled` Boolean - whether or not the dialog was canceled. - * * `filePaths` String[] - An array of file paths chosen by the user. If the - * dialog is cancelled this will be an empty array. - * * `bookmarks` String[] (optional) _macOS_ _mas_ - An array matching the - * `filePaths` array of base64 encoded strings which contains security scoped - * bookmark data. `securityScopedBookmarks` must be enabled for this to be - * populated. (For return values, see table here.) - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - * - * The `filters` specifies an array of file types that can be displayed or selected - * when you want to limit the user to a specific type. For example: - * - * The `extensions` array should contain extensions without wildcards or dots (e.g. - * `'png'` is good but `'.png'` and `'*.png'` are bad). To show all files, use the - * `'*'` wildcard (no other wildcard is supported). - * - * **Note:** On Windows and Linux an open dialog can not be both a file selector - * and a directory selector, so if you set `properties` to `['openFile', - * 'openDirectory']` on these platforms, a directory selector will be shown. - */ - showOpenDialog(options: OpenDialogOptions): Promise; - /** - * the file paths chosen by the user; if the dialog is cancelled it returns - * `undefined`. - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - * - * The `filters` specifies an array of file types that can be displayed or selected - * when you want to limit the user to a specific type. For example: - * - * The `extensions` array should contain extensions without wildcards or dots (e.g. - * `'png'` is good but `'.png'` and `'*.png'` are bad). To show all files, use the - * `'*'` wildcard (no other wildcard is supported). - * - * **Note:** On Windows and Linux an open dialog can not be both a file selector - * and a directory selector, so if you set `properties` to `['openFile', - * 'openDirectory']` on these platforms, a directory selector will be shown. - */ - showOpenDialogSync(browserWindow: BrowserWindow, options: OpenDialogSyncOptions): (string[]) | (undefined); - /** - * the file paths chosen by the user; if the dialog is cancelled it returns - * `undefined`. - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - * - * The `filters` specifies an array of file types that can be displayed or selected - * when you want to limit the user to a specific type. For example: - * - * The `extensions` array should contain extensions without wildcards or dots (e.g. - * `'png'` is good but `'.png'` and `'*.png'` are bad). To show all files, use the - * `'*'` wildcard (no other wildcard is supported). - * - * **Note:** On Windows and Linux an open dialog can not be both a file selector - * and a directory selector, so if you set `properties` to `['openFile', - * 'openDirectory']` on these platforms, a directory selector will be shown. - */ - showOpenDialogSync(options: OpenDialogSyncOptions): (string[]) | (undefined); - /** - * Resolve with an object containing the following: - * - * * `canceled` Boolean - whether or not the dialog was canceled. - * * `filePath` String (optional) - If the dialog is canceled, this will be - * `undefined`. - * * `bookmark` String (optional) _macOS_ _mas_ - Base64 encoded string which - * contains the security scoped bookmark data for the saved file. - * `securityScopedBookmarks` must be enabled for this to be present. (For return - * values, see table here.) - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - * - * The `filters` specifies an array of file types that can be displayed, see - * `dialog.showOpenDialog` for an example. - * - * **Note:** On macOS, using the asynchronous version is recommended to avoid - * issues when expanding and collapsing the dialog. - */ - showSaveDialog(browserWindow: BrowserWindow, options: SaveDialogOptions): Promise; - /** - * Resolve with an object containing the following: - * - * * `canceled` Boolean - whether or not the dialog was canceled. - * * `filePath` String (optional) - If the dialog is canceled, this will be - * `undefined`. - * * `bookmark` String (optional) _macOS_ _mas_ - Base64 encoded string which - * contains the security scoped bookmark data for the saved file. - * `securityScopedBookmarks` must be enabled for this to be present. (For return - * values, see table here.) - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - * - * The `filters` specifies an array of file types that can be displayed, see - * `dialog.showOpenDialog` for an example. - * - * **Note:** On macOS, using the asynchronous version is recommended to avoid - * issues when expanding and collapsing the dialog. - */ - showSaveDialog(options: SaveDialogOptions): Promise; - /** - * the path of the file chosen by the user; if the dialog is cancelled it returns - * `undefined`. - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - * - * The `filters` specifies an array of file types that can be displayed, see - * `dialog.showOpenDialog` for an example. - */ - showSaveDialogSync(browserWindow: BrowserWindow, options: SaveDialogSyncOptions): (string) | (undefined); - /** - * the path of the file chosen by the user; if the dialog is cancelled it returns - * `undefined`. - * - * The `browserWindow` argument allows the dialog to attach itself to a parent - * window, making it modal. - * - * The `filters` specifies an array of file types that can be displayed, see - * `dialog.showOpenDialog` for an example. - */ - showSaveDialogSync(options: SaveDialogSyncOptions): (string) | (undefined); - } - - interface Display { - - // Docs: https://electronjs.org/docs/api/structures/display - - /** - * Can be `available`, `unavailable`, `unknown`. - */ - accelerometerSupport: ('available' | 'unavailable' | 'unknown'); - bounds: Rectangle; - /** - * The number of bits per pixel. - */ - colorDepth: number; - /** - * represent a color space (three-dimensional object which contains all realizable - * color combinations) for the purpose of color conversions - */ - colorSpace: string; - /** - * The number of bits per color component. - */ - depthPerComponent: number; - /** - * The display refresh rate. - */ - displayFrequency: number; - /** - * Unique identifier associated with the display. - */ - id: number; - /** - * `true` for an internal display and `false` for an external display - */ - internal: boolean; - /** - * Whether or not the display is a monochrome display. - */ - monochrome: boolean; - /** - * Can be 0, 90, 180, 270, represents screen rotation in clock-wise degrees. - */ - rotation: number; - /** - * Output device's pixel scale factor. - */ - scaleFactor: number; - size: Size; - /** - * Can be `available`, `unavailable`, `unknown`. - */ - touchSupport: ('available' | 'unavailable' | 'unknown'); - workArea: Rectangle; - workAreaSize: Size; - } - - class Dock { - - // Docs: https://electronjs.org/docs/api/dock - - /** - * an ID representing the request. - * - * When `critical` is passed, the dock icon will bounce until either the - * application becomes active or the request is canceled. - * - * When `informational` is passed, the dock icon will bounce for one second. - * However, the request remains active until either the application becomes active - * or the request is canceled. - * - * **Nota Bene:** This method can only be used while the app is not focused; when - * the app is focused it will return -1. - * - * @platform darwin - */ - bounce(type?: 'critical' | 'informational'): number; - /** - * Cancel the bounce of `id`. - * - * @platform darwin - */ - cancelBounce(id: number): void; - /** - * Bounces the Downloads stack if the filePath is inside the Downloads folder. - * - * @platform darwin - */ - downloadFinished(filePath: string): void; - /** - * The badge string of the dock. - * - * @platform darwin - */ - getBadge(): string; - /** - * The application's [dock menu][dock-menu]. - * - * @platform darwin - */ - getMenu(): (Menu) | (null); - /** - * Hides the dock icon. - * - * @platform darwin - */ - hide(): void; - /** - * Whether the dock icon is visible. - * - * @platform darwin - */ - isVisible(): boolean; - /** - * Sets the string to be displayed in the dock’s badging area. - * - * @platform darwin - */ - setBadge(text: string): void; - /** - * Sets the `image` associated with this dock icon. - * - * @platform darwin - */ - setIcon(image: (NativeImage) | (string)): void; - /** - * Sets the application's [dock menu][dock-menu]. - * - * @platform darwin - */ - setMenu(menu: Menu): void; - /** - * Resolves when the dock icon is shown. - * - * @platform darwin - */ - show(): Promise; - } - - class DownloadItem extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/download-item - - /** - * Emitted when the download is in a terminal state. This includes a completed - * download, a cancelled download (via `downloadItem.cancel()`), and interrupted - * download that can't be resumed. - * - * The `state` can be one of following: - * - * * `completed` - The download completed successfully. - * * `cancelled` - The download has been cancelled. - * * `interrupted` - The download has interrupted and can not resume. - */ - on(event: 'done', listener: (event: Event, - /** - * Can be `completed`, `cancelled` or `interrupted`. - */ - state: ('completed' | 'cancelled' | 'interrupted')) => void): this; - once(event: 'done', listener: (event: Event, - /** - * Can be `completed`, `cancelled` or `interrupted`. - */ - state: ('completed' | 'cancelled' | 'interrupted')) => void): this; - addListener(event: 'done', listener: (event: Event, - /** - * Can be `completed`, `cancelled` or `interrupted`. - */ - state: ('completed' | 'cancelled' | 'interrupted')) => void): this; - removeListener(event: 'done', listener: (event: Event, - /** - * Can be `completed`, `cancelled` or `interrupted`. - */ - state: ('completed' | 'cancelled' | 'interrupted')) => void): this; - /** - * Emitted when the download has been updated and is not done. - * - * The `state` can be one of following: - * - * * `progressing` - The download is in-progress. - * * `interrupted` - The download has interrupted and can be resumed. - */ - on(event: 'updated', listener: (event: Event, - /** - * Can be `progressing` or `interrupted`. - */ - state: ('progressing' | 'interrupted')) => void): this; - once(event: 'updated', listener: (event: Event, - /** - * Can be `progressing` or `interrupted`. - */ - state: ('progressing' | 'interrupted')) => void): this; - addListener(event: 'updated', listener: (event: Event, - /** - * Can be `progressing` or `interrupted`. - */ - state: ('progressing' | 'interrupted')) => void): this; - removeListener(event: 'updated', listener: (event: Event, - /** - * Can be `progressing` or `interrupted`. - */ - state: ('progressing' | 'interrupted')) => void): this; - /** - * Cancels the download operation. - */ - cancel(): void; - /** - * Whether the download can resume. - */ - canResume(): boolean; - /** - * The Content-Disposition field from the response header. - */ - getContentDisposition(): string; - /** - * ETag header value. - */ - getETag(): string; - /** - * The file name of the download item. - * - * **Note:** The file name is not always the same as the actual one saved in local - * disk. If user changes the file name in a prompted download saving dialog, the - * actual name of saved file will be different. - */ - getFilename(): string; - /** - * Last-Modified header value. - */ - getLastModifiedTime(): string; - /** - * The files mime type. - */ - getMimeType(): string; - /** - * The received bytes of the download item. - */ - getReceivedBytes(): number; - /** - * Returns the object previously set by - * `downloadItem.setSaveDialogOptions(options)`. - */ - getSaveDialogOptions(): SaveDialogOptions; - /** - * The save path of the download item. This will be either the path set via - * `downloadItem.setSavePath(path)` or the path selected from the shown save - * dialog. - */ - getSavePath(): string; - /** - * Number of seconds since the UNIX epoch when the download was started. - */ - getStartTime(): number; - /** - * The current state. Can be `progressing`, `completed`, `cancelled` or - * `interrupted`. - * - * **Note:** The following methods are useful specifically to resume a `cancelled` - * item when session is restarted. - */ - getState(): ('progressing' | 'completed' | 'cancelled' | 'interrupted'); - /** - * The total size in bytes of the download item. - * -If the size is unknown, it returns 0. - */ - getTotalBytes(): number; - /** - * The origin URL where the item is downloaded from. - */ - getURL(): string; - /** - * The complete URL chain of the item including any redirects. - */ - getURLChain(): string[]; - /** - * Whether the download has user gesture. - */ - hasUserGesture(): boolean; - /** - * Whether the download is paused. - */ - isPaused(): boolean; - /** - * Pauses the download. - */ - pause(): void; - /** - * Resumes the download that has been paused. - * - * **Note:** To enable resumable downloads the server you are downloading from must - * support range requests and provide both `Last-Modified` and `ETag` header - * values. Otherwise `resume()` will dismiss previously received bytes and restart - * the download from the beginning. - */ - resume(): void; - /** - * This API allows the user to set custom options for the save dialog that opens - * for the download item by default. The API is only available in session's - * `will-download` callback function. - */ - setSaveDialogOptions(options: SaveDialogOptions): void; - /** - * The API is only available in session's `will-download` callback function. If - * `path` doesn't exist, Electron will try to make the directory recursively. If - * user doesn't set the save path via the API, Electron will use the original - * routine to determine the save path; this usually prompts a save dialog. - */ - setSavePath(path: string): void; - savePath: string; - } - - interface Event extends GlobalEvent { - - // Docs: https://electronjs.org/docs/api/structures/event - - preventDefault: (() => void); - } - - interface Extension { - - // Docs: https://electronjs.org/docs/api/structures/extension - - id: string; - /** - * Copy of the extension's manifest data. - */ - manifest: any; - name: string; - /** - * The extension's file path. - */ - path: string; - /** - * The extension's `chrome-extension://` URL. - */ - url: string; - version: string; - } - - interface ExtensionInfo { - - // Docs: https://electronjs.org/docs/api/structures/extension-info - - name: string; - version: string; - } - - interface FileFilter { - - // Docs: https://electronjs.org/docs/api/structures/file-filter - - extensions: string[]; - name: string; - } - - interface FilePathWithHeaders { - - // Docs: https://electronjs.org/docs/api/structures/file-path-with-headers - - /** - * Additional headers to be sent. - */ - headers?: Record; - /** - * The path to the file to send. - */ - path: string; - } - - interface GlobalShortcut { - - // Docs: https://electronjs.org/docs/api/global-shortcut - - /** - * Whether this application has registered `accelerator`. - * - * When the accelerator is already taken by other applications, this call will - * still return `false`. This behavior is intended by operating systems, since they - * don't want applications to fight for global shortcuts. - */ - isRegistered(accelerator: Accelerator): boolean; - /** - * Whether or not the shortcut was registered successfully. - * - * Registers a global shortcut of `accelerator`. The `callback` is called when the - * registered shortcut is pressed by the user. - * - * When the accelerator is already taken by other applications, this call will - * silently fail. This behavior is intended by operating systems, since they don't - * want applications to fight for global shortcuts. - * - * The following accelerators will not be registered successfully on macOS 10.14 - * Mojave unless the app has been authorized as a trusted accessibility client: - * - * * "Media Play/Pause" - * * "Media Next Track" -* "Media Previous Track" -* "Media Stop" - */ - register(accelerator: Accelerator, callback: () => void): boolean; - /** - * Registers a global shortcut of all `accelerator` items in `accelerators`. The - * `callback` is called when any of the registered shortcuts are pressed by the - * user. - * - * When a given accelerator is already taken by other applications, this call will - * silently fail. This behavior is intended by operating systems, since they don't - * want applications to fight for global shortcuts. - * - * The following accelerators will not be registered successfully on macOS 10.14 - * Mojave unless the app has been authorized as a trusted accessibility client: - * - * * "Media Play/Pause" - * * "Media Next Track" -* "Media Previous Track" -* "Media Stop" - */ - registerAll(accelerators: string[], callback: () => void): void; - /** - * Unregisters the global shortcut of `accelerator`. - */ - unregister(accelerator: Accelerator): void; - /** - * Unregisters all of the global shortcuts. - */ - unregisterAll(): void; - } - - interface GPUFeatureStatus { - - // Docs: https://electronjs.org/docs/api/structures/gpu-feature-status - - /** - * Canvas. - */ - '2d_canvas': string; - /** - * Flash. - */ - flash_3d: string; - /** - * Flash Stage3D. - */ - flash_stage3d: string; - /** - * Flash Stage3D Baseline profile. - */ - flash_stage3d_baseline: string; - /** - * Compositing. - */ - gpu_compositing: string; - /** - * Multiple Raster Threads. - */ - multiple_raster_threads: string; - /** - * Native GpuMemoryBuffers. - */ - native_gpu_memory_buffers: string; - /** - * Rasterization. - */ - rasterization: string; - /** - * Video Decode. - */ - video_decode: string; - /** - * Video Encode. - */ - video_encode: string; - /** - * VPx Video Decode. - */ - vpx_decode: string; - /** - * WebGL. - */ - webgl: string; - /** - * WebGL2. - */ - webgl2: string; - } - - interface InAppPurchase extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/in-app-purchase - - on(event: 'transactions-updated', listener: Function): this; - once(event: 'transactions-updated', listener: Function): this; - addListener(event: 'transactions-updated', listener: Function): this; - removeListener(event: 'transactions-updated', listener: Function): this; - /** - * whether a user can make a payment. - */ - canMakePayments(): boolean; - /** - * Completes all pending transactions. - */ - finishAllTransactions(): void; - /** - * Completes the pending transactions corresponding to the date. - */ - finishTransactionByDate(date: string): void; - /** - * Resolves with an array of `Product` objects. - * -Retrieves the product descriptions. - */ - getProducts(productIDs: string[]): Promise; - /** - * the path to the receipt. - */ - getReceiptURL(): string; - /** - * Returns `true` if the product is valid and added to the payment queue. - * - * You should listen for the `transactions-updated` event as soon as possible and - * certainly before you call `purchaseProduct`. - */ - purchaseProduct(productID: string, quantity?: number): Promise; - /** - * Restores finished transactions. This method can be called either to install - * purchases on additional devices, or to restore purchases for an application that - * the user deleted and reinstalled. - * - * The payment queue delivers a new transaction for each previously completed - * transaction that can be restored. Each transaction includes a copy of the - * original transaction. - */ - restoreCompletedTransactions(): void; - } - - class IncomingMessage extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/incoming-message - - /** - * Emitted when a request has been canceled during an ongoing HTTP transaction. - */ - on(event: 'aborted', listener: Function): this; - once(event: 'aborted', listener: Function): this; - addListener(event: 'aborted', listener: Function): this; - removeListener(event: 'aborted', listener: Function): this; - /** - * The `data` event is the usual method of transferring response data into - * applicative code. - */ - on(event: 'data', listener: ( - /** - * A chunk of response body's data. - */ - chunk: Buffer) => void): this; - once(event: 'data', listener: ( - /** - * A chunk of response body's data. - */ - chunk: Buffer) => void): this; - addListener(event: 'data', listener: ( - /** - * A chunk of response body's data. - */ - chunk: Buffer) => void): this; - removeListener(event: 'data', listener: ( - /** - * A chunk of response body's data. - */ - chunk: Buffer) => void): this; - /** - * Indicates that response body has ended. Must be placed before 'data' event. - */ - on(event: 'end', listener: Function): this; - once(event: 'end', listener: Function): this; - addListener(event: 'end', listener: Function): this; - removeListener(event: 'end', listener: Function): this; - /** - * Returns: - * - * `error` Error - Typically holds an error string identifying failure root cause. - * - * Emitted when an error was encountered while streaming response data events. For - * instance, if the server closes the underlying while the response is still - * streaming, an `error` event will be emitted on the response object and a `close` - * event will subsequently follow on the request object. - */ - on(event: 'error', listener: Function): this; - once(event: 'error', listener: Function): this; - addListener(event: 'error', listener: Function): this; - removeListener(event: 'error', listener: Function): this; - headers: Record; - httpVersion: string; - httpVersionMajor: number; - httpVersionMinor: number; - statusCode: number; - statusMessage: string; - } - - interface InputEvent { - - // Docs: https://electronjs.org/docs/api/structures/input-event - - /** - * An array of modifiers of the event, can be `shift`, `control`, `ctrl`, `alt`, - * `meta`, `command`, `cmd`, `isKeypad`, `isAutoRepeat`, `leftButtonDown`, - * `middleButtonDown`, `rightButtonDown`, `capsLock`, `numLock`, `left`, `right`. - */ - modifiers?: Array<'shift' | 'control' | 'ctrl' | 'alt' | 'meta' | 'command' | 'cmd' | 'isKeypad' | 'isAutoRepeat' | 'leftButtonDown' | 'middleButtonDown' | 'rightButtonDown' | 'capsLock' | 'numLock' | 'left' | 'right'>; - } - - interface IOCounters { - - // Docs: https://electronjs.org/docs/api/structures/io-counters - - /** - * Then number of I/O other operations. - */ - otherOperationCount: number; - /** - * Then number of I/O other transfers. - */ - otherTransferCount: number; - /** - * The number of I/O read operations. - */ - readOperationCount: number; - /** - * The number of I/O read transfers. - */ - readTransferCount: number; - /** - * The number of I/O write operations. - */ - writeOperationCount: number; - /** - * The number of I/O write transfers. - */ - writeTransferCount: number; - } - - interface IpcMain extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/ipc-main - - /** - * Adds a handler for an `invoke`able IPC. This handler will be called whenever a - * renderer calls `ipcRenderer.invoke(channel, ...args)`. - * - * If `listener` returns a Promise, the eventual result of the promise will be - * returned as a reply to the remote caller. Otherwise, the return value of the - * listener will be used as the value of the reply. - * - * The `event` that is passed as the first argument to the handler is the same as - * that passed to a regular event listener. It includes information about which - * WebContents is the source of the invoke request. - */ - handle(channel: string, listener: (event: IpcMainInvokeEvent, ...args: any[]) => (Promise) | (any)): void; - /** - * Handles a single `invoke`able IPC message, then removes the listener. See - * `ipcMain.handle(channel, listener)`. - */ - handleOnce(channel: string, listener: (event: IpcMainInvokeEvent, ...args: any[]) => (Promise) | (any)): void; - /** - * Listens to `channel`, when a new message arrives `listener` would be called with - * `listener(event, args...)`. - */ - on(channel: string, listener: (event: IpcMainEvent, ...args: any[]) => void): this; - /** - * Adds a one time `listener` function for the event. This `listener` is invoked - * only the next time a message is sent to `channel`, after which it is removed. - */ - once(channel: string, listener: (event: IpcMainEvent, ...args: any[]) => void): this; - /** - * Removes listeners of the specified `channel`. - */ - removeAllListeners(channel?: string): this; - /** - * Removes any handler for `channel`, if present. - */ - removeHandler(channel: string): void; - /** - * Removes the specified `listener` from the listener array for the specified - * `channel`. - */ - removeListener(channel: string, listener: (...args: any[]) => void): this; - } - - interface IpcMainEvent extends Event { - - // Docs: https://electronjs.org/docs/api/structures/ipc-main-event - - /** - * The ID of the renderer frame that sent this message - */ - frameId: number; - /** - * A list of MessagePorts that were transferred with this message - */ - ports: MessagePortMain[]; - /** - * The internal ID of the renderer process that sent this message - */ - processId: number; - /** - * A function that will send an IPC message to the renderer frame that sent the - * original message that you are currently handling. You should use this method to - * "reply" to the sent message in order to guarantee the reply will go to the - * correct process and frame. - */ - reply: Function; - /** - * Set this to the value to be returned in a synchronous message - */ - returnValue: any; - /** - * Returns the `webContents` that sent the message - */ - sender: WebContents; - /** - * The frame that sent this message - * - */ - readonly senderFrame: WebFrameMain; - } - - interface IpcMainInvokeEvent extends Event { - - // Docs: https://electronjs.org/docs/api/structures/ipc-main-invoke-event - - /** - * The ID of the renderer frame that sent this message - */ - frameId: number; - /** - * The internal ID of the renderer process that sent this message - */ - processId: number; - /** - * Returns the `webContents` that sent the message - */ - sender: WebContents; - /** - * The frame that sent this message - * - */ - readonly senderFrame: WebFrameMain; - } - - interface IpcRenderer extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/ipc-renderer - - /** - * Resolves with the response from the main process. - * - * Send a message to the main process via `channel` and expect a result - * asynchronously. Arguments will be serialized with the Structured Clone - * Algorithm, just like `window.postMessage`, so prototype chains will not be - * included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw - * an exception. - * - * > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special - * Electron objects will throw an exception. - * - * Since the main process does not have support for DOM objects such as - * `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over - * Electron's IPC to the main process, as the main process would have no way to - * decode them. Attempting to send such objects over IPC will result in an error. - * - * The main process should listen for `channel` with `ipcMain.handle()`. - * - * For example: - * - * If you need to transfer a `MessagePort` to the main process, use - * `ipcRenderer.postMessage`. - * - * If you do not need a response to the message, consider using `ipcRenderer.send`. - */ - invoke(channel: string, ...args: any[]): Promise; - /** - * Listens to `channel`, when a new message arrives `listener` would be called with - * `listener(event, args...)`. - */ - on(channel: string, listener: (event: IpcRendererEvent, ...args: any[]) => void): this; - /** - * Adds a one time `listener` function for the event. This `listener` is invoked - * only the next time a message is sent to `channel`, after which it is removed. - */ - once(channel: string, listener: (event: IpcRendererEvent, ...args: any[]) => void): this; - /** - * Send a message to the main process, optionally transferring ownership of zero or - * more `MessagePort` objects. - * - * The transferred `MessagePort` objects will be available in the main process as - * `MessagePortMain` objects by accessing the `ports` property of the emitted - * event. - * - * For example: - * - * For more information on using `MessagePort` and `MessageChannel`, see the MDN - * documentation. - */ - postMessage(channel: string, message: any, transfer?: MessagePort[]): void; - /** - * Removes all listeners, or those of the specified `channel`. - */ - removeAllListeners(channel: string): this; - /** - * Removes the specified `listener` from the listener array for the specified - * `channel`. - */ - removeListener(channel: string, listener: (...args: any[]) => void): this; - /** - * Send an asynchronous message to the main process via `channel`, along with - * arguments. Arguments will be serialized with the Structured Clone Algorithm, - * just like `window.postMessage`, so prototype chains will not be included. - * Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an - * exception. - * - * > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special - * Electron objects will throw an exception. - * - * Since the main process does not have support for DOM objects such as - * `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over - * Electron's IPC to the main process, as the main process would have no way to - * decode them. Attempting to send such objects over IPC will result in an error. - * - * The main process handles it by listening for `channel` with the `ipcMain` - * module. - * - * If you need to transfer a `MessagePort` to the main process, use - * `ipcRenderer.postMessage`. - * - * If you want to receive a single response from the main process, like the result - * of a method call, consider using `ipcRenderer.invoke`. - */ - send(channel: string, ...args: any[]): void; - /** - * The value sent back by the `ipcMain` handler. - * - * Send a message to the main process via `channel` and expect a result - * synchronously. Arguments will be serialized with the Structured Clone Algorithm, - * just like `window.postMessage`, so prototype chains will not be included. - * Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an - * exception. - * - * > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special - * Electron objects will throw an exception. - * - * Since the main process does not have support for DOM objects such as - * `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over - * Electron's IPC to the main process, as the main process would have no way to - * decode them. Attempting to send such objects over IPC will result in an error. - * - * The main process handles it by listening for `channel` with `ipcMain` module, - * and replies by setting `event.returnValue`. - * - * > :warning: **WARNING**: Sending a synchronous message will block the whole - * renderer process until the reply is received, so use this method only as a last - * resort. It's much better to use the asynchronous version, `invoke()`. - */ - sendSync(channel: string, ...args: any[]): any; - /** - * Sends a message to a window with `webContentsId` via `channel`. - */ - sendTo(webContentsId: number, channel: string, ...args: any[]): void; - /** - * Like `ipcRenderer.send` but the event will be sent to the `` element in - * the host page instead of the main process. - */ - sendToHost(channel: string, ...args: any[]): void; - } - - interface IpcRendererEvent extends Event { - - // Docs: https://electronjs.org/docs/api/structures/ipc-renderer-event - - /** - * A list of MessagePorts that were transferred with this message - */ - ports: MessagePort[]; - /** - * The `IpcRenderer` instance that emitted the event originally - */ - sender: IpcRenderer; - /** - * The `webContents.id` that sent the message, you can call - * `event.sender.sendTo(event.senderId, ...)` to reply to the message, see - * ipcRenderer.sendTo for more information. This only applies to messages sent from - * a different renderer. Messages sent directly from the main process set - * `event.senderId` to `0`. - */ - senderId: number; - } - - interface JumpListCategory { - - // Docs: https://electronjs.org/docs/api/structures/jump-list-category - - /** - * Array of `JumpListItem` objects if `type` is `tasks` or `custom`, otherwise it - * should be omitted. - */ - items?: JumpListItem[]; - /** - * Must be set if `type` is `custom`, otherwise it should be omitted. - */ - name?: string; - /** - * One of the following: - */ - type?: ('tasks' | 'frequent' | 'recent' | 'custom'); - } - - interface JumpListItem { - - // Docs: https://electronjs.org/docs/api/structures/jump-list-item - - /** - * The command line arguments when `program` is executed. Should only be set if - * `type` is `task`. - */ - args?: string; - /** - * Description of the task (displayed in a tooltip). Should only be set if `type` - * is `task`. Maximum length 260 characters. - */ - description?: string; - /** - * The index of the icon in the resource file. If a resource file contains multiple - * icons this value can be used to specify the zero-based index of the icon that - * should be displayed for this task. If a resource file contains only one icon, - * this property should be set to zero. - */ - iconIndex?: number; - /** - * The absolute path to an icon to be displayed in a Jump List, which can be an - * arbitrary resource file that contains an icon (e.g. `.ico`, `.exe`, `.dll`). You - * can usually specify `process.execPath` to show the program icon. - */ - iconPath?: string; - /** - * Path of the file to open, should only be set if `type` is `file`. - */ - path?: string; - /** - * Path of the program to execute, usually you should specify `process.execPath` - * which opens the current program. Should only be set if `type` is `task`. - */ - program?: string; - /** - * The text to be displayed for the item in the Jump List. Should only be set if - * `type` is `task`. - */ - title?: string; - /** - * One of the following: - */ - type?: ('task' | 'separator' | 'file'); - /** - * The working directory. Default is empty. - */ - workingDirectory?: string; - } - - interface KeyboardEvent { - - // Docs: https://electronjs.org/docs/api/structures/keyboard-event - - /** - * whether an Alt key was used in an accelerator to trigger the Event - */ - altKey?: boolean; - /** - * whether the Control key was used in an accelerator to trigger the Event - */ - ctrlKey?: boolean; - /** - * whether a meta key was used in an accelerator to trigger the Event - */ - metaKey?: boolean; - /** - * whether a Shift key was used in an accelerator to trigger the Event - */ - shiftKey?: boolean; - /** - * whether an accelerator was used to trigger the event as opposed to another user - * gesture like mouse click - */ - triggeredByAccelerator?: boolean; - } - - interface KeyboardInputEvent extends InputEvent { - - // Docs: https://electronjs.org/docs/api/structures/keyboard-input-event - - /** - * The character that will be sent as the keyboard event. Should only use the valid - * key codes in Accelerator. - */ - keyCode: string; - /** - * The type of the event, can be `keyDown`, `keyUp` or `char`. - */ - type: ('keyDown' | 'keyUp' | 'char'); - } - - interface MemoryInfo { - - // Docs: https://electronjs.org/docs/api/structures/memory-info - - /** - * The maximum amount of memory that has ever been pinned to actual physical RAM. - */ - peakWorkingSetSize: number; - /** - * The amount of memory not shared by other processes, such as JS heap or HTML - * content. - * - * @platform win32 - */ - privateBytes?: number; - /** - * The amount of memory currently pinned to actual physical RAM. - */ - workingSetSize: number; - } - - interface MemoryUsageDetails { - - // Docs: https://electronjs.org/docs/api/structures/memory-usage-details - - count: number; - liveSize: number; - size: number; - } - - class Menu { - - // Docs: https://electronjs.org/docs/api/menu - - /** - * Emitted when a popup is closed either manually or with `menu.closePopup()`. - */ - on(event: 'menu-will-close', listener: (event: Event) => void): this; - once(event: 'menu-will-close', listener: (event: Event) => void): this; - addListener(event: 'menu-will-close', listener: (event: Event) => void): this; - removeListener(event: 'menu-will-close', listener: (event: Event) => void): this; - /** - * Emitted when `menu.popup()` is called. - */ - on(event: 'menu-will-show', listener: (event: Event) => void): this; - once(event: 'menu-will-show', listener: (event: Event) => void): this; - addListener(event: 'menu-will-show', listener: (event: Event) => void): this; - removeListener(event: 'menu-will-show', listener: (event: Event) => void): this; - /** - * Menu - */ - constructor(); - /** - * Generally, the `template` is an array of `options` for constructing a MenuItem. - * The usage can be referenced above. - * - * You can also attach other fields to the element of the `template` and they will - * become properties of the constructed menu items. - */ - static buildFromTemplate(template: Array<(MenuItemConstructorOptions) | (MenuItem)>): Menu; - /** - * The application menu, if set, or `null`, if not set. - * - * **Note:** The returned `Menu` instance doesn't support dynamic addition or - * removal of menu items. Instance properties can still be dynamically modified. - */ - static getApplicationMenu(): (Menu) | (null); - /** - * Sends the `action` to the first responder of application. This is used for - * emulating default macOS menu behaviors. Usually you would use the `role` - * property of a `MenuItem`. - * - * See the macOS Cocoa Event Handling Guide for more information on macOS' native - * actions. - * - * @platform darwin - */ - static sendActionToFirstResponder(action: string): void; - /** - * Sets `menu` as the application menu on macOS. On Windows and Linux, the `menu` - * will be set as each window's top menu. - * - * Also on Windows and Linux, you can use a `&` in the top-level item name to - * indicate which letter should get a generated accelerator. For example, using - * `&File` for the file menu would result in a generated `Alt-F` accelerator that - * opens the associated menu. The indicated character in the button label gets an - * underline. The `&` character is not displayed on the button label. - * - * Passing `null` will suppress the default menu. On Windows and Linux, this has - * the additional effect of removing the menu bar from the window. - * - * **Note:** The default menu will be created automatically if the app does not set - * one. It contains standard items such as `File`, `Edit`, `View`, `Window` and - * `Help`. - */ - static setApplicationMenu(menu: (Menu) | (null)): void; - /** - * Appends the `menuItem` to the menu. - */ - append(menuItem: MenuItem): void; - /** - * Closes the context menu in the `browserWindow`. - */ - closePopup(browserWindow?: BrowserWindow): void; - /** - * the item with the specified `id` - */ - getMenuItemById(id: string): (MenuItem) | (null); - /** - * Inserts the `menuItem` to the `pos` position of the menu. - */ - insert(pos: number, menuItem: MenuItem): void; - /** - * Pops up this menu as a context menu in the `BrowserWindow`. - */ - popup(options?: PopupOptions): void; - items: MenuItem[]; - } - - class MenuItem { - - // Docs: https://electronjs.org/docs/api/menu-item - - /** - * MenuItem - */ - constructor(options: MenuItemConstructorOptions); - accelerator?: Accelerator; - checked: boolean; - click: Function; - commandId: number; - enabled: boolean; - icon?: (NativeImage) | (string); - id: string; - label: string; - menu: Menu; - registerAccelerator: boolean; - role?: ('undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'pasteAndMatchStyle' | 'delete' | 'selectAll' | 'reload' | 'forceReload' | 'toggleDevTools' | 'resetZoom' | 'zoomIn' | 'zoomOut' | 'togglefullscreen' | 'window' | 'minimize' | 'close' | 'help' | 'about' | 'services' | 'hide' | 'hideOthers' | 'unhide' | 'quit' | 'startSpeaking' | 'stopSpeaking' | 'zoom' | 'front' | 'appMenu' | 'fileMenu' | 'editMenu' | 'viewMenu' | 'recentDocuments' | 'toggleTabBar' | 'selectNextTab' | 'selectPreviousTab' | 'mergeAllWindows' | 'clearRecentDocuments' | 'moveTabToNewWindow' | 'windowMenu'); - sharingItem: SharingItem; - sublabel: string; - submenu?: Menu; - toolTip: string; - type: ('normal' | 'separator' | 'submenu' | 'checkbox' | 'radio'); - visible: boolean; - } - - class MessageChannelMain extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/message-channel-main - - port1: MessagePortMain; - port2: MessagePortMain; - } - - class MessagePortMain extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/message-port-main - - /** - * Emitted when the remote end of a MessagePortMain object becomes disconnected. - */ - on(event: 'close', listener: Function): this; - once(event: 'close', listener: Function): this; - addListener(event: 'close', listener: Function): this; - removeListener(event: 'close', listener: Function): this; - /** - * Emitted when a MessagePortMain object receives a message. - */ - on(event: 'message', listener: (messageEvent: MessageEvent) => void): this; - once(event: 'message', listener: (messageEvent: MessageEvent) => void): this; - addListener(event: 'message', listener: (messageEvent: MessageEvent) => void): this; - removeListener(event: 'message', listener: (messageEvent: MessageEvent) => void): this; - /** - * Disconnects the port, so it is no longer active. - */ - close(): void; - /** - * Sends a message from the port, and optionally, transfers ownership of objects to - * other browsing contexts. - */ - postMessage(message: any, transfer?: MessagePortMain[]): void; - /** - * Starts the sending of messages queued on the port. Messages will be queued until - * this method is called. - */ - start(): void; - } - - interface MimeTypedBuffer { - - // Docs: https://electronjs.org/docs/api/structures/mime-typed-buffer - - /** - * Charset of the buffer. - */ - charset?: string; - /** - * The actual Buffer content. - */ - data: Buffer; - /** - * MIME type of the buffer. - */ - mimeType?: string; - } - - interface MouseInputEvent extends InputEvent { - - // Docs: https://electronjs.org/docs/api/structures/mouse-input-event - - /** - * The button pressed, can be `left`, `middle`, `right`. - */ - button?: ('left' | 'middle' | 'right'); - clickCount?: number; - globalX?: number; - globalY?: number; - movementX?: number; - movementY?: number; - /** - * The type of the event, can be `mouseDown`, `mouseUp`, `mouseEnter`, - * `mouseLeave`, `contextMenu`, `mouseWheel` or `mouseMove`. - */ - type: ('mouseDown' | 'mouseUp' | 'mouseEnter' | 'mouseLeave' | 'contextMenu' | 'mouseWheel' | 'mouseMove'); - x: number; - y: number; - } - - interface MouseWheelInputEvent extends MouseInputEvent { - - // Docs: https://electronjs.org/docs/api/structures/mouse-wheel-input-event - - accelerationRatioX?: number; - accelerationRatioY?: number; - canScroll?: boolean; - deltaX?: number; - deltaY?: number; - hasPreciseScrollingDeltas?: boolean; - /** - * The type of the event, can be `mouseWheel`. - */ - type: ('mouseWheel'); - wheelTicksX?: number; - wheelTicksY?: number; - } - - class NativeImage { - - // Docs: https://electronjs.org/docs/api/native-image - - /** - * Creates an empty `NativeImage` instance. - */ - static createEmpty(): NativeImage; - /** - * Creates a new `NativeImage` instance from `buffer` that contains the raw bitmap - * pixel data returned by `toBitmap()`. The specific format is platform-dependent. - */ - static createFromBitmap(buffer: Buffer, options: CreateFromBitmapOptions): NativeImage; - /** - * Creates a new `NativeImage` instance from `buffer`. Tries to decode as PNG or - * JPEG first. - */ - static createFromBuffer(buffer: Buffer, options?: CreateFromBufferOptions): NativeImage; - /** - * Creates a new `NativeImage` instance from `dataURL`. - */ - static createFromDataURL(dataURL: string): NativeImage; - /** - * Creates a new `NativeImage` instance from the NSImage that maps to the given - * image name. See `System Icons` for a list of possible values. - * - * The `hslShift` is applied to the image with the following rules: - * - * * `hsl_shift[0]` (hue): The absolute hue value for the image - 0 and 1 map to 0 - * and 360 on the hue color wheel (red). - * * `hsl_shift[1]` (saturation): A saturation shift for the image, with the - * following key values: 0 = remove all color. 0.5 = leave unchanged. 1 = fully - * saturate the image. - * * `hsl_shift[2]` (lightness): A lightness shift for the image, with the - * following key values: 0 = remove all lightness (make all pixels black). 0.5 = - * leave unchanged. 1 = full lightness (make all pixels white). - * - * This means that `[-1, 0, 1]` will make the image completely white and `[-1, 1, - * 0]` will make the image completely black. - * - * In some cases, the `NSImageName` doesn't match its string representation; one - * example of this is `NSFolderImageName`, whose string representation would - * actually be `NSFolder`. Therefore, you'll need to determine the correct string - * representation for your image before passing it in. This can be done with the - * following: - * - * `echo -e '#import \nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); - * }' | clang -otest -x objective-c -framework Cocoa - && ./test` - * -where `SYSTEM_IMAGE_NAME` should be replaced with any value from this list. - * - * @platform darwin - */ - static createFromNamedImage(imageName: string, hslShift?: number[]): NativeImage; - /** - * Creates a new `NativeImage` instance from a file located at `path`. This method - * returns an empty image if the `path` does not exist, cannot be read, or is not a - * valid image. - */ - static createFromPath(path: string): NativeImage; - /** - * fulfilled with the file's thumbnail preview image, which is a NativeImage. - * - * @platform darwin,win32 - */ - static createThumbnailFromPath(path: string, maxSize: Size): Promise; - /** - * Add an image representation for a specific scale factor. This can be used to - * explicitly add different scale factor representations to an image. This can be - * called on empty images. - */ - addRepresentation(options: AddRepresentationOptions): void; - /** - * The cropped image. - */ - crop(rect: Rectangle): NativeImage; - /** - * The image's aspect ratio. - * - * If `scaleFactor` is passed, this will return the aspect ratio corresponding to - * the image representation most closely matching the passed value. - */ - getAspectRatio(scaleFactor?: number): number; - /** - * A Buffer that contains the image's raw bitmap pixel data. - * - * The difference between `getBitmap()` and `toBitmap()` is that `getBitmap()` does - * not copy the bitmap data, so you have to use the returned Buffer immediately in - * current event loop tick; otherwise the data might be changed or destroyed. - */ - getBitmap(options?: BitmapOptions): Buffer; - /** - * A Buffer that stores C pointer to underlying native handle of the image. On - * macOS, a pointer to `NSImage` instance would be returned. - * - * Notice that the returned pointer is a weak pointer to the underlying native - * image instead of a copy, so you _must_ ensure that the associated `nativeImage` - * instance is kept around. - * - * @platform darwin - */ - getNativeHandle(): Buffer; - /** - * An array of all scale factors corresponding to representations for a given - * nativeImage. - */ - getScaleFactors(): number[]; - /** - * If `scaleFactor` is passed, this will return the size corresponding to the image - * representation most closely matching the passed value. - */ - getSize(scaleFactor?: number): Size; - /** - * Whether the image is empty. - */ - isEmpty(): boolean; - /** - * Whether the image is a template image. - */ - isTemplateImage(): boolean; - /** - * The resized image. - * - * If only the `height` or the `width` are specified then the current aspect ratio - * will be preserved in the resized image. - */ - resize(options: ResizeOptions): NativeImage; - /** - * Marks the image as a template image. - */ - setTemplateImage(option: boolean): void; - /** - * A Buffer that contains a copy of the image's raw bitmap pixel data. - */ - toBitmap(options?: ToBitmapOptions): Buffer; - /** - * The data URL of the image. - */ - toDataURL(options?: ToDataURLOptions): string; - /** - * A Buffer that contains the image's `JPEG` encoded data. - */ - toJPEG(quality: number): Buffer; - /** - * A Buffer that contains the image's `PNG` encoded data. - */ - toPNG(options?: ToPNGOptions): Buffer; - isMacTemplateImage: boolean; - } - - interface NativeTheme extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/native-theme - - /** - * Emitted when something in the underlying NativeTheme has changed. This normally - * means that either the value of `shouldUseDarkColors`, - * `shouldUseHighContrastColors` or `shouldUseInvertedColorScheme` has changed. You - * will have to check them to determine which one has changed. - */ - on(event: 'updated', listener: Function): this; - once(event: 'updated', listener: Function): this; - addListener(event: 'updated', listener: Function): this; - removeListener(event: 'updated', listener: Function): this; - /** - * A `Boolean` for if the OS / Chromium currently has a dark mode enabled or is - * being instructed to show a dark-style UI. If you want to modify this value you - * should use `themeSource` below. - * - */ - readonly shouldUseDarkColors: boolean; - /** - * A `Boolean` for if the OS / Chromium currently has high-contrast mode enabled or - * is being instructed to show a high-contrast UI. - * - * @platform darwin,win32 - */ - readonly shouldUseHighContrastColors: boolean; - /** - * A `Boolean` for if the OS / Chromium currently has an inverted color scheme or - * is being instructed to use an inverted color scheme. - * - * @platform darwin,win32 - */ - readonly shouldUseInvertedColorScheme: boolean; - /** - * A `String` property that can be `system`, `light` or `dark`. It is used to - * override and supersede the value that Chromium has chosen to use internally. - * - * Setting this property to `system` will remove the override and everything will - * be reset to the OS default. By default `themeSource` is `system`. - * - * Settings this property to `dark` will have the following effects: - * - * * `nativeTheme.shouldUseDarkColors` will be `true` when accessed - * * Any UI Electron renders on Linux and Windows including context menus, - * devtools, etc. will use the dark UI. - * * Any UI the OS renders on macOS including menus, window frames, etc. will use - * the dark UI. - * * The `prefers-color-scheme` CSS query will match `dark` mode. - * * The `updated` event will be emitted - * - * Settings this property to `light` will have the following effects: - * - * * `nativeTheme.shouldUseDarkColors` will be `false` when accessed - * * Any UI Electron renders on Linux and Windows including context menus, - * devtools, etc. will use the light UI. - * * Any UI the OS renders on macOS including menus, window frames, etc. will use - * the light UI. - * * The `prefers-color-scheme` CSS query will match `light` mode. - * * The `updated` event will be emitted - * - * The usage of this property should align with a classic "dark mode" state machine - * in your application where the user has three options. - * - * * `Follow OS` --> `themeSource = 'system'` - * * `Dark Mode` --> `themeSource = 'dark'` - * * `Light Mode` --> `themeSource = 'light'` - * - * Your application should then always use `shouldUseDarkColors` to determine what - * CSS to apply. - */ - themeSource: ('system' | 'light' | 'dark'); - } - - interface Net { - - // Docs: https://electronjs.org/docs/api/net - - /** - * Whether there is currently internet connection. - * - * A return value of `false` is a pretty strong indicator that the user won't be - * able to connect to remote sites. However, a return value of `true` is - * inconclusive; even if some link is up, it is uncertain whether a particular - * connection attempt to a particular remote site will be successful. - */ - isOnline(): boolean; - /** - * Creates a `ClientRequest` instance using the provided `options` which are - * directly forwarded to the `ClientRequest` constructor. The `net.request` method - * would be used to issue both secure and insecure HTTP requests according to the - * specified protocol scheme in the `options` object. - */ - request(options: (ClientRequestConstructorOptions) | (string)): ClientRequest; - /** - * A `Boolean` property. Whether there is currently internet connection. - * - * A return value of `false` is a pretty strong indicator that the user won't be - * able to connect to remote sites. However, a return value of `true` is - * inconclusive; even if some link is up, it is uncertain whether a particular - * connection attempt to a particular remote site will be successful. - * - */ - readonly online: boolean; - } - - interface NetLog { - - // Docs: https://electronjs.org/docs/api/net-log - - /** - * resolves when the net log has begun recording. - * -Starts recording network events to `path`. - */ - startLogging(path: string, options?: StartLoggingOptions): Promise; - /** - * resolves when the net log has been flushed to disk. - * - * Stops recording network events. If not called, net logging will automatically - * end when app quits. - */ - stopLogging(): Promise; - /** - * A `Boolean` property that indicates whether network logs are currently being - * recorded. - * - */ - readonly currentlyLogging: boolean; - } - - interface NewWindowWebContentsEvent extends Event { - - // Docs: https://electronjs.org/docs/api/structures/new-window-web-contents-event - - newGuest?: BrowserWindow; - } - - class Notification extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/notification - - on(event: 'action', listener: (event: Event, - /** - * The index of the action that was activated. - */ - index: number) => void): this; - once(event: 'action', listener: (event: Event, - /** - * The index of the action that was activated. - */ - index: number) => void): this; - addListener(event: 'action', listener: (event: Event, - /** - * The index of the action that was activated. - */ - index: number) => void): this; - removeListener(event: 'action', listener: (event: Event, - /** - * The index of the action that was activated. - */ - index: number) => void): this; - /** - * Emitted when the notification is clicked by the user. - */ - on(event: 'click', listener: (event: Event) => void): this; - once(event: 'click', listener: (event: Event) => void): this; - addListener(event: 'click', listener: (event: Event) => void): this; - removeListener(event: 'click', listener: (event: Event) => void): this; - /** - * Emitted when the notification is closed by manual intervention from the user. - * - * This event is not guaranteed to be emitted in all cases where the notification - * is closed. - */ - on(event: 'close', listener: (event: Event) => void): this; - once(event: 'close', listener: (event: Event) => void): this; - addListener(event: 'close', listener: (event: Event) => void): this; - removeListener(event: 'close', listener: (event: Event) => void): this; - /** - * Emitted when an error is encountered while creating and showing the native - * notification. - * - * @platform win32 - */ - on(event: 'failed', listener: (event: Event, - /** - * The error encountered during execution of the `show()` method. - */ - error: string) => void): this; - once(event: 'failed', listener: (event: Event, - /** - * The error encountered during execution of the `show()` method. - */ - error: string) => void): this; - addListener(event: 'failed', listener: (event: Event, - /** - * The error encountered during execution of the `show()` method. - */ - error: string) => void): this; - removeListener(event: 'failed', listener: (event: Event, - /** - * The error encountered during execution of the `show()` method. - */ - error: string) => void): this; - /** - * Emitted when the user clicks the "Reply" button on a notification with - * `hasReply: true`. - * - * @platform darwin - */ - on(event: 'reply', listener: (event: Event, - /** - * The string the user entered into the inline reply field. - */ - reply: string) => void): this; - once(event: 'reply', listener: (event: Event, - /** - * The string the user entered into the inline reply field. - */ - reply: string) => void): this; - addListener(event: 'reply', listener: (event: Event, - /** - * The string the user entered into the inline reply field. - */ - reply: string) => void): this; - removeListener(event: 'reply', listener: (event: Event, - /** - * The string the user entered into the inline reply field. - */ - reply: string) => void): this; - /** - * Emitted when the notification is shown to the user, note this could be fired - * multiple times as a notification can be shown multiple times through the - * `show()` method. - */ - on(event: 'show', listener: (event: Event) => void): this; - once(event: 'show', listener: (event: Event) => void): this; - addListener(event: 'show', listener: (event: Event) => void): this; - removeListener(event: 'show', listener: (event: Event) => void): this; - /** - * Notification - */ - constructor(options?: NotificationConstructorOptions); - /** - * Whether or not desktop notifications are supported on the current system - */ - static isSupported(): boolean; - /** - * Dismisses the notification. - */ - close(): void; - /** - * Immediately shows the notification to the user, please note this means unlike - * the HTML5 Notification implementation, instantiating a `new Notification` does - * not immediately show it to the user, you need to call this method before the OS - * will display it. - * - * If the notification has been shown before, this method will dismiss the - * previously shown notification and create a new one with identical properties. - */ - show(): void; - actions: NotificationAction[]; - body: string; - closeButtonText: string; - hasReply: boolean; - replyPlaceholder: string; - silent: boolean; - sound: string; - subtitle: string; - timeoutType: ('default' | 'never'); - title: string; - toastXml: string; - urgency: ('normal' | 'critical' | 'low'); - } - - interface NotificationAction { - - // Docs: https://electronjs.org/docs/api/structures/notification-action - - /** - * The label for the given action. - */ - text?: string; - /** - * The type of action, can be `button`. - */ - type: ('button'); - } - - interface NotificationResponse { - - // Docs: https://electronjs.org/docs/api/structures/notification-response - - /** - * The identifier string of the action that the user selected. - */ - actionIdentifier: string; - /** - * The delivery date of the notification. - */ - date: number; - /** - * The unique identifier for this notification request. - */ - identifier: string; - /** - * A dictionary of custom information associated with the notification. - */ - userInfo: Record; - /** - * The text entered or chosen by the user. - */ - userText?: string; - } - - interface Point { - - // Docs: https://electronjs.org/docs/api/structures/point - - x: number; - y: number; - } - - interface PostBody { - - // Docs: https://electronjs.org/docs/api/structures/post-body - - /** - * The boundary used to separate multiple parts of the message. Only valid when - * `contentType` is `multipart/form-data`. - */ - boundary?: string; - /** - * The `content-type` header used for the data. One of - * `application/x-www-form-urlencoded` or `multipart/form-data`. Corresponds to the - * `enctype` attribute of the submitted HTML form. - */ - contentType: string; - /** - * The post data to be sent to the new window. - */ - data: Array; - } - - interface PostData { - - // Docs: https://electronjs.org/docs/api/structures/post-data - - /** - * The `UUID` of the `Blob` being uploaded. Required for the `blob` type. - */ - blobUUID?: string; - /** - * The raw bytes of the post data in a `Buffer`. Required for the `rawData` type. - */ - bytes?: string; - /** - * The path of the file being uploaded. Required for the `file` type. - */ - filePath?: string; - /** - * The length of the file being uploaded, in bytes. If set to `-1`, the whole file - * will be uploaded. Only valid for `file` types. - */ - length?: number; - /** - * The modification time of the file represented by a double, which is the number - * of seconds since the `UNIX Epoch` (Jan 1, 1970). Only valid for `file` types. - */ - modificationTime?: number; - /** - * The offset from the beginning of the file being uploaded, in bytes. Only valid - * for `file` types. - */ - offset?: number; - /** - * One of the following: - */ - type: ('rawData' | 'file' | 'blob'); - } - - interface PowerMonitor extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/power-monitor - - /** - * Emitted when the system is about to lock the screen. - * - * @platform darwin,win32 - */ - on(event: 'lock-screen', listener: Function): this; - once(event: 'lock-screen', listener: Function): this; - addListener(event: 'lock-screen', listener: Function): this; - removeListener(event: 'lock-screen', listener: Function): this; - /** - * Emitted when the system changes to AC power. - * - * @platform darwin,win32 - */ - on(event: 'on-ac', listener: Function): this; - once(event: 'on-ac', listener: Function): this; - addListener(event: 'on-ac', listener: Function): this; - removeListener(event: 'on-ac', listener: Function): this; - /** - * Emitted when system changes to battery power. - * - * @platform darwin - */ - on(event: 'on-battery', listener: Function): this; - once(event: 'on-battery', listener: Function): this; - addListener(event: 'on-battery', listener: Function): this; - removeListener(event: 'on-battery', listener: Function): this; - /** - * Emitted when system is resuming. - * - * @platform darwin,win32 - */ - on(event: 'resume', listener: Function): this; - once(event: 'resume', listener: Function): this; - addListener(event: 'resume', listener: Function): this; - removeListener(event: 'resume', listener: Function): this; - /** - * Emitted when the system is about to reboot or shut down. If the event handler - * invokes `e.preventDefault()`, Electron will attempt to delay system shutdown in - * order for the app to exit cleanly. If `e.preventDefault()` is called, the app - * should exit as soon as possible by calling something like `app.quit()`. - * - * @platform linux,darwin - */ - on(event: 'shutdown', listener: Function): this; - once(event: 'shutdown', listener: Function): this; - addListener(event: 'shutdown', listener: Function): this; - removeListener(event: 'shutdown', listener: Function): this; - /** - * Emitted when the system is suspending. - * - * @platform darwin,win32 - */ - on(event: 'suspend', listener: Function): this; - once(event: 'suspend', listener: Function): this; - addListener(event: 'suspend', listener: Function): this; - removeListener(event: 'suspend', listener: Function): this; - /** - * Emitted as soon as the systems screen is unlocked. - * - * @platform darwin,win32 - */ - on(event: 'unlock-screen', listener: Function): this; - once(event: 'unlock-screen', listener: Function): this; - addListener(event: 'unlock-screen', listener: Function): this; - removeListener(event: 'unlock-screen', listener: Function): this; - /** - * Emitted when a login session is activated. See documentation for more - * information. - * - * @platform darwin - */ - on(event: 'user-did-become-active', listener: Function): this; - once(event: 'user-did-become-active', listener: Function): this; - addListener(event: 'user-did-become-active', listener: Function): this; - removeListener(event: 'user-did-become-active', listener: Function): this; - /** - * Emitted when a login session is deactivated. See documentation for more - * information. - * - * @platform darwin - */ - on(event: 'user-did-resign-active', listener: Function): this; - once(event: 'user-did-resign-active', listener: Function): this; - addListener(event: 'user-did-resign-active', listener: Function): this; - removeListener(event: 'user-did-resign-active', listener: Function): this; - /** - * The system's current state. Can be `active`, `idle`, `locked` or `unknown`. - * - * Calculate the system idle state. `idleThreshold` is the amount of time (in - * seconds) before considered idle. `locked` is available on supported systems - * only. - */ - getSystemIdleState(idleThreshold: number): ('active' | 'idle' | 'locked' | 'unknown'); - /** - * Idle time in seconds - -Calculate system idle time in seconds. - */ - getSystemIdleTime(): number; - /** - * Whether the system is on battery power. - * - * To monitor for changes in this property, use the `on-battery` and `on-ac` - * events. - */ - isOnBatteryPower(): boolean; - /** - * A `Boolean` property. True if the system is on battery power. - * -See `powerMonitor.isOnBatteryPower()`. - */ - onBatteryPower: boolean; - } - - interface PowerSaveBlocker { - - // Docs: https://electronjs.org/docs/api/power-save-blocker - - /** - * Whether the corresponding `powerSaveBlocker` has started. - */ - isStarted(id: number): boolean; - /** - * The blocker ID that is assigned to this power blocker. - * - * Starts preventing the system from entering lower-power mode. Returns an integer - * identifying the power save blocker. - * - * **Note:** `prevent-display-sleep` has higher precedence over - * `prevent-app-suspension`. Only the highest precedence type takes effect. In - * other words, `prevent-display-sleep` always takes precedence over - * `prevent-app-suspension`. - * - * For example, an API calling A requests for `prevent-app-suspension`, and another - * calling B requests for `prevent-display-sleep`. `prevent-display-sleep` will be - * used until B stops its request. After that, `prevent-app-suspension` is used. - */ - start(type: 'prevent-app-suspension' | 'prevent-display-sleep'): number; - /** - * Stops the specified power save blocker. - */ - stop(id: number): void; - } - - interface PrinterInfo { - - // Docs: https://electronjs.org/docs/api/structures/printer-info - - /** - * a longer description of the printer's type. - */ - description: string; - /** - * the name of the printer as shown in Print Preview. - */ - displayName: string; - /** - * whether or not a given printer is set as the default printer on the OS. - */ - isDefault: boolean; - /** - * the name of the printer as understood by the OS. - */ - name: string; - /** - * an object containing a variable number of platform-specific printer information. - */ - options: Options; - /** - * the current status of the printer. - */ - status: number; - } - - interface ProcessMemoryInfo { - - // Docs: https://electronjs.org/docs/api/structures/process-memory-info - - /** - * The amount of memory not shared by other processes, such as JS heap or HTML - * content in Kilobytes. - */ - private: number; - /** - * The amount of memory currently pinned to actual physical RAM in Kilobytes. - * - * @platform linux,win32 - */ - residentSet: number; - /** - * The amount of memory shared between processes, typically memory consumed by the - * Electron code itself in Kilobytes. - */ - shared: number; - } - - interface ProcessMetric { - - // Docs: https://electronjs.org/docs/api/structures/process-metric - - /** - * CPU usage of the process. - */ - cpu: CPUUsage; - /** - * Creation time for this process. The time is represented as number of - * milliseconds since epoch. Since the `pid` can be reused after a process dies, it - * is useful to use both the `pid` and the `creationTime` to uniquely identify a - * process. - */ - creationTime: number; - /** - * One of the following values: - * - * @platform win32 - */ - integrityLevel?: ('untrusted' | 'low' | 'medium' | 'high' | 'unknown'); - /** - * Memory information for the process. - */ - memory: MemoryInfo; - /** - * The name of the process. Examples for utility: `Audio Service`, `Content - * Decryption Module Service`, `Network Service`, `Video Capture`, etc. - */ - name?: string; - /** - * Process id of the process. - */ - pid: number; - /** - * Whether the process is sandboxed on OS level. - * - * @platform darwin,win32 - */ - sandboxed?: boolean; - /** - * The non-localized name of the process. - */ - serviceName?: string; - /** - * Process type. One of the following values: - */ - type: ('Browser' | 'Tab' | 'Utility' | 'Zygote' | 'Sandbox helper' | 'GPU' | 'Pepper Plugin' | 'Pepper Plugin Broker' | 'Unknown'); - } - - interface Product { - - // Docs: https://electronjs.org/docs/api/structures/product - - /** - * The total size of the content, in bytes. - */ - contentLengths: number[]; - /** - * A string that identifies the version of the content. - */ - contentVersion: string; - /** - * 3 character code presenting a product's currency based on the ISO 4217 standard. - */ - currencyCode: string; - /** - * The locale formatted price of the product. - */ - formattedPrice: string; - /** - * A Boolean value that indicates whether the App Store has downloadable content - * for this product. `true` if at least one file has been associated with the - * product. - */ - isDownloadable: boolean; - /** - * A description of the product. - */ - localizedDescription: string; - /** - * The name of the product. - */ - localizedTitle: string; - /** - * The cost of the product in the local currency. - */ - price: number; - /** - * The string that identifies the product to the Apple App Store. - */ - productIdentifier: string; - } - - interface Protocol { - - // Docs: https://electronjs.org/docs/api/protocol - - /** - * Whether the protocol was successfully intercepted - * - * Intercepts `scheme` protocol and uses `handler` as the protocol's new handler - * which sends a `Buffer` as a response. - */ - interceptBufferProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (Buffer) | (ProtocolResponse)) => void) => void): boolean; - /** - * Whether the protocol was successfully intercepted - * - * Intercepts `scheme` protocol and uses `handler` as the protocol's new handler - * which sends a file as a response. - */ - interceptFileProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (string) | (ProtocolResponse)) => void) => void): boolean; - /** - * Whether the protocol was successfully intercepted - * - * Intercepts `scheme` protocol and uses `handler` as the protocol's new handler - * which sends a new HTTP request as a response. - */ - interceptHttpProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: ProtocolResponse) => void) => void): boolean; - /** - * Whether the protocol was successfully intercepted - * - * Same as `protocol.registerStreamProtocol`, except that it replaces an existing - * protocol handler. - */ - interceptStreamProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (NodeJS.ReadableStream) | (ProtocolResponse)) => void) => void): boolean; - /** - * Whether the protocol was successfully intercepted - * - * Intercepts `scheme` protocol and uses `handler` as the protocol's new handler - * which sends a `String` as a response. - */ - interceptStringProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (string) | (ProtocolResponse)) => void) => void): boolean; - /** - * Whether `scheme` is already intercepted. - */ - isProtocolIntercepted(scheme: string): boolean; - /** - * Whether `scheme` is already registered. - */ - isProtocolRegistered(scheme: string): boolean; - /** - * Whether the protocol was successfully registered - * - * Registers a protocol of `scheme` that will send a `Buffer` as a response. - * - * The usage is the same with `registerFileProtocol`, except that the `callback` - * should be called with either a `Buffer` object or an object that has the `data` - * property. - -Example: - */ - registerBufferProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (Buffer) | (ProtocolResponse)) => void) => void): boolean; - /** - * Whether the protocol was successfully registered - * - * Registers a protocol of `scheme` that will send a file as the response. The - * `handler` will be called with `request` and `callback` where `request` is an - * incoming request for the `scheme`. - * - * To handle the `request`, the `callback` should be called with either the file's - * path or an object that has a `path` property, e.g. `callback(filePath)` or - * `callback({ path: filePath })`. The `filePath` must be an absolute path. - * - * By default the `scheme` is treated like `http:`, which is parsed differently - * from protocols that follow the "generic URI syntax" like `file:`. - */ - registerFileProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: (string) | (ProtocolResponse)) => void) => void): boolean; - /** - * Whether the protocol was successfully registered - * - * Registers a protocol of `scheme` that will send an HTTP request as a response. - * - * The usage is the same with `registerFileProtocol`, except that the `callback` - * should be called with an object that has the `url` property. - */ - registerHttpProtocol(scheme: string, handler: (request: ProtocolRequest, callback: (response: ProtocolResponse) => void) => void): boolean; - /** - * **Note:** This method can only be used before the `ready` event of the `app` - * module gets emitted and can be called only once. - * - * Registers the `scheme` as standard, secure, bypasses content security policy for - * resources, allows registering ServiceWorker, supports fetch API, and streaming - * video/audio. Specify a privilege with the value of `true` to enable the - * capability. - * - * An example of registering a privileged scheme, that bypasses Content Security - * Policy: - * - * A standard scheme adheres to what RFC 3986 calls generic URI syntax. For example - * `http` and `https` are standard schemes, while `file` is not. - * - * Registering a scheme as standard allows relative and absolute resources to be - * resolved correctly when served. Otherwise the scheme will behave like the `file` - * protocol, but without the ability to resolve relative URLs. - * - * For example when you load following page with custom protocol without - * registering it as standard scheme, the image will not be loaded because - * non-standard schemes can not recognize relative URLs: - * - * Registering a scheme as standard will allow access to files through the - * FileSystem API. Otherwise the renderer will throw a security error for the - * scheme. - * - * By default web storage apis (localStorage, sessionStorage, webSQL, indexedDB, - * cookies) are disabled for non standard schemes. So in general if you want to - * register a custom protocol to replace the `http` protocol, you have to register - * it as a standard scheme. - * - * Protocols that use streams (http and stream protocols) should set `stream: - * true`. The `
    `. - * - * By default a new `BrowserWindow` will be created for the `url`. - * - * Calling `event.preventDefault()` will prevent Electron from automatically - * creating a new `BrowserWindow`. If you call `event.preventDefault()` and - * manually create a new `BrowserWindow` then you must set `event.newGuest` to - * reference the new `BrowserWindow` instance, failing to do so may result in - * unexpected behavior. For example: - * - * @deprecated - */ - on(event: 'new-window', listener: (event: NewWindowWebContentsEvent, - url: string, - frameName: string, - /** - * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, - * `save-to-disk` and `other`. - */ - disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'), - /** - * The options which will be used for creating the new `BrowserWindow`. - */ - options: BrowserWindowConstructorOptions, - /** - * The non-standard features (features not handled by Chromium or Electron) given - * to `window.open()`. - */ - additionalFeatures: string[], - /** - * The referrer that will be passed to the new window. May or may not result in the - * `Referer` header being sent, depending on the referrer policy. - */ - referrer: Referrer, - /** - * The post data that will be sent to the new window, along with the appropriate - * headers that will be set. If no post data is to be sent, the value will be - * `null`. Only defined when the window is being created by a form that set - * `target=_blank`. - */ - postBody: PostBody) => void): this; - once(event: 'new-window', listener: (event: NewWindowWebContentsEvent, - url: string, - frameName: string, - /** - * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, - * `save-to-disk` and `other`. - */ - disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'), - /** - * The options which will be used for creating the new `BrowserWindow`. - */ - options: BrowserWindowConstructorOptions, - /** - * The non-standard features (features not handled by Chromium or Electron) given - * to `window.open()`. - */ - additionalFeatures: string[], - /** - * The referrer that will be passed to the new window. May or may not result in the - * `Referer` header being sent, depending on the referrer policy. - */ - referrer: Referrer, - /** - * The post data that will be sent to the new window, along with the appropriate - * headers that will be set. If no post data is to be sent, the value will be - * `null`. Only defined when the window is being created by a form that set - * `target=_blank`. - */ - postBody: PostBody) => void): this; - addListener(event: 'new-window', listener: (event: NewWindowWebContentsEvent, - url: string, - frameName: string, - /** - * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, - * `save-to-disk` and `other`. - */ - disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'), - /** - * The options which will be used for creating the new `BrowserWindow`. - */ - options: BrowserWindowConstructorOptions, - /** - * The non-standard features (features not handled by Chromium or Electron) given - * to `window.open()`. - */ - additionalFeatures: string[], - /** - * The referrer that will be passed to the new window. May or may not result in the - * `Referer` header being sent, depending on the referrer policy. - */ - referrer: Referrer, - /** - * The post data that will be sent to the new window, along with the appropriate - * headers that will be set. If no post data is to be sent, the value will be - * `null`. Only defined when the window is being created by a form that set - * `target=_blank`. - */ - postBody: PostBody) => void): this; - removeListener(event: 'new-window', listener: (event: NewWindowWebContentsEvent, - url: string, - frameName: string, - /** - * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, - * `save-to-disk` and `other`. - */ - disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'), - /** - * The options which will be used for creating the new `BrowserWindow`. - */ - options: BrowserWindowConstructorOptions, - /** - * The non-standard features (features not handled by Chromium or Electron) given - * to `window.open()`. - */ - additionalFeatures: string[], - /** - * The referrer that will be passed to the new window. May or may not result in the - * `Referer` header being sent, depending on the referrer policy. - */ - referrer: Referrer, - /** - * The post data that will be sent to the new window, along with the appropriate - * headers that will be set. If no post data is to be sent, the value will be - * `null`. Only defined when the window is being created by a form that set - * `target=_blank`. - */ - postBody: PostBody) => void): this; - /** - * Emitted when page receives favicon urls. - */ - on(event: 'page-favicon-updated', listener: (event: Event, - /** - * Array of URLs. - */ - favicons: string[]) => void): this; - once(event: 'page-favicon-updated', listener: (event: Event, - /** - * Array of URLs. - */ - favicons: string[]) => void): this; - addListener(event: 'page-favicon-updated', listener: (event: Event, - /** - * Array of URLs. - */ - favicons: string[]) => void): this; - removeListener(event: 'page-favicon-updated', listener: (event: Event, - /** - * Array of URLs. - */ - favicons: string[]) => void): this; - /** - * Fired when page title is set during navigation. `explicitSet` is false when - * title is synthesized from file url. - */ - on(event: 'page-title-updated', listener: (event: Event, - title: string, - explicitSet: boolean) => void): this; - once(event: 'page-title-updated', listener: (event: Event, - title: string, - explicitSet: boolean) => void): this; - addListener(event: 'page-title-updated', listener: (event: Event, - title: string, - explicitSet: boolean) => void): this; - removeListener(event: 'page-title-updated', listener: (event: Event, - title: string, - explicitSet: boolean) => void): this; - /** - * Emitted when a new frame is generated. Only the dirty area is passed in the - * buffer. - */ - on(event: 'paint', listener: (event: Event, - dirtyRect: Rectangle, - /** - * The image data of the whole frame. - */ - image: NativeImage) => void): this; - once(event: 'paint', listener: (event: Event, - dirtyRect: Rectangle, - /** - * The image data of the whole frame. - */ - image: NativeImage) => void): this; - addListener(event: 'paint', listener: (event: Event, - dirtyRect: Rectangle, - /** - * The image data of the whole frame. - */ - image: NativeImage) => void): this; - removeListener(event: 'paint', listener: (event: Event, - dirtyRect: Rectangle, - /** - * The image data of the whole frame. - */ - image: NativeImage) => void): this; - /** - * Emitted when a plugin process has crashed. - */ - on(event: 'plugin-crashed', listener: (event: Event, - name: string, - version: string) => void): this; - once(event: 'plugin-crashed', listener: (event: Event, - name: string, - version: string) => void): this; - addListener(event: 'plugin-crashed', listener: (event: Event, - name: string, - version: string) => void): this; - removeListener(event: 'plugin-crashed', listener: (event: Event, - name: string, - version: string) => void): this; - /** - * Emitted when the `WebContents` preferred size has changed. - * - * This event will only be emitted when `enablePreferredSizeMode` is set to `true` - * in `webPreferences`. - */ - on(event: 'preferred-size-changed', listener: (event: Event, - /** - * The minimum size needed to contain the layout of the document—without requiring - * scrolling. - */ - preferredSize: Size) => void): this; - once(event: 'preferred-size-changed', listener: (event: Event, - /** - * The minimum size needed to contain the layout of the document—without requiring - * scrolling. - */ - preferredSize: Size) => void): this; - addListener(event: 'preferred-size-changed', listener: (event: Event, - /** - * The minimum size needed to contain the layout of the document—without requiring - * scrolling. - */ - preferredSize: Size) => void): this; - removeListener(event: 'preferred-size-changed', listener: (event: Event, - /** - * The minimum size needed to contain the layout of the document—without requiring - * scrolling. - */ - preferredSize: Size) => void): this; - /** - * Emitted when the preload script `preloadPath` throws an unhandled exception - * `error`. - */ - on(event: 'preload-error', listener: (event: Event, - preloadPath: string, - error: Error) => void): this; - once(event: 'preload-error', listener: (event: Event, - preloadPath: string, - error: Error) => void): this; - addListener(event: 'preload-error', listener: (event: Event, - preloadPath: string, - error: Error) => void): this; - removeListener(event: 'preload-error', listener: (event: Event, - preloadPath: string, - error: Error) => void): this; - /** - * Emitted when `remote.getBuiltin()` is called in the renderer process. Calling - * `event.preventDefault()` will prevent the module from being returned. Custom - * value can be returned by setting `event.returnValue`. - * - * @deprecated - */ - on(event: 'remote-get-builtin', listener: (event: IpcMainEvent, - moduleName: string) => void): this; - once(event: 'remote-get-builtin', listener: (event: IpcMainEvent, - moduleName: string) => void): this; - addListener(event: 'remote-get-builtin', listener: (event: IpcMainEvent, - moduleName: string) => void): this; - removeListener(event: 'remote-get-builtin', listener: (event: IpcMainEvent, - moduleName: string) => void): this; - /** - * Emitted when `remote.getCurrentWebContents()` is called in the renderer process. - * Calling `event.preventDefault()` will prevent the object from being returned. - * Custom value can be returned by setting `event.returnValue`. - * - * @deprecated - */ - on(event: 'remote-get-current-web-contents', listener: (event: IpcMainEvent) => void): this; - once(event: 'remote-get-current-web-contents', listener: (event: IpcMainEvent) => void): this; - addListener(event: 'remote-get-current-web-contents', listener: (event: IpcMainEvent) => void): this; - removeListener(event: 'remote-get-current-web-contents', listener: (event: IpcMainEvent) => void): this; - /** - * Emitted when `remote.getCurrentWindow()` is called in the renderer process. - * Calling `event.preventDefault()` will prevent the object from being returned. - * Custom value can be returned by setting `event.returnValue`. - * - * @deprecated - */ - on(event: 'remote-get-current-window', listener: (event: IpcMainEvent) => void): this; - once(event: 'remote-get-current-window', listener: (event: IpcMainEvent) => void): this; - addListener(event: 'remote-get-current-window', listener: (event: IpcMainEvent) => void): this; - removeListener(event: 'remote-get-current-window', listener: (event: IpcMainEvent) => void): this; - /** - * Emitted when `remote.getGlobal()` is called in the renderer process. Calling - * `event.preventDefault()` will prevent the global from being returned. Custom - * value can be returned by setting `event.returnValue`. - * - * @deprecated - */ - on(event: 'remote-get-global', listener: (event: IpcMainEvent, - globalName: string) => void): this; - once(event: 'remote-get-global', listener: (event: IpcMainEvent, - globalName: string) => void): this; - addListener(event: 'remote-get-global', listener: (event: IpcMainEvent, - globalName: string) => void): this; - removeListener(event: 'remote-get-global', listener: (event: IpcMainEvent, - globalName: string) => void): this; - /** - * Emitted when `remote.require()` is called in the renderer process. Calling - * `event.preventDefault()` will prevent the module from being returned. Custom - * value can be returned by setting `event.returnValue`. - * - * @deprecated - */ - on(event: 'remote-require', listener: (event: IpcMainEvent, - moduleName: string) => void): this; - once(event: 'remote-require', listener: (event: IpcMainEvent, - moduleName: string) => void): this; - addListener(event: 'remote-require', listener: (event: IpcMainEvent, - moduleName: string) => void): this; - removeListener(event: 'remote-require', listener: (event: IpcMainEvent, - moduleName: string) => void): this; - /** - * Emitted when the renderer process unexpectedly disappears. This is normally - * because it was crashed or killed. - */ - on(event: 'render-process-gone', listener: (event: Event, - details: RenderProcessGoneDetails) => void): this; - once(event: 'render-process-gone', listener: (event: Event, - details: RenderProcessGoneDetails) => void): this; - addListener(event: 'render-process-gone', listener: (event: Event, - details: RenderProcessGoneDetails) => void): this; - removeListener(event: 'render-process-gone', listener: (event: Event, - details: RenderProcessGoneDetails) => void): this; - /** - * Emitted when the unresponsive web page becomes responsive again. - */ - on(event: 'responsive', listener: Function): this; - once(event: 'responsive', listener: Function): this; - addListener(event: 'responsive', listener: Function): this; - removeListener(event: 'responsive', listener: Function): this; - /** - * Emitted when bluetooth device needs to be selected on call to - * `navigator.bluetooth.requestDevice`. To use `navigator.bluetooth` api - * `webBluetooth` should be enabled. If `event.preventDefault` is not called, first - * available device will be selected. `callback` should be called with `deviceId` - * to be selected, passing empty string to `callback` will cancel the request. - */ - on(event: 'select-bluetooth-device', listener: (event: Event, - devices: BluetoothDevice[], - callback: (deviceId: string) => void) => void): this; - once(event: 'select-bluetooth-device', listener: (event: Event, - devices: BluetoothDevice[], - callback: (deviceId: string) => void) => void): this; - addListener(event: 'select-bluetooth-device', listener: (event: Event, - devices: BluetoothDevice[], - callback: (deviceId: string) => void) => void): this; - removeListener(event: 'select-bluetooth-device', listener: (event: Event, - devices: BluetoothDevice[], - callback: (deviceId: string) => void) => void): this; - /** - * Emitted when a client certificate is requested. - * -The usage is the same with the `select-client-certificate` event of `app`. - */ - on(event: 'select-client-certificate', listener: (event: Event, - url: string, - certificateList: Certificate[], - callback: (certificate: Certificate) => void) => void): this; - once(event: 'select-client-certificate', listener: (event: Event, - url: string, - certificateList: Certificate[], - callback: (certificate: Certificate) => void) => void): this; - addListener(event: 'select-client-certificate', listener: (event: Event, - url: string, - certificateList: Certificate[], - callback: (certificate: Certificate) => void) => void): this; - removeListener(event: 'select-client-certificate', listener: (event: Event, - url: string, - certificateList: Certificate[], - callback: (certificate: Certificate) => void) => void): this; - /** - * Emitted when the web page becomes unresponsive. - */ - on(event: 'unresponsive', listener: Function): this; - once(event: 'unresponsive', listener: Function): this; - addListener(event: 'unresponsive', listener: Function): this; - removeListener(event: 'unresponsive', listener: Function): this; - /** - * Emitted when mouse moves over a link or the keyboard moves the focus to a link. - */ - on(event: 'update-target-url', listener: (event: Event, - url: string) => void): this; - once(event: 'update-target-url', listener: (event: Event, - url: string) => void): this; - addListener(event: 'update-target-url', listener: (event: Event, - url: string) => void): this; - removeListener(event: 'update-target-url', listener: (event: Event, - url: string) => void): this; - /** - * Emitted when a ``'s web contents is being attached to this web - * contents. Calling `event.preventDefault()` will destroy the guest page. - * - * This event can be used to configure `webPreferences` for the `webContents` of a - * `` before it's loaded, and provides the ability to set settings that - * can't be set via `` attributes. - * - * **Note:** The specified `preload` script option will appear as `preloadURL` (not - * `preload`) in the `webPreferences` object emitted with this event. - */ - on(event: 'will-attach-webview', listener: (event: Event, - /** - * The web preferences that will be used by the guest page. This object can be - * modified to adjust the preferences for the guest page. - */ - webPreferences: WebPreferences, - /** - * The other `` parameters such as the `src` URL. This object can be - * modified to adjust the parameters of the guest page. - */ - params: Record) => void): this; - once(event: 'will-attach-webview', listener: (event: Event, - /** - * The web preferences that will be used by the guest page. This object can be - * modified to adjust the preferences for the guest page. - */ - webPreferences: WebPreferences, - /** - * The other `` parameters such as the `src` URL. This object can be - * modified to adjust the parameters of the guest page. - */ - params: Record) => void): this; - addListener(event: 'will-attach-webview', listener: (event: Event, - /** - * The web preferences that will be used by the guest page. This object can be - * modified to adjust the preferences for the guest page. - */ - webPreferences: WebPreferences, - /** - * The other `` parameters such as the `src` URL. This object can be - * modified to adjust the parameters of the guest page. - */ - params: Record) => void): this; - removeListener(event: 'will-attach-webview', listener: (event: Event, - /** - * The web preferences that will be used by the guest page. This object can be - * modified to adjust the preferences for the guest page. - */ - webPreferences: WebPreferences, - /** - * The other `` parameters such as the `src` URL. This object can be - * modified to adjust the parameters of the guest page. - */ - params: Record) => void): this; - /** - * Emitted when a user or the page wants to start navigation. It can happen when - * the `window.location` object is changed or a user clicks a link in the page. - * - * This event will not emit when the navigation is started programmatically with - * APIs like `webContents.loadURL` and `webContents.back`. - * - * It is also not emitted for in-page navigations, such as clicking anchor links or - * updating the `window.location.hash`. Use `did-navigate-in-page` event for this - * purpose. - -Calling `event.preventDefault()` will prevent the navigation. - */ - on(event: 'will-navigate', listener: (event: Event, - url: string) => void): this; - once(event: 'will-navigate', listener: (event: Event, - url: string) => void): this; - addListener(event: 'will-navigate', listener: (event: Event, - url: string) => void): this; - removeListener(event: 'will-navigate', listener: (event: Event, - url: string) => void): this; - /** - * Emitted when a `beforeunload` event handler is attempting to cancel a page - * unload. - * - * Calling `event.preventDefault()` will ignore the `beforeunload` event handler - * and allow the page to be unloaded. - */ - on(event: 'will-prevent-unload', listener: (event: Event) => void): this; - once(event: 'will-prevent-unload', listener: (event: Event) => void): this; - addListener(event: 'will-prevent-unload', listener: (event: Event) => void): this; - removeListener(event: 'will-prevent-unload', listener: (event: Event) => void): this; - /** - * Emitted as a server side redirect occurs during navigation. For example a 302 - * redirect. - * - * This event will be emitted after `did-start-navigation` and always before the - * `did-redirect-navigation` event for the same navigation. - * - * Calling `event.preventDefault()` will prevent the navigation (not just the - * redirect). - */ - on(event: 'will-redirect', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - once(event: 'will-redirect', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - addListener(event: 'will-redirect', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - removeListener(event: 'will-redirect', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - /** - * Emitted when the user is requesting to change the zoom level using the mouse - * wheel. - */ - on(event: 'zoom-changed', listener: (event: Event, - /** - * Can be `in` or `out`. - */ - zoomDirection: ('in' | 'out')) => void): this; - once(event: 'zoom-changed', listener: (event: Event, - /** - * Can be `in` or `out`. - */ - zoomDirection: ('in' | 'out')) => void): this; - addListener(event: 'zoom-changed', listener: (event: Event, - /** - * Can be `in` or `out`. - */ - zoomDirection: ('in' | 'out')) => void): this; - removeListener(event: 'zoom-changed', listener: (event: Event, - /** - * Can be `in` or `out`. - */ - zoomDirection: ('in' | 'out')) => void): this; - /** - * Adds the specified path to DevTools workspace. Must be used after DevTools - * creation: - */ - addWorkSpace(path: string): void; - /** - * Begin subscribing for presentation events and captured frames, the `callback` - * will be called with `callback(image, dirtyRect)` when there is a presentation - * event. - * - * The `image` is an instance of NativeImage that stores the captured frame. - * - * The `dirtyRect` is an object with `x, y, width, height` properties that - * describes which part of the page was repainted. If `onlyDirty` is set to `true`, - * `image` will only contain the repainted area. `onlyDirty` defaults to `false`. - */ - beginFrameSubscription(onlyDirty: boolean, callback: (image: NativeImage, dirtyRect: Rectangle) => void): void; - /** - * Begin subscribing for presentation events and captured frames, the `callback` - * will be called with `callback(image, dirtyRect)` when there is a presentation - * event. - * - * The `image` is an instance of NativeImage that stores the captured frame. - * - * The `dirtyRect` is an object with `x, y, width, height` properties that - * describes which part of the page was repainted. If `onlyDirty` is set to `true`, - * `image` will only contain the repainted area. `onlyDirty` defaults to `false`. - */ - beginFrameSubscription(callback: (image: NativeImage, dirtyRect: Rectangle) => void): void; - /** - * Whether the browser can go back to previous web page. - */ - canGoBack(): boolean; - /** - * Whether the browser can go forward to next web page. - */ - canGoForward(): boolean; - /** - * Whether the web page can go to `offset`. - */ - canGoToOffset(offset: number): boolean; - /** - * Resolves with a NativeImage - * - * Captures a snapshot of the page within `rect`. Omitting `rect` will capture the - * whole visible page. - */ - capturePage(rect?: Rectangle): Promise; - /** - * Clears the navigation history. - */ - clearHistory(): void; - /** - * Closes the devtools. - */ - closeDevTools(): void; - /** - * Executes the editing command `copy` in web page. - */ - copy(): void; - /** - * Copy the image at the given position to the clipboard. - */ - copyImageAt(x: number, y: number): void; - /** - * Executes the editing command `cut` in web page. - */ - cut(): void; - /** - * Decrease the capturer count by one. The page will be set to hidden or occluded - * state when its browser window is hidden or occluded and the capturer count - * reaches zero. If you want to decrease the hidden capturer count instead you - * should set `stayHidden` to true. - */ - decrementCapturerCount(stayHidden?: boolean): void; - /** - * Executes the editing command `delete` in web page. - */ - delete(): void; - /** - * Disable device emulation enabled by `webContents.enableDeviceEmulation`. - */ - disableDeviceEmulation(): void; - /** - * Initiates a download of the resource at `url` without navigating. The - * `will-download` event of `session` will be triggered. - */ - downloadURL(url: string): void; - /** - * Enable device emulation with the given parameters. - */ - enableDeviceEmulation(parameters: Parameters): void; - /** - * End subscribing for frame presentation events. - */ - endFrameSubscription(): void; - /** - * A promise that resolves with the result of the executed code or is rejected if - * the result of the code is a rejected promise. - * - * Evaluates `code` in page. - * - * In the browser window some HTML APIs like `requestFullScreen` can only be - * invoked by a gesture from the user. Setting `userGesture` to `true` will remove - * this limitation. - -Code execution will be suspended until web page stop loading. - */ - executeJavaScript(code: string, userGesture?: boolean): Promise; - /** - * A promise that resolves with the result of the executed code or is rejected if - * the result of the code is a rejected promise. - * -Works like `executeJavaScript` but evaluates `scripts` in an isolated context. - */ - executeJavaScriptInIsolatedWorld(worldId: number, scripts: WebSource[], userGesture?: boolean): Promise; - /** - * The request id used for the request. - * - * Starts a request to find all matches for the `text` in the web page. The result - * of the request can be obtained by subscribing to `found-in-page` event. - */ - findInPage(text: string, options?: FindInPageOptions): number; - /** - * Focuses the web page. - */ - focus(): void; - /** - * Forcefully terminates the renderer process that is currently hosting this - * `webContents`. This will cause the `render-process-gone` event to be emitted - * with the `reason=killed || reason=crashed`. Please note that some webContents - * share renderer processes and therefore calling this method may also crash the - * host process for other webContents as well. - * - * Calling `reload()` immediately after calling this method will force the reload - * to occur in a new process. This should be used when this process is unstable or - * unusable, for instance in order to recover from the `unresponsive` event. - */ - forcefullyCrashRenderer(): void; - /** - * Information about all Shared Workers. - */ - getAllSharedWorkers(): SharedWorkerInfo[]; - /** - * whether or not this WebContents will throttle animations and timers when the - * page becomes backgrounded. This also affects the Page Visibility API. - */ - getBackgroundThrottling(): boolean; - /** - * If *offscreen rendering* is enabled returns the current frame rate. - */ - getFrameRate(): number; - /** - * The operating system `pid` of the associated renderer process. - */ - getOSProcessId(): number; - /** - * Get the system printer list. - */ - getPrinters(): PrinterInfo[]; - /** - * The Chromium internal `pid` of the associated renderer. Can be compared to the - * `frameProcessId` passed by frame specific navigation events (e.g. - * `did-frame-navigate`) - */ - getProcessId(): number; - /** - * The title of the current web page. - */ - getTitle(): string; - /** - * the type of the webContent. Can be `backgroundPage`, `window`, `browserView`, - * `remote`, `webview` or `offscreen`. - */ - getType(): ('backgroundPage' | 'window' | 'browserView' | 'remote' | 'webview' | 'offscreen'); - /** - * The URL of the current web page. - */ - getURL(): string; - /** - * The user agent for this web page. - */ - getUserAgent(): string; - /** - * Returns the WebRTC IP Handling Policy. - */ - getWebRTCIPHandlingPolicy(): string; - /** - * the current zoom factor. - */ - getZoomFactor(): number; - /** - * the current zoom level. - */ - getZoomLevel(): number; - /** - * Makes the browser go back a web page. - */ - goBack(): void; - /** - * Makes the browser go forward a web page. - */ - goForward(): void; - /** - * Navigates browser to the specified absolute web page index. - */ - goToIndex(index: number): void; - /** - * Navigates to the specified offset from the "current entry". - */ - goToOffset(offset: number): void; - /** - * Increase the capturer count by one. The page is considered visible when its - * browser window is hidden and the capturer count is non-zero. If you would like - * the page to stay hidden, you should ensure that `stayHidden` is set to true. - * -This also affects the Page Visibility API. - */ - incrementCapturerCount(size?: Size, stayHidden?: boolean): void; - /** - * A promise that resolves with a key for the inserted CSS that can later be used - * to remove the CSS via `contents.removeInsertedCSS(key)`. - * - * Injects CSS into the current web page and returns a unique key for the inserted - * stylesheet. - */ - insertCSS(css: string, options?: InsertCSSOptions): Promise; - /** - * Inserts `text` to the focused element. - */ - insertText(text: string): Promise; - /** - * Starts inspecting element at position (`x`, `y`). - */ - inspectElement(x: number, y: number): void; - /** - * Opens the developer tools for the service worker context. - */ - inspectServiceWorker(): void; - /** - * Opens the developer tools for the shared worker context. - */ - inspectSharedWorker(): void; - /** - * Inspects the shared worker based on its ID. - */ - inspectSharedWorkerById(workerId: string): void; - /** - * Schedules a full repaint of the window this web contents is in. - * - * If *offscreen rendering* is enabled invalidates the frame and generates a new - * one through the `'paint'` event. - */ - invalidate(): void; - /** - * Whether this page has been muted. - */ - isAudioMuted(): boolean; - /** - * Whether this page is being captured. It returns true when the capturer count is - * large then 0. - */ - isBeingCaptured(): boolean; - /** - * Whether the renderer process has crashed. - */ - isCrashed(): boolean; - /** - * Whether audio is currently playing. - */ - isCurrentlyAudible(): boolean; - /** - * Whether the web page is destroyed. - */ - isDestroyed(): boolean; - /** - * Whether the devtools view is focused . - */ - isDevToolsFocused(): boolean; - /** - * Whether the devtools is opened. - */ - isDevToolsOpened(): boolean; - /** - * Whether the web page is focused. - */ - isFocused(): boolean; - /** - * Whether web page is still loading resources. - */ - isLoading(): boolean; - /** - * Whether the main frame (and not just iframes or frames within it) is still - * loading. - */ - isLoadingMainFrame(): boolean; - /** - * Indicates whether *offscreen rendering* is enabled. - */ - isOffscreen(): boolean; - /** - * If *offscreen rendering* is enabled returns whether it is currently painting. - */ - isPainting(): boolean; - /** - * Whether the web page is waiting for a first-response from the main resource of - * the page. - */ - isWaitingForResponse(): boolean; - /** - * the promise will resolve when the page has finished loading (see - * `did-finish-load`), and rejects if the page fails to load (see `did-fail-load`). - * - * Loads the given file in the window, `filePath` should be a path to an HTML file - * relative to the root of your application. For instance an app structure like - * this: - -Would require code like this - */ - loadFile(filePath: string, options?: LoadFileOptions): Promise; - /** - * the promise will resolve when the page has finished loading (see - * `did-finish-load`), and rejects if the page fails to load (see `did-fail-load`). - * A noop rejection handler is already attached, which avoids unhandled rejection - * errors. - * - * Loads the `url` in the window. The `url` must contain the protocol prefix, e.g. - * the `http://` or `file://`. If the load should bypass http cache then use the - * `pragma` header to achieve it. - */ - loadURL(url: string, options?: LoadURLOptions): Promise; - /** - * Opens the devtools. - * - * When `contents` is a `` tag, the `mode` would be `detach` by default, - * explicitly passing an empty `mode` can force using last used dock state. - */ - openDevTools(options?: OpenDevToolsOptions): void; - /** - * Executes the editing command `paste` in web page. - */ - paste(): void; - /** - * Executes the editing command `pasteAndMatchStyle` in web page. - */ - pasteAndMatchStyle(): void; - /** - * Send a message to the renderer process, optionally transferring ownership of - * zero or more [`MessagePortMain`][] objects. - * - * The transferred `MessagePortMain` objects will be available in the renderer - * process by accessing the `ports` property of the emitted event. When they arrive - * in the renderer, they will be native DOM `MessagePort` objects. - -For example: - */ - postMessage(channel: string, message: any, transfer?: MessagePortMain[]): void; - /** - * When a custom `pageSize` is passed, Chromium attempts to validate platform - * specific minimum values for `width_microns` and `height_microns`. Width and - * height must both be minimum 353 microns but may be higher on some operating - * systems. - * - * Prints window's web page. When `silent` is set to `true`, Electron will pick the - * system's default printer if `deviceName` is empty and the default settings for - * printing. - * - * Use `page-break-before: always;` CSS style to force to print to a new page. - * -Example usage: - */ - print(options?: WebContentsPrintOptions, callback?: (success: boolean, failureReason: string) => void): void; - /** - * Resolves with the generated PDF data. - * - * Prints window's web page as PDF with Chromium's preview printing custom - * settings. - * - * The `landscape` will be ignored if `@page` CSS at-rule is used in the web page. - * - * By default, an empty `options` will be regarded as: - * - * Use `page-break-before: always; ` CSS style to force to print to a new page. - * -An example of `webContents.printToPDF`: - */ - printToPDF(options: PrintToPDFOptions): Promise; - /** - * Executes the editing command `redo` in web page. - */ - redo(): void; - /** - * Reloads the current web page. - */ - reload(): void; - /** - * Reloads current page and ignores cache. - */ - reloadIgnoringCache(): void; - /** - * Resolves if the removal was successful. - * - * Removes the inserted CSS from the current web page. The stylesheet is identified - * by its key, which is returned from `contents.insertCSS(css)`. - */ - removeInsertedCSS(key: string): Promise; - /** - * Removes the specified path from DevTools workspace. - */ - removeWorkSpace(path: string): void; - /** - * Executes the editing command `replace` in web page. - */ - replace(text: string): void; - /** - * Executes the editing command `replaceMisspelling` in web page. - */ - replaceMisspelling(text: string): void; - /** - * resolves if the page is saved. - */ - savePage(fullPath: string, saveType: 'HTMLOnly' | 'HTMLComplete' | 'MHTML'): Promise; - /** - * Executes the editing command `selectAll` in web page. - */ - selectAll(): void; - /** - * Send an asynchronous message to the renderer process via `channel`, along with - * arguments. Arguments will be serialized with the Structured Clone Algorithm, - * just like `postMessage`, so prototype chains will not be included. Sending - * Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. - * - * > **NOTE**: Sending non-standard JavaScript types such as DOM objects or special - * Electron objects will throw an exception. - * - * The renderer process can handle the message by listening to `channel` with the - * `ipcRenderer` module. - * -An example of sending messages from the main process to the renderer process: - */ - send(channel: string, ...args: any[]): void; - /** - * Sends an input `event` to the page. **Note:** The `BrowserWindow` containing the - * contents needs to be focused for `sendInputEvent()` to work. - */ - sendInputEvent(inputEvent: (MouseInputEvent) | (MouseWheelInputEvent) | (KeyboardInputEvent)): void; - /** - * Send an asynchronous message to a specific frame in a renderer process via - * `channel`, along with arguments. Arguments will be serialized with the - * Structured Clone Algorithm, just like `postMessage`, so prototype chains will - * not be included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets - * will throw an exception. - * - * > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special - * Electron objects will throw an exception. - * - * The renderer process can handle the message by listening to `channel` with the - * `ipcRenderer` module. - * - * If you want to get the `frameId` of a given renderer context you should use the - * `webFrame.routingId` value. E.g. - * -You can also read `frameId` from all incoming IPC messages in the main process. - */ - sendToFrame(frameId: (number) | ([number, number]), channel: string, ...args: any[]): void; - /** - * Mute the audio on the current web page. - */ - setAudioMuted(muted: boolean): void; - /** - * Controls whether or not this WebContents will throttle animations and timers - * when the page becomes backgrounded. This also affects the Page Visibility API. - */ - setBackgroundThrottling(allowed: boolean): void; - /** - * Uses the `devToolsWebContents` as the target `WebContents` to show devtools. - * - * The `devToolsWebContents` must not have done any navigation, and it should not - * be used for other purposes after the call. - * - * By default Electron manages the devtools by creating an internal `WebContents` - * with native view, which developers have very limited control of. With the - * `setDevToolsWebContents` method, developers can use any `WebContents` to show - * the devtools in it, including `BrowserWindow`, `BrowserView` and `` - * tag. - * - * Note that closing the devtools does not destroy the `devToolsWebContents`, it is - * caller's responsibility to destroy `devToolsWebContents`. - * - * An example of showing devtools in a `` tag: - * -An example of showing devtools in a `BrowserWindow`: - */ - setDevToolsWebContents(devToolsWebContents: WebContents): void; - /** - * If *offscreen rendering* is enabled sets the frame rate to the specified number. - * Only values between 1 and 240 are accepted. - */ - setFrameRate(fps: number): void; - /** - * Ignore application menu shortcuts while this web contents is focused. - */ - setIgnoreMenuShortcuts(ignore: boolean): void; - /** - * Overrides the user agent for this web page. - */ - setUserAgent(userAgent: string): void; - /** - * Sets the maximum and minimum pinch-to-zoom level. - * - * > **NOTE**: Visual zoom is disabled by default in Electron. To re-enable it, - * call: - */ - setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): Promise; - /** - * Setting the WebRTC IP handling policy allows you to control which IPs are - * exposed via WebRTC. See BrowserLeaks for more details. - */ - setWebRTCIPHandlingPolicy(policy: 'default' | 'default_public_interface_only' | 'default_public_and_private_interfaces' | 'disable_non_proxied_udp'): void; - /** - * Called before creating a window when `window.open()` is called from the - * renderer. See `window.open()` for more details and how to use this in - * conjunction with `did-create-window`. - */ - setWindowOpenHandler(handler: (details: HandlerDetails) => ({action: 'deny'}) | ({action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions})): void; - /** - * Changes the zoom factor to the specified factor. Zoom factor is zoom percent - * divided by 100, so 300% = 3.0. - -The factor must be greater than 0.0. - */ - setZoomFactor(factor: number): void; - /** - * Changes the zoom level to the specified level. The original size is 0 and each - * increment above or below represents zooming 20% larger or smaller to default - * limits of 300% and 50% of original size, respectively. The formula for this is - * `scale := 1.2 ^ level`. - * - * > **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that - * the zoom level for a specific domain propagates across all instances of windows - * with the same domain. Differentiating the window URLs will make zoom work - * per-window. - */ - setZoomLevel(level: number): void; - /** - * Shows pop-up dictionary that searches the selected word on the page. - * - * @platform darwin - */ - showDefinitionForSelection(): void; - /** - * Sets the `item` as dragging item for current drag-drop operation, `file` is the - * absolute path of the file to be dragged, and `icon` is the image showing under - * the cursor when dragging. - */ - startDrag(item: Item): void; - /** - * If *offscreen rendering* is enabled and not painting, start painting. - */ - startPainting(): void; - /** - * Stops any pending navigation. - */ - stop(): void; - /** - * Stops any `findInPage` request for the `webContents` with the provided `action`. - */ - stopFindInPage(action: 'clearSelection' | 'keepSelection' | 'activateSelection'): void; - /** - * If *offscreen rendering* is enabled and painting, stop painting. - */ - stopPainting(): void; - /** - * Indicates whether the snapshot has been created successfully. - * -Takes a V8 heap snapshot and saves it to `filePath`. - */ - takeHeapSnapshot(filePath: string): Promise; - /** - * Toggles the developer tools. - */ - toggleDevTools(): void; - /** - * Executes the editing command `undo` in web page. - */ - undo(): void; - /** - * Executes the editing command `unselect` in web page. - */ - unselect(): void; - audioMuted: boolean; - backgroundThrottling: boolean; - readonly debugger: Debugger; - readonly devToolsWebContents: (WebContents) | (null); - frameRate: number; - readonly hostWebContents: WebContents; - readonly id: number; - readonly mainFrame: WebFrameMain; - readonly session: Session; - userAgent: string; - zoomFactor: number; - zoomLevel: number; - } - - interface WebFrame extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/web-frame - - /** - * Attempts to free memory that is no longer being used (like images from a - * previous navigation). - * - * Note that blindly calling this method probably makes Electron slower since it - * will have to refill these emptied caches, you should only call it if an event in - * your app has occurred that makes you think your page is actually using less - * memory (i.e. you have navigated from a super heavy page to a mostly empty one, - * and intend to stay there). - */ - clearCache(): void; - /** - * A promise that resolves with the result of the executed code or is rejected if - * execution throws or results in a rejected promise. - * - * Evaluates `code` in page. - * - * In the browser window some HTML APIs like `requestFullScreen` can only be - * invoked by a gesture from the user. Setting `userGesture` to `true` will remove - * this limitation. - */ - executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any, error: Error) => void): Promise; - /** - * A promise that resolves with the result of the executed code or is rejected if - * execution could not start. - * - * Works like `executeJavaScript` but evaluates `scripts` in an isolated context. - * - * Note that when the execution of script fails, the returned promise will not - * reject and the `result` would be `undefined`. This is because Chromium does not - * dispatch errors of isolated worlds to foreign worlds. - */ - executeJavaScriptInIsolatedWorld(worldId: number, scripts: WebSource[], userGesture?: boolean, callback?: (result: any, error: Error) => void): Promise; - /** - * A child of `webFrame` with the supplied `name`, `null` would be returned if - * there's no such frame or if the frame is not in the current renderer process. - */ - findFrameByName(name: string): WebFrame; - /** - * that has the supplied `routingId`, `null` if not found. - */ - findFrameByRoutingId(routingId: number): WebFrame; - /** - * The frame element in `webFrame's` document selected by `selector`, `null` would - * be returned if `selector` does not select a frame or if the frame is not in the - * current renderer process. - */ - getFrameForSelector(selector: string): WebFrame; - /** - * * `images` MemoryUsageDetails - * * `scripts` MemoryUsageDetails - * * `cssStyleSheets` MemoryUsageDetails - * * `xslStyleSheets` MemoryUsageDetails - * * `fonts` MemoryUsageDetails - * * `other` MemoryUsageDetails - * - * Returns an object describing usage information of Blink's internal memory - * caches. - -This will generate: - */ - getResourceUsage(): ResourceUsage; - /** - * A list of suggested words for a given word. If the word is spelled correctly, - * the result will be empty. - */ - getWordSuggestions(word: string): string[]; - /** - * The current zoom factor. - */ - getZoomFactor(): number; - /** - * The current zoom level. - */ - getZoomLevel(): number; - /** - * A key for the inserted CSS that can later be used to remove the CSS via - * `webFrame.removeInsertedCSS(key)`. - * - * Injects CSS into the current web page and returns a unique key for the inserted - * stylesheet. - */ - insertCSS(css: string): string; - /** - * Inserts `text` to the focused element. - */ - insertText(text: string): void; - /** - * True if the word is misspelled according to the built in spellchecker, false - * otherwise. If no dictionary is loaded, always return false. - */ - isWordMisspelled(word: string): boolean; - /** - * Removes the inserted CSS from the current web page. The stylesheet is identified - * by its key, which is returned from `webFrame.insertCSS(css)`. - */ - removeInsertedCSS(key: string): void; - /** - * Set the security origin, content security policy and name of the isolated world. - * Note: If the `csp` is specified, then the `securityOrigin` also has to be - * specified. - */ - setIsolatedWorldInfo(worldId: number, info: Info): void; - /** - * Sets a provider for spell checking in input fields and text areas. - * - * If you want to use this method you must disable the builtin spellchecker when - * you construct the window. - * - * The `provider` must be an object that has a `spellCheck` method that accepts an - * array of individual words for spellchecking. The `spellCheck` function runs - * asynchronously and calls the `callback` function with an array of misspelt words - * when complete. - -An example of using node-spellchecker as provider: - */ - setSpellCheckProvider(language: string, provider: Provider): void; - /** - * Sets the maximum and minimum pinch-to-zoom level. - * - * > **NOTE**: Visual zoom is disabled by default in Electron. To re-enable it, - * call: - */ - setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; - /** - * Changes the zoom factor to the specified factor. Zoom factor is zoom percent - * divided by 100, so 300% = 3.0. - -The factor must be greater than 0.0. - */ - setZoomFactor(factor: number): void; - /** - * Changes the zoom level to the specified level. The original size is 0 and each - * increment above or below represents zooming 20% larger or smaller to default - * limits of 300% and 50% of original size, respectively. - * - * > **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that - * the zoom level for a specific domain propagates across all instances of windows - * with the same domain. Differentiating the window URLs will make zoom work - * per-window. - */ - setZoomLevel(level: number): void; - /** - * A `WebFrame | null` representing the first child frame of `webFrame`, the - * property would be `null` if `webFrame` has no children or if first child is not - * in the current renderer process. - * - */ - readonly firstChild: (WebFrame) | (null); - /** - * A `WebFrame | null` representing next sibling frame, the property would be - * `null` if `webFrame` is the last frame in its parent or if the next sibling is - * not in the current renderer process. - * - */ - readonly nextSibling: (WebFrame) | (null); - /** - * A `WebFrame | null` representing the frame which opened `webFrame`, the property - * would be `null` if there's no opener or opener is not in the current renderer - * process. - * - */ - readonly opener: (WebFrame) | (null); - /** - * A `WebFrame | null` representing parent frame of `webFrame`, the property would - * be `null` if `webFrame` is top or parent is not in the current renderer process. - * - */ - readonly parent: (WebFrame) | (null); - /** - * An `Integer` representing the unique frame id in the current renderer process. - * Distinct WebFrame instances that refer to the same underlying frame will have - * the same `routingId`. - * - */ - readonly routingId: number; - /** - * A `WebFrame | null` representing top frame in frame hierarchy to which - * `webFrame` belongs, the property would be `null` if top frame is not in the - * current renderer process. - * - */ - readonly top: (WebFrame) | (null); - } - - class WebFrameMain extends NodeEventEmitter { - - // Docs: https://electronjs.org/docs/api/web-frame-main - - /** - * A frame with the given process and routing IDs, or `undefined` if there is no - * WebFrameMain associated with the given IDs. - */ - static fromId(processId: number, routingId: number): (WebFrameMain) | (undefined); - /** - * A promise that resolves with the result of the executed code or is rejected if - * execution throws or results in a rejected promise. - * - * Evaluates `code` in page. - * - * In the browser window some HTML APIs like `requestFullScreen` can only be - * invoked by a gesture from the user. Setting `userGesture` to `true` will remove - * this limitation. - */ - executeJavaScript(code: string, userGesture?: boolean): Promise; - /** - * Send a message to the renderer process, optionally transferring ownership of - * zero or more [`MessagePortMain`][] objects. - * - * The transferred `MessagePortMain` objects will be available in the renderer - * process by accessing the `ports` property of the emitted event. When they arrive - * in the renderer, they will be native DOM `MessagePort` objects. - -For example: - */ - postMessage(channel: string, message: any, transfer?: MessagePortMain[]): void; - /** - * Whether the reload was initiated successfully. Only results in `false` when the - * frame has no history. - */ - reload(): boolean; - /** - * Send an asynchronous message to the renderer process via `channel`, along with - * arguments. Arguments will be serialized with the [Structured Clone - * Algorithm][SCA], just like [`postMessage`][], so prototype chains will not be - * included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw - * an exception. - * - * The renderer process can handle the message by listening to `channel` with the - * `ipcRenderer` module. - */ - send(channel: string, ...args: any[]): void; - readonly frames: WebFrameMain[]; - readonly framesInSubtree: WebFrameMain[]; - readonly frameTreeNodeId: number; - readonly name: string; - readonly osProcessId: number; - readonly parent: (WebFrameMain) | (null); - readonly processId: number; - readonly routingId: number; - readonly top: (WebFrameMain) | (null); - readonly url: string; - } - - class WebRequest { - - // Docs: https://electronjs.org/docs/api/web-request - - /** - * The `listener` will be called with `listener(details)` when a server initiated - * redirect is about to occur. - */ - onBeforeRedirect(filter: Filter, listener: ((details: OnBeforeRedirectListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` when a server initiated - * redirect is about to occur. - */ - onBeforeRedirect(listener: ((details: OnBeforeRedirectListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details, callback)` when a request - * is about to occur. - * - * The `uploadData` is an array of `UploadData` objects. - * - * The `callback` has to be called with an `response` object. - * -Some examples of valid `urls`: - */ - onBeforeRequest(filter: Filter, listener: ((details: OnBeforeRequestListenerDetails, callback: (response: Response) => void) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details, callback)` when a request - * is about to occur. - * - * The `uploadData` is an array of `UploadData` objects. - * - * The `callback` has to be called with an `response` object. - * -Some examples of valid `urls`: - */ - onBeforeRequest(listener: ((details: OnBeforeRequestListenerDetails, callback: (response: Response) => void) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details, callback)` before sending - * an HTTP request, once the request headers are available. This may occur after a - * TCP connection is made to the server, but before any http data is sent. - * -The `callback` has to be called with a `response` object. - */ - onBeforeSendHeaders(filter: Filter, listener: ((details: OnBeforeSendHeadersListenerDetails, callback: (beforeSendResponse: BeforeSendResponse) => void) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details, callback)` before sending - * an HTTP request, once the request headers are available. This may occur after a - * TCP connection is made to the server, but before any http data is sent. - * -The `callback` has to be called with a `response` object. - */ - onBeforeSendHeaders(listener: ((details: OnBeforeSendHeadersListenerDetails, callback: (beforeSendResponse: BeforeSendResponse) => void) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` when a request is - * completed. - */ - onCompleted(filter: Filter, listener: ((details: OnCompletedListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` when a request is - * completed. - */ - onCompleted(listener: ((details: OnCompletedListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` when an error occurs. - */ - onErrorOccurred(filter: Filter, listener: ((details: OnErrorOccurredListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` when an error occurs. - */ - onErrorOccurred(listener: ((details: OnErrorOccurredListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details, callback)` when HTTP - * response headers of a request have been received. - * -The `callback` has to be called with a `response` object. - */ - onHeadersReceived(filter: Filter, listener: ((details: OnHeadersReceivedListenerDetails, callback: (headersReceivedResponse: HeadersReceivedResponse) => void) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details, callback)` when HTTP - * response headers of a request have been received. - * -The `callback` has to be called with a `response` object. - */ - onHeadersReceived(listener: ((details: OnHeadersReceivedListenerDetails, callback: (headersReceivedResponse: HeadersReceivedResponse) => void) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` when first byte of the - * response body is received. For HTTP requests, this means that the status line - * and response headers are available. - */ - onResponseStarted(filter: Filter, listener: ((details: OnResponseStartedListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` when first byte of the - * response body is received. For HTTP requests, this means that the status line - * and response headers are available. - */ - onResponseStarted(listener: ((details: OnResponseStartedListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` just before a request is - * going to be sent to the server, modifications of previous `onBeforeSendHeaders` - * response are visible by the time this listener is fired. - */ - onSendHeaders(filter: Filter, listener: ((details: OnSendHeadersListenerDetails) => void) | (null)): void; - /** - * The `listener` will be called with `listener(details)` just before a request is - * going to be sent to the server, modifications of previous `onBeforeSendHeaders` - * response are visible by the time this listener is fired. - */ - onSendHeaders(listener: ((details: OnSendHeadersListenerDetails) => void) | (null)): void; - } - - interface WebSource { - - // Docs: https://electronjs.org/docs/api/structures/web-source - - code: string; - /** - * Default is 1. - */ - startLine?: number; - url?: string; - } - - interface WebviewTag extends HTMLElement { - - // Docs: https://electronjs.org/docs/api/webview-tag - - /** - * Fired when a load has committed. This includes navigation within the current - * document as well as subframe document-level loads, but does not include - * asynchronous resource loads. - */ - addEventListener(event: 'load-commit', listener: (event: LoadCommitEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'load-commit', listener: (event: LoadCommitEvent) => void): this; - /** - * Fired when the navigation is done, i.e. the spinner of the tab will stop - * spinning, and the `onload` event is dispatched. - */ - addEventListener(event: 'did-finish-load', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-finish-load', listener: (event: Event) => void): this; - /** - * This event is like `did-finish-load`, but fired when the load failed or was - * cancelled, e.g. `window.stop()` is invoked. - */ - addEventListener(event: 'did-fail-load', listener: (event: DidFailLoadEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-fail-load', listener: (event: DidFailLoadEvent) => void): this; - /** - * Fired when a frame has done navigation. - */ - addEventListener(event: 'did-frame-finish-load', listener: (event: DidFrameFinishLoadEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-frame-finish-load', listener: (event: DidFrameFinishLoadEvent) => void): this; - /** - * Corresponds to the points in time when the spinner of the tab starts spinning. - */ - addEventListener(event: 'did-start-loading', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-start-loading', listener: (event: Event) => void): this; - /** - * Corresponds to the points in time when the spinner of the tab stops spinning. - */ - addEventListener(event: 'did-stop-loading', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-stop-loading', listener: (event: Event) => void): this; - /** - * Fired when document in the given frame is loaded. - */ - addEventListener(event: 'dom-ready', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'dom-ready', listener: (event: Event) => void): this; - /** - * Fired when page title is set during navigation. `explicitSet` is false when - * title is synthesized from file url. - */ - addEventListener(event: 'page-title-updated', listener: (event: PageTitleUpdatedEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'page-title-updated', listener: (event: PageTitleUpdatedEvent) => void): this; - /** - * Fired when page receives favicon urls. - */ - addEventListener(event: 'page-favicon-updated', listener: (event: PageFaviconUpdatedEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'page-favicon-updated', listener: (event: PageFaviconUpdatedEvent) => void): this; - /** - * Fired when page enters fullscreen triggered by HTML API. - */ - addEventListener(event: 'enter-html-full-screen', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'enter-html-full-screen', listener: (event: Event) => void): this; - /** - * Fired when page leaves fullscreen triggered by HTML API. - */ - addEventListener(event: 'leave-html-full-screen', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'leave-html-full-screen', listener: (event: Event) => void): this; - /** - * Fired when the guest window logs a console message. - * - * The following example code forwards all log messages to the embedder's console - * without regard for log level or other properties. - */ - addEventListener(event: 'console-message', listener: (event: ConsoleMessageEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'console-message', listener: (event: ConsoleMessageEvent) => void): this; - /** - * Fired when a result is available for `webview.findInPage` request. - */ - addEventListener(event: 'found-in-page', listener: (event: FoundInPageEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'found-in-page', listener: (event: FoundInPageEvent) => void): this; - /** - * Fired when the guest page attempts to open a new browser window. - * -The following example code opens the new url in system's default browser. - */ - addEventListener(event: 'new-window', listener: (event: NewWindowEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'new-window', listener: (event: NewWindowEvent) => void): this; - /** - * Emitted when a user or the page wants to start navigation. It can happen when - * the `window.location` object is changed or a user clicks a link in the page. - * - * This event will not emit when the navigation is started programmatically with - * APIs like `.loadURL` and `.back`. - * - * It is also not emitted during in-page navigation, such as clicking anchor links - * or updating the `window.location.hash`. Use `did-navigate-in-page` event for - * this purpose. - -Calling `event.preventDefault()` does __NOT__ have any effect. - */ - addEventListener(event: 'will-navigate', listener: (event: WillNavigateEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'will-navigate', listener: (event: WillNavigateEvent) => void): this; - /** - * Emitted when a navigation is done. - * - * This event is not emitted for in-page navigations, such as clicking anchor links - * or updating the `window.location.hash`. Use `did-navigate-in-page` event for - * this purpose. - */ - addEventListener(event: 'did-navigate', listener: (event: DidNavigateEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-navigate', listener: (event: DidNavigateEvent) => void): this; - /** - * Emitted when an in-page navigation happened. - * - * When in-page navigation happens, the page URL changes but does not cause - * navigation outside of the page. Examples of this occurring are when anchor links - * are clicked or when the DOM `hashchange` event is triggered. - */ - addEventListener(event: 'did-navigate-in-page', listener: (event: DidNavigateInPageEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-navigate-in-page', listener: (event: DidNavigateInPageEvent) => void): this; - /** - * Fired when the guest page attempts to close itself. - * - * The following example code navigates the `webview` to `about:blank` when the - * guest attempts to close itself. - */ - addEventListener(event: 'close', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'close', listener: (event: Event) => void): this; - /** - * Fired when the guest page has sent an asynchronous message to embedder page. - * - * With `sendToHost` method and `ipc-message` event you can communicate between - * guest page and embedder page: - */ - addEventListener(event: 'ipc-message', listener: (event: IpcMessageEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'ipc-message', listener: (event: IpcMessageEvent) => void): this; - /** - * Fired when the renderer process is crashed. - */ - addEventListener(event: 'crashed', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'crashed', listener: (event: Event) => void): this; - /** - * Fired when a plugin process is crashed. - */ - addEventListener(event: 'plugin-crashed', listener: (event: PluginCrashedEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'plugin-crashed', listener: (event: PluginCrashedEvent) => void): this; - /** - * Fired when the WebContents is destroyed. - */ - addEventListener(event: 'destroyed', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'destroyed', listener: (event: Event) => void): this; - /** - * Emitted when media starts playing. - */ - addEventListener(event: 'media-started-playing', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'media-started-playing', listener: (event: Event) => void): this; - /** - * Emitted when media is paused or done playing. - */ - addEventListener(event: 'media-paused', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'media-paused', listener: (event: Event) => void): this; - /** - * Emitted when a page's theme color changes. This is usually due to encountering a - * meta tag: - */ - addEventListener(event: 'did-change-theme-color', listener: (event: DidChangeThemeColorEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'did-change-theme-color', listener: (event: DidChangeThemeColorEvent) => void): this; - /** - * Emitted when mouse moves over a link or the keyboard moves the focus to a link. - */ - addEventListener(event: 'update-target-url', listener: (event: UpdateTargetUrlEvent) => void, useCapture?: boolean): this; - removeEventListener(event: 'update-target-url', listener: (event: UpdateTargetUrlEvent) => void): this; - /** - * Emitted when DevTools is opened. - */ - addEventListener(event: 'devtools-opened', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'devtools-opened', listener: (event: Event) => void): this; - /** - * Emitted when DevTools is closed. - */ - addEventListener(event: 'devtools-closed', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'devtools-closed', listener: (event: Event) => void): this; - /** - * Emitted when DevTools is focused / opened. - */ - addEventListener(event: 'devtools-focused', listener: (event: Event) => void, useCapture?: boolean): this; - removeEventListener(event: 'devtools-focused', listener: (event: Event) => void): this; - addEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - removeEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, useCapture?: boolean): void; - removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; - /** - * Whether the guest page can go back. - */ - canGoBack(): boolean; - /** - * Whether the guest page can go forward. - */ - canGoForward(): boolean; - /** - * Whether the guest page can go to `offset`. - */ - canGoToOffset(offset: number): boolean; - /** - * Resolves with a NativeImage - * - * Captures a snapshot of the page within `rect`. Omitting `rect` will capture the - * whole visible page. - */ - capturePage(rect?: Rectangle): Promise; - /** - * Clears the navigation history. - */ - clearHistory(): void; - /** - * Closes the DevTools window of guest page. - */ - closeDevTools(): void; - /** - * Executes editing command `copy` in page. - */ - copy(): void; - /** - * Executes editing command `cut` in page. - */ - cut(): void; - /** - * Executes editing command `delete` in page. - */ - delete(): void; - /** - * Initiates a download of the resource at `url` without navigating. - */ - downloadURL(url: string): void; - /** - * A promise that resolves with the result of the executed code or is rejected if - * the result of the code is a rejected promise. - * - * Evaluates `code` in page. If `userGesture` is set, it will create the user - * gesture context in the page. HTML APIs like `requestFullScreen`, which require - * user action, can take advantage of this option for automation. - */ - executeJavaScript(code: string, userGesture?: boolean): Promise; - /** - * The request id used for the request. - * - * Starts a request to find all matches for the `text` in the web page. The result - * of the request can be obtained by subscribing to `found-in-page` event. - */ - findInPage(text: string, options?: FindInPageOptions): number; - /** - * The title of guest page. - */ - getTitle(): string; - /** - * The URL of guest page. - */ - getURL(): string; - /** - * The user agent for guest page. - */ - getUserAgent(): string; - /** - * The WebContents ID of this `webview`. - */ - getWebContentsId(): number; - /** - * the current zoom factor. - */ - getZoomFactor(): number; - /** - * the current zoom level. - */ - getZoomLevel(): number; - /** - * Makes the guest page go back. - */ - goBack(): void; - /** - * Makes the guest page go forward. - */ - goForward(): void; - /** - * Navigates to the specified absolute index. - */ - goToIndex(index: number): void; - /** - * Navigates to the specified offset from the "current entry". - */ - goToOffset(offset: number): void; - /** - * A promise that resolves with a key for the inserted CSS that can later be used - * to remove the CSS via `.removeInsertedCSS(key)`. - * - * Injects CSS into the current web page and returns a unique key for the inserted - * stylesheet. - */ - insertCSS(css: string): Promise; - /** - * Inserts `text` to the focused element. - */ - insertText(text: string): Promise; - /** - * Starts inspecting element at position (`x`, `y`) of guest page. - */ - inspectElement(x: number, y: number): void; - /** - * Opens the DevTools for the service worker context present in the guest page. - */ - inspectServiceWorker(): void; - /** - * Opens the DevTools for the shared worker context present in the guest page. - */ - inspectSharedWorker(): void; - /** - * Whether guest page has been muted. - */ - isAudioMuted(): boolean; - /** - * Whether the renderer process has crashed. - */ - isCrashed(): boolean; - /** - * Whether audio is currently playing. - */ - isCurrentlyAudible(): boolean; - /** - * Whether DevTools window of guest page is focused. - */ - isDevToolsFocused(): boolean; - /** - * Whether guest page has a DevTools window attached. - */ - isDevToolsOpened(): boolean; - /** - * Whether guest page is still loading resources. - */ - isLoading(): boolean; - /** - * Whether the main frame (and not just iframes or frames within it) is still - * loading. - */ - isLoadingMainFrame(): boolean; - /** - * Whether the guest page is waiting for a first-response for the main resource of - * the page. - */ - isWaitingForResponse(): boolean; - /** - * The promise will resolve when the page has finished loading (see - * `did-finish-load`), and rejects if the page fails to load (see `did-fail-load`). - * - * Loads the `url` in the webview, the `url` must contain the protocol prefix, e.g. - * the `http://` or `file://`. - */ - loadURL(url: string, options?: LoadURLOptions): Promise; - /** - * Opens a DevTools window for guest page. - */ - openDevTools(): void; - /** - * Executes editing command `paste` in page. - */ - paste(): void; - /** - * Executes editing command `pasteAndMatchStyle` in page. - */ - pasteAndMatchStyle(): void; - /** - * Prints `webview`'s web page. Same as `webContents.print([options])`. - */ - print(options?: WebviewTagPrintOptions): Promise; - /** - * Resolves with the generated PDF data. - * -Prints `webview`'s web page as PDF, Same as `webContents.printToPDF(options)`. - */ - printToPDF(options: PrintToPDFOptions): Promise; - /** - * Executes editing command `redo` in page. - */ - redo(): void; - /** - * Reloads the guest page. - */ - reload(): void; - /** - * Reloads the guest page and ignores cache. - */ - reloadIgnoringCache(): void; - /** - * Resolves if the removal was successful. - * - * Removes the inserted CSS from the current web page. The stylesheet is identified - * by its key, which is returned from `.insertCSS(css)`. - */ - removeInsertedCSS(key: string): Promise; - /** - * Executes editing command `replace` in page. - */ - replace(text: string): void; - /** - * Executes editing command `replaceMisspelling` in page. - */ - replaceMisspelling(text: string): void; - /** - * Executes editing command `selectAll` in page. - */ - selectAll(): void; - /** - * Send an asynchronous message to renderer process via `channel`, you can also - * send arbitrary arguments. The renderer process can handle the message by - * listening to the `channel` event with the `ipcRenderer` module. - * -See webContents.send for examples. - */ - send(channel: string, ...args: any[]): Promise; - /** - * Sends an input `event` to the page. - * -See webContents.sendInputEvent for detailed description of `event` object. - */ - sendInputEvent(event: (MouseInputEvent) | (MouseWheelInputEvent) | (KeyboardInputEvent)): Promise; - /** - * Set guest page muted. - */ - setAudioMuted(muted: boolean): void; - /** - * Overrides the user agent for the guest page. - */ - setUserAgent(userAgent: string): void; - /** - * Sets the maximum and minimum pinch-to-zoom level. - */ - setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): Promise; - /** - * Changes the zoom factor to the specified factor. Zoom factor is zoom percent - * divided by 100, so 300% = 3.0. - */ - setZoomFactor(factor: number): void; - /** - * Changes the zoom level to the specified level. The original size is 0 and each - * increment above or below represents zooming 20% larger or smaller to default - * limits of 300% and 50% of original size, respectively. The formula for this is - * `scale := 1.2 ^ level`. - * - * > **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that - * the zoom level for a specific domain propagates across all instances of windows - * with the same domain. Differentiating the window URLs will make zoom work - * per-window. - */ - setZoomLevel(level: number): void; - /** - * Shows pop-up dictionary that searches the selected word on the page. - * - * @platform darwin - */ - showDefinitionForSelection(): void; - /** - * Stops any pending navigation. - */ - stop(): void; - /** - * Stops any `findInPage` request for the `webview` with the provided `action`. - */ - stopFindInPage(action: 'clearSelection' | 'keepSelection' | 'activateSelection'): void; - /** - * Executes editing command `undo` in page. - */ - undo(): void; - /** - * Executes editing command `unselect` in page. - */ - unselect(): void; - /** - * A `Boolean`. When this attribute is present the guest page will be allowed to - * open new windows. Popups are disabled by default. - */ - allowpopups: boolean; - /** - * A `String` which is a list of strings which specifies the blink features to be - * disabled separated by `,`. The full list of supported feature strings can be - * found in the RuntimeEnabledFeatures.json5 file. - */ - disableblinkfeatures: string; - /** - * A `Boolean`. When this attribute is present the guest page will have web - * security disabled. Web security is enabled by default. - */ - disablewebsecurity: boolean; - /** - * A `String` which is a list of strings which specifies the blink features to be - * enabled separated by `,`. The full list of supported feature strings can be - * found in the RuntimeEnabledFeatures.json5 file. - */ - enableblinkfeatures: string; - /** - * A `Boolean`. When this attribute is `false` the guest page in `webview` will not - * have access to the `remote` module. The remote module is unavailable by default. - */ - enableremotemodule: boolean; - /** - * A `String` that sets the referrer URL for the guest page. - */ - httpreferrer: string; - /** - * A `Boolean`. When this attribute is present the guest page in `webview` will - * have node integration and can use node APIs like `require` and `process` to - * access low level system resources. Node integration is disabled by default in - * the guest page. - */ - nodeintegration: boolean; - /** - * A `Boolean` for the experimental option for enabling NodeJS support in - * sub-frames such as iframes inside the `webview`. All your preloads will load for - * every iframe, you can use `process.isMainFrame` to determine if you are in the - * main frame or not. This option is disabled by default in the guest page. - */ - nodeintegrationinsubframes: boolean; - /** - * A `String` that sets the session used by the page. If `partition` starts with - * `persist:`, the page will use a persistent session available to all pages in the - * app with the same `partition`. if there is no `persist:` prefix, the page will - * use an in-memory session. By assigning the same `partition`, multiple pages can - * share the same session. If the `partition` is unset then default session of the - * app will be used. - * - * This value can only be modified before the first navigation, since the session - * of an active renderer process cannot change. Subsequent attempts to modify the - * value will fail with a DOM exception. - */ - partition: string; - /** - * A `Boolean`. When this attribute is present the guest page in `webview` will be - * able to use browser plugins. Plugins are disabled by default. - */ - plugins: boolean; - /** - * A `String` that specifies a script that will be loaded before other scripts run - * in the guest page. The protocol of script's URL must be either `file:` or - * `asar:`, because it will be loaded by `require` in guest page under the hood. - * - * When the guest page doesn't have node integration this script will still have - * access to all Node APIs, but global objects injected by Node will be deleted - * after this script has finished executing. - * - * **Note:** This option will appear as `preloadURL` (not `preload`) in the - * `webPreferences` specified to the `will-attach-webview` event. - */ - preload: string; - /** - * A `String` representing the visible URL. Writing to this attribute initiates - * top-level navigation. - * - * Assigning `src` its own value will reload the current page. - * - * The `src` attribute can also accept data URLs, such as `data:text/plain,Hello, - * world!`. - */ - src: string; - /** - * A `String` that sets the user agent for the guest page before the page is - * navigated to. Once the page is loaded, use the `setUserAgent` method to change - * the user agent. - */ - useragent: string; - /** - * A `String` which is a comma separated list of strings which specifies the web - * preferences to be set on the webview. The full list of supported preference - * strings can be found in BrowserWindow. - * - * The string follows the same format as the features string in `window.open`. A - * name by itself is given a `true` boolean value. A preference can be set to - * another value by including an `=`, followed by the value. Special values `yes` - * and `1` are interpreted as `true`, while `no` and `0` are interpreted as - * `false`. - */ - webpreferences: string; - } - - interface AboutPanelOptionsOptions { - /** - * The app's name. - */ - applicationName?: string; - /** - * The app's version. - */ - applicationVersion?: string; - /** - * Copyright information. - */ - copyright?: string; - /** - * The app's build version number. - * - * @platform darwin - */ - version?: string; - /** - * Credit information. - * - * @platform darwin,win32 - */ - credits?: string; - /** - * List of app authors. - * - * @platform linux - */ - authors?: string[]; - /** - * The app's website. - * - * @platform linux - */ - website?: string; - /** - * Path to the app's icon in a JPEG or PNG file format. On Linux, will be shown as - * 64x64 pixels while retaining aspect ratio. - * - * @platform linux,win32 - */ - iconPath?: string; - } - - interface AddRepresentationOptions { - /** - * The scale factor to add the image representation for. - */ - scaleFactor: number; - /** - * Defaults to 0. Required if a bitmap buffer is specified as `buffer`. - */ - width?: number; - /** - * Defaults to 0. Required if a bitmap buffer is specified as `buffer`. - */ - height?: number; - /** - * The buffer containing the raw image data. - */ - buffer?: Buffer; - /** - * The data URL containing either a base 64 encoded PNG or JPEG image. - */ - dataURL?: string; - } - - interface AnimationSettings { - /** - * Returns true if rich animations should be rendered. Looks at session type (e.g. - * remote desktop) and accessibility settings to give guidance for heavy - * animations. - */ - shouldRenderRichAnimation: boolean; - /** - * Determines on a per-platform basis whether scroll animations (e.g. produced by - * home/end key) should be enabled. - */ - scrollAnimationsEnabledBySystem: boolean; - /** - * Determines whether the user desires reduced motion based on platform APIs. - */ - prefersReducedMotion: boolean; - } - - interface AppDetailsOptions { - /** - * Window's App User Model ID. It has to be set, otherwise the other options will - * have no effect. - */ - appId?: string; - /** - * Window's Relaunch Icon. - */ - appIconPath?: string; - /** - * Index of the icon in `appIconPath`. Ignored when `appIconPath` is not set. - * Default is `0`. - */ - appIconIndex?: number; - /** - * Window's Relaunch Command. - */ - relaunchCommand?: string; - /** - * Window's Relaunch Display Name. - */ - relaunchDisplayName?: string; - } - - interface ApplicationInfoForProtocolReturnValue { - /** - * the display icon of the app handling the protocol. - */ - icon: NativeImage; - /** - * installation path of the app handling the protocol. - */ - path: string; - /** - * display name of the app handling the protocol. - */ - name: string; - } - - interface AuthenticationResponseDetails { - url: string; - } - - interface AuthInfo { - isProxy: boolean; - scheme: string; - host: string; - port: number; - realm: string; - } - - interface AutoResizeOptions { - /** - * If `true`, the view's width will grow and shrink together with the window. - * `false` by default. - */ - width?: boolean; - /** - * If `true`, the view's height will grow and shrink together with the window. - * `false` by default. - */ - height?: boolean; - /** - * If `true`, the view's x position and width will grow and shrink proportionally - * with the window. `false` by default. - */ - horizontal?: boolean; - /** - * If `true`, the view's y position and height will grow and shrink proportionally - * with the window. `false` by default. - */ - vertical?: boolean; - } - - interface BeforeSendResponse { - cancel?: boolean; - /** - * When provided, request will be made with these headers. - */ - requestHeaders?: Record; - } - - interface BitmapOptions { - /** - * Defaults to 1.0. - */ - scaleFactor?: number; - } - - interface BlinkMemoryInfo { - /** - * Size of all allocated objects in Kilobytes. - */ - allocated: number; - /** - * Size of all marked objects in Kilobytes. - */ - marked: number; - /** - * Total allocated space in Kilobytes. - */ - total: number; - } - - interface BrowserViewConstructorOptions { - /** - * See BrowserWindow. - */ - webPreferences?: WebPreferences; - } - - interface BrowserWindowConstructorOptions { - /** - * Window's width in pixels. Default is `800`. - */ - width?: number; - /** - * Window's height in pixels. Default is `600`. - */ - height?: number; - /** - * (**required** if y is used) Window's left offset from screen. Default is to - * center the window. - */ - x?: number; - /** - * (**required** if x is used) Window's top offset from screen. Default is to - * center the window. - */ - y?: number; - /** - * The `width` and `height` would be used as web page's size, which means the - * actual window's size will include window frame's size and be slightly larger. - * Default is `false`. - */ - useContentSize?: boolean; - /** - * Show window in the center of the screen. - */ - center?: boolean; - /** - * Window's minimum width. Default is `0`. - */ - minWidth?: number; - /** - * Window's minimum height. Default is `0`. - */ - minHeight?: number; - /** - * Window's maximum width. Default is no limit. - */ - maxWidth?: number; - /** - * Window's maximum height. Default is no limit. - */ - maxHeight?: number; - /** - * Whether window is resizable. Default is `true`. - */ - resizable?: boolean; - /** - * Whether window is movable. This is not implemented on Linux. Default is `true`. - */ - movable?: boolean; - /** - * Whether window is minimizable. This is not implemented on Linux. Default is - * `true`. - */ - minimizable?: boolean; - /** - * Whether window is maximizable. This is not implemented on Linux. Default is - * `true`. - */ - maximizable?: boolean; - /** - * Whether window is closable. This is not implemented on Linux. Default is `true`. - */ - closable?: boolean; - /** - * Whether the window can be focused. Default is `true`. On Windows setting - * `focusable: false` also implies setting `skipTaskbar: true`. On Linux setting - * `focusable: false` makes the window stop interacting with wm, so the window will - * always stay on top in all workspaces. - */ - focusable?: boolean; - /** - * Whether the window should always stay on top of other windows. Default is - * `false`. - */ - alwaysOnTop?: boolean; - /** - * Whether the window should show in fullscreen. When explicitly set to `false` the - * fullscreen button will be hidden or disabled on macOS. Default is `false`. - */ - fullscreen?: boolean; - /** - * Whether the window can be put into fullscreen mode. On macOS, also whether the - * maximize/zoom button should toggle full screen mode or maximize window. Default - * is `true`. - */ - fullscreenable?: boolean; - /** - * Use pre-Lion fullscreen on macOS. Default is `false`. - */ - simpleFullscreen?: boolean; - /** - * Whether to show the window in taskbar. Default is `false`. - */ - skipTaskbar?: boolean; - /** - * Whether the window is in kiosk mode. Default is `false`. - */ - kiosk?: boolean; - /** - * Default window title. Default is `"Electron"`. If the HTML tag `` is - * defined in the HTML file loaded by `loadURL()`, this property will be ignored. - */ - title?: string; - /** - * The window icon. On Windows it is recommended to use `ICO` icons to get best - * visual effects, you can also leave it undefined so the executable's icon will be - * used. - */ - icon?: (NativeImage) | (string); - /** - * Whether window should be shown when created. Default is `true`. - */ - show?: boolean; - /** - * Whether the renderer should be active when `show` is `false` and it has just - * been created. In order for `document.visibilityState` to work correctly on - * first load with `show: false` you should set this to `false`. Setting this to - * `false` will cause the `ready-to-show` event to not fire. Default is `true`. - */ - paintWhenInitiallyHidden?: boolean; - /** - * Specify `false` to create a Frameless Window. Default is `true`. - */ - frame?: boolean; - /** - * Specify parent window. Default is `null`. - */ - parent?: BrowserWindow; - /** - * Whether this is a modal window. This only works when the window is a child - * window. Default is `false`. - */ - modal?: boolean; - /** - * Whether the web view accepts a single mouse-down event that simultaneously - * activates the window. Default is `false`. - */ - acceptFirstMouse?: boolean; - /** - * Whether to hide cursor when typing. Default is `false`. - */ - disableAutoHideCursor?: boolean; - /** - * Auto hide the menu bar unless the `Alt` key is pressed. Default is `false`. - */ - autoHideMenuBar?: boolean; - /** - * Enable the window to be resized larger than screen. Only relevant for macOS, as - * other OSes allow larger-than-screen windows by default. Default is `false`. - */ - enableLargerThanScreen?: boolean; - /** - * Window's background color as a hexadecimal value, like `#66CD00` or `#FFF` or - * `#80FFFFFF` (alpha in #AARRGGBB format is supported if `transparent` is set to - * `true`). Default is `#FFF` (white). - */ - backgroundColor?: string; - /** - * Whether window should have a shadow. Default is `true`. - */ - hasShadow?: boolean; - /** - * Set the initial opacity of the window, between 0.0 (fully transparent) and 1.0 - * (fully opaque). This is only implemented on Windows and macOS. - */ - opacity?: number; - /** - * Forces using dark theme for the window, only works on some GTK+3 desktop - * environments. Default is `false`. - */ - darkTheme?: boolean; - /** - * Makes the window transparent. Default is `false`. On Windows, does not work - * unless the window is frameless. - */ - transparent?: boolean; - /** - * The type of window, default is normal window. See more about this below. - */ - type?: string; - /** - * Specify how the material appearance should reflect window activity state on - * macOS. Must be used with the `vibrancy` property. Possible values are: - */ - visualEffectState?: ('followWindow' | 'active' | 'inactive'); - /** - * The style of window title bar. Default is `default`. Possible values are: - */ - titleBarStyle?: ('default' | 'hidden' | 'hiddenInset' | 'customButtonsOnHover'); - /** - * Set a custom position for the traffic light buttons. Can only be used with - * `titleBarStyle` set to `hidden` - */ - trafficLightPosition?: Point; - /** - * Shows the title in the title bar in full screen mode on macOS for all - * `titleBarStyle` options. Default is `false`. - */ - fullscreenWindowTitle?: boolean; - /** - * Use `WS_THICKFRAME` style for frameless windows on Windows, which adds standard - * window frame. Setting it to `false` will remove window shadow and window - * animations. Default is `true`. - */ - thickFrame?: boolean; - /** - * Add a type of vibrancy effect to the window, only on macOS. Can be - * `appearance-based`, `light`, `dark`, `titlebar`, `selection`, `menu`, `popover`, - * `sidebar`, `medium-light`, `ultra-dark`, `header`, `sheet`, `window`, `hud`, - * `fullscreen-ui`, `tooltip`, `content`, `under-window`, or `under-page`. Please - * note that using `frame: false` in combination with a vibrancy value requires - * that you use a non-default `titleBarStyle` as well. Also note that - * `appearance-based`, `light`, `dark`, `medium-light`, and `ultra-dark` have been - * deprecated and will be removed in an upcoming version of macOS. - */ - vibrancy?: ('appearance-based' | 'light' | 'dark' | 'titlebar' | 'selection' | 'menu' | 'popover' | 'sidebar' | 'medium-light' | 'ultra-dark' | 'header' | 'sheet' | 'window' | 'hud' | 'fullscreen-ui' | 'tooltip' | 'content' | 'under-window' | 'under-page'); - /** - * Controls the behavior on macOS when option-clicking the green stoplight button - * on the toolbar or by clicking the Window > Zoom menu item. If `true`, the window - * will grow to the preferred width of the web page when zoomed, `false` will cause - * it to zoom to the width of the screen. This will also affect the behavior when - * calling `maximize()` directly. Default is `false`. - */ - zoomToPageWidth?: boolean; - /** - * Tab group name, allows opening the window as a native tab on macOS 10.12+. - * Windows with the same tabbing identifier will be grouped together. This also - * adds a native new tab button to your window's tab bar and allows your `app` and - * window to receive the `new-window-for-tab` event. - */ - tabbingIdentifier?: string; - /** - * Settings of web page's features. - */ - webPreferences?: WebPreferences; - } - - interface CertificateTrustDialogOptions { - /** - * The certificate to trust/import. - */ - certificate: Certificate; - /** - * The message to display to the user. - */ - message: string; - } - - interface ClearStorageDataOptions { - /** - * Should follow `window.location.origin`’s representation `scheme://host:port`. - */ - origin?: string; - /** - * The types of storages to clear, can contain: `appcache`, `cookies`, - * `filesystem`, `indexdb`, `localstorage`, `shadercache`, `websql`, - * `serviceworkers`, `cachestorage`. If not specified, clear all storage types. - */ - storages?: string[]; - /** - * The types of quotas to clear, can contain: `temporary`, `persistent`, - * `syncable`. If not specified, clear all quotas. - */ - quotas?: string[]; - } - - interface ClientRequestConstructorOptions { - /** - * The HTTP request method. Defaults to the GET method. - */ - method?: string; - /** - * The request URL. Must be provided in the absolute form with the protocol scheme - * specified as http or https. - */ - url?: string; - /** - * The `Session` instance with which the request is associated. - */ - session?: Session; - /** - * The name of the `partition` with which the request is associated. Defaults to - * the empty string. The `session` option supersedes `partition`. Thus if a - * `session` is explicitly specified, `partition` is ignored. - */ - partition?: string; - /** - * Can be `include` or `omit`. Whether to send credentials with this request. If - * set to `include`, credentials from the session associated with the request will - * be used. If set to `omit`, credentials will not be sent with the request (and - * the `'login'` event will not be triggered in the event of a 401). This matches - * the behavior of the fetch option of the same name. If this option is not - * specified, authentication data from the session will be sent, and cookies will - * not be sent (unless `useSessionCookies` is set). - */ - credentials?: ('include' | 'omit'); - /** - * Whether to send cookies with this request from the provided session. If - * `credentials` is specified, this option has no effect. Default is `false`. - */ - useSessionCookies?: boolean; - /** - * Can be `http:` or `https:`. The protocol scheme in the form 'scheme:'. Defaults - * to 'http:'. - */ - protocol?: string; - /** - * The server host provided as a concatenation of the hostname and the port number - * 'hostname:port'. - */ - host?: string; - /** - * The server host name. - */ - hostname?: string; - /** - * The server's listening port number. - */ - port?: number; - /** - * The path part of the request URL. - */ - path?: string; - /** - * Can be `follow`, `error` or `manual`. The redirect mode for this request. When - * mode is `error`, any redirection will be aborted. When mode is `manual` the - * redirection will be cancelled unless `request.followRedirect` is invoked - * synchronously during the `redirect` event. Defaults to `follow`. - */ - redirect?: ('follow' | 'error' | 'manual'); - /** - * The origin URL of the request. - */ - origin?: string; - } - - interface Config { - /** - * The proxy mode. Should be one of `direct`, `auto_detect`, `pac_script`, - * `fixed_servers` or `system`. If it's unspecified, it will be automatically - * determined based on other specified options. - */ - mode?: ('direct' | 'auto_detect' | 'pac_script' | 'fixed_servers' | 'system'); - /** - * The URL associated with the PAC file. - */ - pacScript?: string; - /** - * Rules indicating which proxies to use. - */ - proxyRules?: string; - /** - * Rules indicating which URLs should bypass the proxy settings. - */ - proxyBypassRules?: string; - } - - interface ConsoleMessageEvent extends Event { - /** - * The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and - * `error`. - */ - level: number; - /** - * The actual console message - */ - message: string; - /** - * The line number of the source that triggered this console message - */ - line: number; - sourceId: string; - } - - interface ContextMenuParams { - /** - * x coordinate. - */ - x: number; - /** - * y coordinate. - */ - y: number; - /** - * URL of the link that encloses the node the context menu was invoked on. - */ - linkURL: string; - /** - * Text associated with the link. May be an empty string if the contents of the - * link are an image. - */ - linkText: string; - /** - * URL of the top level page that the context menu was invoked on. - */ - pageURL: string; - /** - * URL of the subframe that the context menu was invoked on. - */ - frameURL: string; - /** - * Source URL for the element that the context menu was invoked on. Elements with - * source URLs are images, audio and video. - */ - srcURL: string; - /** - * Type of the node the context menu was invoked on. Can be `none`, `image`, - * `audio`, `video`, `canvas`, `file` or `plugin`. - */ - mediaType: ('none' | 'image' | 'audio' | 'video' | 'canvas' | 'file' | 'plugin'); - /** - * Whether the context menu was invoked on an image which has non-empty contents. - */ - hasImageContents: boolean; - /** - * Whether the context is editable. - */ - isEditable: boolean; - /** - * Text of the selection that the context menu was invoked on. - */ - selectionText: string; - /** - * Title or alt text of the selection that the context was invoked on. - */ - titleText: string; - /** - * The misspelled word under the cursor, if any. - */ - misspelledWord: string; - /** - * An array of suggested words to show the user to replace the `misspelledWord`. - * Only available if there is a misspelled word and spellchecker is enabled. - */ - dictionarySuggestions: string[]; - /** - * The character encoding of the frame on which the menu was invoked. - */ - frameCharset: string; - /** - * If the context menu was invoked on an input field, the type of that field. - * Possible values are `none`, `plainText`, `password`, `other`. - */ - inputFieldType: string; - /** - * Input source that invoked the context menu. Can be `none`, `mouse`, `keyboard`, - * `touch` or `touchMenu`. - */ - menuSourceType: ('none' | 'mouse' | 'keyboard' | 'touch' | 'touchMenu'); - /** - * The flags for the media element the context menu was invoked on. - */ - mediaFlags: MediaFlags; - /** - * These flags indicate whether the renderer believes it is able to perform the - * corresponding action. - */ - editFlags: EditFlags; - } - - interface CookiesGetFilter { - /** - * Retrieves cookies which are associated with `url`. Empty implies retrieving - * cookies of all URLs. - */ - url?: string; - /** - * Filters cookies by name. - */ - name?: string; - /** - * Retrieves cookies whose domains match or are subdomains of `domains`. - */ - domain?: string; - /** - * Retrieves cookies whose path matches `path`. - */ - path?: string; - /** - * Filters cookies by their Secure property. - */ - secure?: boolean; - /** - * Filters out session or persistent cookies. - */ - session?: boolean; - } - - interface CookiesSetDetails { - /** - * The URL to associate the cookie with. The promise will be rejected if the URL is - * invalid. - */ - url: string; - /** - * The name of the cookie. Empty by default if omitted. - */ - name?: string; - /** - * The value of the cookie. Empty by default if omitted. - */ - value?: string; - /** - * The domain of the cookie; this will be normalized with a preceding dot so that - * it's also valid for subdomains. Empty by default if omitted. - */ - domain?: string; - /** - * The path of the cookie. Empty by default if omitted. - */ - path?: string; - /** - * Whether the cookie should be marked as Secure. Defaults to false. - */ - secure?: boolean; - /** - * Whether the cookie should be marked as HTTP only. Defaults to false. - */ - httpOnly?: boolean; - /** - * The expiration date of the cookie as the number of seconds since the UNIX epoch. - * If omitted then the cookie becomes a session cookie and will not be retained - * between sessions. - */ - expirationDate?: number; - /** - * The Same Site policy to apply to this cookie. Can be `unspecified`, - * `no_restriction`, `lax` or `strict`. Default is `no_restriction`. - */ - sameSite?: ('unspecified' | 'no_restriction' | 'lax' | 'strict'); - } - - interface CrashReporterStartOptions { - /** - * URL that crash reports will be sent to as POST. - */ - submitURL: string; - /** - * Defaults to `app.name`. - */ - productName?: string; - /** - * Deprecated alias for `{ globalExtra: { _companyName: ... } }`. - * - * @deprecated - */ - companyName?: string; - /** - * Whether crash reports should be sent to the server. If false, crash reports will - * be collected and stored in the crashes directory, but not uploaded. Default is - * `true`. - */ - uploadToServer?: boolean; - /** - * If true, crashes generated in the main process will not be forwarded to the - * system crash handler. Default is `false`. - */ - ignoreSystemCrashHandler?: boolean; - /** - * If true, limit the number of crashes uploaded to 1/hour. Default is `false`. - * - * @platform darwin,win32 - */ - rateLimit?: boolean; - /** - * If true, crash reports will be compressed and uploaded with `Content-Encoding: - * gzip`. Default is `true`. - */ - compress?: boolean; - /** - * Extra string key/value annotations that will be sent along with crash reports - * that are generated in the main process. Only string values are supported. - * Crashes generated in child processes will not contain these extra parameters to - * crash reports generated from child processes, call `addExtraParameter` from the - * child process. - */ - extra?: Record<string, string>; - /** - * Extra string key/value annotations that will be sent along with any crash - * reports generated in any process. These annotations cannot be changed once the - * crash reporter has been started. If a key is present in both the global extra - * parameters and the process-specific extra parameters, then the global one will - * take precedence. By default, `productName` and the app version are included, as - * well as the Electron version. - */ - globalExtra?: Record<string, string>; - } - - interface CreateFromBitmapOptions { - width: number; - height: number; - /** - * Defaults to 1.0. - */ - scaleFactor?: number; - } - - interface CreateFromBufferOptions { - /** - * Required for bitmap buffers. - */ - width?: number; - /** - * Required for bitmap buffers. - */ - height?: number; - /** - * Defaults to 1.0. - */ - scaleFactor?: number; - } - - interface CreateInterruptedDownloadOptions { - /** - * Absolute path of the download. - */ - path: string; - /** - * Complete URL chain for the download. - */ - urlChain: string[]; - mimeType?: string; - /** - * Start range for the download. - */ - offset: number; - /** - * Total length of the download. - */ - length: number; - /** - * Last-Modified header value. - */ - lastModified?: string; - /** - * ETag header value. - */ - eTag?: string; - /** - * Time when download was started in number of seconds since UNIX epoch. - */ - startTime?: number; - } - - interface Data { - text?: string; - html?: string; - image?: NativeImage; - rtf?: string; - /** - * The title of the URL at `text`. - */ - bookmark?: string; - } - - interface Details { - /** - * Process type. One of the following values: - */ - type: ('Utility' | 'Zygote' | 'Sandbox helper' | 'GPU' | 'Pepper Plugin' | 'Pepper Plugin Broker' | 'Unknown'); - /** - * The reason the child process is gone. Possible values: - */ - reason: ('clean-exit' | 'abnormal-exit' | 'killed' | 'crashed' | 'oom' | 'launch-failed' | 'integrity-failure'); - /** - * The exit code for the process (e.g. status from waitpid if on posix, from - * GetExitCodeProcess on Windows). - */ - exitCode: number; - /** - * The non-localized name of the process. - */ - serviceName?: string; - /** - * The name of the process. Examples for utility: `Audio Service`, `Content - * Decryption Module Service`, `Network Service`, `Video Capture`, etc. - */ - name?: string; - } - - interface DidChangeThemeColorEvent extends Event { - themeColor: string; - } - - interface DidCreateWindowDetails { - /** - * URL for the created window. - */ - url: string; - /** - * Name given to the created window in the `window.open()` call. - */ - frameName: string; - /** - * The options used to create the BrowserWindow. They are merged in increasing - * precedence: options inherited from the parent, parsed options from the - * `features` string from `window.open()`, and options given by - * `webContents.setWindowOpenHandler`. Unrecognized options are not filtered out. - */ - options: BrowserWindowConstructorOptions; - /** - * The non-standard features (features not handled Chromium or Electron) - * _Deprecated_ - */ - additionalFeatures: string[]; - /** - * The referrer that will be passed to the new window. May or may not result in the - * `Referer` header being sent, depending on the referrer policy. - */ - referrer: Referrer; - /** - * The post data that will be sent to the new window, along with the appropriate - * headers that will be set. If no post data is to be sent, the value will be - * `null`. Only defined when the window is being created by a form that set - * `target=_blank`. - */ - postBody?: PostBody; - /** - * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, - * `save-to-disk` and `other`. - */ - disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'); - } - - interface DidFailLoadEvent extends Event { - errorCode: number; - errorDescription: string; - validatedURL: string; - isMainFrame: boolean; - } - - interface DidFrameFinishLoadEvent extends Event { - isMainFrame: boolean; - } - - interface DidNavigateEvent extends Event { - url: string; - } - - interface DidNavigateInPageEvent extends Event { - isMainFrame: boolean; - url: string; - } - - interface DisplayBalloonOptions { - /** - * Icon to use when `iconType` is `custom`. - */ - icon?: (NativeImage) | (string); - /** - * Can be `none`, `info`, `warning`, `error` or `custom`. Default is `custom`. - */ - iconType?: ('none' | 'info' | 'warning' | 'error' | 'custom'); - title: string; - content: string; - /** - * The large version of the icon should be used. Default is `true`. Maps to - * `NIIF_LARGE_ICON`. - */ - largeIcon?: boolean; - /** - * Do not play the associated sound. Default is `false`. Maps to `NIIF_NOSOUND`. - */ - noSound?: boolean; - /** - * Do not display the balloon notification if the current user is in "quiet time". - * Default is `false`. Maps to `NIIF_RESPECT_QUIET_TIME`. - */ - respectQuietTime?: boolean; - } - - interface EnableNetworkEmulationOptions { - /** - * Whether to emulate network outage. Defaults to false. - */ - offline?: boolean; - /** - * RTT in ms. Defaults to 0 which will disable latency throttling. - */ - latency?: number; - /** - * Download rate in Bps. Defaults to 0 which will disable download throttling. - */ - downloadThroughput?: number; - /** - * Upload rate in Bps. Defaults to 0 which will disable upload throttling. - */ - uploadThroughput?: number; - } - - interface FeedURLOptions { - url: string; - /** - * HTTP request headers. - * - * @platform darwin - */ - headers?: Record<string, string>; - /** - * Can be `json` or `default`, see the Squirrel.Mac README for more information. - * - * @platform darwin - */ - serverType?: ('json' | 'default'); - } - - interface FileIconOptions { - size: ('small' | 'normal' | 'large'); - } - - interface Filter { - /** - * Array of URL patterns that will be used to filter out the requests that do not - * match the URL patterns. - */ - urls: string[]; - } - - interface FindInPageOptions { - /** - * Whether to search forward or backward, defaults to `true`. - */ - forward?: boolean; - /** - * Whether the operation is first request or a follow up, defaults to `false`. - */ - findNext?: boolean; - /** - * Whether search should be case-sensitive, defaults to `false`. - */ - matchCase?: boolean; - } - - interface FocusOptions { - /** - * Make the receiver the active app even if another app is currently active. - * - * @platform darwin - */ - steal: boolean; - } - - interface FoundInPageEvent extends Event { - result: FoundInPageResult; - } - - interface FromPartitionOptions { - /** - * Whether to enable cache. - */ - cache: boolean; - } - - interface HandlerDetails { - /** - * The _resolved_ version of the URL passed to `window.open()`. e.g. opening a - * window with `window.open('foo')` will yield something like - * `https://the-origin/the/current/path/foo`. - */ - url: string; - /** - * Name of the window provided in `window.open()` - */ - frameName: string; - /** - * Comma separated list of window features provided to `window.open()`. - */ - features: string; - } - - interface HeadersReceivedResponse { - cancel?: boolean; - /** - * When provided, the server is assumed to have responded with these headers. - */ - responseHeaders?: Record<string, (string) | (string[])>; - /** - * Should be provided when overriding `responseHeaders` to change header status - * otherwise original response header's status will be used. - */ - statusLine?: string; - } - - interface HeapStatistics { - totalHeapSize: number; - totalHeapSizeExecutable: number; - totalPhysicalSize: number; - totalAvailableSize: number; - usedHeapSize: number; - heapSizeLimit: number; - mallocedMemory: number; - peakMallocedMemory: number; - doesZapGarbage: boolean; - } - - interface IgnoreMouseEventsOptions { - /** - * If true, forwards mouse move messages to Chromium, enabling mouse related events - * such as `mouseleave`. Only used when `ignore` is true. If `ignore` is false, - * forwarding is always disabled regardless of this value. - * - * @platform darwin,win32 - */ - forward?: boolean; - } - - interface ImportCertificateOptions { - /** - * Path for the pkcs12 file. - */ - certificate: string; - /** - * Passphrase for the certificate. - */ - password: string; - } - - interface Info { - /** - * Security origin for the isolated world. - */ - securityOrigin?: string; - /** - * Content Security Policy for the isolated world. - */ - csp?: string; - /** - * Name for isolated world. Useful in devtools. - */ - name?: string; - } - - interface Input { - /** - * Either `keyUp` or `keyDown`. - */ - type: string; - /** - * Equivalent to KeyboardEvent.key. - */ - key: string; - /** - * Equivalent to KeyboardEvent.code. - */ - code: string; - /** - * Equivalent to KeyboardEvent.repeat. - */ - isAutoRepeat: boolean; - /** - * Equivalent to KeyboardEvent.isComposing. - */ - isComposing: boolean; - /** - * Equivalent to KeyboardEvent.shiftKey. - */ - shift: boolean; - /** - * Equivalent to KeyboardEvent.controlKey. - */ - control: boolean; - /** - * Equivalent to KeyboardEvent.altKey. - */ - alt: boolean; - /** - * Equivalent to KeyboardEvent.metaKey. - */ - meta: boolean; - } - - interface InsertCSSOptions { - /** - * Can be either 'user' or 'author'; Specifying 'user' enables you to prevent - * websites from overriding the CSS you insert. Default is 'author'. - */ - cssOrigin?: string; - } - - interface IpcMessageEvent extends Event { - channel: string; - args: any[]; - } - - interface Item { - /** - * The path(s) to the file(s) being dragged. - */ - file: (string[]) | (string); - /** - * The image must be non-empty on macOS. - */ - icon: (NativeImage) | (string); - } - - interface JumpListSettings { - /** - * The minimum number of items that will be shown in the Jump List (for a more - * detailed description of this value see the MSDN docs). - */ - minItems: number; - /** - * Array of `JumpListItem` objects that correspond to items that the user has - * explicitly removed from custom categories in the Jump List. These items must not - * be re-added to the Jump List in the **next** call to `app.setJumpList()`, - * Windows will not display any custom category that contains any of the removed - * items. - */ - removedItems: JumpListItem[]; - } - - interface LoadCommitEvent extends Event { - url: string; - isMainFrame: boolean; - } - - interface LoadExtensionOptions { - /** - * Whether to allow the extension to read local files over `file://` protocol and - * inject content scripts into `file://` pages. This is required e.g. for loading - * devtools extensions on `file://` URLs. Defaults to false. - */ - allowFileAccess: boolean; - } - - interface LoadFileOptions { - /** - * Passed to `url.format()`. - */ - query?: Record<string, string>; - /** - * Passed to `url.format()`. - */ - search?: string; - /** - * Passed to `url.format()`. - */ - hash?: string; - } - - interface LoadURLOptions { - /** - * An HTTP Referrer url. - */ - httpReferrer?: (string) | (Referrer); - /** - * A user agent originating the request. - */ - userAgent?: string; - /** - * Extra headers separated by "\n" - */ - extraHeaders?: string; - postData?: (UploadRawData[]) | (UploadFile[]); - /** - * Base url (with trailing path separator) for files to be loaded by the data url. - * This is needed only if the specified `url` is a data url and needs to load other - * files. - */ - baseURLForDataURL?: string; - } - - interface LoginItemSettings { - /** - * `true` if the app is set to open at login. - */ - openAtLogin: boolean; - /** - * `true` if the app is set to open as hidden at login. This setting is not - * available on MAS builds. - * - * @platform darwin - */ - openAsHidden: boolean; - /** - * `true` if the app was opened at login automatically. This setting is not - * available on MAS builds. - * - * @platform darwin - */ - wasOpenedAtLogin: boolean; - /** - * `true` if the app was opened as a hidden login item. This indicates that the app - * should not open any windows at startup. This setting is not available on MAS - * builds. - * - * @platform darwin - */ - wasOpenedAsHidden: boolean; - /** - * `true` if the app was opened as a login item that should restore the state from - * the previous session. This indicates that the app should restore the windows - * that were open the last time the app was closed. This setting is not available - * on MAS builds. - * - * @platform darwin - */ - restoreState: boolean; - /** - * `true` if app is set to open at login and its run key is not deactivated. This - * differs from `openAtLogin` as it ignores the `args` option, this property will - * be true if the given executable would be launched at login with **any** - * arguments. - * - * @platform win32 - */ - executableWillLaunchAtLogin: boolean; - launchItems: LaunchItems[]; - } - - interface LoginItemSettingsOptions { - /** - * The executable path to compare against. Defaults to `process.execPath`. - * - * @platform win32 - */ - path?: string; - /** - * The command-line arguments to compare against. Defaults to an empty array. - * - * @platform win32 - */ - args?: string[]; - } - - interface MenuItemConstructorOptions { - /** - * Will be called with `click(menuItem, browserWindow, event)` when the menu item - * is clicked. - */ - click?: (menuItem: MenuItem, browserWindow: (BrowserWindow) | (undefined), event: KeyboardEvent) => void; - /** - * Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, - * `selectAll`, `reload`, `forceReload`, `toggleDevTools`, `resetZoom`, `zoomIn`, - * `zoomOut`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, - * `services`, `hide`, `hideOthers`, `unhide`, `quit`, `startSpeaking`, - * `stopSpeaking`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu`, - * `shareMenu`, `recentDocuments`, `toggleTabBar`, `selectNextTab`, - * `selectPreviousTab`, `mergeAllWindows`, `clearRecentDocuments`, - * `moveTabToNewWindow` or `windowMenu` - Define the action of the menu item, when - * specified the `click` property will be ignored. See roles. - */ - role?: ('undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'pasteAndMatchStyle' | 'delete' | 'selectAll' | 'reload' | 'forceReload' | 'toggleDevTools' | 'resetZoom' | 'zoomIn' | 'zoomOut' | 'togglefullscreen' | 'window' | 'minimize' | 'close' | 'help' | 'about' | 'services' | 'hide' | 'hideOthers' | 'unhide' | 'quit' | 'startSpeaking' | 'stopSpeaking' | 'zoom' | 'front' | 'appMenu' | 'fileMenu' | 'editMenu' | 'viewMenu' | 'shareMenu' | 'recentDocuments' | 'toggleTabBar' | 'selectNextTab' | 'selectPreviousTab' | 'mergeAllWindows' | 'clearRecentDocuments' | 'moveTabToNewWindow' | 'windowMenu'); - /** - * Can be `normal`, `separator`, `submenu`, `checkbox` or `radio`. - */ - type?: ('normal' | 'separator' | 'submenu' | 'checkbox' | 'radio'); - label?: string; - sublabel?: string; - /** - * Hover text for this menu item. - * - * @platform darwin - */ - toolTip?: string; - accelerator?: Accelerator; - icon?: (NativeImage) | (string); - /** - * If false, the menu item will be greyed out and unclickable. - */ - enabled?: boolean; - /** - * default is `true`, and when `false` will prevent the accelerator from triggering - * the item if the item is not visible`. - * - * @platform darwin - */ - acceleratorWorksWhenHidden?: boolean; - /** - * If false, the menu item will be entirely hidden. - */ - visible?: boolean; - /** - * Should only be specified for `checkbox` or `radio` type menu items. - */ - checked?: boolean; - /** - * If false, the accelerator won't be registered with the system, but it will still - * be displayed. Defaults to true. - * - * @platform linux,win32 - */ - registerAccelerator?: boolean; - /** - * The item to share when the `role` is `shareMenu`. - * - * @platform darwin - */ - sharingItem?: SharingItem; - /** - * Should be specified for `submenu` type menu items. If `submenu` is specified, - * the `type: 'submenu'` can be omitted. If the value is not a `Menu` then it will - * be automatically converted to one using `Menu.buildFromTemplate`. - */ - submenu?: (MenuItemConstructorOptions[]) | (Menu); - /** - * Unique within a single menu. If defined then it can be used as a reference to - * this item by the position attribute. - */ - id?: string; - /** - * Inserts this item before the item with the specified label. If the referenced - * item doesn't exist the item will be inserted at the end of the menu. Also - * implies that the menu item in question should be placed in the same “group” as - * the item. - */ - before?: string[]; - /** - * Inserts this item after the item with the specified label. If the referenced - * item doesn't exist the item will be inserted at the end of the menu. - */ - after?: string[]; - /** - * Provides a means for a single context menu to declare the placement of their - * containing group before the containing group of the item with the specified - * label. - */ - beforeGroupContaining?: string[]; - /** - * Provides a means for a single context menu to declare the placement of their - * containing group after the containing group of the item with the specified - * label. - */ - afterGroupContaining?: string[]; - } - - interface MessageBoxOptions { - /** - * Content of the message box. - */ - message: string; - /** - * Can be `"none"`, `"info"`, `"error"`, `"question"` or `"warning"`. On Windows, - * `"question"` displays the same icon as `"info"`, unless you set an icon using - * the `"icon"` option. On macOS, both `"warning"` and `"error"` display the same - * warning icon. - */ - type?: string; - /** - * Array of texts for buttons. On Windows, an empty array will result in one button - * labeled "OK". - */ - buttons?: string[]; - /** - * Index of the button in the buttons array which will be selected by default when - * the message box opens. - */ - defaultId?: number; - /** - * Title of the message box, some platforms will not show it. - */ - title?: string; - /** - * Extra information of the message. - */ - detail?: string; - /** - * If provided, the message box will include a checkbox with the given label. - */ - checkboxLabel?: string; - /** - * Initial checked state of the checkbox. `false` by default. - */ - checkboxChecked?: boolean; - icon?: NativeImage; - /** - * The index of the button to be used to cancel the dialog, via the `Esc` key. By - * default this is assigned to the first button with "cancel" or "no" as the label. - * If no such labeled buttons exist and this option is not set, `0` will be used as - * the return value. - */ - cancelId?: number; - /** - * On Windows Electron will try to figure out which one of the `buttons` are common - * buttons (like "Cancel" or "Yes"), and show the others as command links in the - * dialog. This can make the dialog appear in the style of modern Windows apps. If - * you don't like this behavior, you can set `noLink` to `true`. - */ - noLink?: boolean; - /** - * Normalize the keyboard access keys across platforms. Default is `false`. - * Enabling this assumes `&` is used in the button labels for the placement of the - * keyboard shortcut access key and labels will be converted so they work correctly - * on each platform, `&` characters are removed on macOS, converted to `_` on - * Linux, and left untouched on Windows. For example, a button label of `Vie&w` - * will be converted to `Vie_w` on Linux and `View` on macOS and can be selected - * via `Alt-W` on Windows and Linux. - */ - normalizeAccessKeys?: boolean; - } - - interface MessageBoxReturnValue { - /** - * The index of the clicked button. - */ - response: number; - /** - * The checked state of the checkbox if `checkboxLabel` was set. Otherwise `false`. - */ - checkboxChecked: boolean; - } - - interface MessageBoxSyncOptions { - /** - * Content of the message box. - */ - message: string; - /** - * Can be `"none"`, `"info"`, `"error"`, `"question"` or `"warning"`. On Windows, - * `"question"` displays the same icon as `"info"`, unless you set an icon using - * the `"icon"` option. On macOS, both `"warning"` and `"error"` display the same - * warning icon. - */ - type?: string; - /** - * Array of texts for buttons. On Windows, an empty array will result in one button - * labeled "OK". - */ - buttons?: string[]; - /** - * Index of the button in the buttons array which will be selected by default when - * the message box opens. - */ - defaultId?: number; - /** - * Title of the message box, some platforms will not show it. - */ - title?: string; - /** - * Extra information of the message. - */ - detail?: string; - /** - * If provided, the message box will include a checkbox with the given label. - */ - checkboxLabel?: string; - /** - * Initial checked state of the checkbox. `false` by default. - */ - checkboxChecked?: boolean; - icon?: (NativeImage) | (string); - /** - * The index of the button to be used to cancel the dialog, via the `Esc` key. By - * default this is assigned to the first button with "cancel" or "no" as the label. - * If no such labeled buttons exist and this option is not set, `0` will be used as - * the return value. - */ - cancelId?: number; - /** - * On Windows Electron will try to figure out which one of the `buttons` are common - * buttons (like "Cancel" or "Yes"), and show the others as command links in the - * dialog. This can make the dialog appear in the style of modern Windows apps. If - * you don't like this behavior, you can set `noLink` to `true`. - */ - noLink?: boolean; - /** - * Normalize the keyboard access keys across platforms. Default is `false`. - * Enabling this assumes `&` is used in the button labels for the placement of the - * keyboard shortcut access key and labels will be converted so they work correctly - * on each platform, `&` characters are removed on macOS, converted to `_` on - * Linux, and left untouched on Windows. For example, a button label of `Vie&w` - * will be converted to `Vie_w` on Linux and `View` on macOS and can be selected - * via `Alt-W` on Windows and Linux. - */ - normalizeAccessKeys?: boolean; - } - - interface MessageDetails { - /** - * The actual console message - */ - message: string; - /** - * The version ID of the service worker that sent the log message - */ - versionId: number; - /** - * The type of source for this message. Can be `javascript`, `xml`, `network`, - * `console-api`, `storage`, `app-cache`, `rendering`, `security`, `deprecation`, - * `worker`, `violation`, `intervention`, `recommendation` or `other`. - */ - source: ('javascript' | 'xml' | 'network' | 'console-api' | 'storage' | 'app-cache' | 'rendering' | 'security' | 'deprecation' | 'worker' | 'violation' | 'intervention' | 'recommendation' | 'other'); - /** - * The log level, from 0 to 3. In order it matches `verbose`, `info`, `warning` and - * `error`. - */ - level: number; - /** - * The URL the message came from - */ - sourceUrl: string; - /** - * The line number of the source that triggered this console message - */ - lineNumber: number; - } - - interface MessageEvent { - data: any; - ports: MessagePortMain[]; - } - - interface MoveToApplicationsFolderOptions { - /** - * A handler for potential conflict in move failure. - */ - conflictHandler?: (conflictType: 'exists' | 'existsAndRunning') => boolean; - } - - interface NewWindowEvent extends Event { - url: string; - frameName: string; - /** - * Can be `default`, `foreground-tab`, `background-tab`, `new-window`, - * `save-to-disk` and `other`. - */ - disposition: ('default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'); - /** - * The options which should be used for creating the new `BrowserWindow`. - */ - options: BrowserWindowConstructorOptions; - } - - interface NotificationConstructorOptions { - /** - * A title for the notification, which will be shown at the top of the notification - * window when it is shown. - */ - title?: string; - /** - * A subtitle for the notification, which will be displayed below the title. - * - * @platform darwin - */ - subtitle?: string; - /** - * The body text of the notification, which will be displayed below the title or - * subtitle. - */ - body?: string; - /** - * Whether or not to emit an OS notification noise when showing the notification. - */ - silent?: boolean; - /** - * An icon to use in the notification. - */ - icon?: (string) | (NativeImage); - /** - * Whether or not to add an inline reply option to the notification. - * - * @platform darwin - */ - hasReply?: boolean; - /** - * The timeout duration of the notification. Can be 'default' or 'never'. - * - * @platform linux,win32 - */ - timeoutType?: ('default' | 'never'); - /** - * The placeholder to write in the inline reply input field. - * - * @platform darwin - */ - replyPlaceholder?: string; - /** - * The name of the sound file to play when the notification is shown. - * - * @platform darwin - */ - sound?: string; - /** - * The urgency level of the notification. Can be 'normal', 'critical', or 'low'. - * - * @platform linux - */ - urgency?: ('normal' | 'critical' | 'low'); - /** - * Actions to add to the notification. Please read the available actions and - * limitations in the `NotificationAction` documentation. - * - * @platform darwin - */ - actions?: NotificationAction[]; - /** - * A custom title for the close button of an alert. An empty string will cause the - * default localized text to be used. - * - * @platform darwin - */ - closeButtonText?: string; - /** - * A custom description of the Notification on Windows superseding all properties - * above. Provides full customization of design and behavior of the notification. - * - * @platform win32 - */ - toastXml?: string; - } - - interface OnBeforeRedirectListenerDetails { - id: number; - url: string; - method: string; - webContentsId?: number; - webContents?: WebContents; - frame?: WebFrameMain; - resourceType: string; - referrer: string; - timestamp: number; - redirectURL: string; - statusCode: number; - statusLine: string; - /** - * The server IP address that the request was actually sent to. - */ - ip?: string; - fromCache: boolean; - responseHeaders?: Record<string, string[]>; - } - - interface OnBeforeRequestListenerDetails { - id: number; - url: string; - method: string; - webContentsId?: number; - webContents?: WebContents; - frame?: WebFrameMain; - resourceType: string; - referrer: string; - timestamp: number; - uploadData: UploadData[]; - } - - interface OnBeforeSendHeadersListenerDetails { - id: number; - url: string; - method: string; - webContentsId?: number; - webContents?: WebContents; - frame?: WebFrameMain; - resourceType: string; - referrer: string; - timestamp: number; - requestHeaders: Record<string, string>; - } - - interface OnCompletedListenerDetails { - id: number; - url: string; - method: string; - webContentsId?: number; - webContents?: WebContents; - frame?: WebFrameMain; - resourceType: string; - referrer: string; - timestamp: number; - responseHeaders?: Record<string, string[]>; - fromCache: boolean; - statusCode: number; - statusLine: string; - error: string; - } - - interface OnErrorOccurredListenerDetails { - id: number; - url: string; - method: string; - webContentsId?: number; - webContents?: WebContents; - frame?: WebFrameMain; - resourceType: string; - referrer: string; - timestamp: number; - fromCache: boolean; - /** - * The error description. - */ - error: string; - } - - interface OnHeadersReceivedListenerDetails { - id: number; - url: string; - method: string; - webContentsId?: number; - webContents?: WebContents; - frame?: WebFrameMain; - resourceType: string; - referrer: string; - timestamp: number; - statusLine: string; - statusCode: number; - requestHeaders: Record<string, string>; - responseHeaders?: Record<string, string[]>; - } - - interface OnResponseStartedListenerDetails { - id: number; - url: string; - method: string; - webContentsId?: number; - webContents?: WebContents; - frame?: WebFrameMain; - resourceType: string; - referrer: string; - timestamp: number; - responseHeaders?: Record<string, string[]>; - /** - * Indicates whether the response was fetched from disk cache. - */ - fromCache: boolean; - statusCode: number; - statusLine: string; - } - - interface OnSendHeadersListenerDetails { - id: number; - url: string; - method: string; - webContentsId?: number; - webContents?: WebContents; - frame?: WebFrameMain; - resourceType: string; - referrer: string; - timestamp: number; - requestHeaders: Record<string, string>; - } - - interface OpenDevToolsOptions { - /** - * Opens the devtools with specified dock state, can be `right`, `bottom`, - * `undocked`, `detach`. Defaults to last used dock state. In `undocked` mode it's - * possible to dock back. In `detach` mode it's not. - */ - mode: ('right' | 'bottom' | 'undocked' | 'detach'); - /** - * Whether to bring the opened devtools window to the foreground. The default is - * `true`. - */ - activate?: boolean; - } - - interface OpenDialogOptions { - title?: string; - defaultPath?: string; - /** - * Custom label for the confirmation button, when left empty the default label will - * be used. - */ - buttonLabel?: string; - filters?: FileFilter[]; - /** - * Contains which features the dialog should use. The following values are - * supported: - */ - properties?: Array<'openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles' | 'createDirectory' | 'promptToCreate' | 'noResolveAliases' | 'treatPackageAsDirectory' | 'dontAddToRecent'>; - /** - * Message to display above input boxes. - * - * @platform darwin - */ - message?: string; - /** - * Create security scoped bookmarks when packaged for the Mac App Store. - * - * @platform darwin,mas - */ - securityScopedBookmarks?: boolean; - } - - interface OpenDialogReturnValue { - /** - * whether or not the dialog was canceled. - */ - canceled: boolean; - /** - * An array of file paths chosen by the user. If the dialog is cancelled this will - * be an empty array. - */ - filePaths: string[]; - /** - * An array matching the `filePaths` array of base64 encoded strings which contains - * security scoped bookmark data. `securityScopedBookmarks` must be enabled for - * this to be populated. (For return values, see table here.) - * - * @platform darwin,mas - */ - bookmarks?: string[]; - } - - interface OpenDialogSyncOptions { - title?: string; - defaultPath?: string; - /** - * Custom label for the confirmation button, when left empty the default label will - * be used. - */ - buttonLabel?: string; - filters?: FileFilter[]; - /** - * Contains which features the dialog should use. The following values are - * supported: - */ - properties?: Array<'openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles' | 'createDirectory' | 'promptToCreate' | 'noResolveAliases' | 'treatPackageAsDirectory' | 'dontAddToRecent'>; - /** - * Message to display above input boxes. - * - * @platform darwin - */ - message?: string; - /** - * Create security scoped bookmarks when packaged for the Mac App Store. - * - * @platform darwin,mas - */ - securityScopedBookmarks?: boolean; - } - - interface OpenExternalOptions { - /** - * `true` to bring the opened application to the foreground. The default is `true`. - * - * @platform darwin - */ - activate?: boolean; - /** - * The working directory. - * - * @platform win32 - */ - workingDirectory?: string; - } - - interface Options { - } - - interface PageFaviconUpdatedEvent extends Event { - /** - * Array of URLs. - */ - favicons: string[]; - } - - interface PageTitleUpdatedEvent extends Event { - title: string; - explicitSet: boolean; - } - - interface Parameters { - /** - * Specify the screen type to emulate (default: `desktop`): - */ - screenPosition: ('desktop' | 'mobile'); - /** - * Set the emulated screen size (screenPosition == mobile). - */ - screenSize: Size; - /** - * Position the view on the screen (screenPosition == mobile) (default: `{ x: 0, y: - * 0 }`). - */ - viewPosition: Point; - /** - * Set the device scale factor (if zero defaults to original device scale factor) - * (default: `0`). - */ - deviceScaleFactor: number; - /** - * Set the emulated view size (empty means no override) - */ - viewSize: Size; - /** - * Scale of emulated view inside available space (not in fit to view mode) - * (default: `1`). - */ - scale: number; - } - - interface Payment { - /** - * The identifier of the purchased product. - */ - productIdentifier: string; - /** - * The quantity purchased. - */ - quantity: number; - } - - interface PermissionCheckHandlerHandlerDetails { - /** - * The security origin of the `media` check. - */ - securityOrigin: string; - /** - * The type of media access being requested, can be `video`, `audio` or `unknown` - */ - mediaType: ('video' | 'audio' | 'unknown'); - /** - * The last URL the requesting frame loaded - */ - requestingUrl: string; - /** - * Whether the frame making the request is the main frame - */ - isMainFrame: boolean; - } - - interface PermissionRequestHandlerHandlerDetails { - /** - * The url of the `openExternal` request. - */ - externalURL?: string; - /** - * The types of media access being requested, elements can be `video` or `audio` - */ - mediaTypes?: Array<'video' | 'audio'>; - /** - * The last URL the requesting frame loaded - */ - requestingUrl: string; - /** - * Whether the frame making the request is the main frame - */ - isMainFrame: boolean; - } - - interface PluginCrashedEvent extends Event { - name: string; - version: string; - } - - interface PopupOptions { - /** - * Default is the focused window. - */ - window?: BrowserWindow; - /** - * Default is the current mouse cursor position. Must be declared if `y` is - * declared. - */ - x?: number; - /** - * Default is the current mouse cursor position. Must be declared if `x` is - * declared. - */ - y?: number; - /** - * The index of the menu item to be positioned under the mouse cursor at the - * specified coordinates. Default is -1. - * - * @platform darwin - */ - positioningItem?: number; - /** - * Called when menu is closed. - */ - callback?: () => void; - } - - interface PreconnectOptions { - /** - * URL for preconnect. Only the origin is relevant for opening the socket. - */ - url: string; - /** - * number of sockets to preconnect. Must be between 1 and 6. Defaults to 1. - */ - numSockets?: number; - } - - interface PrintToPDFOptions { - /** - * the header and footer for the PDF. - */ - headerFooter?: Record<string, string>; - /** - * `true` for landscape, `false` for portrait. - */ - landscape?: boolean; - /** - * Specifies the type of margins to use. Uses 0 for default margin, 1 for no - * margin, and 2 for minimum margin. and `width` in microns. - */ - marginsType?: number; - /** - * The scale factor of the web page. Can range from 0 to 100. - */ - scaleFactor?: number; - /** - * The page range to print. On macOS, only the first range is honored. - */ - pageRanges?: Record<string, number>; - /** - * Specify page size of the generated PDF. Can be `A3`, `A4`, `A5`, `Legal`, - * `Letter`, `Tabloid` or an Object containing `height` - */ - pageSize?: (string) | (Size); - /** - * Whether to print CSS backgrounds. - */ - printBackground?: boolean; - /** - * Whether to print selection only. - */ - printSelectionOnly?: boolean; - } - - interface Privileges { - /** - * Default false. - */ - standard?: boolean; - /** - * Default false. - */ - secure?: boolean; - /** - * Default false. - */ - bypassCSP?: boolean; - /** - * Default false. - */ - allowServiceWorkers?: boolean; - /** - * Default false. - */ - supportFetchAPI?: boolean; - /** - * Default false. - */ - corsEnabled?: boolean; - /** - * Default false. - */ - stream?: boolean; - } - - interface ProgressBarOptions { - /** - * Mode for the progress bar. Can be `none`, `normal`, `indeterminate`, `error` or - * `paused`. - * - * @platform win32 - */ - mode: ('none' | 'normal' | 'indeterminate' | 'error' | 'paused'); - } - - interface Provider { - spellCheck: (words: string[], callback: (misspeltWords: string[]) => void) => void; - } - - interface ReadBookmark { - title: string; - url: string; - } - - interface RelaunchOptions { - args?: string[]; - execPath?: string; - } - - interface RenderProcessGoneDetails { - /** - * The reason the render process is gone. Possible values: - */ - reason: ('clean-exit' | 'abnormal-exit' | 'killed' | 'crashed' | 'oom' | 'launch-failed' | 'integrity-failure'); - /** - * The exit code of the process, unless `reason` is `launch-failed`, in which case - * `exitCode` will be a platform-specific launch failure error code. - */ - exitCode: number; - } - - interface Request { - hostname: string; - certificate: Certificate; - validatedCertificate: Certificate; - /** - * Verification result from chromium. - */ - verificationResult: string; - /** - * Error code. - */ - errorCode: number; - } - - interface ResizeOptions { - /** - * Defaults to the image's width. - */ - width?: number; - /** - * Defaults to the image's height. - */ - height?: number; - /** - * The desired quality of the resize image. Possible values are `good`, `better`, - * or `best`. The default is `best`. These values express a desired quality/speed - * tradeoff. They are translated into an algorithm-specific method that depends on - * the capabilities (CPU, GPU) of the underlying platform. It is possible for all - * three methods to be mapped to the same algorithm on a given platform. - */ - quality?: string; - } - - interface ResourceUsage { - images: MemoryUsageDetails; - scripts: MemoryUsageDetails; - cssStyleSheets: MemoryUsageDetails; - xslStyleSheets: MemoryUsageDetails; - fonts: MemoryUsageDetails; - other: MemoryUsageDetails; - } - - interface Response { - cancel?: boolean; - /** - * The original request is prevented from being sent or completed and is instead - * redirected to the given URL. - */ - redirectURL?: string; - } - - interface Result { - requestId: number; - /** - * Position of the active match. - */ - activeMatchOrdinal: number; - /** - * Number of Matches. - */ - matches: number; - /** - * Coordinates of first match region. - */ - selectionArea: Rectangle; - finalUpdate: boolean; - } - - interface SaveDialogOptions { - title?: string; - /** - * Absolute directory path, absolute file path, or file name to use by default. - */ - defaultPath?: string; - /** - * Custom label for the confirmation button, when left empty the default label will - * be used. - */ - buttonLabel?: string; - filters?: FileFilter[]; - /** - * Message to display above text fields. - * - * @platform darwin - */ - message?: string; - /** - * Custom label for the text displayed in front of the filename text field. - * - * @platform darwin - */ - nameFieldLabel?: string; - /** - * Show the tags input box, defaults to `true`. - * - * @platform darwin - */ - showsTagField?: boolean; - properties?: Array<'showHiddenFiles' | 'createDirectory' | 'treatPackageAsDirectory' | 'showOverwriteConfirmation' | 'dontAddToRecent'>; - /** - * Create a security scoped bookmark when packaged for the Mac App Store. If this - * option is enabled and the file doesn't already exist a blank file will be - * created at the chosen path. - * - * @platform darwin,mas - */ - securityScopedBookmarks?: boolean; - } - - interface SaveDialogReturnValue { - /** - * whether or not the dialog was canceled. - */ - canceled: boolean; - /** - * If the dialog is canceled, this will be `undefined`. - */ - filePath?: string; - /** - * Base64 encoded string which contains the security scoped bookmark data for the - * saved file. `securityScopedBookmarks` must be enabled for this to be present. - * (For return values, see table here.) - * - * @platform darwin,mas - */ - bookmark?: string; - } - - interface SaveDialogSyncOptions { - title?: string; - /** - * Absolute directory path, absolute file path, or file name to use by default. - */ - defaultPath?: string; - /** - * Custom label for the confirmation button, when left empty the default label will - * be used. - */ - buttonLabel?: string; - filters?: FileFilter[]; - /** - * Message to display above text fields. - * - * @platform darwin - */ - message?: string; - /** - * Custom label for the text displayed in front of the filename text field. - * - * @platform darwin - */ - nameFieldLabel?: string; - /** - * Show the tags input box, defaults to `true`. - * - * @platform darwin - */ - showsTagField?: boolean; - properties?: Array<'showHiddenFiles' | 'createDirectory' | 'treatPackageAsDirectory' | 'showOverwriteConfirmation' | 'dontAddToRecent'>; - /** - * Create a security scoped bookmark when packaged for the Mac App Store. If this - * option is enabled and the file doesn't already exist a blank file will be - * created at the chosen path. - * - * @platform darwin,mas - */ - securityScopedBookmarks?: boolean; - } - - interface Settings { - /** - * `true` to open the app at login, `false` to remove the app as a login item. - * Defaults to `false`. - */ - openAtLogin?: boolean; - /** - * `true` to open the app as hidden. Defaults to `false`. The user can edit this - * setting from the System Preferences so - * `app.getLoginItemSettings().wasOpenedAsHidden` should be checked when the app is - * opened to know the current value. This setting is not available on MAS builds. - * - * @platform darwin - */ - openAsHidden?: boolean; - /** - * The executable to launch at login. Defaults to `process.execPath`. - * - * @platform win32 - */ - path?: string; - /** - * The command-line arguments to pass to the executable. Defaults to an empty - * array. Take care to wrap paths in quotes. - * - * @platform win32 - */ - args?: string[]; - /** - * `true` will change the startup approved registry key and `enable / disable` the - * App in Task Manager and Windows Settings. Defaults to `true`. - * - * @platform win32 - */ - enabled?: boolean; - /** - * value name to write into registry. Defaults to the app's AppUserModelId(). Set - * the app's login item settings. - * - * @platform win32 - */ - name?: string; - } - - interface SourcesOptions { - /** - * An array of Strings that lists the types of desktop sources to be captured, - * available types are `screen` and `window`. - */ - types: string[]; - /** - * The size that the media source thumbnail should be scaled to. Default is `150` x - * `150`. Set width or height to 0 when you do not need the thumbnails. This will - * save the processing time required for capturing the content of each window and - * screen. - */ - thumbnailSize?: Size; - /** - * Set to true to enable fetching window icons. The default value is false. When - * false the appIcon property of the sources return null. Same if a source has the - * type screen. - */ - fetchWindowIcons?: boolean; - } - - interface SSLConfigConfig { - /** - * Can be `tls1`, `tls1.1`, `tls1.2` or `tls1.3`. The minimum SSL version to allow - * when connecting to remote servers. Defaults to `tls1`. - */ - minVersion?: string; - /** - * Can be `tls1.2` or `tls1.3`. The maximum SSL version to allow when connecting to - * remote servers. Defaults to `tls1.3`. - */ - maxVersion?: string; - /** - * List of cipher suites which should be explicitly prevented from being used in - * addition to those disabled by the net built-in policy. Supported literal forms: - * 0xAABB, where AA is `cipher_suite[0]` and BB is `cipher_suite[1]`, as defined in - * RFC 2246, Section 7.4.1.2. Unrecognized but parsable cipher suites in this form - * will not return an error. Ex: To disable TLS_RSA_WITH_RC4_128_MD5, specify - * 0x0004, while to disable TLS_ECDH_ECDSA_WITH_RC4_128_SHA, specify 0xC002. Note - * that TLSv1.3 ciphers cannot be disabled using this mechanism. - */ - disabledCipherSuites?: number[]; - } - - interface StartLoggingOptions { - /** - * What kinds of data should be captured. By default, only metadata about requests - * will be captured. Setting this to `includeSensitive` will include cookies and - * authentication data. Setting it to `everything` will include all bytes - * transferred on sockets. Can be `default`, `includeSensitive` or `everything`. - */ - captureMode?: ('default' | 'includeSensitive' | 'everything'); - /** - * When the log grows beyond this size, logging will automatically stop. Defaults - * to unlimited. - */ - maxFileSize?: number; - } - - interface SystemMemoryInfo { - /** - * The total amount of physical memory in Kilobytes available to the system. - */ - total: number; - /** - * The total amount of memory not being used by applications or disk cache. - */ - free: number; - /** - * The total amount of swap memory in Kilobytes available to the system. - * - * @platform win32,linux - */ - swapTotal: number; - /** - * The free amount of swap memory in Kilobytes available to the system. - * - * @platform win32,linux - */ - swapFree: number; - } - - interface TitleOptions { - /** - * The font family variant to display, can be `monospaced` or `monospacedDigit`. - * `monospaced` is available in macOS 10.15+ and `monospacedDigit` is available in - * macOS 10.11+. When left blank, the title uses the default system font. - */ - fontType?: ('monospaced' | 'monospacedDigit'); - } - - interface ToBitmapOptions { - /** - * Defaults to 1.0. - */ - scaleFactor?: number; - } - - interface ToDataURLOptions { - /** - * Defaults to 1.0. - */ - scaleFactor?: number; - } - - interface ToPNGOptions { - /** - * Defaults to 1.0. - */ - scaleFactor?: number; - } - - interface TouchBarButtonConstructorOptions { - /** - * Button text. - */ - label?: string; - /** - * A short description of the button for use by screenreaders like VoiceOver. - */ - accessibilityLabel?: string; - /** - * Button background color in hex format, i.e `#ABCDEF`. - */ - backgroundColor?: string; - /** - * Button icon. - */ - icon?: (NativeImage) | (string); - /** - * Can be `left`, `right` or `overlay`. Defaults to `overlay`. - */ - iconPosition?: ('left' | 'right' | 'overlay'); - /** - * Function to call when the button is clicked. - */ - click?: () => void; - /** - * Whether the button is in an enabled state. Default is `true`. - */ - enabled?: boolean; - } - - interface TouchBarColorPickerConstructorOptions { - /** - * Array of hex color strings to appear as possible colors to select. - */ - availableColors?: string[]; - /** - * The selected hex color in the picker, i.e `#ABCDEF`. - */ - selectedColor?: string; - /** - * Function to call when a color is selected. - */ - change?: (color: string) => void; - } - - interface TouchBarConstructorOptions { - items?: Array<(TouchBarButton) | (TouchBarColorPicker) | (TouchBarGroup) | (TouchBarLabel) | (TouchBarPopover) | (TouchBarScrubber) | (TouchBarSegmentedControl) | (TouchBarSlider) | (TouchBarSpacer)>; - escapeItem?: (TouchBarButton) | (TouchBarColorPicker) | (TouchBarGroup) | (TouchBarLabel) | (TouchBarPopover) | (TouchBarScrubber) | (TouchBarSegmentedControl) | (TouchBarSlider) | (TouchBarSpacer) | (null); - } - - interface TouchBarGroupConstructorOptions { - /** - * Items to display as a group. - */ - items: TouchBar; - } - - interface TouchBarLabelConstructorOptions { - /** - * Text to display. - */ - label?: string; - /** - * A short description of the button for use by screenreaders like VoiceOver. - */ - accessibilityLabel?: string; - /** - * Hex color of text, i.e `#ABCDEF`. - */ - textColor?: string; - } - - interface TouchBarPopoverConstructorOptions { - /** - * Popover button text. - */ - label?: string; - /** - * Popover button icon. - */ - icon?: NativeImage; - /** - * Items to display in the popover. - */ - items: TouchBar; - /** - * `true` to display a close button on the left of the popover, `false` to not show - * it. Default is `true`. - */ - showCloseButton?: boolean; - } - - interface TouchBarScrubberConstructorOptions { - /** - * An array of items to place in this scrubber. - */ - items: ScrubberItem[]; - /** - * Called when the user taps an item that was not the last tapped item. - */ - select?: (selectedIndex: number) => void; - /** - * Called when the user taps any item. - */ - highlight?: (highlightedIndex: number) => void; - /** - * Selected item style. Can be `background`, `outline` or `none`. Defaults to - * `none`. - */ - selectedStyle?: ('background' | 'outline' | 'none'); - /** - * Selected overlay item style. Can be `background`, `outline` or `none`. Defaults - * to `none`. - */ - overlayStyle?: ('background' | 'outline' | 'none'); - /** - * Defaults to `false`. - */ - showArrowButtons?: boolean; - /** - * Can be `fixed` or `free`. The default is `free`. - */ - mode?: ('fixed' | 'free'); - /** - * Defaults to `true`. - */ - continuous?: boolean; - } - - interface TouchBarSegmentedControlConstructorOptions { - /** - * Style of the segments: - */ - segmentStyle?: ('automatic' | 'rounded' | 'textured-rounded' | 'round-rect' | 'textured-square' | 'capsule' | 'small-square' | 'separated'); - /** - * The selection mode of the control: - */ - mode?: ('single' | 'multiple' | 'buttons'); - /** - * An array of segments to place in this control. - */ - segments: SegmentedControlSegment[]; - /** - * The index of the currently selected segment, will update automatically with user - * interaction. When the mode is `multiple` it will be the last selected item. - */ - selectedIndex?: number; - /** - * Called when the user selects a new segment. - */ - change?: (selectedIndex: number, isSelected: boolean) => void; - } - - interface TouchBarSliderConstructorOptions { - /** - * Label text. - */ - label?: string; - /** - * Selected value. - */ - value?: number; - /** - * Minimum value. - */ - minValue?: number; - /** - * Maximum value. - */ - maxValue?: number; - /** - * Function to call when the slider is changed. - */ - change?: (newValue: number) => void; - } - - interface TouchBarSpacerConstructorOptions { - /** - * Size of spacer, possible values are: - */ - size?: ('small' | 'large' | 'flexible'); - } - - interface TraceBufferUsageReturnValue { - value: number; - percentage: number; - } - - interface UpdateTargetUrlEvent extends Event { - url: string; - } - - interface UploadProgress { - /** - * Whether the request is currently active. If this is false no other properties - * will be set - */ - active: boolean; - /** - * Whether the upload has started. If this is false both `current` and `total` will - * be set to 0. - */ - started: boolean; - /** - * The number of bytes that have been uploaded so far - */ - current: number; - /** - * The number of bytes that will be uploaded this request - */ - total: number; - } - - interface VisibleOnAllWorkspacesOptions { - /** - * Sets whether the window should be visible above fullscreen windows - * - * @platform darwin - */ - visibleOnFullScreen?: boolean; - } - - interface WebContentsPrintOptions { - /** - * Don't ask user for print settings. Default is `false`. - */ - silent?: boolean; - /** - * Prints the background color and image of the web page. Default is `false`. - */ - printBackground?: boolean; - /** - * Set the printer device name to use. Must be the system-defined name and not the - * 'friendly' name, e.g 'Brother_QL_820NWB' and not 'Brother QL-820NWB'. - */ - deviceName?: string; - /** - * Set whether the printed web page will be in color or grayscale. Default is - * `true`. - */ - color?: boolean; - margins?: Margins; - /** - * Whether the web page should be printed in landscape mode. Default is `false`. - */ - landscape?: boolean; - /** - * The scale factor of the web page. - */ - scaleFactor?: number; - /** - * The number of pages to print per page sheet. - */ - pagesPerSheet?: number; - /** - * Whether the web page should be collated. - */ - collate?: boolean; - /** - * The number of copies of the web page to print. - */ - copies?: number; - /** - * The page range to print. On macOS, only one range is honored. - */ - pageRanges?: PageRanges[]; - /** - * Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or - * `longEdge`. - */ - duplexMode?: ('simplex' | 'shortEdge' | 'longEdge'); - dpi?: Record<string, number>; - /** - * String to be printed as page header. - */ - header?: string; - /** - * String to be printed as page footer. - */ - footer?: string; - /** - * Specify page size of the printed document. Can be `A3`, `A4`, `A5`, `Legal`, - * `Letter`, `Tabloid` or an Object containing `height`. - */ - pageSize?: (string) | (Size); - } - - interface WebviewTagPrintOptions { - /** - * Don't ask user for print settings. Default is `false`. - */ - silent?: boolean; - /** - * Prints the background color and image of the web page. Default is `false`. - */ - printBackground?: boolean; - /** - * Set the printer device name to use. Must be the system-defined name and not the - * 'friendly' name, e.g 'Brother_QL_820NWB' and not 'Brother QL-820NWB'. - */ - deviceName?: string; - /** - * Set whether the printed web page will be in color or grayscale. Default is - * `true`. - */ - color?: boolean; - margins?: Margins; - /** - * Whether the web page should be printed in landscape mode. Default is `false`. - */ - landscape?: boolean; - /** - * The scale factor of the web page. - */ - scaleFactor?: number; - /** - * The number of pages to print per page sheet. - */ - pagesPerSheet?: number; - /** - * Whether the web page should be collated. - */ - collate?: boolean; - /** - * The number of copies of the web page to print. - */ - copies?: number; - /** - * The page range to print. - */ - pageRanges?: PageRanges[]; - /** - * Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or - * `longEdge`. - */ - duplexMode?: ('simplex' | 'shortEdge' | 'longEdge'); - dpi?: Record<string, number>; - /** - * String to be printed as page header. - */ - header?: string; - /** - * String to be printed as page footer. - */ - footer?: string; - /** - * Specify page size of the printed document. Can be `A3`, `A4`, `A5`, `Legal`, - * `Letter`, `Tabloid` or an Object containing `height`. - */ - pageSize?: (string) | (Size); - } - - interface WillNavigateEvent extends Event { - url: string; - } - - interface EditFlags { - /** - * Whether the renderer believes it can undo. - */ - canUndo: boolean; - /** - * Whether the renderer believes it can redo. - */ - canRedo: boolean; - /** - * Whether the renderer believes it can cut. - */ - canCut: boolean; - /** - * Whether the renderer believes it can copy - */ - canCopy: boolean; - /** - * Whether the renderer believes it can paste. - */ - canPaste: boolean; - /** - * Whether the renderer believes it can delete. - */ - canDelete: boolean; - /** - * Whether the renderer believes it can select all. - */ - canSelectAll: boolean; - } - - interface FoundInPageResult { - requestId: number; - /** - * Position of the active match. - */ - activeMatchOrdinal: number; - /** - * Number of Matches. - */ - matches: number; - /** - * Coordinates of first match region. - */ - selectionArea: Rectangle; - finalUpdate: boolean; - } - - interface LaunchItems { - /** - * name value of a registry entry. - * - * @platform win32 - */ - name: string; - /** - * The executable to an app that corresponds to a registry entry. - * - * @platform win32 - */ - path: string; - /** - * the command-line arguments to pass to the executable. - * - * @platform win32 - */ - args: string[]; - /** - * one of `user` or `machine`. Indicates whether the registry entry is under - * `HKEY_CURRENT USER` or `HKEY_LOCAL_MACHINE`. - * - * @platform win32 - */ - scope: string; - /** - * `true` if the app registry key is startup approved and therefore shows as - * `enabled` in Task Manager and Windows settings. - * - * @platform win32 - */ - enabled: boolean; - } - - interface Margins { - /** - * Can be `default`, `none`, `printableArea`, or `custom`. If `custom` is chosen, - * you will also need to specify `top`, `bottom`, `left`, and `right`. - */ - marginType?: ('default' | 'none' | 'printableArea' | 'custom'); - /** - * The top margin of the printed web page, in pixels. - */ - top?: number; - /** - * The bottom margin of the printed web page, in pixels. - */ - bottom?: number; - /** - * The left margin of the printed web page, in pixels. - */ - left?: number; - /** - * The right margin of the printed web page, in pixels. - */ - right?: number; - } - - interface MediaFlags { - /** - * Whether the media element has crashed. - */ - inError: boolean; - /** - * Whether the media element is paused. - */ - isPaused: boolean; - /** - * Whether the media element is muted. - */ - isMuted: boolean; - /** - * Whether the media element has audio. - */ - hasAudio: boolean; - /** - * Whether the media element is looping. - */ - isLooping: boolean; - /** - * Whether the media element's controls are visible. - */ - isControlsVisible: boolean; - /** - * Whether the media element's controls are toggleable. - */ - canToggleControls: boolean; - /** - * Whether the media element can be rotated. - */ - canRotate: boolean; - } - - interface PageRanges { - /** - * Index of the first page to print (0-based). - */ - from: number; - /** - * Index of the last page to print (inclusive) (0-based). - */ - to: number; - } - - interface WebPreferences { - /** - * Whether to enable DevTools. If it is set to `false`, can not use - * `BrowserWindow.webContents.openDevTools()` to open DevTools. Default is `true`. - */ - devTools?: boolean; - /** - * Whether node integration is enabled. Default is `false`. - */ - nodeIntegration?: boolean; - /** - * Whether node integration is enabled in web workers. Default is `false`. More - * about this can be found in Multithreading. - */ - nodeIntegrationInWorker?: boolean; - /** - * Experimental option for enabling Node.js support in sub-frames such as iframes - * and child windows. All your preloads will load for every iframe, you can use - * `process.isMainFrame` to determine if you are in the main frame or not. - */ - nodeIntegrationInSubFrames?: boolean; - /** - * Specifies a script that will be loaded before other scripts run in the page. - * This script will always have access to node APIs no matter whether node - * integration is turned on or off. The value should be the absolute file path to - * the script. When node integration is turned off, the preload script can - * reintroduce Node global symbols back to the global scope. See example here. - */ - preload?: string; - /** - * If set, this will sandbox the renderer associated with the window, making it - * compatible with the Chromium OS-level sandbox and disabling the Node.js engine. - * This is not the same as the `nodeIntegration` option and the APIs available to - * the preload script are more limited. Read more about the option here. - */ - sandbox?: boolean; - /** - * Whether to enable the `remote` module. Default is `false`. - */ - enableRemoteModule?: boolean; - /** - * Sets the session used by the page. Instead of passing the Session object - * directly, you can also choose to use the `partition` option instead, which - * accepts a partition string. When both `session` and `partition` are provided, - * `session` will be preferred. Default is the default session. - */ - session?: Session; - /** - * Sets the session used by the page according to the session's partition string. - * If `partition` starts with `persist:`, the page will use a persistent session - * available to all pages in the app with the same `partition`. If there is no - * `persist:` prefix, the page will use an in-memory session. By assigning the same - * `partition`, multiple pages can share the same session. Default is the default - * session. - */ - partition?: string; - /** - * When specified, web pages with the same `affinity` will run in the same renderer - * process. Note that due to reusing the renderer process, certain `webPreferences` - * options will also be shared between the web pages even when you specified - * different values for them, including but not limited to `preload`, `sandbox` and - * `nodeIntegration`. So it is suggested to use exact same `webPreferences` for web - * pages with the same `affinity`. _Deprecated_ - */ - affinity?: string; - /** - * The default zoom factor of the page, `3.0` represents `300%`. Default is `1.0`. - */ - zoomFactor?: number; - /** - * Enables JavaScript support. Default is `true`. - */ - javascript?: boolean; - /** - * When `false`, it will disable the same-origin policy (usually using testing - * websites by people), and set `allowRunningInsecureContent` to `true` if this - * options has not been set by user. Default is `true`. - */ - webSecurity?: boolean; - /** - * Allow an https page to run JavaScript, CSS or plugins from http URLs. Default is - * `false`. - */ - allowRunningInsecureContent?: boolean; - /** - * Enables image support. Default is `true`. - */ - images?: boolean; - /** - * Make TextArea elements resizable. Default is `true`. - */ - textAreasAreResizable?: boolean; - /** - * Enables WebGL support. Default is `true`. - */ - webgl?: boolean; - /** - * Whether plugins should be enabled. Default is `false`. - */ - plugins?: boolean; - /** - * Enables Chromium's experimental features. Default is `false`. - */ - experimentalFeatures?: boolean; - /** - * Enables scroll bounce (rubber banding) effect on macOS. Default is `false`. - */ - scrollBounce?: boolean; - /** - * A list of feature strings separated by `,`, like `CSSVariables,KeyboardEventKey` - * to enable. The full list of supported feature strings can be found in the - * RuntimeEnabledFeatures.json5 file. - */ - enableBlinkFeatures?: string; - /** - * A list of feature strings separated by `,`, like `CSSVariables,KeyboardEventKey` - * to disable. The full list of supported feature strings can be found in the - * RuntimeEnabledFeatures.json5 file. - */ - disableBlinkFeatures?: string; - /** - * Sets the default font for the font-family. - */ - defaultFontFamily?: DefaultFontFamily; - /** - * Defaults to `16`. - */ - defaultFontSize?: number; - /** - * Defaults to `13`. - */ - defaultMonospaceFontSize?: number; - /** - * Defaults to `0`. - */ - minimumFontSize?: number; - /** - * Defaults to `ISO-8859-1`. - */ - defaultEncoding?: string; - /** - * Whether to throttle animations and timers when the page becomes background. This - * also affects the Page Visibility API. Defaults to `true`. - */ - backgroundThrottling?: boolean; - /** - * Whether to enable offscreen rendering for the browser window. Defaults to - * `false`. See the offscreen rendering tutorial for more details. - */ - offscreen?: boolean; - /** - * Whether to run Electron APIs and the specified `preload` script in a separate - * JavaScript context. Defaults to `true`. The context that the `preload` script - * runs in will only have access to its own dedicated `document` and `window` - * globals, as well as its own set of JavaScript builtins (`Array`, `Object`, - * `JSON`, etc.), which are all invisible to the loaded content. The Electron API - * will only be available in the `preload` script and not the loaded page. This - * option should be used when loading potentially untrusted remote content to - * ensure the loaded content cannot tamper with the `preload` script and any - * Electron APIs being used. This option uses the same technique used by Chrome - * Content Scripts. You can access this context in the dev tools by selecting the - * 'Electron Isolated Context' entry in the combo box at the top of the Console - * tab. - */ - contextIsolation?: boolean; - /** - * If true, values returned from `webFrame.executeJavaScript` will be sanitized to - * ensure JS values can't unsafely cross between worlds when using - * `contextIsolation`. Defaults to `true`. _Deprecated_ - */ - worldSafeExecuteJavaScript?: boolean; - /** - * Whether to use native `window.open()`. Defaults to `false`. Child windows will - * always have node integration disabled unless `nodeIntegrationInSubFrames` is - * true. **Note:** This option is currently experimental. - */ - nativeWindowOpen?: boolean; - /** - * Whether to enable the `<webview>` tag. Defaults to `false`. **Note:** The - * `preload` script configured for the `<webview>` will have node integration - * enabled when it is executed so you should ensure remote/untrusted content is not - * able to create a `<webview>` tag with a possibly malicious `preload` script. You - * can use the `will-attach-webview` event on webContents to strip away the - * `preload` script and to validate or alter the `<webview>`'s initial settings. - */ - webviewTag?: boolean; - /** - * A list of strings that will be appended to `process.argv` in the renderer - * process of this app. Useful for passing small bits of data down to renderer - * process preload scripts. - */ - additionalArguments?: string[]; - /** - * Whether to enable browser style consecutive dialog protection. Default is - * `false`. - */ - safeDialogs?: boolean; - /** - * The message to display when consecutive dialog protection is triggered. If not - * defined the default message would be used, note that currently the default - * message is in English and not localized. - */ - safeDialogsMessage?: string; - /** - * Whether to disable dialogs completely. Overrides `safeDialogs`. Default is - * `false`. - */ - disableDialogs?: boolean; - /** - * Whether dragging and dropping a file or link onto the page causes a navigation. - * Default is `false`. - */ - navigateOnDragDrop?: boolean; - /** - * Autoplay policy to apply to content in the window, can be - * `no-user-gesture-required`, `user-gesture-required`, - * `document-user-activation-required`. Defaults to `no-user-gesture-required`. - */ - autoplayPolicy?: ('no-user-gesture-required' | 'user-gesture-required' | 'document-user-activation-required'); - /** - * Whether to prevent the window from resizing when entering HTML Fullscreen. - * Default is `false`. - */ - disableHtmlFullscreenWindowResize?: boolean; - /** - * An alternative title string provided only to accessibility tools such as screen - * readers. This string is not directly visible to users. - */ - accessibleTitle?: string; - /** - * Whether to enable the builtin spellchecker. Default is `true`. - */ - spellcheck?: boolean; - /** - * Whether to enable the WebSQL api. Default is `true`. - */ - enableWebSQL?: boolean; - /** - * Enforces the v8 code caching policy used by blink. Accepted values are - */ - v8CacheOptions?: ('none' | 'code' | 'bypassHeatCheck' | 'bypassHeatCheckAndEagerCompile'); - /** - * Whether to enable preferred size mode. The preferred size is the minimum size - * needed to contain the layout of the document—without requiring scrolling. - * Enabling this will cause the `preferred-size-changed` event to be emitted on the - * `WebContents` when the preferred size changes. Default is `false`. - */ - enablePreferredSizeMode?: boolean; - } - - interface DefaultFontFamily { - /** - * Defaults to `Times New Roman`. - */ - standard?: string; - /** - * Defaults to `Times New Roman`. - */ - serif?: string; - /** - * Defaults to `Arial`. - */ - sansSerif?: string; - /** - * Defaults to `Courier New`. - */ - monospace?: string; - /** - * Defaults to `Script`. - */ - cursive?: string; - /** - * Defaults to `Impact`. - */ - fantasy?: string; - } - - interface RemoteMainInterface { - app: App; - autoUpdater: AutoUpdater; - BrowserView: typeof BrowserView; - BrowserWindow: typeof BrowserWindow; - ClientRequest: typeof ClientRequest; - clipboard: Clipboard; - CommandLine: typeof CommandLine; - contentTracing: ContentTracing; - Cookies: typeof Cookies; - crashReporter: CrashReporter; - Debugger: typeof Debugger; - desktopCapturer: DesktopCapturer; - dialog: Dialog; - Dock: typeof Dock; - DownloadItem: typeof DownloadItem; - globalShortcut: GlobalShortcut; - inAppPurchase: InAppPurchase; - IncomingMessage: typeof IncomingMessage; - ipcMain: IpcMain; - Menu: typeof Menu; - MenuItem: typeof MenuItem; - MessageChannelMain: typeof MessageChannelMain; - MessagePortMain: typeof MessagePortMain; - nativeImage: typeof NativeImage; - nativeTheme: NativeTheme; - net: Net; - netLog: NetLog; - Notification: typeof Notification; - powerMonitor: PowerMonitor; - powerSaveBlocker: PowerSaveBlocker; - protocol: Protocol; - screen: Screen; - ServiceWorkers: typeof ServiceWorkers; - session: typeof Session; - ShareMenu: typeof ShareMenu; - shell: Shell; - systemPreferences: SystemPreferences; - TouchBar: typeof TouchBar; - TouchBarButton: typeof TouchBarButton; - TouchBarColorPicker: typeof TouchBarColorPicker; - TouchBarGroup: typeof TouchBarGroup; - TouchBarLabel: typeof TouchBarLabel; - TouchBarOtherItemsProxy: typeof TouchBarOtherItemsProxy; - TouchBarPopover: typeof TouchBarPopover; - TouchBarScrubber: typeof TouchBarScrubber; - TouchBarSegmentedControl: typeof TouchBarSegmentedControl; - TouchBarSlider: typeof TouchBarSlider; - TouchBarSpacer: typeof TouchBarSpacer; - Tray: typeof Tray; - webContents: typeof WebContents; - webFrameMain: typeof WebFrameMain; - WebRequest: typeof WebRequest; - } - - - - namespace Common { - const clipboard: Clipboard; - const crashReporter: CrashReporter; - const desktopCapturer: DesktopCapturer; - class NativeImage extends Electron.NativeImage {} - type nativeImage = NativeImage; - const nativeImage: typeof NativeImage; - const shell: Shell; - type AboutPanelOptionsOptions = Electron.AboutPanelOptionsOptions; - type AddRepresentationOptions = Electron.AddRepresentationOptions; - type AnimationSettings = Electron.AnimationSettings; - type AppDetailsOptions = Electron.AppDetailsOptions; - type ApplicationInfoForProtocolReturnValue = Electron.ApplicationInfoForProtocolReturnValue; - type AuthenticationResponseDetails = Electron.AuthenticationResponseDetails; - type AuthInfo = Electron.AuthInfo; - type AutoResizeOptions = Electron.AutoResizeOptions; - type BeforeSendResponse = Electron.BeforeSendResponse; - type BitmapOptions = Electron.BitmapOptions; - type BlinkMemoryInfo = Electron.BlinkMemoryInfo; - type BrowserViewConstructorOptions = Electron.BrowserViewConstructorOptions; - type BrowserWindowConstructorOptions = Electron.BrowserWindowConstructorOptions; - type CertificateTrustDialogOptions = Electron.CertificateTrustDialogOptions; - type ClearStorageDataOptions = Electron.ClearStorageDataOptions; - type ClientRequestConstructorOptions = Electron.ClientRequestConstructorOptions; - type Config = Electron.Config; - type ConsoleMessageEvent = Electron.ConsoleMessageEvent; - type ContextMenuParams = Electron.ContextMenuParams; - type CookiesGetFilter = Electron.CookiesGetFilter; - type CookiesSetDetails = Electron.CookiesSetDetails; - type CrashReporterStartOptions = Electron.CrashReporterStartOptions; - type CreateFromBitmapOptions = Electron.CreateFromBitmapOptions; - type CreateFromBufferOptions = Electron.CreateFromBufferOptions; - type CreateInterruptedDownloadOptions = Electron.CreateInterruptedDownloadOptions; - type Data = Electron.Data; - type Details = Electron.Details; - type DidChangeThemeColorEvent = Electron.DidChangeThemeColorEvent; - type DidCreateWindowDetails = Electron.DidCreateWindowDetails; - type DidFailLoadEvent = Electron.DidFailLoadEvent; - type DidFrameFinishLoadEvent = Electron.DidFrameFinishLoadEvent; - type DidNavigateEvent = Electron.DidNavigateEvent; - type DidNavigateInPageEvent = Electron.DidNavigateInPageEvent; - type DisplayBalloonOptions = Electron.DisplayBalloonOptions; - type EnableNetworkEmulationOptions = Electron.EnableNetworkEmulationOptions; - type FeedURLOptions = Electron.FeedURLOptions; - type FileIconOptions = Electron.FileIconOptions; - type Filter = Electron.Filter; - type FindInPageOptions = Electron.FindInPageOptions; - type FocusOptions = Electron.FocusOptions; - type FoundInPageEvent = Electron.FoundInPageEvent; - type FromPartitionOptions = Electron.FromPartitionOptions; - type HandlerDetails = Electron.HandlerDetails; - type HeadersReceivedResponse = Electron.HeadersReceivedResponse; - type HeapStatistics = Electron.HeapStatistics; - type IgnoreMouseEventsOptions = Electron.IgnoreMouseEventsOptions; - type ImportCertificateOptions = Electron.ImportCertificateOptions; - type Info = Electron.Info; - type Input = Electron.Input; - type InsertCSSOptions = Electron.InsertCSSOptions; - type IpcMessageEvent = Electron.IpcMessageEvent; - type Item = Electron.Item; - type JumpListSettings = Electron.JumpListSettings; - type LoadCommitEvent = Electron.LoadCommitEvent; - type LoadExtensionOptions = Electron.LoadExtensionOptions; - type LoadFileOptions = Electron.LoadFileOptions; - type LoadURLOptions = Electron.LoadURLOptions; - type LoginItemSettings = Electron.LoginItemSettings; - type LoginItemSettingsOptions = Electron.LoginItemSettingsOptions; - type MenuItemConstructorOptions = Electron.MenuItemConstructorOptions; - type MessageBoxOptions = Electron.MessageBoxOptions; - type MessageBoxReturnValue = Electron.MessageBoxReturnValue; - type MessageBoxSyncOptions = Electron.MessageBoxSyncOptions; - type MessageDetails = Electron.MessageDetails; - type MessageEvent = Electron.MessageEvent; - type MoveToApplicationsFolderOptions = Electron.MoveToApplicationsFolderOptions; - type NewWindowEvent = Electron.NewWindowEvent; - type NotificationConstructorOptions = Electron.NotificationConstructorOptions; - type OnBeforeRedirectListenerDetails = Electron.OnBeforeRedirectListenerDetails; - type OnBeforeRequestListenerDetails = Electron.OnBeforeRequestListenerDetails; - type OnBeforeSendHeadersListenerDetails = Electron.OnBeforeSendHeadersListenerDetails; - type OnCompletedListenerDetails = Electron.OnCompletedListenerDetails; - type OnErrorOccurredListenerDetails = Electron.OnErrorOccurredListenerDetails; - type OnHeadersReceivedListenerDetails = Electron.OnHeadersReceivedListenerDetails; - type OnResponseStartedListenerDetails = Electron.OnResponseStartedListenerDetails; - type OnSendHeadersListenerDetails = Electron.OnSendHeadersListenerDetails; - type OpenDevToolsOptions = Electron.OpenDevToolsOptions; - type OpenDialogOptions = Electron.OpenDialogOptions; - type OpenDialogReturnValue = Electron.OpenDialogReturnValue; - type OpenDialogSyncOptions = Electron.OpenDialogSyncOptions; - type OpenExternalOptions = Electron.OpenExternalOptions; - type Options = Electron.Options; - type PageFaviconUpdatedEvent = Electron.PageFaviconUpdatedEvent; - type PageTitleUpdatedEvent = Electron.PageTitleUpdatedEvent; - type Parameters = Electron.Parameters; - type Payment = Electron.Payment; - type PermissionCheckHandlerHandlerDetails = Electron.PermissionCheckHandlerHandlerDetails; - type PermissionRequestHandlerHandlerDetails = Electron.PermissionRequestHandlerHandlerDetails; - type PluginCrashedEvent = Electron.PluginCrashedEvent; - type PopupOptions = Electron.PopupOptions; - type PreconnectOptions = Electron.PreconnectOptions; - type PrintToPDFOptions = Electron.PrintToPDFOptions; - type Privileges = Electron.Privileges; - type ProgressBarOptions = Electron.ProgressBarOptions; - type Provider = Electron.Provider; - type ReadBookmark = Electron.ReadBookmark; - type RelaunchOptions = Electron.RelaunchOptions; - type RenderProcessGoneDetails = Electron.RenderProcessGoneDetails; - type Request = Electron.Request; - type ResizeOptions = Electron.ResizeOptions; - type ResourceUsage = Electron.ResourceUsage; - type Response = Electron.Response; - type Result = Electron.Result; - type SaveDialogOptions = Electron.SaveDialogOptions; - type SaveDialogReturnValue = Electron.SaveDialogReturnValue; - type SaveDialogSyncOptions = Electron.SaveDialogSyncOptions; - type Settings = Electron.Settings; - type SourcesOptions = Electron.SourcesOptions; - type SSLConfigConfig = Electron.SSLConfigConfig; - type StartLoggingOptions = Electron.StartLoggingOptions; - type SystemMemoryInfo = Electron.SystemMemoryInfo; - type TitleOptions = Electron.TitleOptions; - type ToBitmapOptions = Electron.ToBitmapOptions; - type ToDataURLOptions = Electron.ToDataURLOptions; - type ToPNGOptions = Electron.ToPNGOptions; - type TouchBarButtonConstructorOptions = Electron.TouchBarButtonConstructorOptions; - type TouchBarColorPickerConstructorOptions = Electron.TouchBarColorPickerConstructorOptions; - type TouchBarConstructorOptions = Electron.TouchBarConstructorOptions; - type TouchBarGroupConstructorOptions = Electron.TouchBarGroupConstructorOptions; - type TouchBarLabelConstructorOptions = Electron.TouchBarLabelConstructorOptions; - type TouchBarPopoverConstructorOptions = Electron.TouchBarPopoverConstructorOptions; - type TouchBarScrubberConstructorOptions = Electron.TouchBarScrubberConstructorOptions; - type TouchBarSegmentedControlConstructorOptions = Electron.TouchBarSegmentedControlConstructorOptions; - type TouchBarSliderConstructorOptions = Electron.TouchBarSliderConstructorOptions; - type TouchBarSpacerConstructorOptions = Electron.TouchBarSpacerConstructorOptions; - type TraceBufferUsageReturnValue = Electron.TraceBufferUsageReturnValue; - type UpdateTargetUrlEvent = Electron.UpdateTargetUrlEvent; - type UploadProgress = Electron.UploadProgress; - type VisibleOnAllWorkspacesOptions = Electron.VisibleOnAllWorkspacesOptions; - type WebContentsPrintOptions = Electron.WebContentsPrintOptions; - type WebviewTagPrintOptions = Electron.WebviewTagPrintOptions; - type WillNavigateEvent = Electron.WillNavigateEvent; - type EditFlags = Electron.EditFlags; - type FoundInPageResult = Electron.FoundInPageResult; - type LaunchItems = Electron.LaunchItems; - type Margins = Electron.Margins; - type MediaFlags = Electron.MediaFlags; - type PageRanges = Electron.PageRanges; - type WebPreferences = Electron.WebPreferences; - type DefaultFontFamily = Electron.DefaultFontFamily; - type BluetoothDevice = Electron.BluetoothDevice; - type Certificate = Electron.Certificate; - type CertificatePrincipal = Electron.CertificatePrincipal; - type Cookie = Electron.Cookie; - type CPUUsage = Electron.CPUUsage; - type CrashReport = Electron.CrashReport; - type CustomScheme = Electron.CustomScheme; - type DesktopCapturerSource = Electron.DesktopCapturerSource; - type Display = Electron.Display; - type Event = Electron.Event; - type Extension = Electron.Extension; - type ExtensionInfo = Electron.ExtensionInfo; - type FileFilter = Electron.FileFilter; - type FilePathWithHeaders = Electron.FilePathWithHeaders; - type GPUFeatureStatus = Electron.GPUFeatureStatus; - type InputEvent = Electron.InputEvent; - type IOCounters = Electron.IOCounters; - type IpcMainEvent = Electron.IpcMainEvent; - type IpcMainInvokeEvent = Electron.IpcMainInvokeEvent; - type IpcRendererEvent = Electron.IpcRendererEvent; - type JumpListCategory = Electron.JumpListCategory; - type JumpListItem = Electron.JumpListItem; - type KeyboardEvent = Electron.KeyboardEvent; - type KeyboardInputEvent = Electron.KeyboardInputEvent; - type MemoryInfo = Electron.MemoryInfo; - type MemoryUsageDetails = Electron.MemoryUsageDetails; - type MimeTypedBuffer = Electron.MimeTypedBuffer; - type MouseInputEvent = Electron.MouseInputEvent; - type MouseWheelInputEvent = Electron.MouseWheelInputEvent; - type NewWindowWebContentsEvent = Electron.NewWindowWebContentsEvent; - type NotificationAction = Electron.NotificationAction; - type NotificationResponse = Electron.NotificationResponse; - type Point = Electron.Point; - type PostBody = Electron.PostBody; - type PostData = Electron.PostData; - type PrinterInfo = Electron.PrinterInfo; - type ProcessMemoryInfo = Electron.ProcessMemoryInfo; - type ProcessMetric = Electron.ProcessMetric; - type Product = Electron.Product; - type ProtocolRequest = Electron.ProtocolRequest; - type ProtocolResponse = Electron.ProtocolResponse; - type ProtocolResponseUploadData = Electron.ProtocolResponseUploadData; - type Rectangle = Electron.Rectangle; - type Referrer = Electron.Referrer; - type ScrubberItem = Electron.ScrubberItem; - type SegmentedControlSegment = Electron.SegmentedControlSegment; - type SerialPort = Electron.SerialPort; - type ServiceWorkerInfo = Electron.ServiceWorkerInfo; - type SharedWorkerInfo = Electron.SharedWorkerInfo; - type SharingItem = Electron.SharingItem; - type ShortcutDetails = Electron.ShortcutDetails; - type Size = Electron.Size; - type Task = Electron.Task; - type ThumbarButton = Electron.ThumbarButton; - type TraceCategoriesAndOptions = Electron.TraceCategoriesAndOptions; - type TraceConfig = Electron.TraceConfig; - type Transaction = Electron.Transaction; - type UploadData = Electron.UploadData; - type UploadFile = Electron.UploadFile; - type UploadRawData = Electron.UploadRawData; - type WebSource = Electron.WebSource; - } - - namespace Main { - const app: App; - const autoUpdater: AutoUpdater; - class BrowserView extends Electron.BrowserView {} - class BrowserWindow extends Electron.BrowserWindow {} - class ClientRequest extends Electron.ClientRequest {} - class CommandLine extends Electron.CommandLine {} - const contentTracing: ContentTracing; - class Cookies extends Electron.Cookies {} - class Debugger extends Electron.Debugger {} - const dialog: Dialog; - class Dock extends Electron.Dock {} - class DownloadItem extends Electron.DownloadItem {} - const globalShortcut: GlobalShortcut; - const inAppPurchase: InAppPurchase; - class IncomingMessage extends Electron.IncomingMessage {} - const ipcMain: IpcMain; - class Menu extends Electron.Menu {} - class MenuItem extends Electron.MenuItem {} - class MessageChannelMain extends Electron.MessageChannelMain {} - class MessagePortMain extends Electron.MessagePortMain {} - const nativeTheme: NativeTheme; - const net: Net; - const netLog: NetLog; - class Notification extends Electron.Notification {} - const powerMonitor: PowerMonitor; - const powerSaveBlocker: PowerSaveBlocker; - const protocol: Protocol; - const screen: Screen; - class ServiceWorkers extends Electron.ServiceWorkers {} - class Session extends Electron.Session {} - type session = Session; - const session: typeof Session; - class ShareMenu extends Electron.ShareMenu {} - const systemPreferences: SystemPreferences; - class TouchBar extends Electron.TouchBar {} - class TouchBarButton extends Electron.TouchBarButton {} - class TouchBarColorPicker extends Electron.TouchBarColorPicker {} - class TouchBarGroup extends Electron.TouchBarGroup {} - class TouchBarLabel extends Electron.TouchBarLabel {} - class TouchBarOtherItemsProxy extends Electron.TouchBarOtherItemsProxy {} - class TouchBarPopover extends Electron.TouchBarPopover {} - class TouchBarScrubber extends Electron.TouchBarScrubber {} - class TouchBarSegmentedControl extends Electron.TouchBarSegmentedControl {} - class TouchBarSlider extends Electron.TouchBarSlider {} - class TouchBarSpacer extends Electron.TouchBarSpacer {} - class Tray extends Electron.Tray {} - class WebContents extends Electron.WebContents {} - type webContents = WebContents; - const webContents: typeof WebContents; - class WebFrameMain extends Electron.WebFrameMain {} - type webFrameMain = WebFrameMain; - const webFrameMain: typeof WebFrameMain; - class WebRequest extends Electron.WebRequest {} - type AboutPanelOptionsOptions = Electron.AboutPanelOptionsOptions; - type AddRepresentationOptions = Electron.AddRepresentationOptions; - type AnimationSettings = Electron.AnimationSettings; - type AppDetailsOptions = Electron.AppDetailsOptions; - type ApplicationInfoForProtocolReturnValue = Electron.ApplicationInfoForProtocolReturnValue; - type AuthenticationResponseDetails = Electron.AuthenticationResponseDetails; - type AuthInfo = Electron.AuthInfo; - type AutoResizeOptions = Electron.AutoResizeOptions; - type BeforeSendResponse = Electron.BeforeSendResponse; - type BitmapOptions = Electron.BitmapOptions; - type BlinkMemoryInfo = Electron.BlinkMemoryInfo; - type BrowserViewConstructorOptions = Electron.BrowserViewConstructorOptions; - type BrowserWindowConstructorOptions = Electron.BrowserWindowConstructorOptions; - type CertificateTrustDialogOptions = Electron.CertificateTrustDialogOptions; - type ClearStorageDataOptions = Electron.ClearStorageDataOptions; - type ClientRequestConstructorOptions = Electron.ClientRequestConstructorOptions; - type Config = Electron.Config; - type ConsoleMessageEvent = Electron.ConsoleMessageEvent; - type ContextMenuParams = Electron.ContextMenuParams; - type CookiesGetFilter = Electron.CookiesGetFilter; - type CookiesSetDetails = Electron.CookiesSetDetails; - type CrashReporterStartOptions = Electron.CrashReporterStartOptions; - type CreateFromBitmapOptions = Electron.CreateFromBitmapOptions; - type CreateFromBufferOptions = Electron.CreateFromBufferOptions; - type CreateInterruptedDownloadOptions = Electron.CreateInterruptedDownloadOptions; - type Data = Electron.Data; - type Details = Electron.Details; - type DidChangeThemeColorEvent = Electron.DidChangeThemeColorEvent; - type DidCreateWindowDetails = Electron.DidCreateWindowDetails; - type DidFailLoadEvent = Electron.DidFailLoadEvent; - type DidFrameFinishLoadEvent = Electron.DidFrameFinishLoadEvent; - type DidNavigateEvent = Electron.DidNavigateEvent; - type DidNavigateInPageEvent = Electron.DidNavigateInPageEvent; - type DisplayBalloonOptions = Electron.DisplayBalloonOptions; - type EnableNetworkEmulationOptions = Electron.EnableNetworkEmulationOptions; - type FeedURLOptions = Electron.FeedURLOptions; - type FileIconOptions = Electron.FileIconOptions; - type Filter = Electron.Filter; - type FindInPageOptions = Electron.FindInPageOptions; - type FocusOptions = Electron.FocusOptions; - type FoundInPageEvent = Electron.FoundInPageEvent; - type FromPartitionOptions = Electron.FromPartitionOptions; - type HandlerDetails = Electron.HandlerDetails; - type HeadersReceivedResponse = Electron.HeadersReceivedResponse; - type HeapStatistics = Electron.HeapStatistics; - type IgnoreMouseEventsOptions = Electron.IgnoreMouseEventsOptions; - type ImportCertificateOptions = Electron.ImportCertificateOptions; - type Info = Electron.Info; - type Input = Electron.Input; - type InsertCSSOptions = Electron.InsertCSSOptions; - type IpcMessageEvent = Electron.IpcMessageEvent; - type Item = Electron.Item; - type JumpListSettings = Electron.JumpListSettings; - type LoadCommitEvent = Electron.LoadCommitEvent; - type LoadExtensionOptions = Electron.LoadExtensionOptions; - type LoadFileOptions = Electron.LoadFileOptions; - type LoadURLOptions = Electron.LoadURLOptions; - type LoginItemSettings = Electron.LoginItemSettings; - type LoginItemSettingsOptions = Electron.LoginItemSettingsOptions; - type MenuItemConstructorOptions = Electron.MenuItemConstructorOptions; - type MessageBoxOptions = Electron.MessageBoxOptions; - type MessageBoxReturnValue = Electron.MessageBoxReturnValue; - type MessageBoxSyncOptions = Electron.MessageBoxSyncOptions; - type MessageDetails = Electron.MessageDetails; - type MessageEvent = Electron.MessageEvent; - type MoveToApplicationsFolderOptions = Electron.MoveToApplicationsFolderOptions; - type NewWindowEvent = Electron.NewWindowEvent; - type NotificationConstructorOptions = Electron.NotificationConstructorOptions; - type OnBeforeRedirectListenerDetails = Electron.OnBeforeRedirectListenerDetails; - type OnBeforeRequestListenerDetails = Electron.OnBeforeRequestListenerDetails; - type OnBeforeSendHeadersListenerDetails = Electron.OnBeforeSendHeadersListenerDetails; - type OnCompletedListenerDetails = Electron.OnCompletedListenerDetails; - type OnErrorOccurredListenerDetails = Electron.OnErrorOccurredListenerDetails; - type OnHeadersReceivedListenerDetails = Electron.OnHeadersReceivedListenerDetails; - type OnResponseStartedListenerDetails = Electron.OnResponseStartedListenerDetails; - type OnSendHeadersListenerDetails = Electron.OnSendHeadersListenerDetails; - type OpenDevToolsOptions = Electron.OpenDevToolsOptions; - type OpenDialogOptions = Electron.OpenDialogOptions; - type OpenDialogReturnValue = Electron.OpenDialogReturnValue; - type OpenDialogSyncOptions = Electron.OpenDialogSyncOptions; - type OpenExternalOptions = Electron.OpenExternalOptions; - type Options = Electron.Options; - type PageFaviconUpdatedEvent = Electron.PageFaviconUpdatedEvent; - type PageTitleUpdatedEvent = Electron.PageTitleUpdatedEvent; - type Parameters = Electron.Parameters; - type Payment = Electron.Payment; - type PermissionCheckHandlerHandlerDetails = Electron.PermissionCheckHandlerHandlerDetails; - type PermissionRequestHandlerHandlerDetails = Electron.PermissionRequestHandlerHandlerDetails; - type PluginCrashedEvent = Electron.PluginCrashedEvent; - type PopupOptions = Electron.PopupOptions; - type PreconnectOptions = Electron.PreconnectOptions; - type PrintToPDFOptions = Electron.PrintToPDFOptions; - type Privileges = Electron.Privileges; - type ProgressBarOptions = Electron.ProgressBarOptions; - type Provider = Electron.Provider; - type ReadBookmark = Electron.ReadBookmark; - type RelaunchOptions = Electron.RelaunchOptions; - type RenderProcessGoneDetails = Electron.RenderProcessGoneDetails; - type Request = Electron.Request; - type ResizeOptions = Electron.ResizeOptions; - type ResourceUsage = Electron.ResourceUsage; - type Response = Electron.Response; - type Result = Electron.Result; - type SaveDialogOptions = Electron.SaveDialogOptions; - type SaveDialogReturnValue = Electron.SaveDialogReturnValue; - type SaveDialogSyncOptions = Electron.SaveDialogSyncOptions; - type Settings = Electron.Settings; - type SourcesOptions = Electron.SourcesOptions; - type SSLConfigConfig = Electron.SSLConfigConfig; - type StartLoggingOptions = Electron.StartLoggingOptions; - type SystemMemoryInfo = Electron.SystemMemoryInfo; - type TitleOptions = Electron.TitleOptions; - type ToBitmapOptions = Electron.ToBitmapOptions; - type ToDataURLOptions = Electron.ToDataURLOptions; - type ToPNGOptions = Electron.ToPNGOptions; - type TouchBarButtonConstructorOptions = Electron.TouchBarButtonConstructorOptions; - type TouchBarColorPickerConstructorOptions = Electron.TouchBarColorPickerConstructorOptions; - type TouchBarConstructorOptions = Electron.TouchBarConstructorOptions; - type TouchBarGroupConstructorOptions = Electron.TouchBarGroupConstructorOptions; - type TouchBarLabelConstructorOptions = Electron.TouchBarLabelConstructorOptions; - type TouchBarPopoverConstructorOptions = Electron.TouchBarPopoverConstructorOptions; - type TouchBarScrubberConstructorOptions = Electron.TouchBarScrubberConstructorOptions; - type TouchBarSegmentedControlConstructorOptions = Electron.TouchBarSegmentedControlConstructorOptions; - type TouchBarSliderConstructorOptions = Electron.TouchBarSliderConstructorOptions; - type TouchBarSpacerConstructorOptions = Electron.TouchBarSpacerConstructorOptions; - type TraceBufferUsageReturnValue = Electron.TraceBufferUsageReturnValue; - type UpdateTargetUrlEvent = Electron.UpdateTargetUrlEvent; - type UploadProgress = Electron.UploadProgress; - type VisibleOnAllWorkspacesOptions = Electron.VisibleOnAllWorkspacesOptions; - type WebContentsPrintOptions = Electron.WebContentsPrintOptions; - type WebviewTagPrintOptions = Electron.WebviewTagPrintOptions; - type WillNavigateEvent = Electron.WillNavigateEvent; - type EditFlags = Electron.EditFlags; - type FoundInPageResult = Electron.FoundInPageResult; - type LaunchItems = Electron.LaunchItems; - type Margins = Electron.Margins; - type MediaFlags = Electron.MediaFlags; - type PageRanges = Electron.PageRanges; - type WebPreferences = Electron.WebPreferences; - type DefaultFontFamily = Electron.DefaultFontFamily; - type BluetoothDevice = Electron.BluetoothDevice; - type Certificate = Electron.Certificate; - type CertificatePrincipal = Electron.CertificatePrincipal; - type Cookie = Electron.Cookie; - type CPUUsage = Electron.CPUUsage; - type CrashReport = Electron.CrashReport; - type CustomScheme = Electron.CustomScheme; - type DesktopCapturerSource = Electron.DesktopCapturerSource; - type Display = Electron.Display; - type Event = Electron.Event; - type Extension = Electron.Extension; - type ExtensionInfo = Electron.ExtensionInfo; - type FileFilter = Electron.FileFilter; - type FilePathWithHeaders = Electron.FilePathWithHeaders; - type GPUFeatureStatus = Electron.GPUFeatureStatus; - type InputEvent = Electron.InputEvent; - type IOCounters = Electron.IOCounters; - type IpcMainEvent = Electron.IpcMainEvent; - type IpcMainInvokeEvent = Electron.IpcMainInvokeEvent; - type IpcRendererEvent = Electron.IpcRendererEvent; - type JumpListCategory = Electron.JumpListCategory; - type JumpListItem = Electron.JumpListItem; - type KeyboardEvent = Electron.KeyboardEvent; - type KeyboardInputEvent = Electron.KeyboardInputEvent; - type MemoryInfo = Electron.MemoryInfo; - type MemoryUsageDetails = Electron.MemoryUsageDetails; - type MimeTypedBuffer = Electron.MimeTypedBuffer; - type MouseInputEvent = Electron.MouseInputEvent; - type MouseWheelInputEvent = Electron.MouseWheelInputEvent; - type NewWindowWebContentsEvent = Electron.NewWindowWebContentsEvent; - type NotificationAction = Electron.NotificationAction; - type NotificationResponse = Electron.NotificationResponse; - type Point = Electron.Point; - type PostBody = Electron.PostBody; - type PostData = Electron.PostData; - type PrinterInfo = Electron.PrinterInfo; - type ProcessMemoryInfo = Electron.ProcessMemoryInfo; - type ProcessMetric = Electron.ProcessMetric; - type Product = Electron.Product; - type ProtocolRequest = Electron.ProtocolRequest; - type ProtocolResponse = Electron.ProtocolResponse; - type ProtocolResponseUploadData = Electron.ProtocolResponseUploadData; - type Rectangle = Electron.Rectangle; - type Referrer = Electron.Referrer; - type ScrubberItem = Electron.ScrubberItem; - type SegmentedControlSegment = Electron.SegmentedControlSegment; - type SerialPort = Electron.SerialPort; - type ServiceWorkerInfo = Electron.ServiceWorkerInfo; - type SharedWorkerInfo = Electron.SharedWorkerInfo; - type SharingItem = Electron.SharingItem; - type ShortcutDetails = Electron.ShortcutDetails; - type Size = Electron.Size; - type Task = Electron.Task; - type ThumbarButton = Electron.ThumbarButton; - type TraceCategoriesAndOptions = Electron.TraceCategoriesAndOptions; - type TraceConfig = Electron.TraceConfig; - type Transaction = Electron.Transaction; - type UploadData = Electron.UploadData; - type UploadFile = Electron.UploadFile; - type UploadRawData = Electron.UploadRawData; - type WebSource = Electron.WebSource; - } - - namespace Renderer { - class BrowserWindowProxy extends Electron.BrowserWindowProxy {} - const contextBridge: ContextBridge; - const ipcRenderer: IpcRenderer; - const remote: Remote; - const webFrame: WebFrame; - const webviewTag: WebviewTag; - type AboutPanelOptionsOptions = Electron.AboutPanelOptionsOptions; - type AddRepresentationOptions = Electron.AddRepresentationOptions; - type AnimationSettings = Electron.AnimationSettings; - type AppDetailsOptions = Electron.AppDetailsOptions; - type ApplicationInfoForProtocolReturnValue = Electron.ApplicationInfoForProtocolReturnValue; - type AuthenticationResponseDetails = Electron.AuthenticationResponseDetails; - type AuthInfo = Electron.AuthInfo; - type AutoResizeOptions = Electron.AutoResizeOptions; - type BeforeSendResponse = Electron.BeforeSendResponse; - type BitmapOptions = Electron.BitmapOptions; - type BlinkMemoryInfo = Electron.BlinkMemoryInfo; - type BrowserViewConstructorOptions = Electron.BrowserViewConstructorOptions; - type BrowserWindowConstructorOptions = Electron.BrowserWindowConstructorOptions; - type CertificateTrustDialogOptions = Electron.CertificateTrustDialogOptions; - type ClearStorageDataOptions = Electron.ClearStorageDataOptions; - type ClientRequestConstructorOptions = Electron.ClientRequestConstructorOptions; - type Config = Electron.Config; - type ConsoleMessageEvent = Electron.ConsoleMessageEvent; - type ContextMenuParams = Electron.ContextMenuParams; - type CookiesGetFilter = Electron.CookiesGetFilter; - type CookiesSetDetails = Electron.CookiesSetDetails; - type CrashReporterStartOptions = Electron.CrashReporterStartOptions; - type CreateFromBitmapOptions = Electron.CreateFromBitmapOptions; - type CreateFromBufferOptions = Electron.CreateFromBufferOptions; - type CreateInterruptedDownloadOptions = Electron.CreateInterruptedDownloadOptions; - type Data = Electron.Data; - type Details = Electron.Details; - type DidChangeThemeColorEvent = Electron.DidChangeThemeColorEvent; - type DidCreateWindowDetails = Electron.DidCreateWindowDetails; - type DidFailLoadEvent = Electron.DidFailLoadEvent; - type DidFrameFinishLoadEvent = Electron.DidFrameFinishLoadEvent; - type DidNavigateEvent = Electron.DidNavigateEvent; - type DidNavigateInPageEvent = Electron.DidNavigateInPageEvent; - type DisplayBalloonOptions = Electron.DisplayBalloonOptions; - type EnableNetworkEmulationOptions = Electron.EnableNetworkEmulationOptions; - type FeedURLOptions = Electron.FeedURLOptions; - type FileIconOptions = Electron.FileIconOptions; - type Filter = Electron.Filter; - type FindInPageOptions = Electron.FindInPageOptions; - type FocusOptions = Electron.FocusOptions; - type FoundInPageEvent = Electron.FoundInPageEvent; - type FromPartitionOptions = Electron.FromPartitionOptions; - type HandlerDetails = Electron.HandlerDetails; - type HeadersReceivedResponse = Electron.HeadersReceivedResponse; - type HeapStatistics = Electron.HeapStatistics; - type IgnoreMouseEventsOptions = Electron.IgnoreMouseEventsOptions; - type ImportCertificateOptions = Electron.ImportCertificateOptions; - type Info = Electron.Info; - type Input = Electron.Input; - type InsertCSSOptions = Electron.InsertCSSOptions; - type IpcMessageEvent = Electron.IpcMessageEvent; - type Item = Electron.Item; - type JumpListSettings = Electron.JumpListSettings; - type LoadCommitEvent = Electron.LoadCommitEvent; - type LoadExtensionOptions = Electron.LoadExtensionOptions; - type LoadFileOptions = Electron.LoadFileOptions; - type LoadURLOptions = Electron.LoadURLOptions; - type LoginItemSettings = Electron.LoginItemSettings; - type LoginItemSettingsOptions = Electron.LoginItemSettingsOptions; - type MenuItemConstructorOptions = Electron.MenuItemConstructorOptions; - type MessageBoxOptions = Electron.MessageBoxOptions; - type MessageBoxReturnValue = Electron.MessageBoxReturnValue; - type MessageBoxSyncOptions = Electron.MessageBoxSyncOptions; - type MessageDetails = Electron.MessageDetails; - type MessageEvent = Electron.MessageEvent; - type MoveToApplicationsFolderOptions = Electron.MoveToApplicationsFolderOptions; - type NewWindowEvent = Electron.NewWindowEvent; - type NotificationConstructorOptions = Electron.NotificationConstructorOptions; - type OnBeforeRedirectListenerDetails = Electron.OnBeforeRedirectListenerDetails; - type OnBeforeRequestListenerDetails = Electron.OnBeforeRequestListenerDetails; - type OnBeforeSendHeadersListenerDetails = Electron.OnBeforeSendHeadersListenerDetails; - type OnCompletedListenerDetails = Electron.OnCompletedListenerDetails; - type OnErrorOccurredListenerDetails = Electron.OnErrorOccurredListenerDetails; - type OnHeadersReceivedListenerDetails = Electron.OnHeadersReceivedListenerDetails; - type OnResponseStartedListenerDetails = Electron.OnResponseStartedListenerDetails; - type OnSendHeadersListenerDetails = Electron.OnSendHeadersListenerDetails; - type OpenDevToolsOptions = Electron.OpenDevToolsOptions; - type OpenDialogOptions = Electron.OpenDialogOptions; - type OpenDialogReturnValue = Electron.OpenDialogReturnValue; - type OpenDialogSyncOptions = Electron.OpenDialogSyncOptions; - type OpenExternalOptions = Electron.OpenExternalOptions; - type Options = Electron.Options; - type PageFaviconUpdatedEvent = Electron.PageFaviconUpdatedEvent; - type PageTitleUpdatedEvent = Electron.PageTitleUpdatedEvent; - type Parameters = Electron.Parameters; - type Payment = Electron.Payment; - type PermissionCheckHandlerHandlerDetails = Electron.PermissionCheckHandlerHandlerDetails; - type PermissionRequestHandlerHandlerDetails = Electron.PermissionRequestHandlerHandlerDetails; - type PluginCrashedEvent = Electron.PluginCrashedEvent; - type PopupOptions = Electron.PopupOptions; - type PreconnectOptions = Electron.PreconnectOptions; - type PrintToPDFOptions = Electron.PrintToPDFOptions; - type Privileges = Electron.Privileges; - type ProgressBarOptions = Electron.ProgressBarOptions; - type Provider = Electron.Provider; - type ReadBookmark = Electron.ReadBookmark; - type RelaunchOptions = Electron.RelaunchOptions; - type RenderProcessGoneDetails = Electron.RenderProcessGoneDetails; - type Request = Electron.Request; - type ResizeOptions = Electron.ResizeOptions; - type ResourceUsage = Electron.ResourceUsage; - type Response = Electron.Response; - type Result = Electron.Result; - type SaveDialogOptions = Electron.SaveDialogOptions; - type SaveDialogReturnValue = Electron.SaveDialogReturnValue; - type SaveDialogSyncOptions = Electron.SaveDialogSyncOptions; - type Settings = Electron.Settings; - type SourcesOptions = Electron.SourcesOptions; - type SSLConfigConfig = Electron.SSLConfigConfig; - type StartLoggingOptions = Electron.StartLoggingOptions; - type SystemMemoryInfo = Electron.SystemMemoryInfo; - type TitleOptions = Electron.TitleOptions; - type ToBitmapOptions = Electron.ToBitmapOptions; - type ToDataURLOptions = Electron.ToDataURLOptions; - type ToPNGOptions = Electron.ToPNGOptions; - type TouchBarButtonConstructorOptions = Electron.TouchBarButtonConstructorOptions; - type TouchBarColorPickerConstructorOptions = Electron.TouchBarColorPickerConstructorOptions; - type TouchBarConstructorOptions = Electron.TouchBarConstructorOptions; - type TouchBarGroupConstructorOptions = Electron.TouchBarGroupConstructorOptions; - type TouchBarLabelConstructorOptions = Electron.TouchBarLabelConstructorOptions; - type TouchBarPopoverConstructorOptions = Electron.TouchBarPopoverConstructorOptions; - type TouchBarScrubberConstructorOptions = Electron.TouchBarScrubberConstructorOptions; - type TouchBarSegmentedControlConstructorOptions = Electron.TouchBarSegmentedControlConstructorOptions; - type TouchBarSliderConstructorOptions = Electron.TouchBarSliderConstructorOptions; - type TouchBarSpacerConstructorOptions = Electron.TouchBarSpacerConstructorOptions; - type TraceBufferUsageReturnValue = Electron.TraceBufferUsageReturnValue; - type UpdateTargetUrlEvent = Electron.UpdateTargetUrlEvent; - type UploadProgress = Electron.UploadProgress; - type VisibleOnAllWorkspacesOptions = Electron.VisibleOnAllWorkspacesOptions; - type WebContentsPrintOptions = Electron.WebContentsPrintOptions; - type WebviewTagPrintOptions = Electron.WebviewTagPrintOptions; - type WillNavigateEvent = Electron.WillNavigateEvent; - type EditFlags = Electron.EditFlags; - type FoundInPageResult = Electron.FoundInPageResult; - type LaunchItems = Electron.LaunchItems; - type Margins = Electron.Margins; - type MediaFlags = Electron.MediaFlags; - type PageRanges = Electron.PageRanges; - type WebPreferences = Electron.WebPreferences; - type DefaultFontFamily = Electron.DefaultFontFamily; - type BluetoothDevice = Electron.BluetoothDevice; - type Certificate = Electron.Certificate; - type CertificatePrincipal = Electron.CertificatePrincipal; - type Cookie = Electron.Cookie; - type CPUUsage = Electron.CPUUsage; - type CrashReport = Electron.CrashReport; - type CustomScheme = Electron.CustomScheme; - type DesktopCapturerSource = Electron.DesktopCapturerSource; - type Display = Electron.Display; - type Event = Electron.Event; - type Extension = Electron.Extension; - type ExtensionInfo = Electron.ExtensionInfo; - type FileFilter = Electron.FileFilter; - type FilePathWithHeaders = Electron.FilePathWithHeaders; - type GPUFeatureStatus = Electron.GPUFeatureStatus; - type InputEvent = Electron.InputEvent; - type IOCounters = Electron.IOCounters; - type IpcMainEvent = Electron.IpcMainEvent; - type IpcMainInvokeEvent = Electron.IpcMainInvokeEvent; - type IpcRendererEvent = Electron.IpcRendererEvent; - type JumpListCategory = Electron.JumpListCategory; - type JumpListItem = Electron.JumpListItem; - type KeyboardEvent = Electron.KeyboardEvent; - type KeyboardInputEvent = Electron.KeyboardInputEvent; - type MemoryInfo = Electron.MemoryInfo; - type MemoryUsageDetails = Electron.MemoryUsageDetails; - type MimeTypedBuffer = Electron.MimeTypedBuffer; - type MouseInputEvent = Electron.MouseInputEvent; - type MouseWheelInputEvent = Electron.MouseWheelInputEvent; - type NewWindowWebContentsEvent = Electron.NewWindowWebContentsEvent; - type NotificationAction = Electron.NotificationAction; - type NotificationResponse = Electron.NotificationResponse; - type Point = Electron.Point; - type PostBody = Electron.PostBody; - type PostData = Electron.PostData; - type PrinterInfo = Electron.PrinterInfo; - type ProcessMemoryInfo = Electron.ProcessMemoryInfo; - type ProcessMetric = Electron.ProcessMetric; - type Product = Electron.Product; - type ProtocolRequest = Electron.ProtocolRequest; - type ProtocolResponse = Electron.ProtocolResponse; - type ProtocolResponseUploadData = Electron.ProtocolResponseUploadData; - type Rectangle = Electron.Rectangle; - type Referrer = Electron.Referrer; - type ScrubberItem = Electron.ScrubberItem; - type SegmentedControlSegment = Electron.SegmentedControlSegment; - type SerialPort = Electron.SerialPort; - type ServiceWorkerInfo = Electron.ServiceWorkerInfo; - type SharedWorkerInfo = Electron.SharedWorkerInfo; - type SharingItem = Electron.SharingItem; - type ShortcutDetails = Electron.ShortcutDetails; - type Size = Electron.Size; - type Task = Electron.Task; - type ThumbarButton = Electron.ThumbarButton; - type TraceCategoriesAndOptions = Electron.TraceCategoriesAndOptions; - type TraceConfig = Electron.TraceConfig; - type Transaction = Electron.Transaction; - type UploadData = Electron.UploadData; - type UploadFile = Electron.UploadFile; - type UploadRawData = Electron.UploadRawData; - type WebSource = Electron.WebSource; - } - - const app: App; - const autoUpdater: AutoUpdater; - const clipboard: Clipboard; - const contentTracing: ContentTracing; - const contextBridge: ContextBridge; - const crashReporter: CrashReporter; - const desktopCapturer: DesktopCapturer; - const dialog: Dialog; - const globalShortcut: GlobalShortcut; - const inAppPurchase: InAppPurchase; - const ipcMain: IpcMain; - const ipcRenderer: IpcRenderer; - type nativeImage = NativeImage; - const nativeImage: typeof NativeImage; - const nativeTheme: NativeTheme; - const net: Net; - const netLog: NetLog; - const powerMonitor: PowerMonitor; - const powerSaveBlocker: PowerSaveBlocker; - const protocol: Protocol; - const remote: Remote; - const screen: Screen; - type session = Session; - const session: typeof Session; - const shell: Shell; - const systemPreferences: SystemPreferences; - type webContents = WebContents; - const webContents: typeof WebContents; - const webFrame: WebFrame; - type webFrameMain = WebFrameMain; - const webFrameMain: typeof WebFrameMain; - const webviewTag: WebviewTag; - -} - -declare module 'electron' { - export = Electron; -} - -declare module 'electron/main' { - export = Electron.Main -} - -declare module 'electron/common' { - export = Electron.Common -} - -declare module 'electron/renderer' { - export = Electron.Renderer -} - -interface NodeRequireFunction { - (moduleName: 'electron'): typeof Electron; - (moduleName: 'electron/main'): typeof Electron.Main; - (moduleName: 'electron/common'): typeof Electron.Common; - (moduleName: 'electron/renderer'): typeof Electron.Renderer; -} - -interface NodeRequire { - (moduleName: 'electron'): typeof Electron; - (moduleName: 'electron/main'): typeof Electron.Main; - (moduleName: 'electron/common'): typeof Electron.Common; - (moduleName: 'electron/renderer'): typeof Electron.Renderer; -} - -interface File { - /** - * The real path to the file on the users filesystem - */ - path: string; -} - -declare module 'original-fs' { - import * as fs from 'fs'; - export = fs; -} - -interface Document { - createElement(tagName: 'webview'): Electron.WebviewTag; -} - -declare namespace NodeJS { - interface Process extends NodeJS.EventEmitter { - - // Docs: https://electronjs.org/docs/api/process - - /** - * Emitted when Electron has loaded its internal initialization script and is - * beginning to load the web page or the main script. - */ - on(event: 'loaded', listener: Function): this; - once(event: 'loaded', listener: Function): this; - addListener(event: 'loaded', listener: Function): this; - removeListener(event: 'loaded', listener: Function): this; - /** - * Causes the main thread of the current process crash. - */ - crash(): void; - /** - * * `allocated` Integer - Size of all allocated objects in Kilobytes. - * * `marked` Integer - Size of all marked objects in Kilobytes. - * * `total` Integer - Total allocated space in Kilobytes. - * - * Returns an object with Blink memory information. It can be useful for debugging - * rendering / DOM related memory issues. Note that all values are reported in - * Kilobytes. - */ - getBlinkMemoryInfo(): Electron.BlinkMemoryInfo; - getCPUUsage(): Electron.CPUUsage; - /** - * The number of milliseconds since epoch, or `null` if the information is - * unavailable - * - * Indicates the creation time of the application. The time is represented as - * number of milliseconds since epoch. It returns null if it is unable to get the - * process creation time. - */ - getCreationTime(): (number) | (null); - /** - * * `totalHeapSize` Integer - * * `totalHeapSizeExecutable` Integer - * * `totalPhysicalSize` Integer - * * `totalAvailableSize` Integer - * * `usedHeapSize` Integer - * * `heapSizeLimit` Integer - * * `mallocedMemory` Integer - * * `peakMallocedMemory` Integer - * * `doesZapGarbage` Boolean - * - * Returns an object with V8 heap statistics. Note that all statistics are reported - * in Kilobytes. - */ - getHeapStatistics(): Electron.HeapStatistics; - getIOCounters(): Electron.IOCounters; - /** - * Resolves with a ProcessMemoryInfo - * - * Returns an object giving memory usage statistics about the current process. Note - * that all statistics are reported in Kilobytes. This api should be called after - * app ready. - * - * Chromium does not provide `residentSet` value for macOS. This is because macOS - * performs in-memory compression of pages that haven't been recently used. As a - * result the resident set size value is not what one would expect. `private` - * memory is more representative of the actual pre-compression memory usage of the - * process on macOS. - */ - getProcessMemoryInfo(): Promise<Electron.ProcessMemoryInfo>; - /** - * * `total` Integer - The total amount of physical memory in Kilobytes available - * to the system. - * * `free` Integer - The total amount of memory not being used by applications or - * disk cache. - * * `swapTotal` Integer _Windows_ _Linux_ - The total amount of swap memory in - * Kilobytes available to the system. - * * `swapFree` Integer _Windows_ _Linux_ - The free amount of swap memory in - * Kilobytes available to the system. - * - * Returns an object giving memory usage statistics about the entire system. Note - * that all statistics are reported in Kilobytes. - */ - getSystemMemoryInfo(): Electron.SystemMemoryInfo; - /** - * The version of the host operating system. - * - * Example: - * - * **Note:** It returns the actual operating system version instead of kernel - * version on macOS unlike `os.release()`. - */ - getSystemVersion(): string; - /** - * Causes the main thread of the current process hang. - */ - hang(): void; - /** - * Sets the file descriptor soft limit to `maxDescriptors` or the OS hard limit, - * whichever is lower for the current process. - * - * @platform darwin,linux - */ - setFdLimit(maxDescriptors: number): void; - /** - * Indicates whether the snapshot has been created successfully. - * -Takes a V8 heap snapshot and saves it to `filePath`. - */ - takeHeapSnapshot(filePath: string): boolean; - /** - * A `String` representing Chrome's version string. - * - */ - readonly chrome: string; - /** - * A `Boolean`. When app is started by being passed as parameter to the default - * app, this property is `true` in the main process, otherwise it is `undefined`. - * - */ - readonly defaultApp: boolean; - /** - * A `String` representing Electron's version string. - * - */ - readonly electron: string; - /** - * A `Boolean`, `true` when the current renderer context is the "main" renderer - * frame. If you want the ID of the current frame you should use - * `webFrame.routingId`. - * - */ - readonly isMainFrame: boolean; - /** - * A `Boolean`. For Mac App Store build, this property is `true`, for other builds - * it is `undefined`. - * - */ - readonly mas: boolean; - /** - * A `Boolean` that controls ASAR support inside your application. Setting this to - * `true` will disable the support for `asar` archives in Node's built-in modules. - */ - noAsar: boolean; - /** - * A `Boolean` that controls whether or not deprecation warnings are printed to - * `stderr`. Setting this to `true` will silence deprecation warnings. This - * property is used instead of the `--no-deprecation` command line flag. - */ - noDeprecation: boolean; - /** - * A `String` representing the path to the resources directory. - * - */ - readonly resourcesPath: string; - /** - * A `Boolean`. When the renderer process is sandboxed, this property is `true`, - * otherwise it is `undefined`. - * - */ - readonly sandboxed: boolean; - /** - * A `Boolean` that controls whether or not deprecation warnings will be thrown as - * exceptions. Setting this to `true` will throw errors for deprecations. This - * property is used instead of the `--throw-deprecation` command line flag. - */ - throwDeprecation: boolean; - /** - * A `Boolean` that controls whether or not deprecations printed to `stderr` - * include their stack trace. Setting this to `true` will print stack traces for - * deprecations. This property is instead of the `--trace-deprecation` command line - * flag. - */ - traceDeprecation: boolean; - /** - * A `Boolean` that controls whether or not process warnings printed to `stderr` - * include their stack trace. Setting this to `true` will print stack traces for - * process warnings (including deprecations). This property is instead of the - * `--trace-warnings` command line flag. - */ - traceProcessWarnings: boolean; - /** - * A `String` representing the current process's type, can be: - * - * * `browser` - The main process - * * `renderer` - A renderer process -* `worker` - In a web worker - * - */ - readonly type: ('browser' | 'renderer' | 'worker'); - /** - * A `Boolean`. If the app is running as a Windows Store app (appx), this property - * is `true`, for otherwise it is `undefined`. - * - */ - readonly windowsStore: boolean; - } - interface ProcessVersions { - readonly electron: string; - readonly chrome: string; - } -} \ No newline at end of file diff --git a/lib/vscode/src/typings/keytar.d.ts b/lib/vscode/src/typings/keytar.d.ts deleted file mode 100644 index f47814cf3601..000000000000 --- a/lib/vscode/src/typings/keytar.d.ts +++ /dev/null @@ -1,58 +0,0 @@ -// Definitions by: Milan Burda <https://github.com/miniak>, Brendan Forster <https://github.com/shiftkey>, Hari Juturu <https://github.com/juturu> -// Adapted from DefinitelyTyped: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/keytar/index.d.ts - -// NOTE@coder: copy in from keytar upstream and modify -// keytar pulls in libsecret-dev, which we want to avoid, -// and vscode has a 'fallback' for web use that redirects keytar calls to use localStorage. -// Keep types in here for it to compile correctly. - -declare module 'keytar' { - /** - * Get the stored password for the service and account. - * - * @param service The string service name. - * @param account The string account name. - * - * @returns A promise for the password string. - */ - export function getPassword(service: string, account: string): Promise<string | null>; - - /** - * Add the password for the service and account to the keychain. - * - * @param service The string service name. - * @param account The string account name. - * @param password The string password. - * - * @returns A promise for the set password completion. - */ - export function setPassword(service: string, account: string, password: string): Promise<void>; - - /** - * Delete the stored password for the service and account. - * - * @param service The string service name. - * @param account The string account name. - * - * @returns A promise for the deletion status. True on success. - */ - export function deletePassword(service: string, account: string): Promise<boolean>; - - /** - * Find a password for the service in the keychain. - * - * @param service The string service name. - * - * @returns A promise for the password string. - */ - export function findPassword(service: string): Promise<string | null>; - - /** - * Find all accounts and passwords for `service` in the keychain. - * - * @param service The string service name. - * - * @returns A promise for the array of found credentials. - */ - export function findCredentials(service: string): Promise<Array<{ account: string, password: string}>>; -} diff --git a/lib/vscode/src/typings/native-keymap.d.ts b/lib/vscode/src/typings/native-keymap.d.ts deleted file mode 100644 index 305555f54ed2..000000000000 --- a/lib/vscode/src/typings/native-keymap.d.ts +++ /dev/null @@ -1,75 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -// NOTE@coder: copy from native-keymap -// only used in electron-main, so we remove it to avoid pulling X11 in at build time. -// these types are required during compile, but functions are never used - -declare module 'native-keymap' { - export interface IWindowsKeyMapping { - vkey: string; - value: string; - withShift: string; - withAltGr: string; - withShiftAltGr: string; - } - export interface IWindowsKeyboardMapping { - [code: string]: IWindowsKeyMapping; - } - export interface ILinuxKeyMapping { - value: string; - withShift: string; - withAltGr: string; - withShiftAltGr: string; - } - export interface ILinuxKeyboardMapping { - [code: string]: ILinuxKeyMapping; - } - export interface IMacKeyMapping { - value: string; - valueIsDeadKey: boolean; - withShift: string; - withShiftIsDeadKey: boolean; - withAltGr: string; - withAltGrIsDeadKey: boolean; - withShiftAltGr: string; - withShiftAltGrIsDeadKey: boolean; - } - export interface IMacKeyboardMapping { - [code: string]: IMacKeyMapping; - } - - export type IKeyboardMapping = IWindowsKeyboardMapping | ILinuxKeyboardMapping | IMacKeyboardMapping; - - export function getKeyMap(): IKeyboardMapping; - - export interface IWindowsKeyboardLayoutInfo { - name: string; - id: string; - text: string; - } - - export interface ILinuxKeyboardLayoutInfo { - model: string; - layout: string; - variant: string; - options: string; - rules: string; - } - - export interface IMacKeyboardLayoutInfo { - id: string; - localizedName: string; - lang: string; - } - - export type IKeyboardLayoutInfo = IWindowsKeyboardLayoutInfo | ILinuxKeyboardLayoutInfo | IMacKeyboardLayoutInfo; - - export function getCurrentKeyboardLayout(): IKeyboardLayoutInfo; - - export function onDidChangeKeyboardLayout(callback: () => void): void; - - export function isISOKeyboard(): boolean | undefined; -} diff --git a/lib/vscode/src/vs/base/node/proxy_agent.ts b/lib/vscode/src/vs/base/node/proxy_agent.ts deleted file mode 120000 index 3fd94e050108..000000000000 --- a/lib/vscode/src/vs/base/node/proxy_agent.ts +++ /dev/null @@ -1 +0,0 @@ -../../../../../../src/node/proxy_agent.ts \ No newline at end of file diff --git a/lib/vscode/src/vs/base/test/browser/comparers.test.ts b/lib/vscode/src/vs/base/test/browser/comparers.test.ts deleted file mode 100644 index ef5856b76c65..000000000000 --- a/lib/vscode/src/vs/base/test/browser/comparers.test.ts +++ /dev/null @@ -1,283 +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 { compareFileNames, compareFileExtensions, compareFileNamesDefault, compareFileExtensionsDefault } from 'vs/base/common/comparers'; -import * as assert from 'assert'; - -const compareLocale = (a: string, b: string) => a.localeCompare(b); -const compareLocaleNumeric = (a: string, b: string) => a.localeCompare(b, undefined, { numeric: true }); - - -suite('Comparers', () => { - - test('compareFileNames', () => { - - // - // Comparisons with the same results as compareFileNamesDefault - // - - // name-only comparisons - assert(compareFileNames(null, null) === 0, 'null should be equal'); - assert(compareFileNames(null, 'abc') < 0, 'null should be come before real values'); - assert(compareFileNames('', '') === 0, 'empty should be equal'); - assert(compareFileNames('abc', 'abc') === 0, 'equal names should be equal'); - assert(compareFileNames('z', 'A') > 0, 'z comes is after A regardless of case'); - assert(compareFileNames('Z', 'a') > 0, 'Z comes after a regardless of case'); - - // name plus extension comparisons - assert(compareFileNames('bbb.aaa', 'aaa.bbb') > 0, 'files with extensions are compared first by filename'); - assert(compareFileNames('aggregate.go', 'aggregate_repo.go') > 0, 'compares the whole name all at once by locale'); - - // dotfile comparisons - assert(compareFileNames('.abc', '.abc') === 0, 'equal dotfile names should be equal'); - assert(compareFileNames('.env.', '.gitattributes') < 0, 'filenames starting with dots and with extensions should still sort properly'); - assert(compareFileNames('.env', '.aaa.env') > 0, 'dotfiles sort alphabetically when they contain multiple dots'); - assert(compareFileNames('.env', '.env.aaa') < 0, 'dotfiles with the same root sort shortest first'); - assert(compareFileNames('.aaa_env', '.aaa.env') < 0, 'and underscore in a dotfile name will sort before a dot'); - - // dotfile vs non-dotfile comparisons - assert(compareFileNames(null, '.abc') < 0, 'null should come before dotfiles'); - assert(compareFileNames('.env', 'aaa') < 0, 'dotfiles come before filenames without extensions'); - assert(compareFileNames('.env', 'aaa.env') < 0, 'dotfiles come before filenames with extensions'); - assert(compareFileNames('.md', 'A.MD') < 0, 'dotfiles sort before uppercase files'); - assert(compareFileNames('.MD', 'a.md') < 0, 'dotfiles sort before lowercase files'); - - // numeric comparisons - assert(compareFileNames('1', '1') === 0, 'numerically equal full names should be equal'); - assert(compareFileNames('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal'); - assert(compareFileNames('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order'); - assert(compareFileNames('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order even when they are multiple digits long'); - assert(compareFileNames('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically'); - assert(compareFileNames('abc1.10.txt', 'abc1.2.txt') > 0, 'numbers with dots between them are treated as two separate numbers, not one decimal number'); - - // - // Comparisons with different results than compareFileNamesDefault - // - - // name-only comparisons - assert(compareFileNames('a', 'A') !== compareLocale('a', 'A'), 'the same letter does not sort by locale'); - assert(compareFileNames('â', 'Â') !== compareLocale('â', 'Â'), 'the same accented letter does not sort by locale'); - assert.notDeepStrictEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileNames), ['artichoke', 'Artichoke', 'art', 'Art'].sort(compareLocale), 'words with the same root and different cases do not sort in locale order'); - assert.notDeepStrictEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileNames), ['email', 'Email', 'émail', 'Émail'].sort(compareLocale), 'the same base characters with different case or accents do not sort in locale order'); - - // numeric comparisons - assert(compareFileNames('abc02.txt', 'abc002.txt') > 0, 'filenames with equivalent numbers and leading zeros sort in unicode order'); - assert(compareFileNames('abc.txt1', 'abc.txt01') > 0, 'same name plus extensions with equal numbers sort in unicode order'); - assert(compareFileNames('art01', 'Art01') !== 'art01'.localeCompare('Art01', undefined, { numeric: true }), - 'a numerically equivalent word of a different case does not compare numerically based on locale'); - - }); - - test('compareFileExtensions', () => { - - // - // Comparisons with the same results as compareFileExtensionsDefault - // - - // name-only comparisons - assert(compareFileExtensions(null, null) === 0, 'null should be equal'); - assert(compareFileExtensions(null, 'abc') < 0, 'null should come before real files without extension'); - assert(compareFileExtensions('', '') === 0, 'empty should be equal'); - assert(compareFileExtensions('abc', 'abc') === 0, 'equal names should be equal'); - assert(compareFileExtensions('z', 'A') > 0, 'z comes after A'); - assert(compareFileExtensions('Z', 'a') > 0, 'Z comes after a'); - - // name plus extension comparisons - assert(compareFileExtensions('file.ext', 'file.ext') === 0, 'equal full names should be equal'); - assert(compareFileExtensions('a.ext', 'b.ext') < 0, 'if equal extensions, filenames should be compared'); - assert(compareFileExtensions('file.aaa', 'file.bbb') < 0, 'files with equal names should be compared by extensions'); - assert(compareFileExtensions('bbb.aaa', 'aaa.bbb') < 0, 'files should be compared by extensions even if filenames compare differently'); - assert(compareFileExtensions('agg.go', 'aggrepo.go') < 0, 'shorter names sort before longer names'); - assert(compareFileExtensions('agg.go', 'agg_repo.go') < 0, 'shorter names short before longer names even when the longer name contains an underscore'); - assert(compareFileExtensions('a.MD', 'b.md') < 0, 'when extensions are the same except for case, the files sort by name'); - - // dotfile comparisons - assert(compareFileExtensions('.abc', '.abc') === 0, 'equal dotfiles should be equal'); - assert(compareFileExtensions('.md', '.Gitattributes') > 0, 'dotfiles sort alphabetically regardless of case'); - - // dotfile vs non-dotfile comparisons - assert(compareFileExtensions(null, '.abc') < 0, 'null should come before dotfiles'); - assert(compareFileExtensions('.env', 'aaa.env') < 0, 'if equal extensions, filenames should be compared, empty filename should come before others'); - assert(compareFileExtensions('.MD', 'a.md') < 0, 'if extensions differ in case, files sort by extension in unicode order'); - - // numeric comparisons - assert(compareFileExtensions('1', '1') === 0, 'numerically equal full names should be equal'); - assert(compareFileExtensions('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal'); - assert(compareFileExtensions('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order'); - assert(compareFileExtensions('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order even when they are multiple digits long'); - assert(compareFileExtensions('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically'); - assert(compareFileExtensions('abc1.10.txt', 'abc1.2.txt') > 0, 'numbers with dots between them are treated as two separate numbers, not one decimal number'); - assert(compareFileExtensions('abc2.txt2', 'abc1.txt10') < 0, 'extensions with numbers should be in numerical order, not alphabetical order'); - assert(compareFileExtensions('txt.abc1', 'txt.abc1') === 0, 'equal extensions with numbers should be equal'); - assert(compareFileExtensions('txt.abc1', 'txt.abc2') < 0, 'extensions with numbers should be in numerical order, not alphabetical order'); - assert(compareFileExtensions('txt.abc2', 'txt.abc10') < 0, 'extensions with numbers should be in numerical order even when they are multiple digits long'); - assert(compareFileExtensions('a.ext1', 'b.ext1') < 0, 'if equal extensions with numbers, filenames should be compared'); - assert(compareFileExtensions('a10.txt', 'A2.txt') > 0, 'filenames with number and case differences compare numerically'); - - // - // Comparisons with different results from compareFileExtensionsDefault - // - - // name-only comparisions - assert(compareFileExtensions('a', 'A') !== compareLocale('a', 'A'), 'the same letter of different case does not sort by locale'); - assert(compareFileExtensions('â', 'Â') !== compareLocale('â', 'Â'), 'the same accented letter of different case does not sort by locale'); - assert.notDeepStrictEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileExtensions), ['artichoke', 'Artichoke', 'art', 'Art'].sort(compareLocale), 'words with the same root and different cases do not sort in locale order'); - assert.notDeepStrictEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileExtensions), ['email', 'Email', 'émail', 'Émail'].sort((a, b) => a.localeCompare(b)), 'the same base characters with different case or accents do not sort in locale order'); - - // name plus extension comparisons - assert(compareFileExtensions('a.MD', 'a.md') !== compareLocale('MD', 'md'), 'case differences in extensions do not sort by locale'); - assert(compareFileExtensions('a.md', 'A.md') !== compareLocale('a', 'A'), 'case differences in names do not sort by locale'); - assert(compareFileExtensions('aggregate.go', 'aggregate_repo.go') < 0, 'when extensions are equal, names sort in dictionary order'); - - // dotfile comparisons - assert(compareFileExtensions('.env', '.aaa.env') < 0, 'a dotfile with an extension is treated as a name plus an extension - equal extensions'); - assert(compareFileExtensions('.env', '.env.aaa') > 0, 'a dotfile with an extension is treated as a name plus an extension - unequal extensions'); - - // dotfile vs non-dotfile comparisons - assert(compareFileExtensions('.env', 'aaa') > 0, 'filenames without extensions come before dotfiles'); - assert(compareFileExtensions('.md', 'A.MD') > 0, 'a file with an uppercase extension sorts before a dotfile of the same lowercase extension'); - - // numeric comparisons - assert(compareFileExtensions('abc.txt01', 'abc.txt1') < 0, 'extensions with equal numbers sort in unicode order'); - assert(compareFileExtensions('art01', 'Art01') !== compareLocaleNumeric('art01', 'Art01'), 'a numerically equivalent word of a different case does not compare by locale'); - assert(compareFileExtensions('abc02.txt', 'abc002.txt') > 0, 'filenames with equivalent numbers and leading zeros sort in unicode order'); - assert(compareFileExtensions('txt.abc01', 'txt.abc1') < 0, 'extensions with equivalent numbers sort in unicode order'); - - }); - - test('compareFileNamesDefault', () => { - - // - // Comparisons with the same results as compareFileNames - // - - // name-only comparisons - assert(compareFileNamesDefault(null, null) === 0, 'null should be equal'); - assert(compareFileNamesDefault(null, 'abc') < 0, 'null should be come before real values'); - assert(compareFileNamesDefault('', '') === 0, 'empty should be equal'); - assert(compareFileNamesDefault('abc', 'abc') === 0, 'equal names should be equal'); - assert(compareFileNamesDefault('z', 'A') > 0, 'z comes is after A regardless of case'); - assert(compareFileNamesDefault('Z', 'a') > 0, 'Z comes after a regardless of case'); - - // name plus extension comparisons - assert(compareFileNamesDefault('file.ext', 'file.ext') === 0, 'equal full names should be equal'); - assert(compareFileNamesDefault('a.ext', 'b.ext') < 0, 'if equal extensions, filenames should be compared'); - assert(compareFileNamesDefault('file.aaa', 'file.bbb') < 0, 'files with equal names should be compared by extensions'); - assert(compareFileNamesDefault('bbb.aaa', 'aaa.bbb') > 0, 'files should be compared by names even if extensions compare differently'); - assert(compareFileNamesDefault('aggregate.go', 'aggregate_repo.go') > 0, 'compares the whole filename in locale order'); - - // dotfile comparisons - assert(compareFileNamesDefault('.abc', '.abc') === 0, 'equal dotfile names should be equal'); - assert(compareFileNamesDefault('.env.', '.gitattributes') < 0, 'filenames starting with dots and with extensions should still sort properly'); - assert(compareFileNamesDefault('.env', '.aaa.env') > 0, 'dotfiles sort alphabetically when they contain multiple dots'); - assert(compareFileNamesDefault('.env', '.env.aaa') < 0, 'dotfiles with the same root sort shortest first'); - assert(compareFileNamesDefault('.aaa_env', '.aaa.env') < 0, 'and underscore in a dotfile name will sort before a dot'); - - // dotfile vs non-dotfile comparisons - assert(compareFileNamesDefault(null, '.abc') < 0, 'null should come before dotfiles'); - assert(compareFileNamesDefault('.env', 'aaa') < 0, 'dotfiles come before filenames without extensions'); - assert(compareFileNamesDefault('.env', 'aaa.env') < 0, 'dotfiles come before filenames with extensions'); - assert(compareFileNamesDefault('.md', 'A.MD') < 0, 'dotfiles sort before uppercase files'); - assert(compareFileNamesDefault('.MD', 'a.md') < 0, 'dotfiles sort before lowercase files'); - - // numeric comparisons - assert(compareFileNamesDefault('1', '1') === 0, 'numerically equal full names should be equal'); - assert(compareFileNamesDefault('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal'); - assert(compareFileNamesDefault('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order'); - assert(compareFileNamesDefault('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order even when they are multiple digits long'); - assert(compareFileNamesDefault('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically'); - assert(compareFileNamesDefault('abc1.10.txt', 'abc1.2.txt') > 0, 'numbers with dots between them are treated as two separate numbers, not one decimal number'); - - // - // Comparisons with different results than compareFileNames - // - - // name-only comparisons - assert(compareFileNamesDefault('a', 'A') === compareLocale('a', 'A'), 'the same letter sorts by locale'); - assert(compareFileNamesDefault('â', 'Â') === compareLocale('â', 'Â'), 'the same accented letter sorts by locale'); - assert.deepStrictEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileNamesDefault), ['email', 'Email', 'émail', 'Émail'].sort(compareLocale), 'the same base characters with different case or accents sort in locale order'); - - // numeric comparisons - assert(compareFileNamesDefault('abc02.txt', 'abc002.txt') < 0, 'filenames with equivalent numbers and leading zeros sort shortest number first'); - assert(compareFileNamesDefault('abc.txt1', 'abc.txt01') < 0, 'same name plus extensions with equal numbers sort shortest number first'); - assert(compareFileNamesDefault('art01', 'Art01') === compareLocaleNumeric('art01', 'Art01'), 'a numerically equivalent word of a different case compares numerically based on locale'); - - }); - - test('compareFileExtensionsDefault', () => { - - // - // Comparisons with the same result as compareFileExtensions - // - - // name-only comparisons - assert(compareFileExtensionsDefault(null, null) === 0, 'null should be equal'); - assert(compareFileExtensionsDefault(null, 'abc') < 0, 'null should come before real files without extensions'); - assert(compareFileExtensionsDefault('', '') === 0, 'empty should be equal'); - assert(compareFileExtensionsDefault('abc', 'abc') === 0, 'equal names should be equal'); - assert(compareFileExtensionsDefault('z', 'A') > 0, 'z comes after A'); - assert(compareFileExtensionsDefault('Z', 'a') > 0, 'Z comes after a'); - - // name plus extension comparisons - assert(compareFileExtensionsDefault('file.ext', 'file.ext') === 0, 'equal full filenames should be equal'); - assert(compareFileExtensionsDefault('a.ext', 'b.ext') < 0, 'if equal extensions, filenames should be compared'); - assert(compareFileExtensionsDefault('file.aaa', 'file.bbb') < 0, 'files with equal names should be compared by extensions'); - assert(compareFileExtensionsDefault('bbb.aaa', 'aaa.bbb') < 0, 'files should be compared by extension first'); - assert(compareFileExtensionsDefault('agg.go', 'aggrepo.go') < 0, 'shorter names sort before longer names'); - assert(compareFileExtensionsDefault('a.MD', 'b.md') < 0, 'when extensions are the same except for case, the files sort by name'); - - // dotfile comparisons - assert(compareFileExtensionsDefault('.abc', '.abc') === 0, 'equal dotfiles should be equal'); - assert(compareFileExtensionsDefault('.md', '.Gitattributes') > 0, 'dotfiles sort alphabetically regardless of case'); - - // dotfile vs non-dotfile comparisons - assert(compareFileExtensionsDefault(null, '.abc') < 0, 'null should come before dotfiles'); - assert(compareFileExtensionsDefault('.env', 'aaa.env') < 0, 'dotfiles come before filenames with extensions'); - assert(compareFileExtensionsDefault('.MD', 'a.md') < 0, 'dotfiles sort before lowercase files'); - - // numeric comparisons - assert(compareFileExtensionsDefault('1', '1') === 0, 'numerically equal full names should be equal'); - assert(compareFileExtensionsDefault('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal'); - assert(compareFileExtensionsDefault('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order'); - assert(compareFileExtensionsDefault('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order'); - assert(compareFileExtensionsDefault('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically'); - assert(compareFileExtensionsDefault('abc1.10.txt', 'abc1.2.txt') > 0, 'numbers with dots between them are treated as two separate numbers, not one decimal number'); - assert(compareFileExtensionsDefault('abc2.txt2', 'abc1.txt10') < 0, 'extensions with numbers should be in numerical order, not alphabetical order'); - assert(compareFileExtensionsDefault('txt.abc1', 'txt.abc1') === 0, 'equal extensions with numbers should be equal'); - assert(compareFileExtensionsDefault('txt.abc1', 'txt.abc2') < 0, 'extensions with numbers should be in numerical order, not alphabetical order'); - assert(compareFileExtensionsDefault('txt.abc2', 'txt.abc10') < 0, 'extensions with numbers should be in numerical order even when they are multiple digits long'); - assert(compareFileExtensionsDefault('a.ext1', 'b.ext1') < 0, 'if equal extensions with numbers, filenames should be compared'); - assert(compareFileExtensionsDefault('a10.txt', 'A2.txt') > 0, 'filenames with number and case differences compare numerically'); - - // - // Comparisons with different results than compareFileExtensions - // - - // name-only comparisons - assert(compareFileExtensionsDefault('a', 'A') === compareLocale('a', 'A'), 'the same letter of different case sorts by locale'); - assert(compareFileExtensionsDefault('â', 'Â') === compareLocale('â', 'Â'), 'the same accented letter of different case sorts by locale'); - assert.deepStrictEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileExtensionsDefault), ['email', 'Email', 'émail', 'Émail'].sort((a, b) => a.localeCompare(b)), 'the same base characters with different case or accents sort in locale order'); - - // name plus extension comparisons - assert(compareFileExtensionsDefault('a.MD', 'a.md') === compareLocale('MD', 'md'), 'case differences in extensions sort by locale'); - assert(compareFileExtensionsDefault('a.md', 'A.md') === compareLocale('a', 'A'), 'case differences in names sort by locale'); - assert(compareFileExtensionsDefault('aggregate.go', 'aggregate_repo.go') > 0, 'names with the same extension sort in full filename locale order'); - - // dotfile comparisons - assert(compareFileExtensionsDefault('.env', '.aaa.env') > 0, 'dotfiles sort alphabetically when they contain multiple dots'); - assert(compareFileExtensionsDefault('.env', '.env.aaa') < 0, 'dotfiles with the same root sort shortest first'); - - // dotfile vs non-dotfile comparisons - assert(compareFileExtensionsDefault('.env', 'aaa') < 0, 'dotfiles come before filenames without extensions'); - assert(compareFileExtensionsDefault('.md', 'A.MD') < 0, 'dotfiles sort before uppercase files'); - - // numeric comparisons - assert(compareFileExtensionsDefault('abc.txt01', 'abc.txt1') > 0, 'extensions with equal numbers should be in shortest-first order'); - assert(compareFileExtensionsDefault('art01', 'Art01') === compareLocaleNumeric('art01', 'Art01'), 'a numerically equivalent word of a different case compares numerically based on locale'); - assert(compareFileExtensionsDefault('abc02.txt', 'abc002.txt') < 0, 'filenames with equivalent numbers and leading zeros sort shortest string first'); - assert(compareFileExtensionsDefault('txt.abc01', 'txt.abc1') > 0, 'extensions with equivalent numbers sort shortest extension first'); - - }); -}); diff --git a/lib/vscode/src/vs/code/electron-sandbox/workbench/workbench.js b/lib/vscode/src/vs/code/electron-sandbox/workbench/workbench.js deleted file mode 100644 index 38cd78a89b53..000000000000 --- a/lib/vscode/src/vs/code/electron-sandbox/workbench/workbench.js +++ /dev/null @@ -1,116 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/// <reference path="../../../../typings/require.d.ts" /> - -//@ts-check -(function () { - 'use strict'; - - const bootstrapWindow = bootstrapWindowLib(); - - // Add a perf entry right from the top - performance.mark('code/didStartRenderer'); - - // Load workbench main JS, CSS and NLS all in parallel. This is an - // optimization to prevent a waterfall of loading to happen, because - // we know for a fact that workbench.desktop.sandbox.main will depend on - // the related CSS and NLS counterparts. - bootstrapWindow.load([ - 'vs/workbench/workbench.desktop.sandbox.main', - 'vs/nls!vs/workbench/workbench.desktop.main', - 'vs/css!vs/workbench/workbench.desktop.main' - ], - function (_, configuration) { - - // Mark start of workbench - performance.mark('code/didLoadWorkbenchMain'); - - // @ts-ignore - return require('vs/workbench/electron-sandbox/desktop.main').main(configuration); - }, - { - configureDeveloperSettings: function (windowConfig) { - return { - // disable automated devtools opening on error when running extension tests - // as this can lead to undeterministic test exectuion (devtools steals focus) - forceDisableShowDevtoolsOnError: typeof windowConfig.extensionTestsPath === 'string', - // enable devtools keybindings in extension development window - forceEnableDeveloperKeybindings: Array.isArray(windowConfig.extensionDevelopmentPath) && windowConfig.extensionDevelopmentPath.length > 0, - removeDeveloperKeybindingsAfterLoad: true - }; - }, - canModifyDOM: function (windowConfig) { - // TODO@sandbox part-splash is non-sandboxed only - }, - beforeLoaderConfig: function (loaderConfig) { - loaderConfig.recordStats = true; - }, - beforeRequire: function () { - performance.mark('code/willLoadWorkbenchMain'); - - // It looks like browsers only lazily enable - // the <canvas> element when needed. Since we - // leverage canvas elements in our code in many - // locations, we try to help the browser to - // initialize canvas when it is idle, right - // before we wait for the scripts to be loaded. - // @ts-ignore - window.requestIdleCallback(() => { - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - context.clearRect(0, 0, canvas.width, canvas.height); - canvas.remove(); - }, { timeout: 50 }); - } - } - ); - - // add default trustedTypes-policy for logging and to workaround - // lib/platform limitations - window.trustedTypes?.createPolicy('default', { - createHTML(value) { - // see https://github.com/electron/electron/issues/27211 - // Electron webviews use a static innerHTML default value and - // that isn't trusted. We use a default policy to check for the - // exact value of that innerHTML-string and only allow that. - if (value === '<!DOCTYPE html><style type="text/css">:host { display: flex; }</style>') { - return value; - } - throw new Error('UNTRUSTED html usage, default trusted types policy should NEVER be reached'); - // console.trace('UNTRUSTED html usage, default trusted types policy should NEVER be reached'); - // return value; - } - }); - - //#region Helpers - - /** - * @typedef {import('../../../platform/windows/common/windows').INativeWindowConfiguration} INativeWindowConfiguration - * - * @returns {{ - * load: ( - * modules: string[], - * resultCallback: (result, configuration: INativeWindowConfiguration) => unknown, - * options?: { - * configureDeveloperSettings?: (config: INativeWindowConfiguration & object) => { - * forceEnableDeveloperKeybindings?: boolean, - * disallowReloadKeybinding?: boolean, - * removeDeveloperKeybindingsAfterLoad?: boolean - * }, - * canModifyDOM?: (config: INativeWindowConfiguration & object) => void, - * beforeLoaderConfig?: (loaderConfig: object) => void, - * beforeRequire?: () => void - * } - * ) => Promise<unknown> - * }} - */ - function bootstrapWindowLib() { - // @ts-ignore (defined in bootstrap-window.js) - return window.MonacoBootstrapWindow; - } - - //#endregion -}()); diff --git a/lib/vscode/src/vs/editor/contrib/hover/modesContentHover.ts b/lib/vscode/src/vs/editor/contrib/hover/modesContentHover.ts deleted file mode 100644 index ade944741b10..000000000000 --- a/lib/vscode/src/vs/editor/contrib/hover/modesContentHover.ts +++ /dev/null @@ -1,637 +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 dom from 'vs/base/browser/dom'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { Color, RGBA } from 'vs/base/common/color'; -import { IDisposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle'; -import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; -import { Position } from 'vs/editor/common/core/position'; -import { Range } from 'vs/editor/common/core/range'; -import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; -import { DocumentColorProvider, IColor, TokenizationRegistry } from 'vs/editor/common/modes'; -import { getColorPresentations } from 'vs/editor/contrib/colorPicker/color'; -import { ColorDetector } from 'vs/editor/contrib/colorPicker/colorDetector'; -import { ColorPickerModel } from 'vs/editor/contrib/colorPicker/colorPickerModel'; -import { ColorPickerWidget } from 'vs/editor/contrib/colorPicker/colorPickerWidget'; -import { HoverOperation, HoverStartMode, IHoverComputer } from 'vs/editor/contrib/hover/hoverOperation'; -import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { coalesce } from 'vs/base/common/arrays'; -import { IIdentifiedSingleEditOperation, IModelDecoration, TrackedRangeStickiness } from 'vs/editor/common/model'; -import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; -import { Constants } from 'vs/base/common/uint'; -import { textLinkForeground } from 'vs/platform/theme/common/colorRegistry'; -import { IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { Widget } from 'vs/base/browser/ui/widget'; -import { KeyCode } from 'vs/base/common/keyCodes'; -import { HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget'; -import { MarkerHover, MarkerHoverParticipant } from 'vs/editor/contrib/hover/markerHoverParticipant'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { MarkdownHover, MarkdownHoverParticipant } from 'vs/editor/contrib/hover/markdownHoverParticipant'; - -export interface IHoverPart { - readonly range: Range; - equals(other: IHoverPart): boolean; -} - -export interface IEditorHover { - hide(): void; - onContentsChanged(): void; -} - -export interface IEditorHoverParticipant<T extends IHoverPart = IHoverPart> { - computeSync(hoverRange: Range, lineDecorations: IModelDecoration[]): T[]; - computeAsync?(range: Range, token: CancellationToken): Promise<T[]>; - renderHoverParts(hoverParts: T[], fragment: DocumentFragment): IDisposable; -} - -class ColorHover implements IHoverPart { - - constructor( - public readonly range: Range, - public readonly color: IColor, - public readonly provider: DocumentColorProvider - ) { } - - equals(other: IHoverPart): boolean { - return false; - } -} - -class HoverPartInfo { - constructor( - public readonly owner: IEditorHoverParticipant | null, - public readonly data: IHoverPart - ) { } -} - -class ModesContentComputer implements IHoverComputer<HoverPartInfo[]> { - - private readonly _editor: ICodeEditor; - private _result: HoverPartInfo[]; - private _range: Range | null; - - constructor( - editor: ICodeEditor, - private readonly _markerHoverParticipant: IEditorHoverParticipant<MarkerHover>, - private readonly _markdownHoverParticipant: MarkdownHoverParticipant - ) { - this._editor = editor; - this._result = []; - this._range = null; - } - - public setRange(range: Range): void { - this._range = range; - this._result = []; - } - - public clearResult(): void { - this._result = []; - } - - public async computeAsync(token: CancellationToken): Promise<HoverPartInfo[]> { - if (!this._editor.hasModel() || !this._range) { - return Promise.resolve([]); - } - - const markdownHovers = await this._markdownHoverParticipant.computeAsync(this._range, token); - return markdownHovers.map(h => new HoverPartInfo(this._markdownHoverParticipant, h)); - } - - public computeSync(): HoverPartInfo[] { - if (!this._editor.hasModel() || !this._range) { - return []; - } - - const model = this._editor.getModel(); - const hoverRange = this._range; - const lineNumber = hoverRange.startLineNumber; - - if (lineNumber > this._editor.getModel().getLineCount()) { - // Illegal line number => no results - return []; - } - - const maxColumn = model.getLineMaxColumn(lineNumber); - const lineDecorations = this._editor.getLineDecorations(lineNumber).filter((d) => { - if (d.options.isWholeLine) { - return true; - } - - const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1; - const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn; - if (startColumn > hoverRange.startColumn || hoverRange.endColumn > endColumn) { - return false; - } - return true; - }); - - let result: HoverPartInfo[] = []; - - const colorDetector = ColorDetector.get(this._editor); - for (const d of lineDecorations) { - const colorData = colorDetector.getColorData(d.range.getStartPosition()); - if (colorData) { - const { color, range } = colorData.colorInfo; - result.push(new HoverPartInfo(null, new ColorHover(Range.lift(range), color, colorData.provider))); - break; - } - } - - const markdownHovers = this._markdownHoverParticipant.computeSync(this._range, lineDecorations); - result = result.concat(markdownHovers.map(h => new HoverPartInfo(this._markdownHoverParticipant, h))); - - const markerHovers = this._markerHoverParticipant.computeSync(this._range, lineDecorations); - result = result.concat(markerHovers.map(h => new HoverPartInfo(this._markerHoverParticipant, h))); - - return coalesce(result); - } - - public onResult(result: HoverPartInfo[], isFromSynchronousComputation: boolean): void { - // Always put synchronous messages before asynchronous ones - if (isFromSynchronousComputation) { - this._result = result.concat(this._result); - } else { - this._result = this._result.concat(result); - } - } - - public getResult(): HoverPartInfo[] { - return this._result.slice(0); - } - - public getResultWithLoadingMessage(): HoverPartInfo[] { - if (this._range) { - const loadingMessage = new HoverPartInfo(this._markdownHoverParticipant, this._markdownHoverParticipant.createLoadingMessage(this._range)); - return this._result.slice(0).concat([loadingMessage]); - - } - return this._result.slice(0); - } -} - -export class ModesContentHoverWidget extends Widget implements IContentWidget, IEditorHover { - - static readonly ID = 'editor.contrib.modesContentHoverWidget'; - - private readonly _markerHoverParticipant: IEditorHoverParticipant<MarkerHover>; - private readonly _markdownHoverParticipant: MarkdownHoverParticipant; - - private readonly _hover: HoverWidget; - private readonly _id: string; - private readonly _editor: ICodeEditor; - private _isVisible: boolean; - private _showAtPosition: Position | null; - private _showAtRange: Range | null; - private _stoleFocus: boolean; - - // IContentWidget.allowEditorOverflow - public readonly allowEditorOverflow = true; - - private _messages: HoverPartInfo[]; - private _lastRange: Range | null; - private readonly _computer: ModesContentComputer; - private readonly _hoverOperation: HoverOperation<HoverPartInfo[]>; - private _highlightDecorations: string[]; - private _isChangingDecorations: boolean; - private _shouldFocus: boolean; - private _colorPicker: ColorPickerWidget | null; - private _renderDisposable: IDisposable | null; - - constructor( - editor: ICodeEditor, - private readonly _hoverVisibleKey: IContextKey<boolean>, - instantiationService: IInstantiationService, - private readonly _themeService: IThemeService, - ) { - super(); - - this._markerHoverParticipant = instantiationService.createInstance(MarkerHoverParticipant, editor, this); - this._markdownHoverParticipant = instantiationService.createInstance(MarkdownHoverParticipant, editor, this); - - this._hover = this._register(new HoverWidget()); - this._id = ModesContentHoverWidget.ID; - this._editor = editor; - this._isVisible = false; - this._stoleFocus = false; - this._renderDisposable = null; - - this.onkeydown(this._hover.containerDomNode, (e: IKeyboardEvent) => { - if (e.equals(KeyCode.Escape)) { - this.hide(); - } - }); - - this._register(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { - if (e.hasChanged(EditorOption.fontInfo)) { - this._updateFont(); - } - })); - - this._editor.onDidLayoutChange(() => this.layout()); - - this.layout(); - this._editor.addContentWidget(this); - this._showAtPosition = null; - this._showAtRange = null; - this._stoleFocus = false; - - this._messages = []; - this._lastRange = null; - this._computer = new ModesContentComputer(this._editor, this._markerHoverParticipant, this._markdownHoverParticipant); - this._highlightDecorations = []; - this._isChangingDecorations = false; - this._shouldFocus = false; - this._colorPicker = null; - - this._hoverOperation = new HoverOperation( - this._computer, - result => this._withResult(result, true), - null, - result => this._withResult(result, false), - this._editor.getOption(EditorOption.hover).delay - ); - - this._register(dom.addStandardDisposableListener(this.getDomNode(), dom.EventType.FOCUS, () => { - if (this._colorPicker) { - this.getDomNode().classList.add('colorpicker-hover'); - } - })); - this._register(dom.addStandardDisposableListener(this.getDomNode(), dom.EventType.BLUR, () => { - this.getDomNode().classList.remove('colorpicker-hover'); - })); - this._register(editor.onDidChangeConfiguration(() => { - this._hoverOperation.setHoverTime(this._editor.getOption(EditorOption.hover).delay); - })); - this._register(TokenizationRegistry.onDidChange(() => { - if (this._isVisible && this._lastRange && this._messages.length > 0) { - this._messages = this._messages.map(msg => { - // If a color hover is visible, we need to update the message that - // created it so that the color matches the last chosen color - if (msg.data instanceof ColorHover && !!this._lastRange?.intersectRanges(msg.data.range) && this._colorPicker?.model.color) { - const color = this._colorPicker.model.color; - const newColor = { - red: color.rgba.r / 255, - green: color.rgba.g / 255, - blue: color.rgba.b / 255, - alpha: color.rgba.a - }; - return new HoverPartInfo(msg.owner, new ColorHover(msg.data.range, newColor, msg.data.provider)); - } else { - return msg; - } - }); - - this._hover.contentsDomNode.textContent = ''; - this._renderMessages(this._lastRange, this._messages); - } - })); - } - - public override dispose(): void { - this._hoverOperation.cancel(); - this._editor.removeContentWidget(this); - super.dispose(); - } - - public getId(): string { - return this._id; - } - - public getDomNode(): HTMLElement { - return this._hover.containerDomNode; - } - - public showAt(position: Position, range: Range | null, focus: boolean): void { - // Position has changed - this._showAtPosition = position; - this._showAtRange = range; - this._hoverVisibleKey.set(true); - this._isVisible = true; - this._hover.containerDomNode.classList.toggle('hidden', !this._isVisible); - - this._editor.layoutContentWidget(this); - // Simply force a synchronous render on the editor - // such that the widget does not really render with left = '0px' - this._editor.render(); - this._stoleFocus = focus; - if (focus) { - this._hover.containerDomNode.focus(); - } - } - - public getPosition(): IContentWidgetPosition | null { - if (this._isVisible) { - return { - position: this._showAtPosition, - range: this._showAtRange, - preference: [ - ContentWidgetPositionPreference.ABOVE, - ContentWidgetPositionPreference.BELOW - ] - }; - } - return null; - } - - private _updateFont(): void { - const codeClasses: HTMLElement[] = Array.prototype.slice.call(this._hover.contentsDomNode.getElementsByClassName('code')); - codeClasses.forEach(node => this._editor.applyFontInfo(node)); - } - - private _updateContents(node: Node): void { - this._hover.contentsDomNode.textContent = ''; - this._hover.contentsDomNode.appendChild(node); - this._updateFont(); - - this._editor.layoutContentWidget(this); - this._hover.onContentsChanged(); - } - - private layout(): void { - const height = Math.max(this._editor.getLayoutInfo().height / 4, 250); - const { fontSize, lineHeight } = this._editor.getOption(EditorOption.fontInfo); - - this._hover.contentsDomNode.style.fontSize = `${fontSize}px`; - this._hover.contentsDomNode.style.lineHeight = `${lineHeight}px`; - this._hover.contentsDomNode.style.maxHeight = `${height}px`; - this._hover.contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`; - } - - public onModelDecorationsChanged(): void { - if (this._isChangingDecorations) { - return; - } - if (this._isVisible) { - // The decorations have changed and the hover is visible, - // we need to recompute the displayed text - this._hoverOperation.cancel(); - this._computer.clearResult(); - - if (!this._colorPicker) { // TODO@Michel ensure that displayed text for other decorations is computed even if color picker is in place - this._hoverOperation.start(HoverStartMode.Delayed); - } - } - } - - public startShowingAt(range: Range, mode: HoverStartMode, focus: boolean): void { - if (this._lastRange && this._lastRange.equalsRange(range)) { - // We have to show the widget at the exact same range as before, so no work is needed - return; - } - - this._hoverOperation.cancel(); - - if (this._isVisible) { - // The range might have changed, but the hover is visible - // Instead of hiding it completely, filter out messages that are still in the new range and - // kick off a new computation - if (!this._showAtPosition || this._showAtPosition.lineNumber !== range.startLineNumber) { - this.hide(); - } else { - let filteredMessages: HoverPartInfo[] = []; - for (let i = 0, len = this._messages.length; i < len; i++) { - const msg = this._messages[i]; - const rng = msg.data.range; - if (rng && rng.startColumn <= range.startColumn && rng.endColumn >= range.endColumn) { - filteredMessages.push(msg); - } - } - if (filteredMessages.length > 0) { - if (hoverContentsEquals(filteredMessages, this._messages)) { - return; - } - this._renderMessages(range, filteredMessages); - } else { - this.hide(); - } - } - } - - this._lastRange = range; - this._computer.setRange(range); - this._shouldFocus = focus; - this._hoverOperation.start(mode); - } - - public hide(): void { - this._lastRange = null; - this._hoverOperation.cancel(); - - if (this._isVisible) { - setTimeout(() => { - // Give commands a chance to see the key - if (!this._isVisible) { - this._hoverVisibleKey.set(false); - } - }, 0); - this._isVisible = false; - this._hover.containerDomNode.classList.toggle('hidden', !this._isVisible); - - this._editor.layoutContentWidget(this); - if (this._stoleFocus) { - this._editor.focus(); - } - } - - this._isChangingDecorations = true; - this._highlightDecorations = this._editor.deltaDecorations(this._highlightDecorations, []); - this._isChangingDecorations = false; - if (this._renderDisposable) { - this._renderDisposable.dispose(); - this._renderDisposable = null; - } - this._colorPicker = null; - } - - public isColorPickerVisible(): boolean { - return !!this._colorPicker; - } - - public onContentsChanged(): void { - this._hover.onContentsChanged(); - } - - private _withResult(result: HoverPartInfo[], complete: boolean): void { - this._messages = result; - - if (this._lastRange && this._messages.length > 0) { - this._renderMessages(this._lastRange, this._messages); - } else if (complete) { - this.hide(); - } - } - - private _renderMessages(renderRange: Range, messages: HoverPartInfo[]): void { - if (this._renderDisposable) { - this._renderDisposable.dispose(); - this._renderDisposable = null; - } - this._colorPicker = null; - - // update column from which to show - let renderColumn = Constants.MAX_SAFE_SMALL_INTEGER; - let highlightRange: Range | null = messages[0].data.range ? Range.lift(messages[0].data.range) : null; - let fragment = document.createDocumentFragment(); - - let containColorPicker = false; - const disposables = new DisposableStore(); - const markerMessages: MarkerHover[] = []; - const markdownParts: MarkdownHover[] = []; - messages.forEach((_msg) => { - const msg = _msg.data; - if (!msg.range) { - return; - } - - renderColumn = Math.min(renderColumn, msg.range.startColumn); - highlightRange = highlightRange ? Range.plusRange(highlightRange, msg.range) : Range.lift(msg.range); - - if (msg instanceof ColorHover) { - containColorPicker = true; - - const { red, green, blue, alpha } = msg.color; - const rgba = new RGBA(Math.round(red * 255), Math.round(green * 255), Math.round(blue * 255), alpha); - const color = new Color(rgba); - - if (!this._editor.hasModel()) { - return; - } - - const editorModel = this._editor.getModel(); - let range = new Range(msg.range.startLineNumber, msg.range.startColumn, msg.range.endLineNumber, msg.range.endColumn); - let colorInfo = { range: msg.range, color: msg.color }; - - // create blank olor picker model and widget first to ensure it's positioned correctly. - const model = new ColorPickerModel(color, [], 0); - const widget = new ColorPickerWidget(fragment, model, this._editor.getOption(EditorOption.pixelRatio), this._themeService); - - getColorPresentations(editorModel, colorInfo, msg.provider, CancellationToken.None).then(colorPresentations => { - model.colorPresentations = colorPresentations || []; - if (!this._editor.hasModel()) { - // gone... - return; - } - const originalText = this._editor.getModel().getValueInRange(msg.range); - model.guessColorPresentation(color, originalText); - - const updateEditorModel = () => { - let textEdits: IIdentifiedSingleEditOperation[]; - let newRange: Range; - if (model.presentation.textEdit) { - textEdits = [model.presentation.textEdit as IIdentifiedSingleEditOperation]; - newRange = new Range( - model.presentation.textEdit.range.startLineNumber, - model.presentation.textEdit.range.startColumn, - model.presentation.textEdit.range.endLineNumber, - model.presentation.textEdit.range.endColumn - ); - const trackedRange = this._editor.getModel()!._setTrackedRange(null, newRange, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter); - this._editor.pushUndoStop(); - this._editor.executeEdits('colorpicker', textEdits); - newRange = this._editor.getModel()!._getTrackedRange(trackedRange) || newRange; - } else { - textEdits = [{ identifier: null, range, text: model.presentation.label, forceMoveMarkers: false }]; - newRange = range.setEndPosition(range.endLineNumber, range.startColumn + model.presentation.label.length); - this._editor.pushUndoStop(); - this._editor.executeEdits('colorpicker', textEdits); - } - - if (model.presentation.additionalTextEdits) { - textEdits = [...model.presentation.additionalTextEdits as IIdentifiedSingleEditOperation[]]; - this._editor.executeEdits('colorpicker', textEdits); - this.hide(); - } - this._editor.pushUndoStop(); - range = newRange; - }; - - const updateColorPresentations = (color: Color) => { - return getColorPresentations(editorModel, { - range: range, - color: { - red: color.rgba.r / 255, - green: color.rgba.g / 255, - blue: color.rgba.b / 255, - alpha: color.rgba.a - } - }, msg.provider, CancellationToken.None).then((colorPresentations) => { - model.colorPresentations = colorPresentations || []; - }); - }; - - const colorListener = model.onColorFlushed((color: Color) => { - updateColorPresentations(color).then(updateEditorModel); - }); - const colorChangeListener = model.onDidChangeColor(updateColorPresentations); - - this._colorPicker = widget; - this.showAt(range.getStartPosition(), range, this._shouldFocus); - this._updateContents(fragment); - this._colorPicker.layout(); - - this._renderDisposable = combinedDisposable(colorListener, colorChangeListener, widget, disposables); - }); - } else { - if (msg instanceof MarkerHover) { - markerMessages.push(msg); - } else { - if (msg instanceof MarkdownHover) { - markdownParts.push(msg); - } - } - } - }); - - if (markdownParts.length > 0) { - disposables.add(this._markdownHoverParticipant.renderHoverParts(markdownParts, fragment)); - } - - if (markerMessages.length) { - disposables.add(this._markerHoverParticipant.renderHoverParts(markerMessages, fragment)); - } - - this._renderDisposable = disposables; - - // show - - if (!containColorPicker && fragment.hasChildNodes()) { - this.showAt(new Position(renderRange.startLineNumber, renderColumn), highlightRange, this._shouldFocus); - this._updateContents(fragment); - } - - this._isChangingDecorations = true; - this._highlightDecorations = this._editor.deltaDecorations(this._highlightDecorations, highlightRange ? [{ - range: highlightRange, - options: ModesContentHoverWidget._DECORATION_OPTIONS - }] : []); - this._isChangingDecorations = false; - } - - private static readonly _DECORATION_OPTIONS = ModelDecorationOptions.register({ - className: 'hoverHighlight' - }); -} - -function hoverContentsEquals(first: HoverPartInfo[], second: HoverPartInfo[]): boolean { - if (first.length !== second.length) { - return false; - } - for (let i = 0; i < first.length; i++) { - if (!first[i].data.equals(second[i].data)) { - return false; - } - } - return true; -} - -registerThemingParticipant((theme, collector) => { - const linkFg = theme.getColor(textLinkForeground); - if (linkFg) { - collector.addRule(`.monaco-hover .hover-contents a.code-link span:hover { color: ${linkFg}; }`); - } -}); diff --git a/lib/vscode/src/vs/ipc.d.ts b/lib/vscode/src/vs/ipc.d.ts deleted file mode 120000 index dff4f400f736..000000000000 --- a/lib/vscode/src/vs/ipc.d.ts +++ /dev/null @@ -1 +0,0 @@ -../../../../typings/ipc.d.ts \ No newline at end of file diff --git a/lib/vscode/src/vs/platform/dialogs/test/common/testDialogService.ts b/lib/vscode/src/vs/platform/dialogs/test/common/testDialogService.ts deleted file mode 100644 index 8d3d2465b76e..000000000000 --- a/lib/vscode/src/vs/platform/dialogs/test/common/testDialogService.ts +++ /dev/null @@ -1,17 +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 Severity from 'vs/base/common/severity'; -import { IConfirmation, IConfirmationResult, IDialogService, IDialogOptions, IShowResult, IInputResult } from 'vs/platform/dialogs/common/dialogs'; - -export class TestDialogService implements IDialogService { - - declare readonly _serviceBrand: undefined; - - confirm(_confirmation: IConfirmation): Promise<IConfirmationResult> { return Promise.resolve({ confirmed: false }); } - show(_severity: Severity, _message: string, _buttons: string[], _options?: IDialogOptions): Promise<IShowResult> { return Promise.resolve({ choice: 0 }); } - input(): Promise<IInputResult> { { return Promise.resolve({ choice: 0, values: [] }); } } - about(): Promise<void> { return Promise.resolve(); } -} diff --git a/lib/vscode/src/vs/platform/opener/browser/link.ts b/lib/vscode/src/vs/platform/opener/browser/link.ts deleted file mode 100644 index c3d3d7d02987..000000000000 --- a/lib/vscode/src/vs/platform/opener/browser/link.ts +++ /dev/null @@ -1,92 +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 } from 'vs/base/common/event'; -import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { $, EventHelper, EventLike } from 'vs/base/browser/dom'; -import { domEvent } from 'vs/base/browser/event'; -import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { KeyCode } from 'vs/base/common/keyCodes'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { Color } from 'vs/base/common/color'; - -export interface ILinkDescriptor { - readonly label: string; - readonly href: string; - readonly title?: string; -} - -export interface ILinkStyles { - readonly textLinkForeground?: Color; - readonly disabled?: boolean; -} - -export class Link extends Disposable { - - readonly el: HTMLAnchorElement; - private disabled: boolean; - private styles: ILinkStyles = { - textLinkForeground: Color.fromHex('#006AB1') - }; - - constructor( - link: ILinkDescriptor, - @IOpenerService openerService: IOpenerService - ) { - super(); - - this.el = $<HTMLAnchorElement>('a', { - tabIndex: 0, - href: link.href, - title: link.title - }, link.label); - - const onClick = domEvent(this.el, 'click'); - const onEnterPress = Event.chain(domEvent(this.el, 'keypress')) - .map(e => new StandardKeyboardEvent(e)) - .filter(e => e.keyCode === KeyCode.Enter) - .event; - const onOpen = Event.any<EventLike>(onClick, onEnterPress); - - this._register(onOpen(e => { - EventHelper.stop(e, true); - if (!this.disabled) { - openerService.open(link.href, { allowCommands: true }); - } - })); - - this.disabled = false; - this.applyStyles(); - } - - style(styles: ILinkStyles): void { - this.styles = styles; - this.applyStyles(); - } - - private applyStyles(): void { - const color = this.styles.textLinkForeground?.toString(); - if (color) { - this.el.style.color = color; - } - if (typeof this.styles.disabled === 'boolean' && this.styles.disabled !== this.disabled) { - if (this.styles.disabled) { - this.el.setAttribute('aria-disabled', 'true'); - this.el.tabIndex = -1; - this.el.style.pointerEvents = 'none'; - this.el.style.opacity = '0.4'; - this.el.style.cursor = 'default'; - this.disabled = true; - } else { - this.el.setAttribute('aria-disabled', 'false'); - this.el.tabIndex = 0; - this.el.style.pointerEvents = 'auto'; - this.el.style.opacity = '1'; - this.el.style.cursor = 'pointer'; - this.disabled = false; - } - } - } -} diff --git a/lib/vscode/src/vs/platform/state/node/stateService.ts b/lib/vscode/src/vs/platform/state/node/stateService.ts deleted file mode 100644 index 3799c66d4b04..000000000000 --- a/lib/vscode/src/vs/platform/state/node/stateService.ts +++ /dev/null @@ -1,158 +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 path from 'vs/base/common/path'; -import * as fs from 'fs'; -import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; -import { writeFileSync } from 'vs/base/node/pfs'; -import { isUndefined, isUndefinedOrNull } from 'vs/base/common/types'; -import { IStateService } from 'vs/platform/state/node/state'; -import { ILogService } from 'vs/platform/log/common/log'; - -type StorageDatabase = { [key: string]: any; }; - -export class FileStorage { - - private _database: StorageDatabase | null = null; - private lastFlushedSerializedDatabase: string | null = null; - - constructor(private dbPath: string, private onError: (error: Error) => void) { } - - private get database(): StorageDatabase { - if (!this._database) { - this._database = this.loadSync(); - } - - return this._database; - } - - async init(): Promise<void> { - if (this._database) { - return; // return if database was already loaded - } - - const database = await this.loadAsync(); - - if (this._database) { - return; // return if database was already loaded - } - - this._database = database; - } - - private loadSync(): StorageDatabase { - try { - this.lastFlushedSerializedDatabase = fs.readFileSync(this.dbPath).toString(); - - return JSON.parse(this.lastFlushedSerializedDatabase); - } catch (error) { - if (error.code !== 'ENOENT') { - this.onError(error); - } - - return {}; - } - } - - private async loadAsync(): Promise<StorageDatabase> { - try { - this.lastFlushedSerializedDatabase = (await fs.promises.readFile(this.dbPath)).toString(); - - return JSON.parse(this.lastFlushedSerializedDatabase); - } catch (error) { - if (error.code !== 'ENOENT') { - this.onError(error); - } - - return {}; - } - } - - getItem<T>(key: string, defaultValue: T): T; - getItem<T>(key: string, defaultValue?: T): T | undefined; - getItem<T>(key: string, defaultValue?: T): T | undefined { - const res = this.database[key]; - if (isUndefinedOrNull(res)) { - return defaultValue; - } - - return res; - } - - setItem(key: string, data?: object | string | number | boolean | undefined | null): void { - - // Remove an item when it is undefined or null - if (isUndefinedOrNull(data)) { - return this.removeItem(key); - } - - // Shortcut for primitives that did not change - if (typeof data === 'string' || typeof data === 'number' || typeof data === 'boolean') { - if (this.database[key] === data) { - return; - } - } - - this.database[key] = data; - this.saveSync(); - } - - removeItem(key: string): void { - - // Only update if the key is actually present (not undefined) - if (!isUndefined(this.database[key])) { - this.database[key] = undefined; - this.saveSync(); - } - } - - private saveSync(): void { - const serializedDatabase = JSON.stringify(this.database, null, 4); - if (serializedDatabase === this.lastFlushedSerializedDatabase) { - return; // return early if the database has not changed - } - - try { - writeFileSync(this.dbPath, serializedDatabase); // permission issue can happen here - this.lastFlushedSerializedDatabase = serializedDatabase; - } catch (error) { - this.onError(error); - } - } -} - -export class StateService implements IStateService { - - declare readonly _serviceBrand: undefined; - - private static readonly STATE_FILE = 'storage.json'; - - private fileStorage: FileStorage; - - constructor( - @INativeEnvironmentService environmentService: INativeEnvironmentService, - @ILogService logService: ILogService - ) { - this.fileStorage = new FileStorage(path.join(environmentService.userDataPath, StateService.STATE_FILE), error => logService.error(error)); - } - - init(): Promise<void> { - return this.fileStorage.init(); - } - - getItem<T>(key: string, defaultValue: T): T; - getItem<T>(key: string, defaultValue?: T): T | undefined; - getItem<T>(key: string, defaultValue?: T): T | undefined { - return this.fileStorage.getItem(key, defaultValue); - } - - setItem(key: string, data?: object | string | number | boolean | undefined | null): void { - this.fileStorage.setItem(key, data); - } - - removeItem(key: string): void { - this.fileStorage.removeItem(key); - } -} diff --git a/lib/vscode/src/vs/platform/state/test/node/state.test.ts b/lib/vscode/src/vs/platform/state/test/node/state.test.ts deleted file mode 100644 index 01d2b4e39425..000000000000 --- a/lib/vscode/src/vs/platform/state/test/node/state.test.ts +++ /dev/null @@ -1,57 +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 assert from 'assert'; -import { tmpdir } from 'os'; -import { promises } from 'fs'; -import { join } from 'vs/base/common/path'; -import { flakySuite, getRandomTestPath } from 'vs/base/test/node/testUtils'; -import { FileStorage } from 'vs/platform/state/node/stateService'; -import { rimraf, writeFileSync } from 'vs/base/node/pfs'; - -flakySuite('StateService', () => { - - let testDir: string; - - setup(() => { - testDir = getRandomTestPath(tmpdir(), 'vsctests', 'stateservice'); - - return promises.mkdir(testDir, { recursive: true }); - }); - - teardown(() => { - return rimraf(testDir); - }); - - test('Basics', async function () { - const storageFile = join(testDir, 'storage.json'); - writeFileSync(storageFile, ''); - - let service = new FileStorage(storageFile, () => null); - - service.setItem('some.key', 'some.value'); - assert.strictEqual(service.getItem('some.key'), 'some.value'); - - service.removeItem('some.key'); - assert.strictEqual(service.getItem('some.key', 'some.default'), 'some.default'); - - assert.ok(!service.getItem('some.unknonw.key')); - - service.setItem('some.other.key', 'some.other.value'); - - service = new FileStorage(storageFile, () => null); - - assert.strictEqual(service.getItem('some.other.key'), 'some.other.value'); - - service.setItem('some.other.key', 'some.other.value'); - assert.strictEqual(service.getItem('some.other.key'), 'some.other.value'); - - service.setItem('some.undefined.key', undefined); - assert.strictEqual(service.getItem('some.undefined.key', 'some.default'), 'some.default'); - - service.setItem('some.null.key', null); - assert.strictEqual(service.getItem('some.null.key', 'some.default'), 'some.default'); - }); -}); diff --git a/lib/vscode/src/vs/server/browser/client.ts b/lib/vscode/src/vs/server/browser/client.ts deleted file mode 100644 index c1c5b4507de3..000000000000 --- a/lib/vscode/src/vs/server/browser/client.ts +++ /dev/null @@ -1,198 +0,0 @@ -import * as path from 'vs/base/common/path'; -import { Options } from 'vs/ipc'; -import { localize } from 'vs/nls'; -import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; -import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; -import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { ILogService } from 'vs/platform/log/common/log'; -import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { TelemetryChannelClient } from 'vs/server/common/telemetry'; -import { getOptions } from 'vs/server/common/util'; -import 'vs/workbench/contrib/localizations/browser/localizations.contribution'; -import 'vs/workbench/services/localizations/browser/localizationsService'; -import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; - -/** - * All client-side customization to VS Code should live in this file when - * possible. - */ - -const options = getOptions<Options>(); - -class TelemetryService extends TelemetryChannelClient { - public constructor( - @IRemoteAgentService remoteAgentService: IRemoteAgentService, - ) { - super(remoteAgentService.getConnection()!.getChannel('telemetry')); - } -} - -const TELEMETRY_SECTION_ID = 'telemetry'; -Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({ - 'id': TELEMETRY_SECTION_ID, - 'order': 110, - 'type': 'object', - 'title': localize('telemetryConfigurationTitle', 'Telemetry'), - 'properties': { - 'telemetry.enableTelemetry': { - 'type': 'boolean', - 'description': localize('telemetry.enableTelemetry', 'Enable usage data and errors to be sent to a Microsoft online service.'), - 'default': !options.disableTelemetry, - 'tags': ['usesOnlineServices'] - } - } -}); - -registerSingleton(ITelemetryService, TelemetryService); - -/** - * This is called by vs/workbench/browser/web.main.ts after the workbench has - * been initialized so we can initialize our own client-side code. - */ -export const initialize = async (services: ServiceCollection): Promise<void> => { - const event = new CustomEvent('ide-ready'); - window.dispatchEvent(event); - - if (parent) { - // Tell the parent loading has completed. - parent.postMessage({ event: 'loaded' }, '*'); - - // Proxy or stop proxing events as requested by the parent. - const listeners = new Map<string, (event: Event) => void>(); - window.addEventListener('message', (parentEvent) => { - const eventName = parentEvent.data.bind || parentEvent.data.unbind; - if (eventName) { - const oldListener = listeners.get(eventName); - if (oldListener) { - document.removeEventListener(eventName, oldListener); - } - } - - if (parentEvent.data.bind && parentEvent.data.prop) { - const listener = (event: Event) => { - parent.postMessage({ - event: parentEvent.data.event, - [parentEvent.data.prop]: event[parentEvent.data.prop as keyof Event] - }, window.location.origin); - }; - listeners.set(parentEvent.data.bind, listener); - document.addEventListener(parentEvent.data.bind, listener); - } - }); - } - - if (!window.isSecureContext) { - (services.get(INotificationService) as INotificationService).notify({ - severity: Severity.Warning, - message: 'code-server is being accessed over an insecure domain. Web views, the clipboard, and other functionality will not work as expected.', - actions: { - primary: [{ - id: 'understand', - label: 'I understand', - tooltip: '', - class: undefined, - enabled: true, - checked: true, - dispose: () => undefined, - run: () => { - return Promise.resolve(); - } - }], - } - }); - } - - const logService = (services.get(ILogService) as ILogService); - const storageService = (services.get(IStorageService) as IStorageService); - const updateCheckEndpoint = path.join(options.base, '/update/check'); - const getUpdate = async (): Promise<void> => { - logService.debug('Checking for update...'); - - const response = await fetch(updateCheckEndpoint, { - headers: { 'Accept': 'application/json' }, - }); - if (!response.ok) { - throw new Error(response.statusText); - } - const json = await response.json(); - if (json.error) { - throw new Error(json.error); - } - if (json.isLatest) { - return; - } - - const lastNoti = storageService.getNumber('csLastUpdateNotification', StorageScope.GLOBAL); - if (lastNoti) { - // Only remind them again after 1 week. - const timeout = 1000*60*60*24*7; - const threshold = lastNoti + timeout; - if (Date.now() < threshold) { - return; - } - } - - storageService.store('csLastUpdateNotification', Date.now(), StorageScope.GLOBAL, StorageTarget.MACHINE); - (services.get(INotificationService) as INotificationService).notify({ - severity: Severity.Info, - message: `[code-server v${json.latest}](https://github.com/cdr/code-server/releases/tag/v${json.latest}) has been released!`, - }); - }; - - const updateLoop = (): void => { - getUpdate().catch((error) => { - logService.debug(`failed to check for update: ${error}`); - }).finally(() => { - // Check again every 6 hours. - setTimeout(updateLoop, 1000*60*60*6); - }); - }; - - if (!options.disableUpdateCheck) { - updateLoop(); - } - - // This will be used to set the background color while VS Code loads. - const theme = storageService.get('colorThemeData', StorageScope.GLOBAL); - if (theme) { - localStorage.setItem('colorThemeData', theme); - } - - // Use to show or hide logout commands and menu options. - const contextKeyService = (services.get(IContextKeyService) as IContextKeyService); - contextKeyService.createKey('code-server.authed', options.authed); - - // Add a logout command. - const logoutEndpoint = path.join(options.base, '/logout') + `?base=${options.base}`; - const LOGOUT_COMMAND_ID = 'code-server.logout'; - CommandsRegistry.registerCommand( - LOGOUT_COMMAND_ID, - () => { - window.location.href = logoutEndpoint; - }, - ); - - // Add logout to command palette. - MenuRegistry.appendMenuItem(MenuId.CommandPalette, { - command: { - id: LOGOUT_COMMAND_ID, - title: localize('logout', "Log out") - }, - when: ContextKeyExpr.has('code-server.authed') - }); - - // Add logout to the (web-only) home menu. - MenuRegistry.appendMenuItem(MenuId.MenubarHomeMenu, { - command: { - id: LOGOUT_COMMAND_ID, - title: localize('logout', "Log out") - }, - when: ContextKeyExpr.has('code-server.authed') - }); -}; diff --git a/lib/vscode/src/vs/server/common/telemetry.ts b/lib/vscode/src/vs/server/common/telemetry.ts deleted file mode 100644 index 4ea6d95d36aa..000000000000 --- a/lib/vscode/src/vs/server/common/telemetry.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { ITelemetryData } from 'vs/base/common/actions'; -import { Event } from 'vs/base/common/event'; -import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; -import { ITelemetryInfo, ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; - -export class TelemetryChannel implements IServerChannel { - constructor(private service: ITelemetryService) {} - - listen(_: unknown, event: string): Event<any> { - throw new Error(`Invalid listen ${event}`); - } - - call(_: unknown, command: string, args?: any): Promise<any> { - switch (command) { - case 'publicLog': return this.service.publicLog(args[0], args[1], args[2]); - case 'publicLog2': return this.service.publicLog2(args[0], args[1], args[2]); - case 'publicLogError': return this.service.publicLogError(args[0], args[1]); - case 'publicLogError2': return this.service.publicLogError2(args[0], args[1]); - case 'setEnabled': return Promise.resolve(this.service.setEnabled(args[0])); - case 'getTelemetryInfo': return this.service.getTelemetryInfo(); - case 'setExperimentProperty': return Promise.resolve(this.service.setExperimentProperty(args[0], args[1])); - } - throw new Error(`Invalid call ${command}`); - } -} - -export class TelemetryChannelClient implements ITelemetryService { - _serviceBrand: any; - - // These don't matter; telemetry is sent to the Node side which decides - // whether to send the telemetry event. - public isOptedIn = true; - public sendErrorTelemetry = true; - - constructor(private readonly channel: IChannel) {} - - public publicLog(eventName: string, data?: ITelemetryData, anonymizeFilePaths?: boolean): Promise<void> { - return this.channel.call('publicLog', [eventName, data, anonymizeFilePaths]); - } - - public publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>, anonymizeFilePaths?: boolean): Promise<void> { - return this.channel.call('publicLog2', [eventName, data, anonymizeFilePaths]); - } - - public publicLogError(errorEventName: string, data?: ITelemetryData): Promise<void> { - return this.channel.call('publicLogError', [errorEventName, data]); - } - - public publicLogError2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>): Promise<void> { - return this.channel.call('publicLogError2', [eventName, data]); - } - - public setEnabled(value: boolean): void { - this.channel.call('setEnable', [value]); - } - - public getTelemetryInfo(): Promise<ITelemetryInfo> { - return this.channel.call('getTelemetryInfo'); - } - - public setExperimentProperty(name: string, value: string): void { - this.channel.call('setExperimentProperty', [name, value]); - } -} diff --git a/lib/vscode/src/vs/server/common/util.ts b/lib/vscode/src/vs/server/common/util.ts deleted file mode 120000 index 625cfa1cbf97..000000000000 --- a/lib/vscode/src/vs/server/common/util.ts +++ /dev/null @@ -1 +0,0 @@ -../../../../../../src/common/util.ts \ No newline at end of file diff --git a/lib/vscode/src/vs/server/entry.ts b/lib/vscode/src/vs/server/entry.ts deleted file mode 100644 index 2f458f4035b7..000000000000 --- a/lib/vscode/src/vs/server/entry.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { field } from '@coder/logger'; -import { setUnexpectedErrorHandler } from 'vs/base/common/errors'; -import * as proxyAgent from 'vs/base/node/proxy_agent'; -import { CodeServerMessage, VscodeMessage } from 'vs/ipc'; -import { logger } from 'vs/server/node/logger'; -import { enableCustomMarketplace } from 'vs/server/node/marketplace'; -import { Vscode } from 'vs/server/node/server'; - -setUnexpectedErrorHandler((error) => { - logger.warn('Uncaught error', field('error', error instanceof Error ? error.message : error)); -}); -enableCustomMarketplace(); -proxyAgent.monkeyPatch(true); - -/** - * Ensure we control when the process exits. - */ -const exit = process.exit; -process.exit = function(code?: number) { - logger.warn(`process.exit() was prevented: ${code || 'unknown code'}.`); -} as (code?: number) => never; - -// Kill VS Code if the parent process dies. -if (typeof process.env.CODE_SERVER_PARENT_PID !== 'undefined') { - const parentPid = parseInt(process.env.CODE_SERVER_PARENT_PID, 10); - setInterval(() => { - try { - process.kill(parentPid, 0); // Throws an exception if the process doesn't exist anymore. - } catch (e) { - exit(); - } - }, 5000); -} else { - logger.error('no parent process'); - exit(1); -} - -const vscode = new Vscode(); -const send = (message: VscodeMessage): void => { - if (!process.send) { - throw new Error('not spawned with IPC'); - } - process.send(message); -}; - -// Wait for the init message then start up VS Code. Subsequent messages will -// return new workbench options without starting a new instance. -process.on('message', async (message: CodeServerMessage, socket) => { - logger.debug('got message from code-server', field('type', message.type)); - logger.trace('code-server message content', field('message', message)); - switch (message.type) { - case 'init': - try { - const options = await vscode.initialize(message.options); - send({ type: 'options', id: message.id, options }); - } catch (error) { - logger.error(error.message); - logger.error(error.stack); - exit(1); - } - break; - case 'cli': - try { - await vscode.cli(message.args); - exit(0); - } catch (error) { - logger.error(error.message); - logger.error(error.stack); - exit(1); - } - break; - case 'socket': - vscode.handleWebSocket(socket, message.query, message.permessageDeflate); - break; - } -}); -if (!process.send) { - logger.error('not spawned with IPC'); - exit(1); -} else { - // This lets the parent know the child is ready to receive messages. - send({ type: 'ready' }); -} diff --git a/lib/vscode/src/vs/server/fork.js b/lib/vscode/src/vs/server/fork.js deleted file mode 100644 index 56331ff1fc32..000000000000 --- a/lib/vscode/src/vs/server/fork.js +++ /dev/null @@ -1,3 +0,0 @@ -// This must be a JS file otherwise when it gets compiled it turns into AMD -// syntax which will not work without the right loader. -require('../../bootstrap-amd').load('vs/server/entry'); diff --git a/lib/vscode/src/vs/server/node/channel.ts b/lib/vscode/src/vs/server/node/channel.ts deleted file mode 100644 index 01faa6b9b140..000000000000 --- a/lib/vscode/src/vs/server/node/channel.ts +++ /dev/null @@ -1,813 +0,0 @@ -import { field, logger } from '@coder/logger'; -import * as os from 'os'; -import * as path from 'path'; -import { VSBuffer } from 'vs/base/common/buffer'; -import { CancellationTokenSource } from 'vs/base/common/cancellation'; -import { Emitter, Event } from 'vs/base/common/event'; -import { IDisposable } from 'vs/base/common/lifecycle'; -import * as platform from 'vs/base/common/platform'; -import * as resources from 'vs/base/common/resources'; -import { ReadableStreamEventPayload } from 'vs/base/common/stream'; -import { URI, UriComponents } from 'vs/base/common/uri'; -import { transformOutgoingURIs } from 'vs/base/common/uriIpc'; -import { getSystemShell } from 'vs/base/node/shell'; -import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnostics'; -import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; -import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { FileDeleteOptions, FileOpenOptions, FileOverwriteOptions, FileReadStreamOptions, FileType, FileWriteOptions, IStat, IWatchOptions } from 'vs/platform/files/common/files'; -import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; -import { ILogService } from 'vs/platform/log/common/log'; -import product from 'vs/platform/product/common/product'; -import { IRemoteAgentEnvironment, RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment'; -import { ITelemetryData, ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IProcessDataEvent, IShellLaunchConfig, ITerminalEnvironment, ITerminalLaunchError, ITerminalsLayoutInfo } from 'vs/platform/terminal/common/terminal'; -import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering'; -import { IGetTerminalLayoutInfoArgs, IProcessDetails, IPtyHostProcessReplayEvent, ISetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess'; -import { TerminalProcess } from 'vs/platform/terminal/node/terminalProcess'; -import { getTranslations } from 'vs/server/node/nls'; -import { getUriTransformer } from 'vs/server/node/util'; -import { IFileChangeDto } from 'vs/workbench/api/common/extHost.protocol'; -import { IEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable'; -import { MergedEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableCollection'; -import { deserializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared'; -import * as terminal from 'vs/workbench/contrib/terminal/common/remoteTerminalChannel'; -import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; -import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment'; -import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver'; -import { ExtensionScanner, ExtensionScannerInput } from 'vs/workbench/services/extensions/node/extensionPoints'; - -/** - * Extend the file provider to allow unwatching. - */ -class Watcher extends DiskFileSystemProvider { - public readonly watches = new Map<number, IDisposable>(); - - public override dispose(): void { - this.watches.forEach((w) => w.dispose()); - this.watches.clear(); - super.dispose(); - } - - public _watch(req: number, resource: URI, opts: IWatchOptions): void { - this.watches.set(req, this.watch(resource, opts)); - } - - public unwatch(req: number): void { - this.watches.get(req)!.dispose(); - this.watches.delete(req); - } -} - -export class FileProviderChannel implements IServerChannel<RemoteAgentConnectionContext>, IDisposable { - private readonly provider: DiskFileSystemProvider; - private readonly watchers = new Map<string, Watcher>(); - - public constructor( - private readonly environmentService: INativeEnvironmentService, - private readonly logService: ILogService, - ) { - this.provider = new DiskFileSystemProvider(this.logService); - } - - public listen(context: RemoteAgentConnectionContext, event: string, args?: any): Event<any> { - switch (event) { - case 'filechange': return this.filechange(context, args[0]); - case 'readFileStream': return this.readFileStream(args[0], args[1]); - } - - throw new Error(`Invalid listen '${event}'`); - } - - private filechange(context: RemoteAgentConnectionContext, session: string): Event<IFileChangeDto[]> { - const emitter = new Emitter<IFileChangeDto[]>({ - onFirstListenerAdd: () => { - const provider = new Watcher(this.logService); - this.watchers.set(session, provider); - const transformer = getUriTransformer(context.remoteAuthority); - provider.onDidChangeFile((events) => { - emitter.fire(events.map((event) => ({ - ...event, - resource: transformer.transformOutgoing(event.resource), - }))); - }); - provider.onDidErrorOccur((event) => this.logService.error(event)); - }, - onLastListenerRemove: () => { - this.watchers.get(session)!.dispose(); - this.watchers.delete(session); - }, - }); - - return emitter.event; - } - - private readFileStream(resource: UriComponents, opts: FileReadStreamOptions): Event<ReadableStreamEventPayload<VSBuffer>> { - const cts = new CancellationTokenSource(); - const fileStream = this.provider.readFileStream(this.transform(resource), opts, cts.token); - const emitter = new Emitter<ReadableStreamEventPayload<VSBuffer>>({ - onFirstListenerAdd: () => { - fileStream.on('data', (data) => emitter.fire(VSBuffer.wrap(data))); - fileStream.on('error', (error) => emitter.fire(error)); - fileStream.on('end', () => emitter.fire('end')); - }, - onLastListenerRemove: () => cts.cancel(), - }); - - return emitter.event; - } - - public call(_: unknown, command: string, args?: any): Promise<any> { - switch (command) { - case 'stat': return this.stat(args[0]); - case 'open': return this.open(args[0], args[1]); - case 'close': return this.close(args[0]); - case 'read': return this.read(args[0], args[1], args[2]); - case 'readFile': return this.readFile(args[0]); - case 'write': return this.write(args[0], args[1], args[2], args[3], args[4]); - case 'writeFile': return this.writeFile(args[0], args[1], args[2]); - case 'delete': return this.delete(args[0], args[1]); - case 'mkdir': return this.mkdir(args[0]); - case 'readdir': return this.readdir(args[0]); - case 'rename': return this.rename(args[0], args[1], args[2]); - case 'copy': return this.copy(args[0], args[1], args[2]); - case 'watch': return this.watch(args[0], args[1], args[2], args[3]); - case 'unwatch': return this.unwatch(args[0], args[1]); - } - - throw new Error(`Invalid call '${command}'`); - } - - public dispose(): void { - this.watchers.forEach((w) => w.dispose()); - this.watchers.clear(); - } - - private async stat(resource: UriComponents): Promise<IStat> { - return this.provider.stat(this.transform(resource)); - } - - private async open(resource: UriComponents, opts: FileOpenOptions): Promise<number> { - return this.provider.open(this.transform(resource), opts); - } - - private async close(fd: number): Promise<void> { - return this.provider.close(fd); - } - - private async read(fd: number, pos: number, length: number): Promise<[VSBuffer, number]> { - const buffer = VSBuffer.alloc(length); - const bytesRead = await this.provider.read(fd, pos, buffer.buffer, 0, length); - return [buffer, bytesRead]; - } - - private async readFile(resource: UriComponents): Promise<VSBuffer> { - return VSBuffer.wrap(await this.provider.readFile(this.transform(resource))); - } - - private write(fd: number, pos: number, buffer: VSBuffer, offset: number, length: number): Promise<number> { - return this.provider.write(fd, pos, buffer.buffer, offset, length); - } - - private writeFile(resource: UriComponents, buffer: VSBuffer, opts: FileWriteOptions): Promise<void> { - return this.provider.writeFile(this.transform(resource), buffer.buffer, opts); - } - - private async delete(resource: UriComponents, opts: FileDeleteOptions): Promise<void> { - return this.provider.delete(this.transform(resource), opts); - } - - private async mkdir(resource: UriComponents): Promise<void> { - return this.provider.mkdir(this.transform(resource)); - } - - private async readdir(resource: UriComponents): Promise<[string, FileType][]> { - return this.provider.readdir(this.transform(resource)); - } - - private async rename(resource: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Promise<void> { - return this.provider.rename(this.transform(resource), URI.from(target), opts); - } - - private copy(resource: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Promise<void> { - return this.provider.copy(this.transform(resource), URI.from(target), opts); - } - - private async watch(session: string, req: number, resource: UriComponents, opts: IWatchOptions): Promise<void> { - this.watchers.get(session)!._watch(req, this.transform(resource), opts); - } - - private async unwatch(session: string, req: number): Promise<void> { - this.watchers.get(session)!.unwatch(req); - } - - private transform(resource: UriComponents): URI { - // Used for walkthrough content. - if (/^\/static[^/]*\//.test(resource.path)) { - return URI.file(this.environmentService.appRoot + resource.path.replace(/^\/static[^/]*\//, '/')); - // Used by the webview service worker to load resources. - } else if (resource.path === '/vscode-resource' && resource.query) { - try { - const query = JSON.parse(resource.query); - if (query.requestResourcePath) { - return URI.file(query.requestResourcePath); - } - } catch (error) { /* Carry on. */ } - } - return URI.from(resource); - } -} - -// See ../../workbench/services/remote/common/remoteAgentEnvironmentChannel.ts -export class ExtensionEnvironmentChannel implements IServerChannel { - public constructor( - private readonly environment: INativeEnvironmentService, - private readonly log: ILogService, - private readonly telemetry: ITelemetryService, - private readonly connectionToken: string, - ) {} - - public listen(_: unknown, event: string): Event<any> { - throw new Error(`Invalid listen '${event}'`); - } - - public async call(context: any, command: string, args: any): Promise<any> { - switch (command) { - case 'getEnvironmentData': - return transformOutgoingURIs( - await this.getEnvironmentData(), - getUriTransformer(context.remoteAuthority), - ); - case 'scanExtensions': - return transformOutgoingURIs( - await this.scanExtensions(args.language), - getUriTransformer(context.remoteAuthority), - ); - case 'getDiagnosticInfo': return this.getDiagnosticInfo(); - case 'disableTelemetry': return this.disableTelemetry(); - case 'logTelemetry': return this.logTelemetry(args[0], args[1]); - case 'flushTelemetry': return this.flushTelemetry(); - } - throw new Error(`Invalid call '${command}'`); - } - - private async getEnvironmentData(): Promise<IRemoteAgentEnvironment> { - return { - pid: process.pid, - connectionToken: this.connectionToken, - appRoot: URI.file(this.environment.appRoot), - settingsPath: this.environment.settingsResource, - logsPath: URI.file(this.environment.logsPath), - extensionsPath: URI.file(this.environment.extensionsPath!), - extensionHostLogsPath: URI.file(path.join(this.environment.logsPath, 'extension-host')), - globalStorageHome: this.environment.globalStorageHome, - workspaceStorageHome: this.environment.workspaceStorageHome, - userHome: this.environment.userHome, - useHostProxy: false, - os: platform.OS, - marks: [] - }; - } - - private async scanExtensions(language: string): Promise<IExtensionDescription[]> { - const translations = await getTranslations(language, this.environment.userDataPath); - - const scanMultiple = (isBuiltin: boolean, isUnderDevelopment: boolean, paths: string[]): Promise<IExtensionDescription[][]> => { - return Promise.all(paths.map((path) => { - return ExtensionScanner.scanExtensions(new ExtensionScannerInput( - product.version, - product.commit, - language, - !!process.env.VSCODE_DEV, - path, - isBuiltin, - isUnderDevelopment, - translations, - ), this.log); - })); - }; - - const scanBuiltin = async (): Promise<IExtensionDescription[][]> => { - return scanMultiple(true, false, [this.environment.builtinExtensionsPath, ...this.environment.extraBuiltinExtensionPaths]); - }; - - const scanInstalled = async (): Promise<IExtensionDescription[][]> => { - return scanMultiple(false, true, [this.environment.extensionsPath!, ...this.environment.extraExtensionPaths]); - }; - - return Promise.all([scanBuiltin(), scanInstalled()]).then((allExtensions) => { - const uniqueExtensions = new Map<string, IExtensionDescription>(); - allExtensions.forEach((multipleExtensions) => { - multipleExtensions.forEach((extensions) => { - extensions.forEach((extension) => { - const id = ExtensionIdentifier.toKey(extension.identifier); - if (uniqueExtensions.has(id)) { - const oldPath = uniqueExtensions.get(id)!.extensionLocation.fsPath; - const newPath = extension.extensionLocation.fsPath; - this.log.warn(`${oldPath} has been overridden ${newPath}`); - } - uniqueExtensions.set(id, extension); - }); - }); - }); - return Array.from(uniqueExtensions.values()); - }); - } - - private getDiagnosticInfo(): Promise<IDiagnosticInfo> { - throw new Error('not implemented'); - } - - private async disableTelemetry(): Promise<void> { - this.telemetry.setEnabled(false); - } - - private async logTelemetry(eventName: string, data: ITelemetryData): Promise<void> { - this.telemetry.publicLog(eventName, data); - } - - private async flushTelemetry(): Promise<void> { - // We always send immediately at the moment. - } -} - -// Reference: - ../../workbench/api/common/extHostDebugService.ts -class VariableResolverService extends AbstractVariableResolverService { - constructor( - remoteAuthority: string, - args: terminal.ICreateTerminalProcessArguments, - env: platform.IProcessEnvironment, - ) { - super({ - getFolderUri: (name: string): URI | undefined => { - const folder = args.workspaceFolders.find((f) => f.name === name); - return folder && URI.revive(folder.uri); - }, - getWorkspaceFolderCount: (): number => { - return args.workspaceFolders.length; - }, - // In ../../workbench/contrib/terminal/common/remoteTerminalChannel.ts it - // looks like there are `config:` entries which must be for this? Not sure - // how/if the URI comes into play though. - getConfigurationValue: (_: URI, section: string): string | undefined => { - return args.resolvedVariables[`config:${section}`]; - }, - getAppRoot: (): string | undefined => { - return (args.resolverEnv && args.resolverEnv['VSCODE_CWD']) || env['VSCODE_CWD'] || process.cwd(); - }, - getExecPath: (): string | undefined => { - // Assuming that resolverEnv is just for use in the resolver and not for - // the terminal itself. - return (args.resolverEnv && args.resolverEnv['VSCODE_EXEC_PATH']) || env['VSCODE_EXEC_PATH']; - }, - // This is just a guess; this is the only file-related thing we're sent - // and none of these resolver methods seem to get called so I don't know - // how to test. - getFilePath: (): string | undefined => { - const resource = transformIncoming(remoteAuthority, args.activeFileResource); - if (!resource) { - return undefined; - } - // See ../../editor/standalone/browser/simpleServices.ts; - // `BaseConfigurationResolverService` calls `getUriLabel` from there. - if (resource.scheme === 'file') { - return resource.fsPath; - } - return resource.path; - }, - // It looks like these are set here although they aren't on the types: - // ../../workbench/contrib/terminal/common/remoteTerminalChannel.ts - getSelectedText: (): string | undefined => { - return args.resolvedVariables.selectedText; - }, - getLineNumber: (): string | undefined => { - return args.resolvedVariables.selectedText; - }, - }, undefined, Promise.resolve(env)); - } -} - -class Terminal extends TerminalProcess { - private readonly workspaceId: string; - private readonly workspaceName: string; - - // TODO: Implement once we have persistent terminals. - public isOrphan: boolean = false; - - public get title(): string { return this._currentTitle; } - public get pid(): number { return this._ptyProcess?.pid ?? -1; } - - public constructor( - id: number, - config: IShellLaunchConfig & { cwd: string }, - args: terminal.ICreateTerminalProcessArguments, - env: platform.IProcessEnvironment, - logService: ILogService, - ) { - super( - id, - config, - config.cwd, - args.cols, - args.rows, - env, - process.env as platform.IProcessEnvironment, // Environment used for `findExecutable`. - false, // windowsEnableConpty: boolean, - logService, - ); - - this.workspaceId = args.workspaceId; - this.workspaceName = args.workspaceName; - - // Ensure other listeners run before disposing the emitters. - this.onProcessExit(() => setTimeout(() => this.shutdown(true), 1)); - } - - /** - * Run `fn` when the terminal disposes. - */ - public onDispose(dispose: () => void) { - this._register({ dispose }); - } - - /** - * Serializable terminal information that can be sent to the client. - */ - public async description(id: number): Promise<IProcessDetails> { - const cwd = await this.getCwd(); - return { - id, - pid: this.pid, - title: this.title, - cwd, - workspaceId: this.workspaceId, - workspaceName: this.workspaceName, - isOrphan: this.isOrphan, - icon: 'bash' // TODO@oxy: used for icon, but not sure how to resolve it - }; - } -} - -// References: - ../../workbench/api/node/extHostTerminalService.ts -// - ../../workbench/contrib/terminal/browser/terminalProcessManager.ts -export class TerminalProviderChannel implements IServerChannel<RemoteAgentConnectionContext>, IDisposable { - private readonly terminals = new Map<number, Terminal>(); - private id = 0; - - private readonly layouts = new Map<string, ISetTerminalLayoutInfoArgs>(); - - // These re-emit events from terminals with their IDs attached. - private readonly _onProcessData = new Emitter<{ id: number, event: IProcessDataEvent | string }>({ - // Shut down all terminals when all clients disconnect. Unfortunately this - // means that if you open multiple tabs and close one the terminals spawned - // by that tab won't shut down and they can't be reconnected either since we - // don't have persistence yet. - // TODO: Implement persistence. - onLastListenerRemove: () => { - this.terminals.forEach((t) => t.shutdown(true)); - } - }); - private readonly _onProcessExit = new Emitter<{ id: number, event: number | undefined }>(); - private readonly _onProcessReady = new Emitter<{ id: number, event: { pid: number, cwd: string } }>(); - private readonly _onProcessReplay = new Emitter<{ id: number, event: IPtyHostProcessReplayEvent }>(); - private readonly _onProcessTitleChanged = new Emitter<{ id: number, event: string }>(); - - // Buffer to reduce the number of messages going to the renderer. - private readonly bufferer = new TerminalDataBufferer((id, data) => { - this._onProcessData.fire({ id, event: data }); - }); - - public constructor (private readonly logService: ILogService) {} - - public listen(_: RemoteAgentConnectionContext, event: string, args: any): Event<any> { - logger.trace('TerminalProviderChannel:listen', field('event', event), field('args', args)); - - // TODO@oxy/code-asher: implement these events (currently Event.None) as needed - // Right now, most functionality tested works; - // but VSCode might rely on the other events in the future. - switch (event) { - case '$onPtyHostExitEvent': return Event.None; - case '$onPtyHostStartEvent': return Event.None; - case '$onPtyHostUnresponsiveEvent': return Event.None; - case '$onPtyHostResponsiveEvent': return Event.None; - - case '$onProcessDataEvent': return this._onProcessData.event; - case '$onProcessExitEvent': return this._onProcessExit.event; - case '$onProcessReadyEvent': return this._onProcessReady.event; - case '$onProcessReplayEvent': return this._onProcessReplay.event; - case '$onProcessTitleChangedEvent': return this._onProcessTitleChanged.event; - case '$onProcessShellTypeChangedEvent': return Event.None; - case '$onProcessOverrideDimensionsEvent': return Event.None; - case '$onProcessResolvedShellLaunchConfigEvent': return Event.None; - case '$onProcessOrphanQuestion': return Event.None; - // NOTE@code-asher: I think this must have something to do with running commands on - // the terminal that will do things in VS Code but we already have that - // functionality via a socket so I'm not sure what this is for. - case '$onExecuteCommand': return Event.None; - } - - throw new Error(`Invalid listen '${event}'`); - } - - public call(context: RemoteAgentConnectionContext, command: string, args: any): Promise<any> { - logger.trace('TerminalProviderChannel:call', field('command', command), field('args', args)); - - switch (command) { - case '$restartPtyHost': return this.restartPtyHost(); - case '$createProcess': return this.createProcess(context.remoteAuthority, args); - case '$attachToProcess': return this.attachToProcess(args[0]); - case '$start': return this.start(args[0]); - case '$input': return this.input(args[0], args[1]); - case '$acknowledgeDataEvent': return this.acknowledgeDataEvent(args[0], args[1]); - case '$shutdown': return this.shutdown(args[0], args[1]); - case '$resize': return this.resize(args[0], args[1], args[2]); - case '$getInitialCwd': return this.getInitialCwd(args[0]); - case '$getCwd': return this.getCwd(args[0]); - case '$sendCommandResult': return this.sendCommandResult(args[0], args[1], args[2], args[3]); - case '$orphanQuestionReply': return this.orphanQuestionReply(args[0]); - case '$listProcesses': return this.listProcesses(); - case '$setTerminalLayoutInfo': return this.setTerminalLayoutInfo(args); - case '$getTerminalLayoutInfo': return this.getTerminalLayoutInfo(args); - case '$getShellEnvironment': return this.getShellEnvironment(); - case '$getDefaultSystemShell': return this.getDefaultSystemShell(args[0]); - case '$reduceConnectionGraceTime': return this.reduceConnectionGraceTime(); - } - - throw new Error(`Invalid call '${command}'`); - } - - public dispose(): void { - this.bufferer.dispose(); - this.terminals.forEach((t) => t.shutdown(false)); - } - - private async restartPtyHost(): Promise<void> { - throw new Error('TODO: restartPtyHost'); - } - - private async createProcess(remoteAuthority: string, args: terminal.ICreateTerminalProcessArguments): Promise<terminal.ICreateTerminalProcessResult> { - const terminalId = this.id++; - logger.debug('Creating terminal', field('id', terminalId), field('terminals', this.terminals.size)); - - const shellLaunchConfig: IShellLaunchConfig = { - name: args.shellLaunchConfig.name, - executable: args.shellLaunchConfig.executable, - args: args.shellLaunchConfig.args, - // TODO: Should we transform if it's a string as well? The incoming - // transform only takes `UriComponents` so I suspect it's not necessary. - cwd: typeof args.shellLaunchConfig.cwd !== 'string' - ? transformIncoming(remoteAuthority, args.shellLaunchConfig.cwd) - : args.shellLaunchConfig.cwd, - env: args.shellLaunchConfig.env, - }; - - const activeWorkspaceUri = transformIncoming(remoteAuthority, args.activeWorkspaceFolder?.uri); - const activeWorkspace = activeWorkspaceUri && args.activeWorkspaceFolder ? { - ...args.activeWorkspaceFolder, - uri: activeWorkspaceUri, - toResource: (relativePath: string) => resources.joinPath(activeWorkspaceUri, relativePath), - } : undefined; - - const resolverService = new VariableResolverService(remoteAuthority, args, process.env); - const resolver = terminalEnvironment.createVariableResolver(activeWorkspace, process.env, resolverService); - - const getDefaultShellAndArgs = async (): Promise<{ executable: string; args: string[] | string }> => { - if (shellLaunchConfig.executable) { - const executable = await resolverService.resolveAsync(activeWorkspace, shellLaunchConfig.executable); - let resolvedArgs: string[] | string = []; - if (shellLaunchConfig.args && Array.isArray(shellLaunchConfig.args)) { - for (const arg of shellLaunchConfig.args) { - resolvedArgs.push(await resolverService.resolveAsync(activeWorkspace, arg)); - } - } else if (shellLaunchConfig.args) { - resolvedArgs = await resolverService.resolveAsync(activeWorkspace, shellLaunchConfig.args); - } - return { executable, args: resolvedArgs }; - } - - const executable = terminalEnvironment.getDefaultShell( - (key) => args.configuration[key], - await getSystemShell(platform.OS, process.env as platform.IProcessEnvironment), - process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'), - process.env.windir, - resolver, - this.logService, - false, // useAutomationShell - ); - - const resolvedArgs = terminalEnvironment.getDefaultShellArgs( - (key) => args.configuration[key], - false, // useAutomationShell - resolver, - this.logService, - ); - - return { executable, args: resolvedArgs }; - }; - - const getInitialCwd = (): string => { - return terminalEnvironment.getCwd( - shellLaunchConfig, - os.homedir(), - resolver, - activeWorkspaceUri, - args.configuration['terminal.integrated.cwd'], - this.logService, - ); - }; - - // Use a separate var so Typescript recognizes these properties are no - // longer undefined. - const resolvedShellLaunchConfig = { - ...shellLaunchConfig, - ...(await getDefaultShellAndArgs()), - cwd: getInitialCwd(), - }; - - logger.debug('Resolved shell launch configuration', field('id', terminalId)); - - // Use instead of `terminal.integrated.env.${platform}` to make types work. - const getEnvFromConfig = (): ITerminalEnvironment => { - if (platform.isWindows) { - return args.configuration['terminal.integrated.env.windows']; - } else if (platform.isMacintosh) { - return args.configuration['terminal.integrated.env.osx']; - } - return args.configuration['terminal.integrated.env.linux']; - }; - - const getNonInheritedEnv = async (): Promise<platform.IProcessEnvironment> => { - const env = await getMainProcessParentEnv(process.env); - env.VSCODE_IPC_HOOK_CLI = process.env['VSCODE_IPC_HOOK_CLI']!; - return env; - }; - - const env = terminalEnvironment.createTerminalEnvironment( - shellLaunchConfig, - getEnvFromConfig(), - resolver, - product.version, - args.configuration['terminal.integrated.detectLocale'], - args.configuration['terminal.integrated.inheritEnv'] !== false - ? process.env as platform.IProcessEnvironment - : await getNonInheritedEnv() - ); - - // Apply extension environment variable collections to the environment. - if (!shellLaunchConfig.strictEnv) { - // They come in an array and in serialized format. - const envVariableCollections = new Map<string, IEnvironmentVariableCollection>(); - for (const [k, v] of args.envVariableCollections) { - envVariableCollections.set(k, { map: deserializeEnvironmentVariableCollection(v) }); - } - const mergedCollection = new MergedEnvironmentVariableCollection(envVariableCollections); - mergedCollection.applyToProcessEnvironment(env); - } - - logger.debug('Resolved terminal environment', field('id', terminalId)); - - const terminal = new Terminal(terminalId, resolvedShellLaunchConfig, args, env, this.logService); - this.terminals.set(terminal.id, terminal); - logger.debug('Created terminal', field('id', terminal.id)); - terminal.onDispose(() => { - this.terminals.delete(terminal.id); - this.bufferer.stopBuffering(terminal.id); - }); - - // Hook up terminal events to the global event emitter. - this.bufferer.startBuffering(terminal.id, terminal.onProcessData); - terminal.onProcessExit((exitCode) => { - logger.debug('Terminal exited', field('id', terminal.id), field('code', exitCode)); - this._onProcessExit.fire({ id: terminal.id, event: exitCode }); - }); - terminal.onProcessReady((event) => { - this._onProcessReady.fire({ id: terminal.id, event }); - }); - terminal.onProcessTitleChanged((title) => { - this._onProcessTitleChanged.fire({ id: terminal.id, event: title }); - }); - - return { - persistentTerminalId: terminal.id, - resolvedShellLaunchConfig, - }; - } - - private getTerminal(id: number): Terminal { - const terminal = this.terminals.get(id); - if (!terminal) { - throw new Error(`terminal with id ${id} does not exist`); - } - return terminal; - } - - private async attachToProcess(_id: number): Promise<void> { - // TODO: Won't be necessary until we have persistent terminals. - throw new Error('not implemented'); - } - - private async start(id: number): Promise<ITerminalLaunchError | void> { - return this.getTerminal(id).start(); - } - - private async input(id: number, data: string): Promise<void> { - return this.getTerminal(id).input(data); - } - - private async acknowledgeDataEvent(id: number, charCount: number): Promise<void> { - return this.getTerminal(id).acknowledgeDataEvent(charCount); - } - - private async shutdown(id: number, immediate: boolean): Promise<void> { - return this.getTerminal(id).shutdown(immediate); - } - - private async resize(id: number, cols: number, rows: number): Promise<void> { - return this.getTerminal(id).resize(cols, rows); - } - - private async getInitialCwd(id: number): Promise<string> { - return this.getTerminal(id).getInitialCwd(); - } - - private async getCwd(id: number): Promise<string> { - return this.getTerminal(id).getCwd(); - } - - private async sendCommandResult(_id: number, _reqId: number, _isError: boolean, _payload: any): Promise<void> { - // NOTE: Not required unless we implement the matching event, see above. - throw new Error('not implemented'); - } - - private async orphanQuestionReply(_id: number): Promise<void> { - // NOTE: Not required unless we implement the matching event, see above. - throw new Error('not implemented'); - } - - private async reduceConnectionGraceTime(): Promise<void> { - // NOTE: Not required unless we implement orphan terminals, see above. - // Returning instead of throwing error as VSCode expects this function - // to always succeed and throwing an error causes the terminal to crash. - return; - } - - private async listProcesses(): Promise<IProcessDetails[]> { - const terminals = await Promise.all(Array.from(this.terminals).map(async ([id, terminal]) => { - return terminal.description(id); - })); - - // Only returned orphaned terminals so we don't end up attaching to - // terminals already attached elsewhere. - return terminals.filter((t) => t.isOrphan); - } - - public async setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): Promise<void> { - this.layouts.set(args.workspaceId, args); - } - - public async getTerminalLayoutInfo(args: IGetTerminalLayoutInfoArgs): Promise<ITerminalsLayoutInfo | undefined> { - const layout = this.layouts.get(args.workspaceId); - if (!layout) { - return undefined; - } - - const tabs = await Promise.all(layout.tabs.map(async (tab) => { - // The terminals are stored by ID so look them up. - const terminals = await Promise.all(tab.terminals.map(async (t) => { - const terminal = this.terminals.get(t.terminal); - if (!terminal) { - return undefined; - } - return { - ...t, - terminal: await terminal.description(t.terminal), - }; - })); - - return { - ...tab, - // Filter out terminals that have been killed. - terminals: terminals.filter(isDefined), - }; - })); - - return { tabs }; - } - - async getShellEnvironment(): Promise<platform.IProcessEnvironment> { - return { ...process.env }; - } - - async getDefaultSystemShell(osOverride: platform.OperatingSystem = platform.OS): Promise<string> { - return getSystemShell(osOverride, process.env); - } -} - -function transformIncoming(remoteAuthority: string, uri: UriComponents | undefined): URI | undefined { - const transformer = getUriTransformer(remoteAuthority); - return uri ? URI.revive(transformer.transformIncoming(uri)) : uri; -} - -function isDefined<T>(t: T | undefined): t is T { - return typeof t !== 'undefined'; -} diff --git a/lib/vscode/src/vs/server/node/connection.ts b/lib/vscode/src/vs/server/node/connection.ts deleted file mode 100644 index ef5cecdaa88b..000000000000 --- a/lib/vscode/src/vs/server/node/connection.ts +++ /dev/null @@ -1,231 +0,0 @@ -import { field, Logger, logger } from '@coder/logger'; -import * as cp from 'child_process'; -import { VSBuffer } from 'vs/base/common/buffer'; -import { Emitter } from 'vs/base/common/event'; -import { FileAccess } from 'vs/base/common/network'; -import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IRemoteExtensionHostStartParams } from 'vs/platform/remote/common/remoteAgentConnection'; -import { getNlsConfiguration } from 'vs/server/node/nls'; -import { Protocol } from 'vs/server/node/protocol'; -import { IExtHostReadyMessage } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; - -export abstract class Connection { - private readonly _onClose = new Emitter<void>(); - /** - * Fire when the connection is closed (not just disconnected). This should - * only happen when the connection is offline and old or has an error. - */ - public readonly onClose = this._onClose.event; - private disposed = false; - private _offline: number | undefined; - - protected readonly logger: Logger; - - public constructor( - protected readonly protocol: Protocol, - public readonly name: string, - ) { - this.logger = logger.named( - this.name, - field('token', this.protocol.options.reconnectionToken), - ); - - this.logger.debug('Connecting...'); - this.onClose(() => this.logger.debug('Closed')); - } - - public get offline(): number | undefined { - return this._offline; - } - - public reconnect(protocol: Protocol): void { - this.logger.debug('Reconnecting...'); - this._offline = undefined; - this.doReconnect(protocol); - } - - public dispose(reason?: string): void { - this.logger.debug('Disposing...', field('reason', reason)); - if (!this.disposed) { - this.disposed = true; - this.doDispose(); - this._onClose.fire(); - } - } - - protected setOffline(): void { - this.logger.debug('Disconnected'); - if (!this._offline) { - this._offline = Date.now(); - } - } - - /** - * Set up the connection on a new socket. - */ - protected abstract doReconnect(protcol: Protocol): void; - - /** - * Dispose/destroy everything permanently. - */ - protected abstract doDispose(): void; -} - -/** - * Used for all the IPC channels. - */ -export class ManagementConnection extends Connection { - public constructor(protocol: Protocol) { - super(protocol, 'management'); - protocol.onDidDispose(() => this.dispose()); // Explicit close. - protocol.onSocketClose(() => this.setOffline()); // Might reconnect. - protocol.sendMessage({ type: 'ok' }); - } - - protected doDispose(): void { - this.protocol.destroy(); - } - - protected doReconnect(protocol: Protocol): void { - protocol.sendMessage({ type: 'ok' }); - this.protocol.beginAcceptReconnection(protocol.getSocket(), protocol.readEntireBuffer()); - this.protocol.endAcceptReconnection(); - protocol.dispose(); - } -} - -interface DisconnectedMessage { - type: 'VSCODE_EXTHOST_DISCONNECTED'; -} - -interface ConsoleMessage { - type: '__$console'; - // See bootstrap-fork.js#L135. - severity: 'log' | 'warn' | 'error'; - arguments: any[]; -} - -type ExtHostMessage = DisconnectedMessage | ConsoleMessage | IExtHostReadyMessage; - -export class ExtensionHostConnection extends Connection { - private process?: cp.ChildProcess; - - public constructor( - protocol: Protocol, - private readonly params: IRemoteExtensionHostStartParams, - private readonly environment: INativeEnvironmentService, - ) { - super(protocol, 'exthost'); - - protocol.sendMessage({ debugPort: this.params.port }); - const buffer = protocol.readEntireBuffer(); - const inflateBytes = protocol.inflateBytes; - protocol.dispose(); - protocol.getUnderlyingSocket().pause(); - - this.spawn(buffer, inflateBytes).then((p) => this.process = p); - } - - protected doDispose(): void { - this.protocol.destroy(); - if (this.process) { - this.process.kill(); - } - } - - protected doReconnect(protocol: Protocol): void { - protocol.sendMessage({ debugPort: this.params.port }); - const buffer = protocol.readEntireBuffer(); - const inflateBytes = protocol.inflateBytes; - protocol.dispose(); - protocol.getUnderlyingSocket().pause(); - this.protocol.setSocket(protocol.getSocket()); - - this.sendInitMessage(buffer, inflateBytes); - } - - private sendInitMessage(buffer: VSBuffer, inflateBytes: Uint8Array | undefined): void { - if (!this.process) { - throw new Error('Tried to initialize VS Code before spawning'); - } - - this.logger.debug('Sending socket'); - - // TODO: Do something with the debug port. - this.process.send({ - type: 'VSCODE_EXTHOST_IPC_SOCKET', - initialDataChunk: Buffer.from(buffer.buffer).toString('base64'), - skipWebSocketFrames: this.protocol.options.skipWebSocketFrames, - permessageDeflate: this.protocol.options.permessageDeflate, - inflateBytes: inflateBytes ? Buffer.from(inflateBytes).toString('base64') : undefined, - }, this.protocol.getUnderlyingSocket()); - } - - private async spawn(buffer: VSBuffer, inflateBytes: Uint8Array | undefined): Promise<cp.ChildProcess> { - this.logger.debug('Getting NLS configuration...'); - const config = await getNlsConfiguration(this.params.language, this.environment.userDataPath); - this.logger.debug('Spawning extension host...'); - const proc = cp.fork( - FileAccess.asFileUri('bootstrap-fork', require).fsPath, - // While not technically necessary, makes it easier to tell which process - // bootstrap-fork is executing. Can also do pkill -f extensionHost - // Other spawns in the VS Code codebase behave similarly. - [ '--type=extensionHost' ], - { - env: { - ...process.env, - VSCODE_AMD_ENTRYPOINT: 'vs/workbench/services/extensions/node/extensionHostProcess', - VSCODE_PIPE_LOGGING: 'true', - VSCODE_VERBOSE_LOGGING: 'true', - VSCODE_EXTHOST_WILL_SEND_SOCKET: 'true', - VSCODE_HANDLES_UNCAUGHT_ERRORS: 'true', - VSCODE_LOG_STACK: 'false', - VSCODE_LOG_LEVEL: process.env.LOG_LEVEL, - VSCODE_NLS_CONFIG: JSON.stringify(config), - VSCODE_PARENT_PID: String(process.pid), - }, - silent: true, - }, - ); - - proc.on('error', (error) => { - this.logger.error('Exited unexpectedly', field('error', error)); - this.dispose(); - }); - proc.on('exit', (code) => { - this.logger.debug('Exited', field('code', code)); - this.dispose(); - }); - if (proc.stdout && proc.stderr) { - proc.stdout.setEncoding('utf8').on('data', (d) => this.logger.info(d)); - proc.stderr.setEncoding('utf8').on('data', (d) => this.logger.error(d)); - } - - proc.on('message', (event: ExtHostMessage) => { - switch (event.type) { - case '__$console': - const fn = this.logger[event.severity === 'log' ? 'info' : event.severity]; - if (fn) { - fn.bind(this.logger)('console', field('arguments', event.arguments)); - } else { - this.logger.error('Unexpected severity', field('event', event)); - } - break; - case 'VSCODE_EXTHOST_DISCONNECTED': - this.logger.debug('Got disconnected message'); - this.setOffline(); - break; - case 'VSCODE_EXTHOST_IPC_READY': - this.logger.debug('Handshake completed'); - this.sendInitMessage(buffer, inflateBytes); - break; - default: - this.logger.error('Unexpected message', field('event', event)); - break; - } - }); - - this.logger.debug('Waiting for handshake...'); - return proc; - } -} diff --git a/lib/vscode/src/vs/server/node/insights.ts b/lib/vscode/src/vs/server/node/insights.ts deleted file mode 100644 index a0ece345f28f..000000000000 --- a/lib/vscode/src/vs/server/node/insights.ts +++ /dev/null @@ -1,124 +0,0 @@ -import * as appInsights from 'applicationinsights'; -import * as https from 'https'; -import * as http from 'http'; -import * as os from 'os'; - -class Channel { - public get _sender() { - throw new Error('unimplemented'); - } - public get _buffer() { - throw new Error('unimplemented'); - } - - public setUseDiskRetryCaching(): void { - throw new Error('unimplemented'); - } - public send(): void { - throw new Error('unimplemented'); - } - public triggerSend(): void { - throw new Error('unimplemented'); - } -} - -export class TelemetryClient { - public context: any = undefined; - public commonProperties: any = undefined; - public config: any = {}; - - public channel: any = new Channel(); - - public addTelemetryProcessor(): void { - throw new Error('unimplemented'); - } - - public clearTelemetryProcessors(): void { - throw new Error('unimplemented'); - } - - public runTelemetryProcessors(): void { - throw new Error('unimplemented'); - } - - public trackTrace(): void { - throw new Error('unimplemented'); - } - - public trackMetric(): void { - throw new Error('unimplemented'); - } - - public trackException(): void { - throw new Error('unimplemented'); - } - - public trackRequest(): void { - throw new Error('unimplemented'); - } - - public trackDependency(): void { - throw new Error('unimplemented'); - } - - public track(): void { - throw new Error('unimplemented'); - } - - public trackNodeHttpRequestSync(): void { - throw new Error('unimplemented'); - } - - public trackNodeHttpRequest(): void { - throw new Error('unimplemented'); - } - - public trackNodeHttpDependency(): void { - throw new Error('unimplemented'); - } - - public trackEvent(options: appInsights.Contracts.EventTelemetry): void { - if (!options.properties) { - options.properties = {}; - } - if (!options.measurements) { - options.measurements = {}; - } - - try { - const cpus = os.cpus(); - options.measurements.cores = cpus.length; - options.properties['common.cpuModel'] = cpus[0].model; - } catch (error) {} - - try { - options.measurements.memoryFree = os.freemem(); - options.measurements.memoryTotal = os.totalmem(); - } catch (error) {} - - try { - options.properties['common.shell'] = os.userInfo().shell; - options.properties['common.release'] = os.release(); - options.properties['common.arch'] = os.arch(); - } catch (error) {} - - try { - const url = process.env.TELEMETRY_URL || 'https://v1.telemetry.coder.com/track'; - const request = (/^http:/.test(url) ? http : https).request(url, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - }); - request.on('error', () => { /* We don't care. */ }); - request.write(JSON.stringify(options)); - request.end(); - } catch (error) {} - } - - public flush(options: { callback: (v: string) => void }): void { - if (options.callback) { - options.callback(''); - } - } -} diff --git a/lib/vscode/src/vs/server/node/ipc.ts b/lib/vscode/src/vs/server/node/ipc.ts deleted file mode 100644 index 5e560eb46e6a..000000000000 --- a/lib/vscode/src/vs/server/node/ipc.ts +++ /dev/null @@ -1,61 +0,0 @@ -import * as cp from 'child_process'; -import { Emitter } from 'vs/base/common/event'; - -enum ControlMessage { - okToChild = 'ok>', - okFromChild = 'ok<', -} - -interface RelaunchMessage { - type: 'relaunch'; - version: string; -} - -export type Message = RelaunchMessage; - -class IpcMain { - protected readonly _onMessage = new Emitter<Message>(); - public readonly onMessage = this._onMessage.event; - - public handshake(child?: cp.ChildProcess): Promise<void> { - return new Promise((resolve, reject) => { - const target = child || process; - if (!target.send) { - throw new Error('Not spawned with IPC enabled'); - } - target.on('message', (message) => { - if (message === child ? ControlMessage.okFromChild : ControlMessage.okToChild) { - target.removeAllListeners(); - target.on('message', (msg) => this._onMessage.fire(msg)); - if (child) { - target.send!(ControlMessage.okToChild); - } - resolve(); - } - }); - if (child) { - child.once('error', reject); - child.once('exit', (code) => { - const error = new Error(`Unexpected exit with code ${code}`); - (error as any).code = code; - reject(error); - }); - } else { - target.send(ControlMessage.okFromChild); - } - }); - } - - public relaunch(version: string): void { - this.send({ type: 'relaunch', version }); - } - - private send(message: Message): void { - if (!process.send) { - throw new Error('Not a child process with IPC enabled'); - } - process.send(message); - } -} - -export const ipcMain = new IpcMain(); diff --git a/lib/vscode/src/vs/server/node/logger.ts b/lib/vscode/src/vs/server/node/logger.ts deleted file mode 100644 index 2a39c524aaa1..000000000000 --- a/lib/vscode/src/vs/server/node/logger.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { logger as baseLogger } from '@coder/logger'; -export const logger = baseLogger.named('vscode'); diff --git a/lib/vscode/src/vs/server/node/marketplace.ts b/lib/vscode/src/vs/server/node/marketplace.ts deleted file mode 100644 index 1cb9262be18d..000000000000 --- a/lib/vscode/src/vs/server/node/marketplace.ts +++ /dev/null @@ -1,183 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import * as tarStream from 'tar-stream'; -import * as util from 'util'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import * as vszip from 'vs/base/node/zip'; -import * as nls from 'vs/nls'; -import product from 'vs/platform/product/common/product'; - -// We will be overriding these, so keep a reference to the original. -const vszipExtract = vszip.extract; -const vszipBuffer = vszip.buffer; - -export interface IExtractOptions { - overwrite?: boolean; - /** - * Source path within the TAR/ZIP archive. Only the files - * contained in this path will be extracted. - */ - sourcePath?: string; -} - -export interface IFile { - path: string; - contents?: Buffer | string; - localPath?: string; -} - -export const tar = async (tarPath: string, files: IFile[]): Promise<string> => { - const pack = tarStream.pack(); - const chunks: Buffer[] = []; - const ended = new Promise<Buffer>((resolve) => { - pack.on('end', () => resolve(Buffer.concat(chunks))); - }); - pack.on('data', (chunk: Buffer) => chunks.push(chunk)); - for (let i = 0; i < files.length; i++) { - const file = files[i]; - pack.entry({ name: file.path }, file.contents); - } - pack.finalize(); - await util.promisify(fs.writeFile)(tarPath, await ended); - return tarPath; -}; - -export const extract = async (archivePath: string, extractPath: string, options: IExtractOptions = {}, token: CancellationToken): Promise<void> => { - try { - await extractTar(archivePath, extractPath, options, token); - } catch (error) { - if (error.toString().includes('Invalid tar header')) { - await vszipExtract(archivePath, extractPath, options, token); - } - } -}; - -export const buffer = (targetPath: string, filePath: string): Promise<Buffer> => { - return new Promise<Buffer>(async (resolve, reject) => { - try { - let done: boolean = false; - await extractAssets(targetPath, new RegExp(filePath), (assetPath: string, data: Buffer) => { - if (path.normalize(assetPath) === path.normalize(filePath)) { - done = true; - resolve(data); - } - }); - if (!done) { - throw new Error('couldn\'t find asset ' + filePath); - } - } catch (error) { - if (error.toString().includes('Invalid tar header')) { - vszipBuffer(targetPath, filePath).then(resolve).catch(reject); - } else { - reject(error); - } - } - }); -}; - -const extractAssets = async (tarPath: string, match: RegExp, callback: (path: string, data: Buffer) => void): Promise<void> => { - return new Promise<void>((resolve, reject): void => { - const extractor = tarStream.extract(); - const fail = (error: Error) => { - extractor.destroy(); - reject(error); - }; - extractor.once('error', fail); - extractor.on('entry', async (header, stream, next) => { - const name = header.name; - if (match.test(name)) { - extractData(stream).then((data) => { - callback(name, data); - next(); - }).catch(fail); - } else { - stream.on('end', () => next()); - stream.resume(); // Just drain it. - } - }); - extractor.on('finish', resolve); - fs.createReadStream(tarPath).pipe(extractor); - }); -}; - -const extractData = (stream: NodeJS.ReadableStream): Promise<Buffer> => { - return new Promise((resolve, reject): void => { - const fileData: Buffer[] = []; - stream.on('error', reject); - stream.on('end', () => resolve(Buffer.concat(fileData))); - stream.on('data', (data) => fileData.push(data)); - }); -}; - -const extractTar = async (tarPath: string, targetPath: string, options: IExtractOptions = {}, token: CancellationToken): Promise<void> => { - return new Promise<void>((resolve, reject): void => { - const sourcePathRegex = new RegExp(options.sourcePath ? `^${options.sourcePath}` : ''); - const extractor = tarStream.extract(); - const fail = (error: Error) => { - extractor.destroy(); - reject(error); - }; - extractor.once('error', fail); - extractor.on('entry', async (header, stream, next) => { - const nextEntry = (): void => { - stream.on('end', () => next()); - stream.resume(); - }; - - const rawName = path.normalize(header.name); - if (token.isCancellationRequested || !sourcePathRegex.test(rawName)) { - return nextEntry(); - } - - const fileName = rawName.replace(sourcePathRegex, ''); - const targetFileName = path.join(targetPath, fileName); - if (/\/$/.test(fileName)) { - /* - NOTE:@coder: they removed mkdirp in favor of fs.promises - See commit: https://github.com/microsoft/vscode/commit/a0d76bb9834b63a02fba8017a6306511fe1ab4fe#diff-2bf233effbb62ea789bb7c4739d222a43ccd97ed9f1219f75bb07e9dee91c1a7 - 3/11/21 @jsjoeio - */ - return fs.promises.mkdir(targetFileName, { recursive: true }).then(nextEntry); - } - - const dirName = path.dirname(fileName); - const targetDirName = path.join(targetPath, dirName); - if (targetDirName.indexOf(targetPath) !== 0) { - return fail(new Error(nls.localize('invalid file', 'Error extracting {0}. Invalid file.', fileName))); - } - - /* - NOTE:@coder: they removed mkdirp in favor of fs.promises - See commit: https://github.com/microsoft/vscode/commit/a0d76bb9834b63a02fba8017a6306511fe1ab4fe#diff-2bf233effbb62ea789bb7c4739d222a43ccd97ed9f1219f75bb07e9dee91c1a7 - 3/11/21 @jsjoeio - */ - await fs.promises.mkdir(targetDirName, { recursive: true }); - - const fstream = fs.createWriteStream(targetFileName, { mode: header.mode }); - fstream.once('close', () => next()); - fstream.once('error', fail); - stream.pipe(fstream); - }); - extractor.once('finish', resolve); - fs.createReadStream(tarPath).pipe(extractor); - }); -}; - -/** - * Override original functionality so we can use a custom marketplace with - * either tars or zips. - */ -export const enableCustomMarketplace = (): void => { - (<any>product).extensionsGallery = { // Use `any` to override readonly. - serviceUrl: process.env.SERVICE_URL || 'https://extensions.coder.com/api', - itemUrl: process.env.ITEM_URL || '', - controlUrl: '', - recommendationsUrl: '', - ...(product.extensionsGallery || {}), - }; - - const target = vszip as typeof vszip; - target.zip = tar; - target.extract = extract; - target.buffer = buffer; -}; diff --git a/lib/vscode/src/vs/server/node/nls.ts b/lib/vscode/src/vs/server/node/nls.ts deleted file mode 100644 index 926500c147fb..000000000000 --- a/lib/vscode/src/vs/server/node/nls.ts +++ /dev/null @@ -1,88 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import * as util from 'util'; -import { FileAccess } from 'vs/base/common/network'; -import * as lp from 'vs/base/node/languagePacks'; -import product from 'vs/platform/product/common/product'; -import { Translations } from 'vs/workbench/services/extensions/common/extensionPoints'; - -const configurations = new Map<string, Promise<lp.NLSConfiguration>>(); -const metadataPath = path.join(FileAccess.asFileUri('', require).fsPath, 'nls.metadata.json'); - -export const isInternalConfiguration = (config: lp.NLSConfiguration): config is lp.InternalNLSConfiguration => { - return config && !!(<lp.InternalNLSConfiguration>config)._languagePackId; -}; - -const DefaultConfiguration = { - locale: 'en', - availableLanguages: {}, -}; - -export const getNlsConfiguration = async (locale: string, userDataPath: string): Promise<lp.NLSConfiguration> => { - const id = `${locale}: ${userDataPath}`; - if (!configurations.has(id)) { - configurations.set(id, new Promise(async (resolve) => { - const config = product.commit && await util.promisify(fs.exists)(metadataPath) - ? await lp.getNLSConfiguration(product.commit, userDataPath, metadataPath, locale) - : DefaultConfiguration; - if (isInternalConfiguration(config)) { - config._languagePackSupport = true; - } - // If the configuration has no results keep trying since code-server - // doesn't restart when a language is installed so this result would - // persist (the plugin might not be installed yet or something). - if (config.locale !== 'en' && config.locale !== 'en-us' && Object.keys(config.availableLanguages).length === 0) { - configurations.delete(id); - } - resolve(config); - })); - } - return configurations.get(id)!; -}; - -export const getTranslations = async (locale: string, userDataPath: string): Promise<Translations> => { - const config = await getNlsConfiguration(locale, userDataPath); - if (isInternalConfiguration(config)) { - try { - return JSON.parse(await util.promisify(fs.readFile)(config._translationsConfigFile, 'utf8')); - } catch (error) { /* Nothing yet. */} - } - return {}; -}; - -export const getLocaleFromConfig = async (userDataPath: string): Promise<string> => { - const files = ['locale.json', 'argv.json']; - for (let i = 0; i < files.length; ++i) { - try { - const localeConfigUri = path.join(userDataPath, 'User', files[i]); - const content = stripComments(await util.promisify(fs.readFile)(localeConfigUri, 'utf8')); - return JSON.parse(content).locale; - } catch (error) { /* Ignore. */ } - } - return 'en'; -}; - -// Taken from src/main.js in the main VS Code source. -const stripComments = (content: string): string => { - const regexp = /('(?:[^\\']*(?:\\.)?)*')|('(?:[^\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g; - - return content.replace(regexp, (match, _m1, _m2, m3, m4) => { - // Only one of m1, m2, m3, m4 matches - if (m3) { - // A block comment. Replace with nothing - return ''; - } else if (m4) { - // A line comment. If it ends in \r?\n then keep it. - const length_1 = m4.length; - if (length_1 > 2 && m4[length_1 - 1] === '\n') { - return m4[length_1 - 2] === '\r' ? '\r\n' : '\n'; - } - else { - return ''; - } - } else { - // We match a string - return match; - } - }); -}; diff --git a/lib/vscode/src/vs/server/node/protocol.ts b/lib/vscode/src/vs/server/node/protocol.ts deleted file mode 100644 index fd61d4c95c63..000000000000 --- a/lib/vscode/src/vs/server/node/protocol.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { field, logger, Logger } from '@coder/logger'; -import * as net from 'net'; -import { VSBuffer } from 'vs/base/common/buffer'; -import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net'; -import { NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; -import { AuthRequest, ConnectionTypeRequest, HandshakeMessage } from 'vs/platform/remote/common/remoteAgentConnection'; - -export interface SocketOptions { - /** The token is how we identify and connect to existing sessions. */ - readonly reconnectionToken: string; - /** Specifies that the client is trying to reconnect. */ - readonly reconnection: boolean; - /** If true assume this is not a web socket (always false for code-server). */ - readonly skipWebSocketFrames: boolean; - /** Whether to support compression (web socket only). */ - readonly permessageDeflate?: boolean; - /** - * Seed zlib with these bytes (web socket only). If parts of inflating was - * done in a different zlib instance we need to pass all those bytes into zlib - * otherwise the inflate might hit an inflated portion referencing a distance - * too far back. - */ - readonly inflateBytes?: VSBuffer; -} - -export class Protocol extends PersistentProtocol { - private readonly logger: Logger; - - public constructor(socket: net.Socket, public readonly options: SocketOptions) { - super( - options.skipWebSocketFrames - ? new NodeSocket(socket) - : new WebSocketNodeSocket( - new NodeSocket(socket), - options.permessageDeflate || false, - options.inflateBytes || null, - // Always record inflate bytes if using permessage-deflate. - options.permessageDeflate || false, - ), - ); - - this.logger = logger.named('protocol', field('token', this.options.reconnectionToken)); - } - - public getUnderlyingSocket(): net.Socket { - const socket = this.getSocket(); - return socket instanceof NodeSocket - ? socket.socket - : (socket as WebSocketNodeSocket).socket.socket; - } - - /** - * Perform a handshake to get a connection request. - */ - public handshake(): Promise<ConnectionTypeRequest> { - this.logger.debug('Initiating handshake...'); - - return new Promise((resolve, reject) => { - const cleanup = () => { - handler.dispose(); - onClose.dispose(); - clearTimeout(timeout); - }; - - const onClose = this.onSocketClose(() => { - cleanup(); - this.logger.debug('Handshake failed'); - reject(new Error('Protocol socket closed unexpectedly')); - }); - - const timeout = setTimeout(() => { - cleanup(); - this.logger.debug('Handshake timed out'); - reject(new Error('Protocol handshake timed out')); - }, 10000); // Matches the client timeout. - - const handler = this.onControlMessage((rawMessage) => { - try { - const raw = rawMessage.toString(); - this.logger.trace('Got message', field('message', raw)); - const message = JSON.parse(raw); - switch (message.type) { - case 'auth': - return this.authenticate(message); - case 'connectionType': - cleanup(); - this.logger.debug('Handshake completed'); - return resolve(message); - default: - throw new Error('Unrecognized message type'); - } - } catch (error) { - cleanup(); - reject(error); - } - }); - - // Kick off the handshake in case we missed the client's opening shot. - // TODO: Investigate why that message seems to get lost. - this.authenticate(); - }); - } - - /** - * TODO: This ignores the authentication process entirely for now. - */ - private authenticate(_?: AuthRequest): void { - this.sendMessage({ type: 'sign', data: '' }); - } - - /** - * TODO: implement. - */ - public tunnel(): void { - throw new Error('Tunnel is not implemented yet'); - } - - /** - * Send a handshake message. In the case of the extension host it should just - * send a debug port. - */ - public sendMessage(message: HandshakeMessage | { debugPort?: number | null } ): void { - this.sendControl(VSBuffer.fromString(JSON.stringify(message))); - } - - /** - * Disconnect and dispose everything including the underlying socket. - */ - public destroy(reason?: string): void { - try { - if (reason) { - this.sendMessage({ type: 'error', reason }); - } - // If still connected try notifying the client. - this.sendDisconnect(); - } catch (error) { - // I think the write might fail if already disconnected. - this.logger.warn(error.message || error); - } - this.dispose(); // This disposes timers and socket event handlers. - this.getSocket().dispose(); // This will destroy() the socket. - } - - /** - * Get inflateBytes from the current socket. - */ - public get inflateBytes(): Uint8Array | undefined { - const socket = this.getSocket(); - return socket instanceof WebSocketNodeSocket - ? socket.recordedInflateBytes.buffer - : undefined; - } -} diff --git a/lib/vscode/src/vs/server/node/server.ts b/lib/vscode/src/vs/server/node/server.ts deleted file mode 100644 index a3708045df6e..000000000000 --- a/lib/vscode/src/vs/server/node/server.ts +++ /dev/null @@ -1,300 +0,0 @@ -import * as fs from 'fs'; -import * as net from 'net'; -import { hostname, release } from 'os'; -import * as path from 'path'; -import { Emitter } from 'vs/base/common/event'; -import { Schemas } from 'vs/base/common/network'; -import { URI } from 'vs/base/common/uri'; -import { getMachineId } from 'vs/base/node/id'; -import { ClientConnectionEvent, IPCServer, IServerChannel, ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; -import { LogsDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner'; -import { main } from 'vs/code/node/cliProcessMain'; -import { Query, VscodeOptions, WorkbenchOptions } from 'vs/ipc'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ConfigurationService } from 'vs/platform/configuration/common/configurationService'; -import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc'; -import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; -import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/common/environment'; -import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; -import { IExtensionGalleryService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; -import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; -import { IFileService } from 'vs/platform/files/common/files'; -import { FileService } from 'vs/platform/files/common/fileService'; -import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; -import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; -import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; -import { LocalizationsService } from 'vs/platform/localizations/node/localizations'; -import { ConsoleLogger, getLogLevel, ILoggerService, ILogService, MultiplexLogService } from 'vs/platform/log/common/log'; -import { LogLevelChannel } from 'vs/platform/log/common/logIpc'; -import { LoggerService } from 'vs/platform/log/node/loggerService'; -import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog'; -import product from 'vs/platform/product/common/product'; -import { IProductService } from 'vs/platform/product/common/productService'; -import { ConnectionType, ConnectionTypeRequest } from 'vs/platform/remote/common/remoteAgentConnection'; -import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment'; -import { IRequestService } from 'vs/platform/request/common/request'; -import { RequestChannel } from 'vs/platform/request/common/requestIpc'; -import { RequestService } from 'vs/platform/request/node/requestService'; -import ErrorTelemetry from 'vs/platform/telemetry/browser/errorTelemetry'; -import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProperties'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { TelemetryLogAppender } from 'vs/platform/telemetry/common/telemetryLogAppender'; -import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; -import { combinedAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; -import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender'; -import { TelemetryChannel } from 'vs/server/common/telemetry'; -import { ExtensionEnvironmentChannel, FileProviderChannel, TerminalProviderChannel } from 'vs/server/node/channel'; -import { Connection, ExtensionHostConnection, ManagementConnection } from 'vs/server/node/connection'; -import { TelemetryClient } from 'vs/server/node/insights'; -import { logger } from 'vs/server/node/logger'; -import { getLocaleFromConfig, getNlsConfiguration } from 'vs/server/node/nls'; -import { Protocol } from 'vs/server/node/protocol'; -import { getUriTransformer } from 'vs/server/node/util'; -import { REMOTE_TERMINAL_CHANNEL_NAME } from 'vs/workbench/contrib/terminal/common/remoteTerminalChannel'; -import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from 'vs/workbench/services/remote/common/remoteAgentFileSystemChannel'; -import { RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/remoteAgentService'; - -const commit = product.commit || 'development'; - -export class Vscode { - public readonly _onDidClientConnect = new Emitter<ClientConnectionEvent>(); - public readonly onDidClientConnect = this._onDidClientConnect.event; - private readonly ipc = new IPCServer<RemoteAgentConnectionContext>(this.onDidClientConnect); - - private readonly maxExtraOfflineConnections = 0; - private readonly connections = new Map<ConnectionType, Map<string, Connection>>(); - - private readonly services = new ServiceCollection(); - private servicesPromise?: Promise<void>; - - public async cli(args: NativeParsedArgs): Promise<void> { - return main(args); - } - - public async initialize(options: VscodeOptions): Promise<WorkbenchOptions> { - const transformer = getUriTransformer(options.remoteAuthority); - if (!this.servicesPromise) { - this.servicesPromise = this.initializeServices(options.args); - } - await this.servicesPromise; - const environment = this.services.get(IEnvironmentService) as INativeEnvironmentService; - const startPath = options.startPath; - const parseUrl = (url: string): URI => { - // This might be a fully-specified URL or just a path. - try { - return URI.parse(url, true); - } catch (error) { - return URI.from({ - scheme: Schemas.vscodeRemote, - authority: options.remoteAuthority, - path: url, - }); - } - }; - return { - workbenchWebConfiguration: { - workspaceUri: startPath && startPath.workspace ? parseUrl(startPath.url) : undefined, - folderUri: startPath && !startPath.workspace ? parseUrl(startPath.url) : undefined, - remoteAuthority: options.remoteAuthority, - logLevel: getLogLevel(environment), - workspaceProvider: { - payload: [ - ['userDataPath', environment.userDataPath], - ['enableProposedApi', JSON.stringify(options.args['enable-proposed-api'] || [])] - ], - }, - }, - remoteUserDataUri: transformer.transformOutgoing(URI.file(environment.userDataPath)), - productConfiguration: product, - nlsConfiguration: await getNlsConfiguration(environment.args.locale || await getLocaleFromConfig(environment.userDataPath), environment.userDataPath), - commit, - }; - } - - public async handleWebSocket(socket: net.Socket, query: Query, permessageDeflate: boolean): Promise<true> { - if (!query.reconnectionToken) { - throw new Error('Reconnection token is missing from query parameters'); - } - const protocol = new Protocol(socket, { - reconnectionToken: <string>query.reconnectionToken, - reconnection: query.reconnection === 'true', - skipWebSocketFrames: query.skipWebSocketFrames === 'true', - permessageDeflate, - }); - try { - await this.connect(await protocol.handshake(), protocol); - } catch (error) { - protocol.destroy(error.message); - } - return true; - } - - private async connect(message: ConnectionTypeRequest, protocol: Protocol): Promise<void> { - if (product.commit && message.commit !== product.commit) { - logger.warn(`Version mismatch (${message.commit} instead of ${product.commit})`); - } - - switch (message.desiredConnectionType) { - case ConnectionType.ExtensionHost: - case ConnectionType.Management: - // Initialize connection map for this type of connection. - if (!this.connections.has(message.desiredConnectionType)) { - this.connections.set(message.desiredConnectionType, new Map()); - } - const connections = this.connections.get(message.desiredConnectionType)!; - - const token = protocol.options.reconnectionToken; - let connection = connections.get(token); - if (protocol.options.reconnection && connection) { - return connection.reconnect(protocol); - } - - // This probably means the process restarted so the session was lost - // while the browser remained open. - if (protocol.options.reconnection) { - throw new Error(`Unable to reconnect; session no longer exists (${token})`); - } - - // This will probably never happen outside a chance collision. - if (connection) { - throw new Error('Unable to connect; token is already in use'); - } - - // Now that the initial exchange has completed we can create the actual - // connection on top of the protocol then send it to whatever uses it. - if (message.desiredConnectionType === ConnectionType.Management) { - // The management connection is used by firing onDidClientConnect - // which makes the IPC server become aware of the connection. - connection = new ManagementConnection(protocol); - this._onDidClientConnect.fire({ - protocol, - onDidClientDisconnect: connection.onClose, - }); - } else { - // The extension host connection is used by spawning an extension host - // and passing the socket into it. - connection = new ExtensionHostConnection( - protocol, - { - language: 'en', - ...message.args, - }, - this.services.get(IEnvironmentService) as INativeEnvironmentService, - ); - } - connections.set(token, connection); - connection.onClose(() => connections.delete(token)); - - this.disposeOldOfflineConnections(connections); - logger.debug(`${connections.size} active ${connection.name} connection(s)`); - break; - case ConnectionType.Tunnel: - return protocol.tunnel(); - default: - throw new Error(`Unrecognized connection type ${message.desiredConnectionType}`); - } - } - - private disposeOldOfflineConnections(connections: Map<string, Connection>): void { - const offline = Array.from(connections.values()) - .filter((connection) => typeof connection.offline !== 'undefined'); - for (let i = 0, max = offline.length - this.maxExtraOfflineConnections; i < max; ++i) { - offline[i].dispose('old'); - } - } - - // References: - // ../../electron-browser/sharedProcess/sharedProcessMain.ts#L148 - // ../../../code/electron-main/app.ts - private async initializeServices(args: NativeParsedArgs): Promise<void> { - const productService = { _serviceBrand: undefined, ...product }; - const environmentService = new NativeEnvironmentService(args, productService); - // https://github.com/cdr/code-server/issues/1693 - fs.mkdirSync(environmentService.globalStorageHome.fsPath, { recursive: true }); - const logService = new MultiplexLogService([ - new ConsoleLogger(getLogLevel(environmentService)), - new SpdLogLogger(RemoteExtensionLogFileName, path.join(environmentService.logsPath, `${RemoteExtensionLogFileName}.log`), false, getLogLevel(environmentService)) - ]); - const fileService = new FileService(logService); - fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(logService)); - - const loggerService = new LoggerService(logService, fileService); - - const piiPaths = [ - path.join(environmentService.userDataPath, 'clp'), // Language packs. - environmentService.appRoot, - environmentService.extensionsPath, - environmentService.builtinExtensionsPath, - ...environmentService.extraExtensionPaths, - ...environmentService.extraBuiltinExtensionPaths, - ]; - - this.ipc.registerChannel('logger', new LogLevelChannel(logService)); - this.ipc.registerChannel(ExtensionHostDebugBroadcastChannel.ChannelName, new ExtensionHostDebugBroadcastChannel()); - - this.services.set(ILogService, logService); - this.services.set(IEnvironmentService, environmentService); - this.services.set(INativeEnvironmentService, environmentService); - this.services.set(ILoggerService, loggerService); - - const configurationService = new ConfigurationService(environmentService.settingsResource, fileService); - await configurationService.initialize(); - this.services.set(IConfigurationService, configurationService); - - this.services.set(IRequestService, new SyncDescriptor(RequestService)); - this.services.set(IFileService, fileService); - this.services.set(IProductService, productService); - - const machineId = await getMachineId(); - - await new Promise((resolve) => { - const instantiationService = new InstantiationService(this.services); - - instantiationService.invokeFunction((accessor) => { - instantiationService.createInstance(LogsDataCleaner); - - let telemetryService: ITelemetryService; - if (!environmentService.disableTelemetry) { - telemetryService = new TelemetryService({ - appender: combinedAppender( - new AppInsightsAppender('code-server', null, () => new TelemetryClient() as any), - new TelemetryLogAppender(accessor.get(ILoggerService), environmentService) - ), - sendErrorTelemetry: true, - commonProperties: resolveCommonProperties( - fileService, release(), hostname(), process.arch, commit, product.version, machineId, - undefined, environmentService.installSourcePath, 'code-server', - ), - piiPaths, - }, configurationService); - } else { - telemetryService = NullTelemetryService; - } - - this.services.set(ITelemetryService, telemetryService); - - this.services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); - this.services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); - this.services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService)); - - this.ipc.registerChannel('extensions', new ExtensionManagementChannel( - accessor.get(IExtensionManagementService), - (context) => getUriTransformer(context.remoteAuthority), - )); - this.ipc.registerChannel('remoteextensionsenvironment', new ExtensionEnvironmentChannel( - environmentService, logService, telemetryService, '', - )); - this.ipc.registerChannel('request', new RequestChannel(accessor.get(IRequestService))); - this.ipc.registerChannel('telemetry', new TelemetryChannel(telemetryService)); - this.ipc.registerChannel('localizations', <IServerChannel<any>>ProxyChannel.fromService(accessor.get(ILocalizationsService))); - this.ipc.registerChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME, new FileProviderChannel(environmentService, logService)); - this.ipc.registerChannel(REMOTE_TERMINAL_CHANNEL_NAME, new TerminalProviderChannel(logService)); - resolve(new ErrorTelemetry(telemetryService)); - }); - }); - } -} diff --git a/lib/vscode/src/vs/server/node/util.ts b/lib/vscode/src/vs/server/node/util.ts deleted file mode 100644 index d76f655e3664..000000000000 --- a/lib/vscode/src/vs/server/node/util.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { URITransformer } from 'vs/base/common/uriIpc'; - -export const getUriTransformer = (remoteAuthority: string): URITransformer => { - return new URITransformer(remoteAuthority); -}; - -/** - * Encode a path for opening via the folder or workspace query parameter. This - * preserves slashes so it can be edited by hand more easily. - */ -export const encodePath = (path: string): string => { - return path.split('/').map((p) => encodeURIComponent(p)).join('/'); -}; diff --git a/lib/vscode/src/vs/workbench/api/common/extHostNotebookKernels.ts b/lib/vscode/src/vs/workbench/api/common/extHostNotebookKernels.ts deleted file mode 100644 index add0d63d6666..000000000000 --- a/lib/vscode/src/vs/workbench/api/common/extHostNotebookKernels.ts +++ /dev/null @@ -1,259 +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 { Emitter } from 'vs/base/common/event'; -import { DisposableStore } from 'vs/base/common/lifecycle'; -import { ExtHostNotebookKernelsShape, IMainContext, INotebookKernelDto2, MainContext, MainThreadNotebookKernelsShape } from 'vs/workbench/api/common/extHost.protocol'; -import * as vscode from 'vscode'; -import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook'; -import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { URI, UriComponents } from 'vs/base/common/uri'; -import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters'; -import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; -import { asWebviewUri } from 'vs/workbench/api/common/shared/webview'; - -interface IKernelData { - extensionId: ExtensionIdentifier, - controller: vscode.NotebookController; - onDidChangeSelection: Emitter<{ selected: boolean; notebook: vscode.NotebookDocument; }>; - onDidReceiveMessage: Emitter<{ editor: vscode.NotebookEditor, message: any }>; -} - -export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape { - - private readonly _proxy: MainThreadNotebookKernelsShape; - - private readonly _kernelData = new Map<number, IKernelData>(); - private _handlePool: number = 0; - - constructor( - mainContext: IMainContext, - private readonly _initData: IExtHostInitDataService, - private readonly _extHostNotebook: ExtHostNotebookController - ) { - this._proxy = mainContext.getProxy(MainContext.MainThreadNotebookKernels); - } - - createNotebookController(extension: IExtensionDescription, id: string, viewType: string, label: string, handler?: vscode.NotebookExecuteHandler, preloads?: vscode.NotebookKernelPreload[]): vscode.NotebookController { - - for (let data of this._kernelData.values()) { - if (data.controller.id === id && ExtensionIdentifier.equals(extension.identifier, data.extensionId)) { - throw new Error(`notebook controller with id '${id}' ALREADY exist`); - } - } - - const handle = this._handlePool++; - const that = this; - - const _defaultExecutHandler = () => console.warn(`NO execute handler from notebook controller '${data.id}' of extension: '${extension.identifier}'`); - - let isDisposed = false; - const commandDisposables = new DisposableStore(); - - const onDidChangeSelection = new Emitter<{ selected: boolean, notebook: vscode.NotebookDocument }>(); - const onDidReceiveMessage = new Emitter<{ editor: vscode.NotebookEditor, message: any }>(); - - const data: INotebookKernelDto2 = { - id: `${extension.identifier.value}/${id}`, - viewType, - extensionId: extension.identifier, - extensionLocation: extension.extensionLocation, - label: label || extension.identifier.value, - preloads: preloads ? preloads.map(extHostTypeConverters.NotebookKernelPreload.from) : [] - }; - - // - let _executeHandler: vscode.NotebookExecuteHandler = handler ?? _defaultExecutHandler; - let _interruptHandler: vscode.NotebookInterruptHandler | undefined; - - // todo@jrieken the selector needs to be massaged - this._proxy.$addKernel(handle, data).catch(err => { - // this can happen when a kernel with that ID is already registered - console.log(err); - isDisposed = true; - }); - - // update: all setters write directly into the dto object - // and trigger an update. the actual update will only happen - // once per event loop execution - let tokenPool = 0; - const _update = () => { - if (isDisposed) { - return; - } - const myToken = ++tokenPool; - Promise.resolve().then(() => { - if (myToken === tokenPool) { - this._proxy.$updateKernel(handle, data); - } - }); - }; - - const controller: vscode.NotebookController = { - get id() { return id; }, - get viewType() { return data.viewType; }, - onDidChangeNotebookAssociation: onDidChangeSelection.event, - get label() { - return data.label; - }, - set label(value) { - data.label = value ?? extension.displayName ?? extension.name; - _update(); - }, - get detail() { - return data.detail ?? ''; - }, - set detail(value) { - data.detail = value; - _update(); - }, - get description() { - return data.description ?? ''; - }, - set description(value) { - data.description = value; - _update(); - }, - get supportedLanguages() { - return data.supportedLanguages; - }, - set supportedLanguages(value) { - data.supportedLanguages = value; - _update(); - }, - get hasExecutionOrder() { - return data.hasExecutionOrder ?? false; - }, - set hasExecutionOrder(value) { - data.hasExecutionOrder = value; - _update(); - }, - get preloads() { - return data.preloads ? data.preloads.map(extHostTypeConverters.NotebookKernelPreload.to) : []; - }, - get executeHandler() { - return _executeHandler; - }, - set executeHandler(value) { - _executeHandler = value ?? _defaultExecutHandler; - }, - get interruptHandler() { - return _interruptHandler; - }, - set interruptHandler(value) { - _interruptHandler = value; - data.supportsInterrupt = Boolean(value); - _update(); - }, - createNotebookCellExecutionTask(cell) { - if (isDisposed) { - throw new Error('notebook controller is DISPOSED'); - } - //todo@jrieken - return that._extHostNotebook.createNotebookCellExecution(cell.notebook.uri, cell.index, data.id)!; - }, - dispose: () => { - if (!isDisposed) { - isDisposed = true; - this._kernelData.delete(handle); - commandDisposables.dispose(); - onDidChangeSelection.dispose(); - onDidReceiveMessage.dispose(); - this._proxy.$removeKernel(handle); - } - }, - // --- ipc - onDidReceiveMessage: onDidReceiveMessage.event, - postMessage(message, editor) { - return that._proxy.$postMessage(handle, editor && that._extHostNotebook.getIdByEditor(editor), message); - }, - asWebviewUri(uri: URI) { - return asWebviewUri(that._initData.environment, String(handle), uri); - }, - // --- priority - updateNotebookAffinity(notebook, priority) { - that._proxy.$updateNotebookPriority(handle, notebook.uri, priority); - } - }; - - this._kernelData.set(handle, { extensionId: extension.identifier, controller, onDidChangeSelection, onDidReceiveMessage }); - return controller; - } - - $acceptSelection(handle: number, uri: UriComponents, value: boolean): void { - const obj = this._kernelData.get(handle); - if (obj) { - obj.onDidChangeSelection.fire({ - selected: value, - notebook: this._extHostNotebook.lookupNotebookDocument(URI.revive(uri))!.apiNotebook - }); - } - } - - async $executeCells(handle: number, uri: UriComponents, handles: number[]): Promise<void> { - const obj = this._kernelData.get(handle); - if (!obj) { - // extension can dispose kernels in the meantime - return; - } - const document = this._extHostNotebook.lookupNotebookDocument(URI.revive(uri)); - if (!document) { - throw new Error('MISSING notebook'); - } - - const cells: vscode.NotebookCell[] = []; - for (let cellHandle of handles) { - const cell = document.getCell(cellHandle); - if (cell) { - cells.push(cell.apiCell); - } - } - - try { - await obj.controller.executeHandler.call(obj.controller, cells, document.apiNotebook, obj.controller); - } catch (err) { - // - console.error(err); - } - } - - async $cancelCells(handle: number, uri: UriComponents, handles: number[]): Promise<void> { - const obj = this._kernelData.get(handle); - if (!obj) { - // extension can dispose kernels in the meantime - return; - } - const document = this._extHostNotebook.lookupNotebookDocument(URI.revive(uri)); - if (!document) { - throw new Error('MISSING notebook'); - } - if (obj.controller.interruptHandler) { - await obj.controller.interruptHandler.call(obj.controller, document.apiNotebook); - } - - // we do both? interrupt and cancellation or should we be selective? - for (let cellHandle of handles) { - const cell = document.getCell(cellHandle); - if (cell) { - this._extHostNotebook.cancelOneNotebookCellExecution(cell); - } - } - } - - $acceptRendererMessage(handle: number, editorId: string, message: any): void { - const obj = this._kernelData.get(handle); - if (!obj) { - // extension can dispose kernels in the meantime - return; - } - - const editor = this._extHostNotebook.getEditorById(editorId); - if (!editor) { - throw new Error(`send message for UNKNOWN editor: ${editorId}`); - } - - obj.onDidReceiveMessage.fire(Object.freeze({ editor: editor.apiEditor, message })); - } -} diff --git a/lib/vscode/src/vs/workbench/api/common/shared/webview.ts b/lib/vscode/src/vs/workbench/api/common/shared/webview.ts deleted file mode 100644 index 851a56985db2..000000000000 --- a/lib/vscode/src/vs/workbench/api/common/shared/webview.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 { URI } from 'vs/base/common/uri'; -import type * as vscode from 'vscode'; - -export interface WebviewInitData { - readonly isExtensionDevelopmentDebug: boolean; - readonly webviewResourceRoot: string; - readonly webviewCspSource: string; -} - -export function asWebviewUri( - initData: WebviewInitData, - uuid: string, - resource: vscode.Uri, -): vscode.Uri { - const uri = initData.webviewResourceRoot - // Make sure we preserve the scheme of the resource but convert it into a normal path segment - // The scheme is important as we need to know if we are requesting a local or a remote resource. - .replace('{{resource}}', resource.scheme + withoutScheme(resource)) - .replace('{{uuid}}', uuid); - return URI.parse(uri); -} - -function withoutScheme(resource: vscode.Uri): string { - return resource.toString().replace(/^\S+?:/, ''); -} diff --git a/lib/vscode/src/vs/workbench/api/node/extHostTerminalService.ts b/lib/vscode/src/vs/workbench/api/node/extHostTerminalService.ts deleted file mode 100644 index 872181891471..000000000000 --- a/lib/vscode/src/vs/workbench/api/node/extHostTerminalService.ts +++ /dev/null @@ -1,145 +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 platform from 'vs/base/common/platform'; -import { withNullAsUndefined } from 'vs/base/common/types'; -import { generateUuid } from 'vs/base/common/uuid'; -import { getSystemShell, getSystemShellSync } from 'vs/base/node/shell'; -import { ILogService } from 'vs/platform/log/common/log'; -import { SafeConfigProvider } from 'vs/platform/terminal/common/terminal'; -import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { IShellAndArgsDto } from 'vs/workbench/api/common/extHost.protocol'; -import { ExtHostConfigProvider, ExtHostConfiguration, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration'; -import { ExtHostVariableResolverService } from 'vs/workbench/api/common/extHostDebugService'; -import { ExtHostDocumentsAndEditors, IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; -import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; -import { BaseExtHostTerminalService, ExtHostTerminal } from 'vs/workbench/api/common/extHostTerminalService'; -import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; -import { ITerminalProfile } from 'vs/workbench/contrib/terminal/common/terminal'; -import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; -import { detectAvailableProfiles } from 'vs/workbench/contrib/terminal/node/terminalProfiles'; -import type * as vscode from 'vscode'; - -export class ExtHostTerminalService extends BaseExtHostTerminalService { - - private _variableResolver: ExtHostVariableResolverService | undefined; - private _variableResolverPromise: Promise<ExtHostVariableResolverService>; - private _lastActiveWorkspace: IWorkspaceFolder | undefined; - - private _defaultShell: string | undefined; - - constructor( - @IExtHostRpcService extHostRpc: IExtHostRpcService, - @IExtHostConfiguration private _extHostConfiguration: ExtHostConfiguration, - @IExtHostWorkspace private _extHostWorkspace: ExtHostWorkspace, - @IExtHostDocumentsAndEditors private _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors, - @ILogService private _logService: ILogService - ) { - super(true, extHostRpc); - - // Getting the SystemShell is an async operation, however, the ExtHost terminal service is mostly synchronous - // and the API `vscode.env.shell` is also synchronous. The default shell _should_ be set when extensions are - // starting up but if not, we run getSystemShellSync below which gets a sane default. - getSystemShell(platform.OS, process.env as platform.IProcessEnvironment).then(s => this._defaultShell = s); - - this._updateLastActiveWorkspace(); - this._variableResolverPromise = this._updateVariableResolver(); - this._registerListeners(); - } - - public createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal { - const terminal = new ExtHostTerminal(this._proxy, generateUuid(), { name, shellPath, shellArgs }, name); - this._terminals.push(terminal); - terminal.create(shellPath, shellArgs); - return terminal.value; - } - - public createTerminalFromOptions(options: vscode.TerminalOptions, isFeatureTerminal?: boolean): vscode.Terminal { - const terminal = new ExtHostTerminal(this._proxy, generateUuid(), options, options.name); - this._terminals.push(terminal); - terminal.create( - withNullAsUndefined(options.shellPath), - withNullAsUndefined(options.shellArgs), - withNullAsUndefined(options.cwd), - withNullAsUndefined(options.env), - withNullAsUndefined(options.icon), - withNullAsUndefined(options.message), - /*options.waitOnExit*/ undefined, - withNullAsUndefined(options.strictEnv), - withNullAsUndefined(options.hideFromUser), - withNullAsUndefined(isFeatureTerminal), - true - ); - return terminal.value; - } - - public getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string { - return terminalEnvironment.getDefaultShell( - this._buildSafeConfigProvider(configProvider), - this._defaultShell ?? getSystemShellSync(platform.OS, process.env as platform.IProcessEnvironment), - process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'), - process.env.windir, - terminalEnvironment.createVariableResolver(this._lastActiveWorkspace, process.env, this._variableResolver), - this._logService, - useAutomationShell - ); - } - - public getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string { - return terminalEnvironment.getDefaultShellArgs( - this._buildSafeConfigProvider(configProvider), - useAutomationShell, - terminalEnvironment.createVariableResolver(this._lastActiveWorkspace, process.env, this._variableResolver), - this._logService - ); - } - - private _registerListeners(): void { - this._extHostDocumentsAndEditors.onDidChangeActiveTextEditor(() => this._updateLastActiveWorkspace()); - this._extHostWorkspace.onDidChangeWorkspace(() => { - this._variableResolverPromise = this._updateVariableResolver(); - }); - } - - private _updateLastActiveWorkspace(): void { - const activeEditor = this._extHostDocumentsAndEditors.activeEditor(); - if (activeEditor) { - this._lastActiveWorkspace = this._extHostWorkspace.getWorkspaceFolder(activeEditor.document.uri) as IWorkspaceFolder; - } - } - - private async _updateVariableResolver(): Promise<ExtHostVariableResolverService> { - const configProvider = await this._extHostConfiguration.getConfigProvider(); - const workspaceFolders = await this._extHostWorkspace.getWorkspaceFolders2(); - this._variableResolver = new ExtHostVariableResolverService(workspaceFolders || [], this._extHostDocumentsAndEditors, configProvider); - return this._variableResolver; - } - - public async $getAvailableProfiles(configuredProfilesOnly: boolean): Promise<ITerminalProfile[]> { - const safeConfigProvider = this._buildSafeConfigProvider(await this._extHostConfiguration.getConfigProvider()); - return detectAvailableProfiles(configuredProfilesOnly, safeConfigProvider, undefined, this._logService, await this._variableResolverPromise, this._lastActiveWorkspace); - } - - public async $getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto> { - const configProvider = await this._extHostConfiguration.getConfigProvider(); - return { - shell: this.getDefaultShell(useAutomationShell, configProvider), - args: this.getDefaultShellArgs(useAutomationShell, configProvider) - }; - } - - // TODO: Remove when workspace trust is enabled - private _buildSafeConfigProvider(configProvider: ExtHostConfigProvider): SafeConfigProvider { - const config = configProvider.getConfiguration(); - return (key: string) => { - const isWorkspaceConfigAllowed = config.get('terminal.integrated.allowWorkspaceConfiguration'); - if (isWorkspaceConfigAllowed) { - return config.get(key) as any; - } - const inspected = config.inspect(key); - return inspected?.globalValue || inspected?.defaultValue; - }; - } -} diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/media/back-tb.png b/lib/vscode/src/vs/workbench/browser/parts/editor/media/back-tb.png deleted file mode 100644 index c9d6f935ae4b37dc1dca6f5c14540e0916c715e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 266 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{(Mgt$B+ufw>J)QHakeTJoMD^;9Rz8$>b@M zgf4k{UGV#J*VR?<yT+>@b`l?cO|X6A1=Pd9Ami@xWbdVanf#X0N%svu_QrL}{(Z7S zAbNRdk@1|!q^E5WNxULS(n;t0fD9SSZ|idJl$c(O=ejj@{~w>ps*5_+Zh0&2QoF@_ z(Iwt^*QCWW<Q_f0`17}Nc=wAv>+hUh^f#FiWKH#J1{t|Gx|4mhJV9JfS3j3^P6<r_ DHIZQ4 diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/media/forward-tb.png b/lib/vscode/src/vs/workbench/browser/parts/editor/media/forward-tb.png deleted file mode 100644 index 69c52268ab8035d106013488bd08cff7e8682733..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 258 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{&Y_l$B+ufw>LNP9&+GuxF{@az?5^~$p*$8 z24w?AgF_EB7A{!e6Y%D{3jc?vlh+kw1N9ipzxUhhnNV@YP2Y{%?W&gc_Z<lSKh4_e zQJG=+#YMtGy1U}O1ecgCa(&)+PhWCxrjD}NkL=z3CH_%sZm=9V_vi1Q-iVEyQ@Uh< y$mPaHpEnEomru*?ywR`uD@I9-fuUh*C38&d%^lOL6YYW4F?hQAxvX<aXaWE=vR=Xf diff --git a/lib/vscode/src/vs/workbench/common/editor/resourceEditorInput.ts b/lib/vscode/src/vs/workbench/common/editor/resourceEditorInput.ts deleted file mode 100644 index e897355fbea3..000000000000 --- a/lib/vscode/src/vs/workbench/common/editor/resourceEditorInput.ts +++ /dev/null @@ -1,134 +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 { URI } from 'vs/base/common/uri'; -import { IReference } from 'vs/base/common/lifecycle'; -import { ITextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; -import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel'; -import { IModeSupport, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { IFileService } from 'vs/platform/files/common/files'; -import { ILabelService } from 'vs/platform/label/common/label'; -import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; -import { AbstractTextResourceEditorInput } from 'vs/workbench/common/editor/textResourceEditorInput'; -import { isEqual } from 'vs/base/common/resources'; - -/** - * A read-only text editor input whos contents are made of the provided resource that points to an existing - * code editor model. - */ -export class ResourceEditorInput extends AbstractTextResourceEditorInput implements IModeSupport { - - static readonly ID: string = 'workbench.editors.resourceEditorInput'; - - override get typeId(): string { - return ResourceEditorInput.ID; - } - - private cachedModel: ResourceEditorModel | undefined = undefined; - private modelReference: Promise<IReference<ITextEditorModel>> | undefined = undefined; - - constructor( - resource: URI, - private name: string | undefined, - private description: string | undefined, - private preferredMode: string | undefined, - @ITextModelService private readonly textModelResolverService: ITextModelService, - @ITextFileService textFileService: ITextFileService, - @IEditorService editorService: IEditorService, - @IEditorGroupsService editorGroupService: IEditorGroupsService, - @IFileService fileService: IFileService, - @ILabelService labelService: ILabelService, - @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService - ) { - super(resource, undefined, editorService, editorGroupService, textFileService, labelService, fileService, filesConfigurationService); - } - - override getName(): string { - return this.name || super.getName(); - } - - setName(name: string): void { - if (this.name !== name) { - this.name = name; - - this._onDidChangeLabel.fire(); - } - } - - override getDescription(): string | undefined { - return this.description; - } - - setDescription(description: string): void { - if (this.description !== description) { - this.description = description; - - this._onDidChangeLabel.fire(); - } - } - - setMode(mode: string): void { - this.setPreferredMode(mode); - - if (this.cachedModel) { - this.cachedModel.setMode(mode); - } - } - - setPreferredMode(mode: string): void { - this.preferredMode = mode; - } - - override async resolve(): Promise<ITextEditorModel> { - if (!this.modelReference) { - this.modelReference = this.textModelResolverService.createModelReference(this.resource); - } - - const ref = await this.modelReference; - - // Ensure the resolved model is of expected type - const model = ref.object; - if (!(model instanceof ResourceEditorModel)) { - ref.dispose(); - this.modelReference = undefined; - - throw new Error(`Unexpected model for ResourceEditorInput: ${this.resource}`); - } - - this.cachedModel = model; - - // Set mode if we have a preferred mode configured - if (this.preferredMode) { - model.setMode(this.preferredMode); - } - - return model; - } - - override matches(otherInput: unknown): boolean { - if (otherInput === this) { - return true; - } - - if (otherInput instanceof ResourceEditorInput) { - return isEqual(otherInput.resource, this.resource); - } - - return false; - } - - override dispose(): void { - if (this.modelReference) { - this.modelReference.then(ref => ref.dispose()); - this.modelReference = undefined; - } - - this.cachedModel = undefined; - - super.dispose(); - } -} diff --git a/lib/vscode/src/vs/workbench/contrib/cli/node/cli.contribution.ts b/lib/vscode/src/vs/workbench/contrib/cli/node/cli.contribution.ts deleted file mode 100644 index dcc7623b08ac..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/cli/node/cli.contribution.ts +++ /dev/null @@ -1,193 +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 fs from 'fs'; -import * as cp from 'child_process'; -import * as nls from 'vs/nls'; -import * as path from 'vs/base/common/path'; -import * as pfs from 'vs/base/node/pfs'; -import * as extpath from 'vs/base/node/extpath'; -import { promisify } from 'util'; -import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; -import product from 'vs/platform/product/common/product'; -import { INotificationService } from 'vs/platform/notification/common/notification'; -import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import Severity from 'vs/base/common/severity'; -import { ILogService } from 'vs/platform/log/common/log'; -import { FileAccess } from 'vs/base/common/network'; -import { IProductService } from 'vs/platform/product/common/productService'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { IsMacNativeContext } from 'vs/platform/contextkey/common/contextkeys'; -import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; - -function ignore<T>(code: string, value: T): (err: any) => Promise<T> { - return err => err.code === code ? Promise.resolve<T>(value) : Promise.reject<T>(err); -} - -let _source: string | null = null; -function getSource(): string { - if (!_source) { - const root = FileAccess.asFileUri('', require).fsPath; - _source = path.resolve(root, '..', 'bin', 'code'); - } - return _source; -} - -function isAvailable(): Promise<boolean> { - return Promise.resolve(pfs.exists(getSource())); -} - -const category = nls.localize('shellCommand', "Shell Command"); - -class InstallAction extends Action2 { - - constructor() { - super({ - id: 'workbench.action.installCommandLine', - title: { - value: nls.localize('install', "Install '{0}' command in PATH", product.applicationName), - original: `Shell Command: Install \'${product.applicationName}\' command in PATH` - }, - category, - f1: true, - precondition: ContextKeyExpr.and(IsMacNativeContext, ContextKeyExpr.equals('remoteName', '')) - }); - } - - run(accessor: ServicesAccessor): Promise<void> { - const productService = accessor.get(IProductService); - const notificationService = accessor.get(INotificationService); - const logService = accessor.get(ILogService); - const dialogService = accessor.get(IDialogService); - const target = `/usr/local/bin/${productService.applicationName}`; - - return isAvailable().then(isAvailable => { - if (!isAvailable) { - const message = nls.localize('not available', "This command is not available"); - notificationService.info(message); - return undefined; - } - - return this.isInstalled(target) - .then(isInstalled => { - if (!isAvailable || isInstalled) { - return Promise.resolve(null); - } else { - return fs.promises.unlink(target) - .then(undefined, ignore('ENOENT', null)) - .then(() => fs.promises.symlink(getSource(), target)) - .then(undefined, err => { - if (err.code === 'EACCES' || err.code === 'ENOENT') { - return new Promise<void>((resolve, reject) => { - const buttons = [nls.localize('ok', "OK"), nls.localize('cancel2', "Cancel")]; - - dialogService.show(Severity.Info, nls.localize('warnEscalation', "Code will now prompt with 'osascript' for Administrator privileges to install the shell command."), buttons, { cancelId: 1 }).then(result => { - switch (result.choice) { - case 0 /* OK */: - const command = 'osascript -e "do shell script \\"mkdir -p /usr/local/bin && ln -sf \'' + getSource() + '\' \'' + target + '\'\\" with administrator privileges"'; - - promisify(cp.exec)(command, {}) - .then(undefined, _ => Promise.reject(new Error(nls.localize('cantCreateBinFolder', "Unable to create '/usr/local/bin'.")))) - .then(() => resolve(), reject); - break; - case 1 /* Cancel */: - reject(new Error(nls.localize('aborted', "Aborted"))); - break; - } - }); - }); - } - - return Promise.reject(err); - }); - } - }) - .then(() => { - logService.trace('cli#install', target); - notificationService.info(nls.localize('successIn', "Shell command '{0}' successfully installed in PATH.", productService.applicationName)); - }); - }); - } - - private async isInstalled(target: string): Promise<boolean> { - try { - const stat = await fs.promises.lstat(target); - return stat.isSymbolicLink() && getSource() === await extpath.realpath(target); - } catch (err) { - if (err.code === 'ENOENT') { - return false; - } - - throw err; - } - } -} - -class UninstallAction extends Action2 { - - constructor() { - super({ - id: 'workbench.action.uninstallCommandLine', - title: { - value: nls.localize('uninstall', "Uninstall '{0}' command from PATH", product.applicationName), - original: `Shell Command: Uninstall \'${product.applicationName}\' command from PATH` - }, - category, - f1: true, - precondition: ContextKeyExpr.and(IsMacNativeContext, ContextKeyExpr.equals('remoteName', '')) - }); - } - - run(accessor: ServicesAccessor): Promise<void> { - const productService = accessor.get(IProductService); - const notificationService = accessor.get(INotificationService); - const logService = accessor.get(ILogService); - const dialogService = accessor.get(IDialogService); - const target = `/usr/local/bin/${productService.applicationName}`; - - return isAvailable().then(isAvailable => { - if (!isAvailable) { - const message = nls.localize('not available', "This command is not available"); - notificationService.info(message); - return undefined; - } - - const uninstall = () => { - return fs.promises.unlink(target) - .then(undefined, ignore('ENOENT', null)); - }; - - return uninstall().then(undefined, err => { - if (err.code === 'EACCES') { - return new Promise<void>(async (resolve, reject) => { - const buttons = [nls.localize('ok', "OK"), nls.localize('cancel2', "Cancel")]; - - const { choice } = await dialogService.show(Severity.Info, nls.localize('warnEscalationUninstall', "Code will now prompt with 'osascript' for Administrator privileges to uninstall the shell command."), buttons, { cancelId: 1 }); - switch (choice) { - case 0 /* OK */: - const command = 'osascript -e "do shell script \\"rm \'' + target + '\'\\" with administrator privileges"'; - - promisify(cp.exec)(command, {}) - .then(undefined, _ => Promise.reject(new Error(nls.localize('cantUninstall', "Unable to uninstall the shell command '{0}'.", target)))) - .then(() => resolve(), reject); - break; - case 1 /* Cancel */: - reject(new Error(nls.localize('aborted', "Aborted"))); - break; - } - }); - } - - return Promise.reject(err); - }).then(() => { - logService.trace('cli#uninstall', target); - notificationService.info(nls.localize('successFrom', "Shell command '{0}' successfully uninstalled from PATH.", productService.applicationName)); - }); - }); - } -} - -registerAction2(InstallAction); -registerAction2(UninstallAction); diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts b/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts deleted file mode 100644 index f5e0bb1571f6..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts +++ /dev/null @@ -1,56 +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 { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { CATEGORIES, Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { Action } from 'vs/base/common/actions'; - -class InspectKeyMap extends EditorAction { - - constructor() { - super({ - id: 'workbench.action.inspectKeyMappings', - label: nls.localize('workbench.action.inspectKeyMap', "Developer: Inspect Key Mappings"), - alias: 'Developer: Inspect Key Mappings', - precondition: undefined - }); - } - - public run(accessor: ServicesAccessor, editor: ICodeEditor): void { - const keybindingService = accessor.get(IKeybindingService); - const editorService = accessor.get(IEditorService); - - editorService.openEditor({ contents: keybindingService._dumpDebugInfo(), options: { pinned: true } }); - } -} - -registerEditorAction(InspectKeyMap); - -class InspectKeyMapJSON extends Action { - public static readonly ID = 'workbench.action.inspectKeyMappingsJSON'; - public static readonly LABEL = nls.localize('workbench.action.inspectKeyMapJSON', "Inspect Key Mappings (JSON)"); - - constructor( - id: string, - label: string, - @IKeybindingService private readonly _keybindingService: IKeybindingService, - @IEditorService private readonly _editorService: IEditorService - ) { - super(id, label); - } - - public override run(): Promise<any> { - return this._editorService.openEditor({ contents: this._keybindingService._dumpDebugInfoJSON(), options: { pinned: true } }); - } -} - -const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(SyncActionDescriptor.from(InspectKeyMapJSON), 'Developer: Inspect Key Mappings (JSON)', CATEGORIES.Developer.value); diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts b/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts deleted file mode 100644 index 1da1c3be2d58..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts +++ /dev/null @@ -1,43 +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 { Action } from 'vs/base/common/actions'; -import { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { CATEGORIES, Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; - -export class ToggleMinimapAction extends Action { - public static readonly ID = 'editor.action.toggleMinimap'; - public static readonly LABEL = nls.localize('toggleMinimap', "Toggle Minimap"); - - constructor( - id: string, - label: string, - @IConfigurationService private readonly _configurationService: IConfigurationService - ) { - super(id, label); - } - - public override run(): Promise<any> { - const newValue = !this._configurationService.getValue<boolean>('editor.minimap.enabled'); - return this._configurationService.updateValue('editor.minimap.enabled', newValue); - } -} - -const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleMinimapAction), 'View: Toggle Minimap', CATEGORIES.View.value); - -MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { - group: '5_editor', - command: { - id: ToggleMinimapAction.ID, - title: nls.localize({ key: 'miShowMinimap', comment: ['&& denotes a mnemonic'] }, "Show &&Minimap"), - toggled: ContextKeyExpr.equals('config.editor.minimap.enabled', true) - }, - order: 2 -}); diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts b/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts deleted file mode 100644 index ecf2968c5c19..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts +++ /dev/null @@ -1,44 +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 { Action } from 'vs/base/common/actions'; -import { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { CATEGORIES, Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; - -export class ToggleRenderControlCharacterAction extends Action { - - public static readonly ID = 'editor.action.toggleRenderControlCharacter'; - public static readonly LABEL = nls.localize('toggleRenderControlCharacters', "Toggle Control Characters"); - - constructor( - id: string, - label: string, - @IConfigurationService private readonly _configurationService: IConfigurationService - ) { - super(id, label); - } - - public override run(): Promise<any> { - let newRenderControlCharacters = !this._configurationService.getValue<boolean>('editor.renderControlCharacters'); - return this._configurationService.updateValue('editor.renderControlCharacters', newRenderControlCharacters); - } -} - -const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleRenderControlCharacterAction), 'View: Toggle Control Characters', CATEGORIES.View.value); - -MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { - group: '5_editor', - command: { - id: ToggleRenderControlCharacterAction.ID, - title: nls.localize({ key: 'miToggleRenderControlCharacters', comment: ['&& denotes a mnemonic'] }, "Render &&Control Characters"), - toggled: ContextKeyExpr.equals('config.editor.renderControlCharacters', true) - }, - order: 5 -}); diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts b/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts deleted file mode 100644 index e9835e215b6e..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts +++ /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. - *--------------------------------------------------------------------------------------------*/ - -import * as nls from 'vs/nls'; -import { Action } from 'vs/base/common/actions'; -import { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { CATEGORIES, Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; - -export class ToggleRenderWhitespaceAction extends Action { - - public static readonly ID = 'editor.action.toggleRenderWhitespace'; - public static readonly LABEL = nls.localize('toggleRenderWhitespace', "Toggle Render Whitespace"); - - constructor( - id: string, - label: string, - @IConfigurationService private readonly _configurationService: IConfigurationService - ) { - super(id, label); - } - - public override run(): Promise<any> { - const renderWhitespace = this._configurationService.getValue<string>('editor.renderWhitespace'); - - let newRenderWhitespace: string; - if (renderWhitespace === 'none') { - newRenderWhitespace = 'all'; - } else { - newRenderWhitespace = 'none'; - } - - return this._configurationService.updateValue('editor.renderWhitespace', newRenderWhitespace); - } -} - -const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleRenderWhitespaceAction), 'View: Toggle Render Whitespace', CATEGORIES.View.value); - -MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { - group: '5_editor', - command: { - id: ToggleRenderWhitespaceAction.ID, - title: nls.localize({ key: 'miToggleRenderWhitespace', comment: ['&& denotes a mnemonic'] }, "&&Render Whitespace"), - toggled: ContextKeyExpr.notEquals('config.editor.renderWhitespace', 'none') - }, - order: 4 -}); diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/media/continue-tb.png b/lib/vscode/src/vs/workbench/contrib/debug/browser/media/continue-tb.png deleted file mode 100644 index fe7679985333906d97237f382de06a47f50731e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 339 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{tHhR$B+ufx7YvkIvR=`{TOZ7AUNY78_yAy zBS~fp)DoE8r3DKoeqZeymw#S;=YQ*y<`>nST)<$8Ttn@SnOB(n?e4^6HEfUGu{NST zf1B{}{Chc%ew<Hxl#!-gxaIL#mA-E|Dt+(DG%O3h6uYhLT)bb~%SYyLs_z}oq>tjK z3+(QkvMir?M9s*ryWqG?XMgDj@2)62pVXR1CuV%v)wbmE4d)%HeH$Ye?EkTS%fw3y zc31BZ)~c*HvN5&Zwp1ee*=etA%WZeIZ)SVVnZ04&hBUjxvo(ii{cJJ)%$fa6SWO8G axaD*+=h&7{vbX~DGlQqApUXO@geCyZIETsr diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/media/continue-without-debugging-tb.png b/lib/vscode/src/vs/workbench/contrib/debug/browser/media/continue-without-debugging-tb.png deleted file mode 100644 index f42e02ee0c0b5e1784f33574d88624e922b85598..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 363 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBIR;M`$B+ufx7RQ7HaQ5iJiN@cg?UYYR-kl< z)djwo^E*0I?mj*sahUJ3s*T2;o__+qogHBC;=9X}8U4OdT$L|BU0k9%VSBXQtrkDK zM0LG=d}f83hkfq!<dkaUJ^GvaYuCjkhQiyMzwY(5^PA9F-CX^A&k_EG!tzpUp6@-P zpD4VZ_geOzBkL7~<&Afg=l(geoafr>@`b|xlRm@?$1ndW@s;uHxg*sTlAf<GO#OUe zm-m+W^R^zeDqDT{jqPs#i#)t~Du4cjolg|nw&!2~XLMPCYT_Du{-zHi>kJQn5Zbnc vM>%n|ftY&YX`Z9rH=6t*Xa>X=0yYd$0j+bMG|1frh7E(KtDnm{r-UW|+<ujQ diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/media/pause-tb.png b/lib/vscode/src/vs/workbench/contrib/debug/browser/media/pause-tb.png deleted file mode 100644 index f564b78761f723604eabc4d4f4de6cc38b1357fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBex9d`V@L(#+w-S64+rqLItpI$u=37)sWUfX z+rjAn57w?rchFWmxRQy1p`mcs@9V$+sc(N>!}o4^>ORv0tL5AZtPZ|pSuQ-s4+~@0 ran}9WbMB?(mw!Ee_dd|Bg6lj6%3hx*t4XZ|@)$f_{an^LB{Ts5+Z;=* diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/media/restart-tb.png b/lib/vscode/src/vs/workbench/contrib/debug/browser/media/restart-tb.png deleted file mode 100644 index 619de170ed39bc17b8be7f04da9c7e7c563f2251..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 701 zcmV;u0z&<XP)<h;3K|Lk000e1NJLTq002Ay002A)1^@s6I{evk00009a7bBm000XU z000XU0RWnu7ytkO0drDELIAGL9O(c600d`2O+f$vv5yP<VFdsH0#ZptK~#7F?U?;- z+b|HtpNbBUY#?WVrk$X67icG_+YQ<Y;tASJ(2oh)F3@;_^yB|VnxOUszT814IH5?% z3K@t9?gu;wmdS&jjy#bB48t%C!!QiPFbo3)A|RsjR<NR|aUgBqF?}Y7y3Bjp&ROTI z%F}Pd`o>zaj*u&d80LF#0wzO9+p{c<_ZgNU%etVubH#d!oCq0~2c>41#<F9*LqZ-S zF`AVNmTyRISzlReR;~A>-6`u8Ywom{qWXbjN^v{K)Oa$oq;OGM4#W~I0{tb^b4*RZ zn9DD6K3@Yd3)UA;9GTP87BU*9y30fMm|h{0*o6lTG+ARmSA{Ll#rGJFE0<%|C9Ayg z*M@b%F}9cj8c#JMw&<<XKYA`dLf(8wQ`uW&M7~A@*&60yD;F{Q!}%*}F%tV7USk|J z#vzmWk8`g?1W|@L3k%#oZh?yWH03^rlat)AR#zm%&1j7Xk{DK#vRIHxGh;0hnU;9Z zoqIK=hMKM5XWB0<Hx#)H)R#E(e2334HEOuC42;RLj+m9laETnC?q+|Z8NygJyC<HP z_!GH6&6$-;HP-Zvp<H>g`w}_95A?Cmbf0nB7rti!v!9R~{7^^K>|1@T)Oew~Roz*~ z)Sa^}60<}CqPB-V^uc7V%>qr<XqJn${+4!6&^_L1ksa2Htk18hsoIwmhYaI?luK1U z1RbI~8jtjmdXVp-d<fbvO0Lw%E?`jfUyYWyCz8+MKBzgZI8{mZ+MUpE)?c|!c6?(P jhG7_nVHk#C7!R0htH|O&geMXh00000NkvXXu0mjfu$DCm diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/media/stepinto-tb.png b/lib/vscode/src/vs/workbench/contrib/debug/browser/media/stepinto-tb.png deleted file mode 100644 index f7a4eb230138f2996c22a2af3c37bad926a0961b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 418 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBIde}J$B+ufw>RE)9&!*k_VHwB!F5M1i`;{5 zM}*!eOiN%d6WYKKuN9Evu=YUVwKs=WN%tx!Tie;s;Fmi1$1w7m03*;)Ab64dOgDb^ zghledj5xOO9lWM^!-{49<Qy$6b6NY>&-|B7dl{TplM~?j{{Gu7i*8J<&z~Q<WloM} z@ea<_e>R2`$VgwABK)0u=_28SmtEcjJ)2&1S?I6Nyp0FDFIFCBlU*#Xmc%T-_kY)o z1**5watefVAJ3~j=6-#Chpxv=mt*&9D+5KUmM@fglgw^pJ2NOv*LeEPEVtDU()QbU zuDKvx-#J-R$mCI(baA)%{rA(8)n^)NUZ`RC@Z$Zv-Hrb}8`C~~JZM<X{QktGX{_4& zmUwSEqU%*x=ykNLif4*!-n^DGJ8nkp3fO*IN(kcFhIPi9nx|egYWXe$67Y2Ob6Mw< G&;$T`<*4ug diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/media/stepout-tb.png b/lib/vscode/src/vs/workbench/contrib/debug/browser/media/stepout-tb.png deleted file mode 100644 index b7332b3485c5d307407221bbd156c27be978b89b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 411 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBIRj4@$B+ufw>NI*9&!+9eds)eDTpakA<)Xh zeIZNvgeeZJf|&{djH(G%3{nX<CW@zo?KaczdHS&C(y2|~5B}TOqt74+1{V!nQlyRr zP5+>G?AoOjvF_>{)1{|hY>k+I(RSm$Mfp8n1!Ftzs=nUZ{lY0n^q9@&wNkZPOupY- zy<vx~c#qE){bMSYheNY}@A=@oW%2dIJqbBUUvzFx<LxW9N?Y8c`;u$hhZgq33GXG| z$TqVp7<}QW?l#!A_Nyq5uK`2tqFpivj(ijF`7Y*MI)8qm&&4?}r}{;<-;b^F`#0gw z@Auii*X&mKdw<KHJq9ZTz9^?2|FZT~oKC*?d)eYD#{CByQa|iV|Hr^Q?O?rZ@vr`^ z4dxH6{_4l<zyHB&*88y8601(@3qU-1(~8kEv$T6-6zf-DSTcCJ`njxgN@xNAlclNT diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/media/stepover-tb.png b/lib/vscode/src/vs/workbench/contrib/debug/browser/media/stepover-tb.png deleted file mode 100644 index 8eca81cefb3b3f3812d2753507a3671bc1c6248a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 548 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBxt*Rajv*C{Z)d&@JZ!+zCffIZ3hyD7H3Di4 zoEkn1(g)Z|m|n01h%HEEeDK3xSZu-E1x~wm>=pRr`0Bx|4|e76x0dOscO|)(bpXwV z0Im~?XJpd4J}YoMGkyDYdHNQoH$tBTcRrZ+!pB7H><{axa`ji!Z>;7kGUNWl+q)#= z#Mus4@tt*l%5S)o9D8k?`uRom`wea#w-Xg#{ck&b`-;#UyT0kF?dpprz6jhhXNA+n zeJ}3(IlpM~%ib4rYh32oYIa_U5V?9o@9krz-~1OdXA5p?yUe-jMG`yjuYk8jR>{w2 z{(Sb~!m*n%@r^HLuHIO5L+j&&$=OZ<m#-gDn0O>%y`y|pahXx*LXA~M6aQ_`5H9$5 z!#3-N`<b&Fx;DI>YjtL-=`Q6@64C94V}8!FIsVOd&HF2!%l7z{#JhMlfAe8r_z+*P z_h@j5-`P1QM9&48JYKVGPWU4A#o23(kMC-=SlTE0wq;G3g%$Ji)BATQ+1I@YnR0Yy zN46Ntx<zlYc)r(NP*Y*wQDl+1^6dSCJ(rF0R%RFM`fh6a*z~lt^_->VA9FQ@WP^8Y ksS)LUwa<_d7RU$s{3EUgDm7MBy$1<-y85}Sb4q9e0Qvp#`~Uy| diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/media/stop-tb.png b/lib/vscode/src/vs/workbench/contrib/debug/browser/media/stop-tb.png deleted file mode 100644 index 715c180ccd6d4aa9769770aa09c4e656b2577cf4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 197 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBew3$+V@L(#+nXDC8w?nj9oaYjKh-EH#M!d* zb!^RB7N82FO^NqD?Xf&&u_>eSM`+V+&OG%Ub03spWBk?oab{llxh+6l2j+3B#<SZf S`?5*{c?_PeelF{r5}E*UWj~kz diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionEnablementByWorkspaceTrustRequirement.ts b/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionEnablementByWorkspaceTrustRequirement.ts deleted file mode 100644 index 9cd55e30eb51..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionEnablementByWorkspaceTrustRequirement.ts +++ /dev/null @@ -1,36 +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 { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; -import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; - - -export class ExtensionEnablementByWorkspaceTrustRequirement extends Disposable implements IWorkbenchContribution { - - constructor( - @IWorkspaceTrustManagementService workspaceTrustManagementService: IWorkspaceTrustManagementService, - @IExtensionService private readonly extensionService: IExtensionService, - @IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService, - ) { - super(); - - this._register(workspaceTrustManagementService.onDidChangeTrust(trusted => this.onDidChangeTrustState(trusted))); - } - - private async onDidChangeTrustState(trusted: boolean): Promise<void> { - if (trusted) { - // Untrusted -> Trusted - await this.extensionEnablementService.updateEnablementByWorkspaceTrustRequirement(); - } else { - // Trusted -> Untrusted - this.extensionService.stopExtensionHosts(); - await this.extensionEnablementService.updateEnablementByWorkspaceTrustRequirement(); - this.extensionService.startExtensionHosts(); - } - } -} diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/electron-sandbox/extensionsActions.ts b/lib/vscode/src/vs/workbench/contrib/extensions/electron-sandbox/extensionsActions.ts deleted file mode 100644 index 0ff09d630a05..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/extensions/electron-sandbox/extensionsActions.ts +++ /dev/null @@ -1,45 +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 { 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 { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; -import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; -import { Schemas } from 'vs/base/common/network'; - -export class OpenExtensionsFolderAction extends Action { - - static readonly ID = 'workbench.extensions.action.openExtensionsFolder'; - static readonly LABEL = localize('openExtensionsFolder', "Open Extensions Folder"); - - constructor( - id: string, - label: string, - @INativeHostService private readonly nativeHostService: INativeHostService, - @IFileService private readonly fileService: IFileService, - @INativeWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService - ) { - super(id, label, undefined, true); - } - - override async run(): Promise<void> { - 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.nativeHostService.showItemInFolder(itemToShow.fsPath); - } - } -} - diff --git a/lib/vscode/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts b/lib/vscode/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts deleted file mode 100644 index 2313fe40718d..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts +++ /dev/null @@ -1,50 +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 { Registry } from 'vs/platform/registry/common/platform'; -import * as nls from 'vs/nls'; -import product from 'vs/platform/product/common/product'; -import { SyncActionDescriptor, ICommandAction, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; -import { IWorkbenchActionRegistry, Extensions, CATEGORIES } from 'vs/workbench/common/actions'; -import { ReportPerformanceIssueUsingReporterAction, OpenProcessExplorer } from 'vs/workbench/contrib/issue/electron-sandbox/issueActions'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue'; -import { WorkbenchIssueService } from 'vs/workbench/services/issue/electron-sandbox/issueService'; -import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { IssueReporterData } from 'vs/platform/issue/common/issue'; -import { IIssueService } from 'vs/platform/issue/electron-sandbox/issue'; -import { OpenIssueReporterArgs, OpenIssueReporterActionId } from 'vs/workbench/contrib/issue/common/commands'; - -const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions); - -if (!!product.reportIssueUrl) { - workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(ReportPerformanceIssueUsingReporterAction), 'Help: Report Performance Issue', CATEGORIES.Help.value); - - const OpenIssueReporterActionLabel = nls.localize({ key: 'reportIssueInEnglish', comment: ['Translate this to "Report Issue in English" in all languages please!'] }, "Report Issue..."); - - CommandsRegistry.registerCommand(OpenIssueReporterActionId, function (accessor, args?: [string] | OpenIssueReporterArgs) { - const data: Partial<IssueReporterData> = Array.isArray(args) - ? { extensionId: args[0] } - : args || {}; - - return accessor.get(IWorkbenchIssueService).openReporter(data); - }); - - const command: ICommandAction = { - id: OpenIssueReporterActionId, - title: { value: OpenIssueReporterActionLabel, original: 'Report Issue' }, - category: CATEGORIES.Help - }; - - MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command }); -} - -workbenchActionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(OpenProcessExplorer), 'Developer: Open Process Explorer', CATEGORIES.Developer.value); - -registerSingleton(IWorkbenchIssueService, WorkbenchIssueService, true); - -CommandsRegistry.registerCommand('_issues.getSystemStatus', (accessor) => { - return accessor.get(IIssueService).getSystemStatus(); -}); diff --git a/lib/vscode/src/vs/workbench/contrib/issue/electron-sandbox/issueActions.ts b/lib/vscode/src/vs/workbench/contrib/issue/electron-sandbox/issueActions.ts deleted file mode 100644 index 79b6607dd351..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/issue/electron-sandbox/issueActions.ts +++ /dev/null @@ -1,43 +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 { Action } from 'vs/base/common/actions'; -import * as nls from 'vs/nls'; -import { IssueType } from 'vs/platform/issue/common/issue'; -import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue'; - -export class OpenProcessExplorer extends Action { - static readonly ID = 'workbench.action.openProcessExplorer'; - static readonly LABEL = nls.localize('openProcessExplorer', "Open Process Explorer"); - - constructor( - id: string, - label: string, - @IWorkbenchIssueService private readonly issueService: IWorkbenchIssueService - ) { - super(id, label); - } - - override run(): Promise<void> { - return this.issueService.openProcessExplorer(); - } -} - -export class ReportPerformanceIssueUsingReporterAction extends Action { - static readonly ID = 'workbench.action.reportPerformanceIssueUsingReporter'; - static readonly LABEL = nls.localize({ key: 'reportPerformanceIssue', comment: [`Here, 'issue' means problem or bug`] }, "Report Performance Issue"); - - constructor( - id: string, - label: string, - @IWorkbenchIssueService private readonly issueService: IWorkbenchIssueService - ) { - super(id, label); - } - - override run(): Promise<void> { - return this.issueService.openReporter({ issueType: IssueType.PerformanceIssue }); - } -} diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/constants.ts b/lib/vscode/src/vs/workbench/contrib/notebook/browser/constants.ts deleted file mode 100644 index 06627113262d..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/constants.ts +++ /dev/null @@ -1,46 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -// Scrollable Element - -export const SCROLLABLE_ELEMENT_PADDING_TOP = 20; -// export const SCROLLABLE_ELEMENT_PADDING_TOP_WITH_TOOLBAR = 8; - -// Code cell layout: -// [CODE_CELL_LEFT_MARGIN][CELL_RUN_GUTTER][editorWidth][CELL_RIGHT_MARGIN] - -// Markdown cell layout: -// [CELL_MARGIN][content][CELL_RIGHT_MARGIN] - -// Markdown editor cell layout: -// [CODE_CELL_LEFT_MARGIN][content][CELL_RIGHT_MARGIN] - -// Cell sizing related -export const CELL_RIGHT_MARGIN = 16; -export const CELL_RUN_GUTTER = 28; -export const CODE_CELL_LEFT_MARGIN = 32; - -export const EDITOR_TOOLBAR_HEIGHT = 0; -export const BOTTOM_CELL_TOOLBAR_GAP = 18; -export const BOTTOM_CELL_TOOLBAR_HEIGHT = 22; -export const CELL_STATUSBAR_HEIGHT = 22; - -// Margin above editor -export const CELL_TOP_MARGIN = 6; -export const CELL_BOTTOM_MARGIN = 6; - -export const MARKDOWN_CELL_TOP_MARGIN = 8; -export const MARKDOWN_CELL_BOTTOM_MARGIN = 8; - -// Top and bottom padding inside the monaco editor in a cell, which are included in `cell.editorHeight` -// export const EDITOR_TOP_PADDING = 12; -export const EDITOR_BOTTOM_PADDING = 4; -export const EDITOR_BOTTOM_PADDING_WITHOUT_STATUSBAR = 12; - -export const CELL_OUTPUT_PADDING = 14; - -export const COLLAPSED_INDICATOR_HEIGHT = 24; - -export const MARKDOWN_PREVIEW_PADDING = 8; diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/cellStatusBar.ts b/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/cellStatusBar.ts deleted file mode 100644 index edce9fb60fbf..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/cellStatusBar.ts +++ /dev/null @@ -1,142 +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 { flatten } from 'vs/base/common/arrays'; -import { Throttler } from 'vs/base/common/async'; -import { CancellationTokenSource } from 'vs/base/common/cancellation'; -import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; -import { ICellViewModel, INotebookEditor, INotebookEditorContribution } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { registerNotebookContribution } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions'; -import { CellViewModel, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; -import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService'; -import { INotebookCellStatusBarItemList } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { cellRangesToIndexes } from 'vs/workbench/contrib/notebook/common/notebookRange'; - -export class NotebookStatusBarController extends Disposable implements INotebookEditorContribution { - static id: string = 'workbench.notebook.statusBar'; - - private readonly _visibleCells = new Map<number, CellStatusBarHelper>(); - - private readonly _viewModelDisposables = new DisposableStore(); - - constructor( - private readonly _notebookEditor: INotebookEditor, - @INotebookCellStatusBarService private readonly _notebookCellStatusBarService: INotebookCellStatusBarService - ) { - super(); - this._updateVisibleCells(); - this._register(this._notebookEditor.onDidChangeVisibleRanges(this._updateVisibleCells, this)); - this._register(this._notebookEditor.onDidChangeModel(this._onModelChange, this)); - this._register(this._notebookCellStatusBarService.onDidChangeProviders(this._updateEverything, this)); - this._register(this._notebookCellStatusBarService.onDidChangeItems(this._updateEverything, this)); - } - - private _onModelChange() { - this._viewModelDisposables.clear(); - const vm = this._notebookEditor.viewModel; - if (!vm) { - return; - } - - this._viewModelDisposables.add(vm.onDidChangeViewCells(() => this._updateEverything())); - this._updateEverything(); - } - - private _updateEverything(): void { - this._visibleCells.forEach(cell => cell.dispose()); - this._visibleCells.clear(); - this._updateVisibleCells(); - } - - private _updateVisibleCells(): void { - const vm = this._notebookEditor.viewModel; - if (!vm) { - return; - } - - const newVisibleCells = new Set<number>(); - const rangesWithEnd = this._notebookEditor.visibleRanges - .map(range => ({ start: range.start, end: range.end + 1 })); - cellRangesToIndexes(rangesWithEnd) - .map(index => vm.cellAt(index)) - .filter((cell: CellViewModel | undefined): cell is CellViewModel => !!cell) - .map(cell => { - if (!this._visibleCells.has(cell.handle)) { - const helper = new CellStatusBarHelper(vm, cell, this._notebookCellStatusBarService); - this._visibleCells.set(cell.handle, helper); - } - newVisibleCells.add(cell.handle); - }); - - for (let handle of this._visibleCells.keys()) { - if (!newVisibleCells.has(handle)) { - this._visibleCells.get(handle)?.dispose(); - this._visibleCells.delete(handle); - } - } - } - - override dispose(): void { - this._visibleCells.forEach(cell => cell.dispose()); - this._visibleCells.clear(); - } -} - -class CellStatusBarHelper extends Disposable { - private _currentItemIds: string[] = []; - private _currentItemLists: INotebookCellStatusBarItemList[] = []; - - private readonly _cancelTokenSource: CancellationTokenSource; - - private readonly _updateThrottler = new Throttler(); - - constructor( - private readonly _notebookViewModel: NotebookViewModel, - private readonly _cell: ICellViewModel, - private readonly _notebookCellStatusBarService: INotebookCellStatusBarService - ) { - super(); - - this._cancelTokenSource = new CancellationTokenSource(); - this._register(toDisposable(() => this._cancelTokenSource.dispose(true))); - - this._updateSoon(); - this._register(this._cell.model.onDidChangeContent(() => this._updateSoon())); - this._register(this._cell.model.onDidChangeLanguage(() => this._updateSoon())); - this._register(this._cell.model.onDidChangeMetadata(() => this._updateSoon())); - this._register(this._cell.model.onDidChangeOutputs(() => this._updateSoon())); - } - - private _updateSoon(): void { - this._updateThrottler.queue(() => this._update()); - } - - private async _update() { - const cellIndex = this._notebookViewModel.getCellIndex(this._cell); - const docUri = this._notebookViewModel.notebookDocument.uri; - const viewType = this._notebookViewModel.notebookDocument.viewType; - const itemLists = await this._notebookCellStatusBarService.getStatusBarItemsForCell(docUri, cellIndex, viewType, this._cancelTokenSource.token); - if (this._cancelTokenSource.token.isCancellationRequested) { - itemLists.forEach(itemList => itemList.dispose && itemList.dispose()); - return; - } - - const items = flatten(itemLists.map(itemList => itemList.items)); - const newIds = this._notebookViewModel.deltaCellStatusBarItems(this._currentItemIds, [{ handle: this._cell.handle, items }]); - - this._currentItemLists.forEach(itemList => itemList.dispose && itemList.dispose()); - this._currentItemLists = itemLists; - this._currentItemIds = newIds; - } - - override dispose() { - super.dispose(); - - this._notebookViewModel.deltaCellStatusBarItems(this._currentItemIds, [{ handle: this._cell.handle, items: [] }]); - this._currentItemLists.forEach(itemList => itemList.dispose && itemList.dispose()); - } -} - -registerNotebookContribution(NotebookStatusBarController.id, NotebookStatusBarController); diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts b/lib/vscode/src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts deleted file mode 100644 index c44bf609b456..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts +++ /dev/null @@ -1,85 +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 { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { NotebookRegistry } from 'vs/workbench/contrib/notebook/browser/notebookRegistry'; -import { onUnexpectedError } from 'vs/base/common/errors'; -import { ICellOutputViewModel, ICommonNotebookEditor, IOutputTransformContribution, IRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { URI } from 'vs/base/common/uri'; - -export class OutputRenderer { - protected readonly _contributions: { [key: string]: IOutputTransformContribution; }; - protected readonly _renderers: IOutputTransformContribution[]; - private _richMimeTypeRenderers = new Map<string, IOutputTransformContribution>(); - - constructor( - notebookEditor: ICommonNotebookEditor, - private readonly instantiationService: IInstantiationService - ) { - this._contributions = {}; - this._renderers = []; - - const contributions = NotebookRegistry.getOutputTransformContributions(); - - for (const desc of contributions) { - try { - const contribution = this.instantiationService.createInstance(desc.ctor, notebookEditor); - this._contributions[desc.id] = contribution; - contribution.getMimetypes().forEach(mimetype => { - this._richMimeTypeRenderers.set(mimetype, contribution); - }); - } catch (err) { - onUnexpectedError(err); - } - } - } - - getContribution(preferredMimeType: string | undefined): IOutputTransformContribution | undefined { - if (preferredMimeType) { - return this._richMimeTypeRenderers.get(preferredMimeType); - } - - return undefined; - } - - renderNoop(viewModel: ICellOutputViewModel, container: HTMLElement): IRenderOutput { - const contentNode = document.createElement('p'); - - contentNode.innerText = `No renderer could be found for output.`; - container.appendChild(contentNode); - return { type: RenderOutputType.Mainframe }; - } - - render(viewModel: ICellOutputViewModel, container: HTMLElement, preferredMimeType: string | undefined, notebookUri: URI | undefined): IRenderOutput { - if (!viewModel.model.outputs.length) { - return this.renderNoop(viewModel, container); - } - - if (!preferredMimeType || !this._richMimeTypeRenderers.has(preferredMimeType)) { - const contentNode = document.createElement('p'); - const mimeTypes = viewModel.model.outputs.map(op => op.mime); - - const mimeTypesMessage = mimeTypes.join(', '); - - if (preferredMimeType) { - contentNode.innerText = `No renderer could be found for MIME type: ${preferredMimeType}`; - } else { - contentNode.innerText = `No renderer could be found for output. It has the following MIME types: ${mimeTypesMessage}`; - } - - container.appendChild(contentNode); - return { type: RenderOutputType.Mainframe }; - } - - const renderer = this._richMimeTypeRenderers.get(preferredMimeType); - const items = viewModel.model.outputs.filter(op => op.mime === preferredMimeType); - - if (items.length && renderer) { - return renderer.render(viewModel, items, container, notebookUri); - } else { - return this.renderNoop(viewModel, container); - } - } -} diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/view/renderers/cellActionView.ts b/lib/vscode/src/vs/workbench/contrib/notebook/browser/view/renderers/cellActionView.ts deleted file mode 100644 index 2be9647d5f64..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/view/renderers/cellActionView.ts +++ /dev/null @@ -1,97 +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 { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; -import * as DOM from 'vs/base/browser/dom'; -import { BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; -import { Action, IAction, Separator } from 'vs/base/common/actions'; -import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; -import { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { IMenu, IMenuActionOptions, MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { INotificationService } from 'vs/platform/notification/common/notification'; - -export class VerticalSeparator extends Action { - static readonly ID = 'vs.actions.verticalSeparator'; - - constructor( - label?: string - ) { - super(VerticalSeparator.ID, label, label ? 'verticalSeparator text' : 'verticalSeparator'); - this.checked = false; - this.enabled = false; - } -} - -export class VerticalSeparatorViewItem extends BaseActionViewItem { - override render(container: HTMLElement) { - container.classList.add('verticalSeparator'); - // const iconContainer = DOM.append(container, $('.verticalSeparator')); - // DOM.addClasses(iconContainer, 'codicon', 'codicon-chrome-minimize'); - } -} - -export function createAndFillInActionBarActionsWithVerticalSeparators(menu: IMenu, options: IMenuActionOptions | undefined, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, alwaysFillSecondary?: boolean, isPrimaryGroup?: (group: string) => boolean): IDisposable { - const groups = menu.getActions(options); - // Action bars handle alternative actions on their own so the alternative actions should be ignored - fillInActions(groups, target, false, alwaysFillSecondary, isPrimaryGroup); - return asDisposable(groups); -} - -function fillInActions(groups: ReadonlyArray<[string, ReadonlyArray<MenuItemAction | SubmenuItemAction>]>, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, useAlternativeActions: boolean, alwaysFillSecondary = false, isPrimaryGroup: (group: string) => boolean = group => group === 'navigation'): void { - for (const tuple of groups) { - let [group, actions] = tuple; - if (useAlternativeActions) { - actions = actions.map(a => (a instanceof MenuItemAction) && !!a.alt ? a.alt : a); - } - - const isPrimary = isPrimaryGroup(group); - if (isPrimary) { - const to = Array.isArray(target) ? target : target.primary; - - if (to.length > 0) { - to.push(new VerticalSeparator()); - } - - to.push(...actions); - } - - if (!isPrimary || alwaysFillSecondary) { - const to = Array.isArray(target) ? target : target.secondary; - - if (to.length > 0) { - to.push(new Separator()); - } - - to.push(...actions); - } - } -} - -function asDisposable(groups: ReadonlyArray<[string, ReadonlyArray<MenuItemAction | SubmenuItemAction>]>): IDisposable { - const disposables = new DisposableStore(); - for (const [, actions] of groups) { - for (const action of actions) { - disposables.add(action); - } - } - return disposables; -} - - -export class CodiconActionViewItem extends MenuEntryActionViewItem { - constructor( - _action: MenuItemAction, - keybindingService: IKeybindingService, - notificationService: INotificationService, - ) { - super(_action, keybindingService, notificationService); - } - override updateLabel(): void { - if (this.options.label && this.label) { - DOM.reset(this.label, ...renderLabelWithIcons(this._commandAction.label ?? '')); - } - } -} diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/common/notebookMarkdownRenderer.ts b/lib/vscode/src/vs/workbench/contrib/notebook/common/notebookMarkdownRenderer.ts deleted file mode 100644 index 407fb7731cb1..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/notebook/common/notebookMarkdownRenderer.ts +++ /dev/null @@ -1,39 +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 { joinPath } from 'vs/base/common/resources'; -import { URI } from 'vs/base/common/uri'; -import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { INotebookMarkupRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon'; - -export class NotebookMarkupRendererInfo implements INotebookMarkupRendererInfo { - - readonly id: string; - readonly entrypoint: URI; - readonly displayName: string; - readonly extensionLocation: URI; - readonly extensionId: ExtensionIdentifier; - readonly extensionIsBuiltin: boolean; - readonly dependsOn: string | undefined; - readonly mimeTypes: readonly string[] | undefined; - - constructor(descriptor: { - readonly id: string; - readonly displayName: string; - readonly entrypoint: string; - readonly extension: IExtensionDescription; - readonly mimeTypes: readonly string[] | undefined, - readonly dependsOn: string | undefined, - }) { - this.id = descriptor.id; - this.extensionId = descriptor.extension.identifier; - this.extensionLocation = descriptor.extension.extensionLocation; - this.entrypoint = joinPath(this.extensionLocation, descriptor.entrypoint); - this.displayName = descriptor.displayName; - this.extensionIsBuiltin = descriptor.extension.isBuiltin; - this.dependsOn = descriptor.dependsOn; - this.mimeTypes = descriptor.mimeTypes; - } -} diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/common/notebookSelector.ts b/lib/vscode/src/vs/workbench/contrib/notebook/common/notebookSelector.ts deleted file mode 100644 index 5536377ec79e..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/notebook/common/notebookSelector.ts +++ /dev/null @@ -1,31 +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 { IRelativePattern } from 'vs/base/common/glob'; -import { URI } from 'vs/base/common/uri'; -import * as ls from 'vs/editor/common/modes/languageSelector'; - -export interface NotebookFilter { - readonly viewType?: string; - readonly scheme?: string; - readonly pattern?: string | IRelativePattern; -} - -export type NotebookSelector = NotebookFilter | string | ReadonlyArray<NotebookFilter | string>; - -function _asLanguageSelector(s: NotebookSelector): ls.LanguageFilter | ls.LanguageFilter[] { - if (Array.isArray(s)) { - return <ls.LanguageFilter[]>s.map(_asLanguageSelector); - } else if (typeof s === 'string') { - return { language: s }; - } else { - const { viewType, scheme, pattern } = <NotebookFilter>s; - return { language: viewType, scheme: scheme, pattern: pattern }; - } -} - -export function score(selector: NotebookSelector, candidateUri: URI, candidateViewType: string): number { - return ls.score(_asLanguageSelector(selector), candidateUri, candidateViewType, true); -} diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/test/notebookDiff.test.ts b/lib/vscode/src/vs/workbench/contrib/notebook/test/notebookDiff.test.ts deleted file mode 100644 index 802cdb25837b..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/notebook/test/notebookDiff.test.ts +++ /dev/null @@ -1,177 +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 assert from 'assert'; -import { LcsDiff } from 'vs/base/common/diff/diff'; -import { NotebookDiffEditorEventDispatcher } from 'vs/workbench/contrib/notebook/browser/diff/eventDispatcher'; -import { NotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor'; -import { CellKind, CellSequence } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { withTestNotebookDiffModel } from 'vs/workbench/contrib/notebook/test/testNotebookEditor'; - -suite('NotebookCommon', () => { - - test('diff insert', async () => { - await withTestNotebookDiffModel([ - ['var a = 1;', 'javascript', CellKind.Code, [], {}], - ['var b = 2;', 'javascript', CellKind.Code, [], {}] - ], [ - ['var h = 8;', 'javascript', CellKind.Code, [], {}], - ['var a = 1;', 'javascript', CellKind.Code, [], {}], - ['var b = 2;', 'javascript', CellKind.Code, [], {}] - ], (model, accessor) => { - const eventDispatcher = new NotebookDiffEditorEventDispatcher(); - const diffResult = NotebookTextDiffEditor.computeDiff(accessor, model, eventDispatcher, { - cellsDiff: { - changes: [{ - originalStart: 0, - originalLength: 0, - modifiedStart: 0, - modifiedLength: 1 - }], - quitEarly: false - } - }); - - assert.strictEqual(diffResult.firstChangeIndex, 0); - assert.strictEqual(diffResult.viewModels[0].type, 'insert'); - assert.strictEqual(diffResult.viewModels[1].type, 'unchanged'); - assert.strictEqual(diffResult.viewModels[2].type, 'unchanged'); - }); - }); - - test('diff insert 2', async () => { - - await withTestNotebookDiffModel([ - ['var a = 1;', 'javascript', CellKind.Code, [], {}], - ['var b = 2;', 'javascript', CellKind.Code, [], {}], - ['var c = 3;', 'javascript', CellKind.Code, [], {}], - ['var d = 4;', 'javascript', CellKind.Code, [], {}], - ['var e = 5;', 'javascript', CellKind.Code, [], {}], - ['var f = 6;', 'javascript', CellKind.Code, [], {}], - ['var g = 7;', 'javascript', CellKind.Code, [], {}], - ], [ - ['var h = 8;', 'javascript', CellKind.Code, [], {}], - ['var a = 1;', 'javascript', CellKind.Code, [], {}], - ['var b = 2;', 'javascript', CellKind.Code, [], {}], - ['var c = 3;', 'javascript', CellKind.Code, [], {}], - ['var d = 4;', 'javascript', CellKind.Code, [], {}], - ['var e = 5;', 'javascript', CellKind.Code, [], {}], - ['var f = 6;', 'javascript', CellKind.Code, [], {}], - ['var g = 7;', 'javascript', CellKind.Code, [], {}], - ], async (model, accessor) => { - const eventDispatcher = new NotebookDiffEditorEventDispatcher(); - const diffResult = NotebookTextDiffEditor.computeDiff(accessor, model, eventDispatcher, { - cellsDiff: { - changes: [{ - originalStart: 0, - originalLength: 0, - modifiedStart: 0, - modifiedLength: 1 - }, { - originalStart: 0, - originalLength: 6, - modifiedStart: 1, - modifiedLength: 6 - }], - quitEarly: false - } - }); - - assert.strictEqual(diffResult.firstChangeIndex, 0); - assert.strictEqual(diffResult.viewModels[0].type, 'insert'); - assert.strictEqual(diffResult.viewModels[1].type, 'unchanged'); - assert.strictEqual(diffResult.viewModels[2].type, 'unchanged'); - assert.strictEqual(diffResult.viewModels[3].type, 'unchanged'); - assert.strictEqual(diffResult.viewModels[4].type, 'unchanged'); - assert.strictEqual(diffResult.viewModels[5].type, 'unchanged'); - assert.strictEqual(diffResult.viewModels[6].type, 'unchanged'); - assert.strictEqual(diffResult.viewModels[7].type, 'unchanged'); - }); - }); - - test('LCS', async () => { - await withTestNotebookDiffModel([ - ['# Description', 'markdown', CellKind.Markdown, [], { custom: { metadata: {} } }], - ['x = 3', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: true } }, executionOrder: 1 }], - ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: 'text/plain', value: '3' }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }], - ['x', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: false } } }] - ], [ - ['# Description', 'markdown', CellKind.Markdown, [], { custom: { metadata: {} } }], - ['x = 3', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: true } }, executionOrder: 1 }], - ['x', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: false } } }], - ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: 'text/plain', value: '3' }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }] - ], async (model) => { - const diff = new LcsDiff(new CellSequence(model.original.notebook), new CellSequence(model.modified.notebook)); - const diffResult = diff.ComputeDiff(false); - assert.deepStrictEqual(diffResult.changes.map(change => ({ - originalStart: change.originalStart, - originalLength: change.originalLength, - modifiedStart: change.modifiedStart, - modifiedLength: change.modifiedLength - })), [{ - originalStart: 2, - originalLength: 0, - modifiedStart: 2, - modifiedLength: 1 - }, { - originalStart: 3, - originalLength: 1, - modifiedStart: 4, - modifiedLength: 0 - }]); - }); - }); - - test('LCS 2', async () => { - await withTestNotebookDiffModel([ - ['# Description', 'markdown', CellKind.Markdown, [], { custom: { metadata: {} } }], - ['x = 3', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: true } }, executionOrder: 1 }], - ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: 'text/plain', value: '3' }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }], - ['x', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: false } } }], - ['x = 5', 'javascript', CellKind.Code, [], {}], - ['x', 'javascript', CellKind.Code, [], {}], - ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: 'text/plain', value: '5' }] }], {}], - ], [ - ['# Description', 'markdown', CellKind.Markdown, [], { custom: { metadata: {} } }], - ['x = 3', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: true } }, executionOrder: 1 }], - ['x', 'javascript', CellKind.Code, [], { custom: { metadata: { collapsed: false } } }], - ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: 'text/plain', value: '3' }] }], { custom: { metadata: { collapsed: false } }, executionOrder: 1 }], - ['x = 5', 'javascript', CellKind.Code, [], {}], - ['x', 'javascript', CellKind.Code, [{ outputId: 'someId', outputs: [{ mime: 'text/plain', value: '5' }] }], {}], - ['x', 'javascript', CellKind.Code, [], {}], - ], async (model) => { - const diff = new LcsDiff(new CellSequence(model.original.notebook), new CellSequence(model.modified.notebook)); - const diffResult = diff.ComputeDiff(false); - NotebookTextDiffEditor.prettyChanges(model, diffResult); - - assert.deepStrictEqual(diffResult.changes.map(change => ({ - originalStart: change.originalStart, - originalLength: change.originalLength, - modifiedStart: change.modifiedStart, - modifiedLength: change.modifiedLength - })), [{ - originalStart: 2, - originalLength: 0, - modifiedStart: 2, - modifiedLength: 1 - }, { - originalStart: 3, - originalLength: 1, - modifiedStart: 4, - modifiedLength: 0 - }, { - originalStart: 5, - originalLength: 0, - modifiedStart: 5, - modifiedLength: 1 - }, { - originalStart: 6, - originalLength: 1, - modifiedStart: 7, - modifiedLength: 0 - }]); - }); - }); -}); diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/test/notebookEditorModel.test.ts b/lib/vscode/src/vs/workbench/contrib/notebook/test/notebookEditorModel.test.ts deleted file mode 100644 index 46adfd9eef6e..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/notebook/test/notebookEditorModel.test.ts +++ /dev/null @@ -1,59 +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 assert from 'assert'; -import { Event } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { isEqual } from 'vs/base/common/resources'; -import { URI } from 'vs/base/common/uri'; -import { mock } from 'vs/base/test/common/mock'; -import { IFileService } from 'vs/platform/files/common/files'; -import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; -import { ILabelService } from 'vs/platform/label/common/label'; -import { NullLogService } from 'vs/platform/log/common/log'; -import { INotificationService } from 'vs/platform/notification/common/notification'; -import { ComplexNotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookEditorModel'; -import { INotebookContentProvider, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; -import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/common/workingCopyBackup'; -import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; -import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; -import { IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopy'; - -suite('NotebookEditorModel', function () { - - const instaService = new InstantiationService(); - const notebokService = new class extends mock<INotebookService>() { }; - const backupService = new class extends mock<IWorkingCopyBackupService>() { }; - const notificationService = new class extends mock<INotificationService>() { }; - const untitledTextEditorService = new class extends mock<IUntitledTextEditorService>() { }; - const fileService = new class extends mock<IFileService>() { - override onDidFilesChange = Event.None; - }; - const labelService = new class extends mock<ILabelService>() { - override getUriBasenameLabel(uri: URI) { return uri.toString(); } - }; - - const notebookDataProvider = new class extends mock<INotebookContentProvider>() { }; - - test('working copy uri', function () { - - const r1 = URI.parse('foo-files:///my.nb'); - const r2 = URI.parse('bar-files:///my.nb'); - - const copies: IWorkingCopy[] = []; - const workingCopyService = new class extends mock<IWorkingCopyService>() { - override registerWorkingCopy(copy: IWorkingCopy) { - copies.push(copy); - return Disposable.None; - } - }; - - new ComplexNotebookEditorModel(r1, 'fff', notebookDataProvider, instaService, notebokService, workingCopyService, backupService, fileService, notificationService, new NullLogService(), untitledTextEditorService, labelService); - new ComplexNotebookEditorModel(r2, 'fff', notebookDataProvider, instaService, notebokService, workingCopyService, backupService, fileService, notificationService, new NullLogService(), untitledTextEditorService, labelService); - - assert.strictEqual(copies.length, 2); - assert.strictEqual(!isEqual(copies[0].resource, copies[1].resource), true); - }); -}); diff --git a/lib/vscode/src/vs/workbench/contrib/searchEditor/browser/searchEditorModel.ts b/lib/vscode/src/vs/workbench/contrib/searchEditor/browser/searchEditorModel.ts deleted file mode 100644 index 1a60b9a83540..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/searchEditor/browser/searchEditorModel.ts +++ /dev/null @@ -1,95 +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 { URI } from 'vs/base/common/uri'; -import { ITextModel } from 'vs/editor/common/model'; -import { IModelService } from 'vs/editor/common/services/modelService'; -import { IModeService } from 'vs/editor/common/services/modeService'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { parseSavedSearchEditor } from 'vs/workbench/contrib/searchEditor/browser/searchEditorSerialization'; -import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/common/workingCopyBackup'; -import { SearchConfiguration } from './searchEditorInput'; -import { assertIsDefined } from 'vs/base/common/types'; -import { NO_TYPE_ID } from 'vs/workbench/services/workingCopy/common/workingCopy'; -import { createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; -import { SearchEditorScheme, SearchEditorWorkingCopyTypeId } from 'vs/workbench/contrib/searchEditor/browser/constants'; - - -export class SearchEditorModel { - private cachedContentsModel: ITextModel | undefined = undefined; - private resolveContents!: (model: ITextModel) => void; - public onModelResolved: Promise<ITextModel>; - - private ongoingResolve = Promise.resolve<any>(undefined); - - constructor( - private modelUri: URI, - public config: SearchConfiguration, - private existingData: ({ config: Partial<SearchConfiguration>; backingUri?: URI; } & - ({ modelUri: URI; text?: never; } | - { text: string; modelUri?: never; } | - { backingUri: URI; text?: never; modelUri?: never; })), - @IInstantiationService private readonly instantiationService: IInstantiationService, - @IWorkingCopyBackupService readonly workingCopyBackupService: IWorkingCopyBackupService, - @IModelService private readonly modelService: IModelService, - @IModeService private readonly modeService: IModeService) { - this.onModelResolved = new Promise<ITextModel>(resolve => this.resolveContents = resolve); - this.onModelResolved.then(model => this.cachedContentsModel = model); - - this.ongoingResolve = (async () => { - let discardLegacyBackup = false; - let backup = await workingCopyBackupService.resolve({ resource: modelUri, typeId: SearchEditorWorkingCopyTypeId }); - if (!backup) { - // TODO@bpasero remove this fallback after some releases - backup = await workingCopyBackupService.resolve({ resource: modelUri, typeId: NO_TYPE_ID }); - - if (backup && modelUri.scheme === SearchEditorScheme) { - discardLegacyBackup = true; - } - } - - let model = modelService.getModel(modelUri); - if (!model && backup) { - const factory = await createTextBufferFactoryFromStream(backup.value); - - if (discardLegacyBackup) { - await workingCopyBackupService.discardBackup({ resource: modelUri, typeId: NO_TYPE_ID }); - } - - model = modelService.createModel(factory, modeService.create('search-result'), modelUri); - } - - if (model) { - this.resolveContents(model); - } - - return model; - })(); - } - - async resolve(): Promise<ITextModel> { - await (this.ongoingResolve = this.ongoingResolve.then(() => this.cachedContentsModel || this.createModel())); - return assertIsDefined(this.cachedContentsModel); - } - - private async createModel() { - const getContents = async () => { - if (this.existingData.text !== undefined) { - return this.existingData.text; - } - else if (this.existingData.backingUri !== undefined) { - return (await this.instantiationService.invokeFunction(parseSavedSearchEditor, this.existingData.backingUri)).text; - } - else { - return ''; - } - }; - - const contents = await getContents(); - const model = this.modelService.getModel(this.modelUri) ?? this.modelService.createModel(contents, this.modeService.create('search-result'), this.modelUri); - this.resolveContents(model); - return model; - } -} diff --git a/lib/vscode/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts b/lib/vscode/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts deleted file mode 100644 index db5f64070d98..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts +++ /dev/null @@ -1,143 +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 { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals'; -import { join } from 'vs/base/common/path'; -import { onDidChangeFullscreen, isFullscreen } from 'vs/base/browser/browser'; -import { getTotalHeight, getTotalWidth } from 'vs/base/browser/dom'; -import { Color } from 'vs/base/common/color'; -import { Event } from 'vs/base/common/event'; -import { DisposableStore } from 'vs/base/common/lifecycle'; -import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { ColorIdentifier, editorBackground, foreground } from 'vs/platform/theme/common/colorRegistry'; -import { getThemeTypeSelector, IThemeService } from 'vs/platform/theme/common/themeService'; -import { DEFAULT_EDITOR_MIN_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor'; -import { Extensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; -import * as themes from 'vs/workbench/common/theme'; -import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService'; -import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; -import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { URI } from 'vs/base/common/uri'; -import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import * as perf from 'vs/base/common/performance'; -import { assertIsDefined } from 'vs/base/common/types'; -import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; - -class PartsSplash { - - private static readonly _splashElementId = 'monaco-parts-splash'; - - private readonly _disposables = new DisposableStore(); - - private _didChangeTitleBarStyle?: boolean; - private _lastBaseTheme?: string; - private _lastBackground?: string; - - constructor( - @IThemeService private readonly _themeService: IThemeService, - @IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService, - @ITextFileService private readonly _textFileService: ITextFileService, - @INativeWorkbenchEnvironmentService private readonly _environmentService: INativeWorkbenchEnvironmentService, - @ILifecycleService lifecycleService: ILifecycleService, - @IEditorGroupsService editorGroupsService: IEditorGroupsService, - @IConfigurationService configService: IConfigurationService, - @INativeHostService private readonly _nativeHostService: INativeHostService - ) { - lifecycleService.when(LifecyclePhase.Restored).then(_ => { - this._removePartsSplash(); - perf.mark('code/didRemovePartsSplash'); - }); - Event.debounce(Event.any<any>( - onDidChangeFullscreen, - editorGroupsService.onDidLayout - ), () => { }, 800)(this._savePartsSplash, this, this._disposables); - - configService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration('window.titleBarStyle')) { - this._didChangeTitleBarStyle = true; - this._savePartsSplash(); - } - }, this, this._disposables); - - _themeService.onDidColorThemeChange(_ => { - this._savePartsSplash(); - }, this, this._disposables); - } - - dispose(): void { - this._disposables.dispose(); - } - - private _savePartsSplash() { - const baseTheme = getThemeTypeSelector(this._themeService.getColorTheme().type); - const colorInfo = { - foreground: this._getThemeColor(foreground), - editorBackground: this._getThemeColor(editorBackground), - titleBarBackground: this._getThemeColor(themes.TITLE_BAR_ACTIVE_BACKGROUND), - activityBarBackground: this._getThemeColor(themes.ACTIVITY_BAR_BACKGROUND), - sideBarBackground: this._getThemeColor(themes.SIDE_BAR_BACKGROUND), - statusBarBackground: this._getThemeColor(themes.STATUS_BAR_BACKGROUND), - statusBarNoFolderBackground: this._getThemeColor(themes.STATUS_BAR_NO_FOLDER_BACKGROUND), - windowBorder: this._getThemeColor(themes.WINDOW_ACTIVE_BORDER) ?? this._getThemeColor(themes.WINDOW_INACTIVE_BORDER) - }; - const layoutInfo = !this._shouldSaveLayoutInfo() ? undefined : { - sideBarSide: this._layoutService.getSideBarPosition() === Position.RIGHT ? 'right' : 'left', - editorPartMinWidth: DEFAULT_EDITOR_MIN_DIMENSIONS.width, - titleBarHeight: this._layoutService.isVisible(Parts.TITLEBAR_PART) ? getTotalHeight(assertIsDefined(this._layoutService.getContainer(Parts.TITLEBAR_PART))) : 0, - activityBarWidth: this._layoutService.isVisible(Parts.ACTIVITYBAR_PART) ? getTotalWidth(assertIsDefined(this._layoutService.getContainer(Parts.ACTIVITYBAR_PART))) : 0, - sideBarWidth: this._layoutService.isVisible(Parts.SIDEBAR_PART) ? getTotalWidth(assertIsDefined(this._layoutService.getContainer(Parts.SIDEBAR_PART))) : 0, - statusBarHeight: this._layoutService.isVisible(Parts.STATUSBAR_PART) ? getTotalHeight(assertIsDefined(this._layoutService.getContainer(Parts.STATUSBAR_PART))) : 0, - windowBorder: this._layoutService.hasWindowBorder(), - windowBorderRadius: this._layoutService.getWindowBorderRadius() - }; - this._textFileService.write( - URI.file(join(this._environmentService.userDataPath, 'rapid_render.json')), - JSON.stringify({ - id: PartsSplash._splashElementId, - colorInfo, - layoutInfo, - baseTheme - }), - { encoding: 'utf8' } - ); - - if (baseTheme !== this._lastBaseTheme || colorInfo.editorBackground !== this._lastBackground) { - // notify the main window on background color changes: the main window sets the background color to new windows - this._lastBaseTheme = baseTheme; - this._lastBackground = colorInfo.editorBackground; - - // the color needs to be in hex - const backgroundColor = this._themeService.getColorTheme().getColor(editorBackground) || themes.WORKBENCH_BACKGROUND(this._themeService.getColorTheme()); - const payload = JSON.stringify({ baseTheme, background: Color.Format.CSS.formatHex(backgroundColor) }); - ipcRenderer.send('vscode:changeColorTheme', this._nativeHostService.windowId, payload); - } - } - - private _getThemeColor(id: ColorIdentifier): string | undefined { - const theme = this._themeService.getColorTheme(); - const color = theme.getColor(id); - return color ? color.toString() : undefined; - } - - private _shouldSaveLayoutInfo(): boolean { - return !isFullscreen() && !this._environmentService.isExtensionDevelopment && !this._didChangeTitleBarStyle; - } - - private _removePartsSplash(): void { - let element = document.getElementById(PartsSplash._splashElementId); - if (element) { - element.style.display = 'none'; - } - // remove initial colors - let defaultStyles = document.head.getElementsByClassName('initialShellColors'); - if (defaultStyles.length) { - document.head.removeChild(defaultStyles[0]); - } - } -} - -Registry.as<IWorkbenchContributionsRegistry>(Extensions.Workbench).registerWorkbenchContribution(PartsSplash, LifecyclePhase.Starting); diff --git a/lib/vscode/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts b/lib/vscode/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts deleted file mode 100644 index 64771ba0971d..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts +++ /dev/null @@ -1,61 +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 { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; -import { IDefaultShellAndArgsRequest } from 'vs/workbench/contrib/terminal/common/terminal'; -import type { Terminal as XTermTerminal } from 'xterm'; -import type { SearchAddon as XTermSearchAddon } from 'xterm-addon-search'; -import type { Unicode11Addon as XTermUnicode11Addon } from 'xterm-addon-unicode11'; -import type { WebglAddon as XTermWebglAddon } from 'xterm-addon-webgl'; -import { IProcessEnvironment } from 'vs/base/common/platform'; -import { Emitter } from 'vs/base/common/event'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { Disposable } from 'vs/base/common/lifecycle'; - -let Terminal: typeof XTermTerminal; -let SearchAddon: typeof XTermSearchAddon; -let Unicode11Addon: typeof XTermUnicode11Addon; -let WebglAddon: typeof XTermWebglAddon; - -export class TerminalInstanceService extends Disposable implements ITerminalInstanceService { - public _serviceBrand: undefined; - - protected readonly _onRequestDefaultShellAndArgs = this._register(new Emitter<IDefaultShellAndArgsRequest>()); - readonly onRequestDefaultShellAndArgs = this._onRequestDefaultShellAndArgs.event; - - public async getXtermConstructor(): Promise<typeof XTermTerminal> { - if (!Terminal) { - Terminal = (await import('xterm')).Terminal; - } - return Terminal; - } - - public async getXtermSearchConstructor(): Promise<typeof XTermSearchAddon> { - if (!SearchAddon) { - SearchAddon = (await import('xterm-addon-search')).SearchAddon; - } - return SearchAddon; - } - - public async getXtermUnicode11Constructor(): Promise<typeof XTermUnicode11Addon> { - if (!Unicode11Addon) { - Unicode11Addon = (await import('xterm-addon-unicode11')).Unicode11Addon; - } - return Unicode11Addon; - } - - public async getXtermWebglConstructor(): Promise<typeof XTermWebglAddon> { - if (!WebglAddon) { - WebglAddon = (await import('xterm-addon-webgl')).WebglAddon; - } - return WebglAddon; - } - - public async getMainProcessParentEnv(): Promise<IProcessEnvironment> { - return {}; - } -} - -registerSingleton(ITerminalInstanceService, TerminalInstanceService, true); diff --git a/lib/vscode/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts b/lib/vscode/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts deleted file mode 100644 index fcedae4ecc8b..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts +++ /dev/null @@ -1,336 +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 { Schemas } from 'vs/base/common/network'; -import { env } from 'vs/base/common/process'; -import { withNullAsUndefined } from 'vs/base/common/types'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ILogService } from 'vs/platform/log/common/log'; -import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { IRemoteTerminalService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; -import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; -import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { IProcessEnvironment, OperatingSystem } from 'vs/base/common/platform'; -import { IShellLaunchConfig } from 'vs/platform/terminal/common/terminal'; -import { IShellLaunchConfigResolveOptions, ITerminalProfile, ITerminalProfileResolverService } from 'vs/workbench/contrib/terminal/common/terminal'; -import * as path from 'vs/base/common/path'; -import { Codicon, iconRegistry } from 'vs/base/common/codicons'; - -export interface IProfileContextProvider { - getDefaultSystemShell: (remoteAuthority: string | undefined, os: OperatingSystem) => Promise<string>; - getShellEnvironment: (remoteAuthority: string | undefined) => Promise<IProcessEnvironment>; -} - -const generatedProfileName = 'Generated'; - -export abstract class BaseTerminalProfileResolverService implements ITerminalProfileResolverService { - declare _serviceBrand: undefined; - - constructor( - private readonly _context: IProfileContextProvider, - private readonly _configurationService: IConfigurationService, - private readonly _configurationResolverService: IConfigurationResolverService, - private readonly _historyService: IHistoryService, - private readonly _logService: ILogService, - private readonly _terminalService: ITerminalService, - private readonly _workspaceContextService: IWorkspaceContextService, - ) { - } - - resolveIcon(shellLaunchConfig: IShellLaunchConfig, os: OperatingSystem): void { - if (shellLaunchConfig.executable) { - return; - } - - const defaultProfile = this._getRealDefaultProfile(true, os); - if (defaultProfile) { - shellLaunchConfig.icon = defaultProfile.icon; - } - } - - async resolveShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig, options: IShellLaunchConfigResolveOptions): Promise<void> { - // Resolve the shell and shell args - let resolvedProfile: ITerminalProfile; - if (shellLaunchConfig.executable) { - resolvedProfile = await this._resolveProfile({ - path: shellLaunchConfig.executable, - args: shellLaunchConfig.args, - profileName: generatedProfileName - }, options); - } else { - resolvedProfile = await this.getDefaultProfile(options); - } - shellLaunchConfig.executable = resolvedProfile.path; - shellLaunchConfig.args = resolvedProfile.args; - if (resolvedProfile.env) { - if (shellLaunchConfig.env) { - shellLaunchConfig.env = { ...shellLaunchConfig.env, ...resolvedProfile.env }; - } else { - shellLaunchConfig.env = resolvedProfile.env; - } - } - - // Verify the icon is valid, and fallback correctly to the generic terminal id if there is - // an issue - shellLaunchConfig.icon = this._verifyIcon(shellLaunchConfig.icon) || this._verifyIcon(resolvedProfile.icon) || Codicon.terminal.id; - } - - private _verifyIcon(iconId?: string): string | undefined { - if (!iconId || !iconRegistry.get(iconId)) { - return undefined; - } - return iconId; - } - - async getDefaultShell(options: IShellLaunchConfigResolveOptions): Promise<string> { - return (await this.getDefaultProfile(options)).path; - } - - async getDefaultShellArgs(options: IShellLaunchConfigResolveOptions): Promise<string | string[]> { - return (await this.getDefaultProfile(options)).args || []; - } - - async getDefaultProfile(options: IShellLaunchConfigResolveOptions): Promise<ITerminalProfile> { - return this._resolveProfile(await this._getUnresolvedDefaultProfile(options), options); - } - - getShellEnvironment(remoteAuthority: string | undefined): Promise<IProcessEnvironment> { - return this._context.getShellEnvironment(remoteAuthority); - } - - private async _getUnresolvedDefaultProfile(options: IShellLaunchConfigResolveOptions): Promise<ITerminalProfile> { - // If automation shell is allowed, prefer that - if (options.allowAutomationShell) { - const automationShellProfile = this._getAutomationShellProfile(options); - if (automationShellProfile) { - return automationShellProfile; - } - } - - // Return the real default profile if it exists and is valid - const defaultProfile = await this._getRealDefaultProfile(false, options.os); - if (defaultProfile) { - return defaultProfile; - } - - // If there is no real default profile, create a fallback default profile based on the shell - // and shellArgs settings in addition to the current environment. - return this._getFallbackDefaultProfile(options); - } - - private _getRealDefaultProfile(sync: true, os: OperatingSystem): ITerminalProfile | undefined; - private _getRealDefaultProfile(sync: false, os: OperatingSystem): Promise<ITerminalProfile | undefined>; - private _getRealDefaultProfile(sync: boolean, os: OperatingSystem): ITerminalProfile | undefined | Promise<ITerminalProfile | undefined> { - const defaultProfileName = this.getSafeConfigValue('defaultProfile', os); - if (defaultProfileName && typeof defaultProfileName === 'string') { - if (sync) { - const profiles = this._terminalService.availableProfiles; - return profiles.find(e => e.profileName === defaultProfileName); - } else { - return this._terminalService.availableProfiles.find(e => e.profileName === defaultProfileName); - } - } - return undefined; - } - - private async _getFallbackDefaultProfile(options: IShellLaunchConfigResolveOptions): Promise<ITerminalProfile> { - let executable: string; - let args: string | string[] | undefined; - const shellSetting = this.getSafeConfigValue('shell', options.os); - if (this._isValidShell(shellSetting)) { - executable = shellSetting; - const shellArgsSetting = this.getSafeConfigValue('shellArgs', options.os); - if (this._isValidShellArgs(shellArgsSetting, options.os)) { - args = shellArgsSetting; - } - } else { - executable = await this._context.getDefaultSystemShell(options.remoteAuthority, options.os); - } - - if (args === undefined) { - if (options.os === OperatingSystem.Macintosh && args === undefined) { - // macOS should launch a login shell by default - args = ['--login']; - } else { - // Resolve undefined to [] - args = []; - } - } - - const icon = this._guessProfileIcon(executable); - - return { - profileName: generatedProfileName, - path: executable, - args, - icon - }; - } - - private _getAutomationShellProfile(options: IShellLaunchConfigResolveOptions): ITerminalProfile | undefined { - const automationShell = this.getSafeConfigValue('automationShell', options.os); - if (!automationShell || typeof automationShell !== 'string') { - return undefined; - } - return { - path: automationShell, - profileName: generatedProfileName - }; - } - - private async _resolveProfile(profile: ITerminalProfile, options: IShellLaunchConfigResolveOptions): Promise<ITerminalProfile> { - if (options.os === OperatingSystem.Windows) { - // Change Sysnative to System32 if the OS is Windows but NOT WoW64. It's - // safe to assume that this was used by accident as Sysnative does not - // exist and will break the terminal in non-WoW64 environments. - const env = await this._context.getShellEnvironment(options.remoteAuthority); - const isWoW64 = !!env.hasOwnProperty('PROCESSOR_ARCHITEW6432'); - const windir = env.windir; - if (!isWoW64 && windir) { - const sysnativePath = path.join(windir, 'Sysnative').replace(/\//g, '\\').toLowerCase(); - if (profile.path && profile.path.toLowerCase().indexOf(sysnativePath) === 0) { - profile.path = path.join(windir, 'System32', profile.path.substr(sysnativePath.length + 1)); - } - } - - // Convert / to \ on Windows for convenience - if (profile.path) { - profile.path = profile.path.replace(/\//g, '\\'); - } - } - - // Resolve path variables - const env = await this._context.getShellEnvironment(options.remoteAuthority); - const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(Schemas.file); - const lastActiveWorkspace = activeWorkspaceRootUri ? withNullAsUndefined(this._workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri)) : undefined; - profile.path = this._resolveVariables(profile.path, env, lastActiveWorkspace); - - // Resolve args variables - if (profile.args) { - if (typeof profile.args === 'string') { - profile.args = this._resolveVariables(profile.args, env, lastActiveWorkspace); - } else { - for (let i = 0; i < profile.args.length; i++) { - profile.args[i] = this._resolveVariables(profile.args[i], env, lastActiveWorkspace); - } - } - } - - return profile; - } - - private _resolveVariables(value: string, env: IProcessEnvironment, lastActiveWorkspace: IWorkspaceFolder | undefined) { - try { - value = this._configurationResolverService.resolveWithEnvironment(env, lastActiveWorkspace, value); - } catch (e) { - this._logService.error(`Could not resolve shell`, e); - } - return value; - } - - private _getOsKey(os: OperatingSystem): string { - switch (os) { - case OperatingSystem.Linux: return 'linux'; - case OperatingSystem.Macintosh: return 'osx'; - case OperatingSystem.Windows: return 'windows'; - } - } - - private _guessProfileIcon(shell: string): string | undefined { - const file = path.parse(shell).name; - switch (file) { - case 'bash': - return Codicon.terminalBash.id; - case 'pwsh': - case 'powershell': - return Codicon.terminalPowershell.id; - case 'tmux': - return Codicon.terminalTmux.id; - case 'cmd': - return Codicon.terminalCmd.id; - default: - return undefined; - } - } - - private _isValidShell(shell: unknown): shell is string { - if (!shell) { - return false; - } - return typeof shell === 'string'; - } - - private _isValidShellArgs(shellArgs: unknown, os: OperatingSystem): shellArgs is string | string[] | undefined { - if (shellArgs === undefined) { - return true; - } - if (os === OperatingSystem.Windows && typeof shellArgs === 'string') { - return true; - } - if (Array.isArray(shellArgs) && shellArgs.every(e => typeof e === 'string')) { - return true; - } - return false; - } - - // TODO: Remove when workspace trust is enabled - getSafeConfigValue(key: string, os: OperatingSystem): unknown | undefined { - return this.getSafeConfigValueFullKey(`terminal.integrated.${key}.${this._getOsKey(os)}`); - } - getSafeConfigValueFullKey(key: string): unknown | undefined { - const isWorkspaceConfigAllowed = this._configurationService.getValue('terminal.integrated.allowWorkspaceConfiguration'); - if (isWorkspaceConfigAllowed) { - return this._configurationService.getValue(key); - } else { - const config = this._configurationService.inspect(key); - const value = config.user?.value || config.default?.value; - // Clone if needed to allow extensibility - if (Array.isArray(value)) { - return value.slice(); - } - if (typeof value === 'object') { - return { ...value }; - } - return value; - } - } -} - -export class BrowserTerminalProfileResolverService extends BaseTerminalProfileResolverService { - - constructor( - @IConfigurationResolverService configurationResolverService: IConfigurationResolverService, - @IConfigurationService configurationService: IConfigurationService, - @IHistoryService historyService: IHistoryService, - @ILogService logService: ILogService, - @IRemoteTerminalService remoteTerminalService: IRemoteTerminalService, - @ITerminalService terminalService: ITerminalService, - @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, - ) { - super( - { - getDefaultSystemShell: async (remoteAuthority, os) => { - if (!remoteAuthority) { - // Just return basic values, this is only for serverless web and wouldn't be used - return os === OperatingSystem.Windows ? 'pwsh' : 'bash'; - } - return remoteTerminalService.getDefaultSystemShell(os); - }, - getShellEnvironment: async (remoteAuthority) => { - if (!remoteAuthority) { - return env; - } - return remoteTerminalService.getShellEnvironment(); - } - }, - configurationService, - configurationResolverService, - historyService, - logService, - terminalService, - workspaceContextService - ); - } -} diff --git a/lib/vscode/src/vs/workbench/contrib/terminal/browser/terminalTabsWidget.ts b/lib/vscode/src/vs/workbench/contrib/terminal/browser/terminalTabsWidget.ts deleted file mode 100644 index 1850fcbcc6d2..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/terminal/browser/terminalTabsWidget.ts +++ /dev/null @@ -1,378 +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 { IListService, WorkbenchObjectTree } from 'vs/platform/list/browser/listService'; -import { ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree'; -import { DefaultStyleController } from 'vs/base/browser/ui/list/listWidget'; -import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { ITerminalInstance, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; -import { localize } from 'vs/nls'; -import * as DOM from 'vs/base/browser/dom'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; -import { MenuItemAction } from 'vs/platform/actions/common/actions'; -import { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { KEYBINDING_CONTEXT_TERMINAL_TABS_SINGULAR_SELECTION, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal'; -import { Codicon } from 'vs/base/common/codicons'; -import { Action } from 'vs/base/common/actions'; -import { MarkdownString } from 'vs/base/common/htmlContent'; -import { TerminalDecorationsProvider } from 'vs/workbench/contrib/terminal/browser/terminalDecorationsProvider'; -import { DEFAULT_LABELS_CONTAINER, IResourceLabel, ResourceLabels } from 'vs/workbench/browser/labels'; -import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations'; -import { IHoverAction, IHoverService } from 'vs/workbench/services/hover/browser/hover'; -import Severity from 'vs/base/common/severity'; -import { DisposableStore } from 'vs/base/common/lifecycle'; - -const $ = DOM.$; -const TAB_HEIGHT = 22; -export const MIN_TABS_WIDGET_WIDTH = 46; -export const DEFAULT_TABS_WIDGET_WIDTH = 80; -export const MIDPOINT_WIDGET_WIDTH = (MIN_TABS_WIDGET_WIDTH + DEFAULT_TABS_WIDGET_WIDTH) / 2; - -export class TerminalTabsWidget extends WorkbenchObjectTree<ITerminalInstance> { - private _decorationsProvider: TerminalDecorationsProvider | undefined; - private _terminalTabsSingleSelectedContextKey: IContextKey<boolean>; - - constructor( - container: HTMLElement, - @IContextKeyService contextKeyService: IContextKeyService, - @IListService listService: IListService, - @IThemeService themeService: IThemeService, - @IConfigurationService configurationService: IConfigurationService, - @IKeybindingService keybindingService: IKeybindingService, - @IAccessibilityService accessibilityService: IAccessibilityService, - @ITerminalService private readonly _terminalService: ITerminalService, - @IInstantiationService instantiationService: IInstantiationService, - @IDecorationsService _decorationsService: IDecorationsService - ) { - super('TerminalTabsTree', container, - { - getHeight: () => TAB_HEIGHT, - getTemplateId: () => 'terminal.tabs' - }, - [instantiationService.createInstance(TerminalTabsRenderer, container, instantiationService.createInstance(ResourceLabels, DEFAULT_LABELS_CONTAINER), () => this.getSelection())], - { - horizontalScrolling: false, - supportDynamicHeights: false, - identityProvider: { - getId: e => e?.instanceId - }, - accessibilityProvider: { - getAriaLabel: e => e?.title, - getWidgetAriaLabel: () => localize('terminal.tabs', "Terminal tabs") - }, - styleController: id => new DefaultStyleController(DOM.createStyleSheet(container), id), - filter: undefined, - smoothScrolling: configurationService.getValue<boolean>('workbench.list.smoothScrolling'), - multipleSelectionSupport: true, - expandOnlyOnTwistieClick: true, - selectionNavigation: true, - additionalScrollHeight: TAB_HEIGHT - }, - contextKeyService, - listService, - themeService, - configurationService, - keybindingService, - accessibilityService, - ); - this._terminalService.onInstancesChanged(() => this._render()); - this._terminalService.onInstanceTitleChanged(() => this._render()); - this._terminalService.onActiveInstanceChanged(e => { - if (e) { - this.setSelection([e]); - this.reveal(e); - } - }); - - this.onMouseDblClick(async () => { - if (this.getFocus().length === 0) { - const instance = this._terminalService.createTerminal(); - this._terminalService.setActiveInstance(instance); - await instance.focusWhenReady(); - } - }); - - this.onMouseClick(e => { - // If focus mode is single click focus the element unless a multi-select in happening - const focusMode = configurationService.getValue<'singleClick' | 'doubleClick'>('terminal.integrated.tabs.focusMode'); - if (focusMode === 'singleClick') { - if (this.getSelection().length <= 1) { - e.element?.focus(true); - } - } - }); - - // Set the selection to whatever is right clicked if it is not inside the selection - this.onContextMenu(e => { - if (!e.element) { - this.setSelection([null]); - return; - } - const selection = this.getSelection(); - if (!selection || !selection.find(s => e.element === s)) { - this.setSelection([e.element]); - } - }); - - this._terminalTabsSingleSelectedContextKey = KEYBINDING_CONTEXT_TERMINAL_TABS_SINGULAR_SELECTION.bindTo(contextKeyService); - - this.onDidChangeSelection(e => { - this._terminalTabsSingleSelectedContextKey.set(e.elements.length === 1); - if (this._terminalTabsSingleSelectedContextKey) { - const instance = e.elements[0]; - if (!instance) { - return; - } - this._terminalService.setActiveInstance(instance); - } - }); - - this.onDidChangeFocus(e => { - this._terminalTabsSingleSelectedContextKey.set(e.elements.length === 1); - }); - - this.onDidOpen(async e => { - const instance = e.element; - if (!instance) { - return; - } - this._terminalService.setActiveInstance(instance); - if (!e.editorOptions.preserveFocus) { - await instance.focusWhenReady(); - } - }); - if (!this._decorationsProvider) { - this._decorationsProvider = instantiationService.createInstance(TerminalDecorationsProvider); - _decorationsService.registerDecorationsProvider(this._decorationsProvider); - } - this._terminalService.onInstancePrimaryStatusChanged(() => this._render()); - this._render(); - } - - private _render(): void { - this.setChildren(null, this._terminalService.terminalInstances.map(instance => { - return { - element: instance, - collapsed: true, - collapsible: false - }; - })); - } -} - -class TerminalTabsRenderer implements ITreeRenderer<ITerminalInstance, never, ITerminalTabEntryTemplate> { - templateId = 'terminal.tabs'; - - constructor( - private readonly _container: HTMLElement, - private readonly _labels: ResourceLabels, - private readonly _getSelection: () => (ITerminalInstance | null)[], - @IInstantiationService private readonly _instantiationService: IInstantiationService, - @ITerminalService private readonly _terminalService: ITerminalService, - @IHoverService private readonly _hoverService: IHoverService, - @IConfigurationService private readonly _configurationService: IConfigurationService, - @IKeybindingService private readonly _keybindingService: IKeybindingService, - @IListService private readonly _listService: IListService - ) { - } - - renderTemplate(container: HTMLElement): ITerminalTabEntryTemplate { - (container.parentElement!.parentElement!.querySelector('.monaco-tl-twistie')! as HTMLElement).classList.add('force-no-twistie'); - - const element = DOM.append(container, $('.terminal-tabs-entry')); - const context: { hoverActions?: IHoverAction[] } = {}; - const label = this._labels.create(element, { - supportHighlights: true, - supportDescriptionHighlights: true, - supportIcons: true, - hoverDelegate: { - delay: this._configurationService.getValue<number>('workbench.hover.delay'), - showHover: options => { - return this._hoverService.showHover({ - ...options, - actions: context.hoverActions, - hideOnHover: true - }); - } - } - }); - - const actionsContainer = DOM.append(label.element, $('.actions')); - - const actionBar = new ActionBar(actionsContainer, { - actionViewItemProvider: action => - action instanceof MenuItemAction - ? this._instantiationService.createInstance(MenuEntryActionViewItem, action) - : undefined - }); - - return { - element, - label, - actionBar, - context - }; - } - - shouldHideText(): boolean { - return this._container ? this._container.clientWidth < MIDPOINT_WIDGET_WIDTH : false; - } - - renderElement(node: ITreeNode<ITerminalInstance>, index: number, template: ITerminalTabEntryTemplate): void { - let instance = node.element; - - const tab = this._terminalService.getTabForInstance(instance); - if (!tab) { - throw new Error(`Could not find tab for instance "${instance.instanceId}"`); - } - - const hasText = !this.shouldHideText(); - template.element.classList.toggle('has-text', hasText); - - let ariaLabel: string = ''; - let prefix: string = ''; - if (tab.terminalInstances.length > 1) { - const terminalIndex = tab.terminalInstances.indexOf(instance); - ariaLabel = localize({ - key: 'splitTerminalAriaLabel', - comment: [ - `The terminal's ID`, - `The terminal's title`, - `The terminal's split number`, - `The terminal group's total split number` - ] - }, "Terminal {0} {1}, split {2} of {3}", instance.instanceId, instance.title, terminalIndex + 1, tab.terminalInstances.length); - if (terminalIndex === 0) { - prefix = `┌ `; - } else if (terminalIndex === tab!.terminalInstances.length - 1) { - prefix = `└ `; - } else { - prefix = `├ `; - } - } else { - ariaLabel = localize({ - key: 'terminalAriaLabel', - comment: [ - `The terminal's ID`, - `The terminal's title` - ] - }, "Terminal {0} {1}", instance.instanceId, instance.title); - } - - let title = instance.title; - const statuses = instance.statusList.statuses; - template.context.hoverActions = []; - for (const status of statuses) { - title += `\n\n---\n\n${status.tooltip || status.id}`; - if (status.hoverActions) { - template.context.hoverActions.push(...status.hoverActions); - } - } - - let label: string; - if (!hasText) { - template.actionBar.clear(); - const primaryStatus = instance.statusList.primary; - if (primaryStatus && primaryStatus.severity >= Severity.Warning) { - label = `${prefix}$(${primaryStatus.icon?.id || instance.icon?.id})`; - ariaLabel = ''; - } else { - label = `${prefix}$(${instance.icon?.id})`; - } - } else { - this.fillActionBar(instance, template); - label = `${prefix}$(${instance.icon?.id})`; - // Only add the title if the icon is set, this prevents the title jumping around for - // example when launching with a ShellLaunchConfig.name and no icon - if (instance.icon) { - label += ` ${instance.title}`; - } - } - - if (!template.elementDispoables) { - template.elementDispoables = new DisposableStore(); - } - - // Kill terminal on middle click - template.elementDispoables.add(DOM.addDisposableListener(template.element, DOM.EventType.AUXCLICK, e => { - if (e.button === 1/*middle*/) { - instance.dispose(); - } - })); - - // Set aria lable to expose split information to screen reader - template.label.element.querySelector('.label-name')?.setAttribute('aria-label', ariaLabel); - - template.label.setResource({ - resource: instance.resource, - name: label, - description: hasText ? instance.shellLaunchConfig.description : undefined - }, { - fileDecorations: { - colors: true, - badges: hasText - }, - title: { - markdown: new MarkdownString(title), - markdownNotSupportedFallback: undefined - } - }); - } - - disposeElement(element: ITreeNode<ITerminalInstance, any>, index: number, templateData: ITerminalTabEntryTemplate): void { - templateData.elementDispoables?.dispose(); - templateData.elementDispoables = undefined; - } - - disposeTemplate(templateData: ITerminalTabEntryTemplate): void { - } - - fillActionBar(instance: ITerminalInstance, template: ITerminalTabEntryTemplate): void { - // If the instance is within the selection, split all selected - const actions = [ - new Action(TERMINAL_COMMAND_ID.SPLIT_INSTANCE, localize('terminal.split', "Split"), ThemeIcon.asClassName(Codicon.splitHorizontal), true, async () => { - this._runForSelectionOrInstance(instance, e => this._terminalService.splitInstance(e)); - }), - new Action(TERMINAL_COMMAND_ID.KILL_INSTANCE, localize('terminal.kill', "Kill"), ThemeIcon.asClassName(Codicon.trashcan), true, async () => { - this._runForSelectionOrInstance(instance, e => e.dispose()); - }) - ]; - // TODO: Cache these in a way that will use the correct instance - template.actionBar.clear(); - for (const action of actions) { - template.actionBar.push(action, { icon: true, label: false, keybinding: this._keybindingService.lookupKeybinding(action.id)?.getLabel() }); - } - } - - private _runForSelectionOrInstance(instance: ITerminalInstance, callback: (instance: ITerminalInstance) => void) { - const selection = this._getSelection(); - if (selection.includes(instance)) { - for (const s of selection) { - if (s) { - callback(s); - } - } - } else { - callback(instance); - } - this._terminalService.focusTabs(); - this._listService.lastFocusedList?.focusNext(); - } -} - -interface ITerminalTabEntryTemplate { - element: HTMLElement; - label: IResourceLabel; - actionBar: ActionBar; - context: { - hoverActions?: IHoverAction[]; - }; - elementDispoables?: DisposableStore; -} diff --git a/lib/vscode/src/vs/workbench/contrib/terminal/common/terminalMenu.ts b/lib/vscode/src/vs/workbench/contrib/terminal/common/terminalMenu.ts deleted file mode 100644 index 50f5c02979d4..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/terminal/common/terminalMenu.ts +++ /dev/null @@ -1,54 +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 { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; -import { KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal'; -import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; - -export function setupTerminalMenu() { - - // Manage - const createGroup = '1_create'; - MenuRegistry.appendMenuItem(MenuId.MenubarTerminalMenu, { - group: createGroup, - command: { - id: TERMINAL_COMMAND_ID.NEW, - title: nls.localize({ key: 'miNewTerminal', comment: ['&& denotes a mnemonic'] }, "&&New Terminal") - }, - order: 1 - }); - MenuRegistry.appendMenuItem(MenuId.MenubarTerminalMenu, { - group: createGroup, - command: { - id: TERMINAL_COMMAND_ID.SPLIT, - title: nls.localize({ key: 'miSplitTerminal', comment: ['&& denotes a mnemonic'] }, "&&Split Terminal"), - precondition: ContextKeyExpr.has('terminalIsOpen') - }, - order: 2, - when: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED - }); - - // Run - const runGroup = '2_run'; - MenuRegistry.appendMenuItem(MenuId.MenubarTerminalMenu, { - group: runGroup, - command: { - id: TERMINAL_COMMAND_ID.RUN_ACTIVE_FILE, - title: nls.localize({ key: 'miRunActiveFile', comment: ['&& denotes a mnemonic'] }, "Run &&Active File") - }, - order: 3, - when: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED - }); - MenuRegistry.appendMenuItem(MenuId.MenubarTerminalMenu, { - group: runGroup, - command: { - id: TERMINAL_COMMAND_ID.RUN_SELECTED_TEXT, - title: nls.localize({ key: 'miRunSelectedText', comment: ['&& denotes a mnemonic'] }, "Run &&Selected Text") - }, - order: 4, - when: KEYBINDING_CONTEXT_TERMINAL_PROCESS_SUPPORTED - }); -} diff --git a/lib/vscode/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts b/lib/vscode/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts deleted file mode 100644 index 6f6943b6e23a..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts +++ /dev/null @@ -1,34 +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 { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; -import { TerminalInstanceService } from 'vs/workbench/contrib/terminal/electron-browser/terminalInstanceService'; -import { TerminalNativeContribution } from 'vs/workbench/contrib/terminal/electron-browser/terminalNativeContribution'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { getTerminalShellConfiguration } from 'vs/workbench/contrib/terminal/common/terminalConfiguration'; -import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { getSystemShell } from 'vs/base/node/shell'; -import { process } from 'vs/base/parts/sandbox/electron-sandbox/globals'; -import { OperatingSystem } from 'vs/base/common/platform'; -import { ElectronTerminalProfileResolverService } from 'vs/workbench/contrib/terminal/electron-sandbox/terminalProfileResolverService'; -import { ITerminalProfileResolverService } from 'vs/workbench/contrib/terminal/common/terminal'; - -// This file contains additional desktop-only contributions on top of those in browser/ - -// Register services -registerSingleton(ITerminalInstanceService, TerminalInstanceService, true); -registerSingleton(ITerminalProfileResolverService, ElectronTerminalProfileResolverService, true); - -const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(TerminalNativeContribution, LifecyclePhase.Ready); - -// Register configurations -const configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration); - -const systemShell = async (os: OperatingSystem) => getSystemShell(os, await process.shellEnv()); -getTerminalShellConfiguration(systemShell).then(config => configurationRegistry.registerConfiguration(config)); diff --git a/lib/vscode/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts b/lib/vscode/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts deleted file mode 100644 index 3c47b5eaf5e1..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts +++ /dev/null @@ -1,60 +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 { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { IProcessEnvironment } from 'vs/base/common/platform'; -import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment'; -import type { Terminal as XTermTerminal } from 'xterm'; -import type { SearchAddon as XTermSearchAddon } from 'xterm-addon-search'; -import type { Unicode11Addon as XTermUnicode11Addon } from 'xterm-addon-unicode11'; -import type { WebglAddon as XTermWebglAddon } from 'xterm-addon-webgl'; -import { IShellEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/shellEnvironmentService'; - -let Terminal: typeof XTermTerminal; -let SearchAddon: typeof XTermSearchAddon; -let Unicode11Addon: typeof XTermUnicode11Addon; -let WebglAddon: typeof XTermWebglAddon; - -export class TerminalInstanceService extends Disposable implements ITerminalInstanceService { - public _serviceBrand: undefined; - - constructor( - @IShellEnvironmentService private readonly _shellEnvironmentService: IShellEnvironmentService - ) { - super(); - } - - public async getXtermConstructor(): Promise<typeof XTermTerminal> { - if (!Terminal) { - Terminal = (await import('xterm')).Terminal; - } - return Terminal; - } - - public async getXtermSearchConstructor(): Promise<typeof XTermSearchAddon> { - if (!SearchAddon) { - SearchAddon = (await import('xterm-addon-search')).SearchAddon; - } - return SearchAddon; - } - - public async getXtermUnicode11Constructor(): Promise<typeof XTermUnicode11Addon> { - if (!Unicode11Addon) { - Unicode11Addon = (await import('xterm-addon-unicode11')).Unicode11Addon; - } - return Unicode11Addon; - } - - public async getXtermWebglConstructor(): Promise<typeof XTermWebglAddon> { - if (!WebglAddon) { - WebglAddon = (await import('xterm-addon-webgl')).WebglAddon; - } - return WebglAddon; - } - - public async getMainProcessParentEnv(): Promise<IProcessEnvironment> { - return getMainProcessParentEnv(await this._shellEnvironmentService.getShellEnv()); - } -} diff --git a/lib/vscode/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeContribution.ts b/lib/vscode/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeContribution.ts deleted file mode 100644 index 3c7442aed9d8..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeContribution.ts +++ /dev/null @@ -1,54 +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 { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; -import { execFile } from 'child_process'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { getWindowsBuildNumber } from 'vs/platform/terminal/node/terminalEnvironment'; -import { linuxDistro } from 'vs/workbench/contrib/terminal/node/terminal'; - -export class TerminalNativeContribution extends Disposable implements IWorkbenchContribution { - public _serviceBrand: undefined; - - constructor( - @ITerminalService private readonly _terminalService: ITerminalService, - @IInstantiationService readonly instantiationService: IInstantiationService, - @IRemoteAgentService readonly remoteAgentService: IRemoteAgentService, - @INativeHostService readonly nativeHostService: INativeHostService - ) { - super(); - - this._terminalService.setLinuxDistro(linuxDistro); - this._terminalService.setNativeWindowsDelegate({ - getWslPath: this._getWslPath.bind(this), - getWindowsBuildNumber: this._getWindowsBuildNumber.bind(this) - }); - } - - /** - * Converts a path to a path on WSL using the wslpath utility. - * @param path The original path. - */ - private _getWslPath(path: string): Promise<string> { - if (getWindowsBuildNumber() < 17063) { - throw new Error('wslpath does not exist on Windows build < 17063'); - } - return new Promise<string>(c => { - const proc = execFile('bash.exe', ['-c', `wslpath ${escapeNonWindowsPath(path)}`], {}, (error, stdout, stderr) => { - c(escapeNonWindowsPath(stdout.trim())); - }); - proc.stdin!.end(); - }); - } - - private _getWindowsBuildNumber(): number { - return getWindowsBuildNumber(); - } -} diff --git a/lib/vscode/src/vs/workbench/contrib/terminal/node/terminal.ts b/lib/vscode/src/vs/workbench/contrib/terminal/node/terminal.ts deleted file mode 100644 index adb21019594f..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/terminal/node/terminal.ts +++ /dev/null @@ -1,28 +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 fs from 'fs'; -import { isLinux } from 'vs/base/common/platform'; -import { SymlinkSupport } from 'vs/base/node/pfs'; -import { LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal'; - -let detectedDistro = LinuxDistro.Unknown; -if (isLinux) { - const file = '/etc/os-release'; - SymlinkSupport.existsFile(file).then(async exists => { - if (!exists) { - return; - } - const buffer = await fs.promises.readFile(file); - const contents = buffer.toString(); - if (/NAME="?Fedora"?/.test(contents)) { - detectedDistro = LinuxDistro.Fedora; - } else if (/NAME="?Ubuntu"?/.test(contents)) { - detectedDistro = LinuxDistro.Ubuntu; - } - }); -} - -export const linuxDistro = detectedDistro; diff --git a/lib/vscode/src/vs/workbench/contrib/terminal/node/terminalEnvironment.ts b/lib/vscode/src/vs/workbench/contrib/terminal/node/terminalEnvironment.ts deleted file mode 100644 index 988b9aed510e..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/terminal/node/terminalEnvironment.ts +++ /dev/null @@ -1,79 +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 fs from 'fs'; -import * as path from 'vs/base/common/path'; -import { IProcessEnvironment, isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; - -let mainProcessParentEnv: IProcessEnvironment | undefined; - -export async function getMainProcessParentEnv(baseEnvironment: IProcessEnvironment): Promise<IProcessEnvironment> { - if (mainProcessParentEnv) { - return mainProcessParentEnv; - } - - // For Linux use /proc/<pid>/status to get the parent of the main process and then fetch its - // env using /proc/<pid>/environ. - if (isLinux) { - const mainProcessId = process.ppid; - const codeProcessName = path.basename(process.argv[0]); - let pid: number = 0; - let ppid: number = mainProcessId; - let name: string = codeProcessName; - do { - pid = ppid; - const status = await fs.promises.readFile(`/proc/${pid}/status`, 'utf8'); - const splitByLine = status.split('\n'); - splitByLine.forEach(line => { - if (line.indexOf('Name:') === 0) { - name = line.replace(/^Name:\s+/, ''); - } - if (line.indexOf('PPid:') === 0) { - ppid = parseInt(line.replace(/^PPid:\s+/, '')); - } - }); - } while (name === codeProcessName); - const rawEnv = await fs.promises.readFile(`/proc/${pid}/environ`, 'utf8'); - const env: IProcessEnvironment = {}; - rawEnv.split('\0').forEach(e => { - const i = e.indexOf('='); - env[e.substr(0, i)] = e.substr(i + 1); - }); - mainProcessParentEnv = env; - } - - // For macOS we want the "root" environment as shells by default run as login shells. It - // doesn't appear to be possible to get the "root" environment as `ps eww -o command` for - // PID 1 (the parent of the main process when launched from the dock/finder) returns no - // environment, because of this we will fill in the root environment using a allowlist of - // environment variables that we have. - if (isMacintosh) { - mainProcessParentEnv = {}; - // This list was generated by diffing launching a terminal with {} and the system - // terminal launched from finder. - const rootEnvVars = [ - 'SHELL', - 'SSH_AUTH_SOCK', - 'Apple_PubSub_Socket_Render', - 'XPC_FLAGS', - 'XPC_SERVICE_NAME', - 'HOME', - 'LOGNAME', - 'TMPDIR' - ]; - rootEnvVars.forEach(k => { - if (baseEnvironment[k]) { - mainProcessParentEnv![k] = baseEnvironment[k]!; - } - }); - } - - // TODO: Windows should return a fresh environment block, might need native code? - if (isWindows) { - mainProcessParentEnv = baseEnvironment; - } - - return mainProcessParentEnv!; -} diff --git a/lib/vscode/src/vs/workbench/contrib/terminal/node/terminalProfiles.ts b/lib/vscode/src/vs/workbench/contrib/terminal/node/terminalProfiles.ts deleted file mode 100644 index 305d5aaf67c5..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/terminal/node/terminalProfiles.ts +++ /dev/null @@ -1,318 +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 fs from 'fs'; -import { normalize, basename, delimiter } from 'vs/base/common/path'; -import { enumeratePowerShellInstallations } from 'vs/base/node/powershell'; -import { findExecutable, getWindowsBuildNumber } from 'vs/platform/terminal/node/terminalEnvironment'; -import { ITerminalProfile, ITerminalProfileObject, ProfileSource } from 'vs/workbench/contrib/terminal/common/terminal'; -import * as cp from 'child_process'; -import { ExtHostVariableResolverService } from 'vs/workbench/api/common/extHostDebugService'; -import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { ILogService } from 'vs/platform/log/common/log'; -import * as pfs from 'vs/base/node/pfs'; -import { ITerminalEnvironment, SafeConfigProvider } from 'vs/platform/terminal/common/terminal'; -import { Codicon } from 'vs/base/common/codicons'; -import { isMacintosh, isWindows } from 'vs/base/common/platform'; - -let profileSources: Map<string, IPotentialTerminalProfile> | undefined; - -export function detectAvailableProfiles(configuredProfilesOnly: boolean, safeConfigProvider: SafeConfigProvider, fsProvider?: IFsProvider, logService?: ILogService, variableResolver?: ExtHostVariableResolverService, workspaceFolder?: IWorkspaceFolder, testPaths?: string[]): Promise<ITerminalProfile[]> { - fsProvider = fsProvider || { - existsFile: pfs.SymlinkSupport.existsFile, - readFile: fs.promises.readFile - }; - if (isWindows) { - return detectAvailableWindowsProfiles( - configuredProfilesOnly, - fsProvider, - logService, - safeConfigProvider('terminal.integrated.useWslProfiles') || true, - safeConfigProvider('terminal.integrated.profiles.windows'), - variableResolver, - workspaceFolder - ); - } - return detectAvailableUnixProfiles( - fsProvider, - logService, - configuredProfilesOnly, - safeConfigProvider(`terminal.integrated.profiles.${isMacintosh ? 'osx' : 'linux'}`), - testPaths, - variableResolver, - workspaceFolder - ); -} - -async function detectAvailableWindowsProfiles(configuredProfilesOnly: boolean, fsProvider: IFsProvider, logService?: ILogService, useWslProfiles?: boolean, configProfiles?: { [key: string]: ITerminalProfileObject }, variableResolver?: ExtHostVariableResolverService, workspaceFolder?: IWorkspaceFolder): Promise<ITerminalProfile[]> { - // Determine the correct System32 path. We want to point to Sysnative - // when the 32-bit version of VS Code is running on a 64-bit machine. - // The reason for this is because PowerShell's important PSReadline - // module doesn't work if this is not the case. See #27915. - const is32ProcessOn64Windows = process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'); - const system32Path = `${process.env['windir']}\\${is32ProcessOn64Windows ? 'Sysnative' : 'System32'}`; - - let useWSLexe = false; - - if (getWindowsBuildNumber() >= 16299) { - useWSLexe = true; - } - - await initializeWindowsProfiles(); - - const detectedProfiles: Map<string, ITerminalProfileObject> = new Map(); - - // Add auto detected profiles - if (!configuredProfilesOnly) { - detectedProfiles.set('PowerShell', { - source: ProfileSource.Pwsh, - icon: Codicon.terminalPowershell.id, - isAutoDetected: true - }); - detectedProfiles.set('Windows PowerShell', { - path: `${system32Path}\\WindowsPowerShell\\v1.0\\powershell.exe`, - icon: Codicon.terminalPowershell.id, - isAutoDetected: true - }); - detectedProfiles.set('Git Bash', { source: ProfileSource.GitBash, isAutoDetected: true }); - detectedProfiles.set('Cygwin', { - path: [ - `${process.env['HOMEDRIVE']}\\cygwin64\\bin\\bash.exe`, - `${process.env['HOMEDRIVE']}\\cygwin\\bin\\bash.exe` - ], - args: ['--login'], - isAutoDetected: true - }); - detectedProfiles.set('Command Prompt', - { - path: `${system32Path}\\cmd.exe`, - icon: Codicon.terminalCmd.id, - isAutoDetected: true - }, - ); - } - - applyConfigProfilesToMap(configProfiles, detectedProfiles); - - const resultProfiles: ITerminalProfile[] = await transformToTerminalProfiles(detectedProfiles.entries(), fsProvider, logService, variableResolver, workspaceFolder); - - if (!configuredProfilesOnly || (configuredProfilesOnly && useWslProfiles)) { - try { - const result = await getWslProfiles(`${system32Path}\\${useWSLexe ? 'wsl.exe' : 'bash.exe'}`, useWslProfiles); - if (result) { - resultProfiles.push(...result); - } - } catch (e) { - logService?.info('WSL is not installed, so could not detect WSL profiles'); - } - } - - return resultProfiles; -} - -async function transformToTerminalProfiles(entries: IterableIterator<[string, ITerminalProfileObject]>, fsProvider: IFsProvider, logService?: ILogService, variableResolver?: ExtHostVariableResolverService, workspaceFolder?: IWorkspaceFolder): Promise<ITerminalProfile[]> { - const resultProfiles: ITerminalProfile[] = []; - for (const [profileName, profile] of entries) { - if (profile === null) { continue; } - let originalPaths: string[]; - let args: string[] | string | undefined; - let icon: string | undefined; - if ('source' in profile) { - const source = profileSources?.get(profile.source); - if (!source) { - continue; - } - originalPaths = source.paths; - - // if there are configured args, override the default ones - args = profile.args || source.args; - icon = profile.icon || source.icon; - } else { - originalPaths = Array.isArray(profile.path) ? profile.path : [profile.path]; - args = isWindows ? profile.args : Array.isArray(profile.args) ? profile.args : undefined; - icon = profile.icon; - } - - const paths = originalPaths.slice(); - - for (let i = 0; i < paths.length; i++) { - paths[i] = await variableResolver?.resolveAsync(workspaceFolder, paths[i]) || paths[i]; - } - const validatedProfile = await validateProfilePaths(profileName, paths, fsProvider, args, profile.env, profile.overrideName, profile.isAutoDetected, logService); - if (validatedProfile) { - validatedProfile.isAutoDetected = profile.isAutoDetected; - validatedProfile.icon = icon; - resultProfiles.push(validatedProfile); - } else { - logService?.trace('profile not validated', profileName, originalPaths); - } - } - return resultProfiles; -} - -async function initializeWindowsProfiles(): Promise<void> { - if (profileSources) { - return; - } - - profileSources = new Map(); - profileSources.set( - 'Git Bash', { - profileName: 'Git Bash', - paths: [ - `${process.env['ProgramW6432']}\\Git\\bin\\bash.exe`, - `${process.env['ProgramW6432']}\\Git\\usr\\bin\\bash.exe`, - `${process.env['ProgramFiles']}\\Git\\bin\\bash.exe`, - `${process.env['ProgramFiles']}\\Git\\usr\\bin\\bash.exe`, - `${process.env['LocalAppData']}\\Programs\\Git\\bin\\bash.exe` - ], - args: ['--login'] - }); - profileSources.set('PowerShell', { - profileName: 'PowerShell', - paths: await getPowershellPaths(), - icon: 'terminal-powershell' - }); -} - -async function getPowershellPaths(): Promise<string[]> { - const paths: string[] = []; - // Add all of the different kinds of PowerShells - for await (const pwshExe of enumeratePowerShellInstallations()) { - paths.push(pwshExe.exePath); - } - return paths; -} - -async function getWslProfiles(wslPath: string, useWslProfiles?: boolean): Promise<ITerminalProfile[]> { - const profiles: ITerminalProfile[] = []; - if (useWslProfiles) { - const distroOutput = await new Promise<string>((resolve, reject) => { - // wsl.exe output is encoded in utf16le (ie. A -> 0x4100) - cp.exec('wsl.exe -l -q', { encoding: 'utf16le' }, (err, stdout) => { - if (err) { - return reject('Problem occurred when getting wsl distros'); - } - resolve(stdout); - }); - }); - if (distroOutput) { - const regex = new RegExp(/[\r?\n]/); - const distroNames = distroOutput.split(regex).filter(t => t.trim().length > 0 && t !== ''); - for (let distroName of distroNames) { - // Skip empty lines - if (distroName === '') { - continue; - } - - // docker-desktop and docker-desktop-data are treated as implementation details of - // Docker Desktop for Windows and therefore not exposed - if (distroName.startsWith('docker-desktop')) { - continue; - } - - // Create the profile, adding the icon depending on the distro - const profile: ITerminalProfile = { - profileName: `${distroName} (WSL)`, - path: wslPath, - args: [`-d`, `${distroName}`] - }; - if (distroName.includes('Ubuntu')) { - profile.icon = 'terminal-ubuntu'; - } - else if (distroName.includes('Debian')) { - profile.icon = 'terminal-debian'; - } else { - profile.icon = 'terminal-linux'; - } - - // Add the profile - profiles.push(profile); - } - return profiles; - } - } - return []; -} - -async function detectAvailableUnixProfiles(fsProvider: IFsProvider, logService?: ILogService, configuredProfilesOnly?: boolean, configProfiles?: { [key: string]: ITerminalProfileObject }, testPaths?: string[], variableResolver?: ExtHostVariableResolverService, workspaceFolder?: IWorkspaceFolder): Promise<ITerminalProfile[]> { - const detectedProfiles: Map<string, ITerminalProfileObject> = new Map(); - - // Add non-quick launch profiles - if (!configuredProfilesOnly) { - const contents = await fsProvider.readFile('/etc/shells', 'utf8'); - const profiles = testPaths || contents.split('\n').filter(e => e.trim().indexOf('#') !== 0 && e.trim().length > 0); - const counts: Map<string, number> = new Map(); - for (const profile of profiles) { - let profileName = basename(profile); - let count = counts.get(profileName) || 0; - count++; - if (count > 1) { - profileName = `${profileName} (${count})`; - } - counts.set(profileName, count); - detectedProfiles.set(profileName, { path: profile, isAutoDetected: true }); - } - } - - applyConfigProfilesToMap(configProfiles, detectedProfiles); - - return await transformToTerminalProfiles(detectedProfiles.entries(), fsProvider, logService, variableResolver, workspaceFolder); -} - -function applyConfigProfilesToMap(configProfiles: { [key: string]: ITerminalProfileObject } | undefined, profilesMap: Map<string, ITerminalProfileObject>) { - if (!configProfiles) { - return; - } - for (const [profileName, value] of Object.entries(configProfiles)) { - if (value === null || (!('path' in value) && !('source' in value))) { - profilesMap.delete(profileName); - } else { - profilesMap.set(profileName, value); - } - } -} - -async function validateProfilePaths(profileName: string, potentialPaths: string[], fsProvider: IFsProvider, args?: string[] | string, env?: ITerminalEnvironment, overrideName?: boolean, isAutoDetected?: boolean, logService?: ILogService): Promise<ITerminalProfile | undefined> { - if (potentialPaths.length === 0) { - return Promise.resolve(undefined); - } - const path = potentialPaths.shift()!; - if (path === '') { - return validateProfilePaths(profileName, potentialPaths, fsProvider, args, env, overrideName, isAutoDetected); - } - - const profile: ITerminalProfile = { profileName, path, args, env, overrideName, isAutoDetected }; - - // For non-absolute paths, check if it's available on $PATH - if (basename(path) === path) { - // The executable isn't an absolute path, try find it on the PATH - const envPaths: string[] | undefined = process.env.PATH ? process.env.PATH.split(delimiter) : undefined; - const executable = await findExecutable(path, undefined, envPaths, undefined, fsProvider.existsFile); - if (!executable) { - return validateProfilePaths(profileName, potentialPaths, fsProvider, args); - } - return profile; - } - - const result = await fsProvider.existsFile(normalize(path)); - if (result) { - return profile; - } - - return validateProfilePaths(profileName, potentialPaths, fsProvider, args, env, overrideName, isAutoDetected); -} - -export interface IFsProvider { - existsFile(path: string): Promise<boolean>, - readFile(path: string, options: { encoding: BufferEncoding, flag?: string | number } | BufferEncoding): Promise<string>; -} - -interface IPotentialTerminalProfile { - profileName: string; - paths: string[]; - args?: string[]; - icon?: string; -} diff --git a/lib/vscode/src/vs/workbench/contrib/testing/browser/explorerProjections/locationStore.ts b/lib/vscode/src/vs/workbench/contrib/testing/browser/explorerProjections/locationStore.ts deleted file mode 100644 index f604a164eec4..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/testing/browser/explorerProjections/locationStore.ts +++ /dev/null @@ -1,76 +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 { findFirstInSorted } from 'vs/base/common/arrays'; -import { URI } from 'vs/base/common/uri'; -import { Position } from 'vs/editor/common/core/position'; -import { Range } from 'vs/editor/common/core/range'; -import { IRichLocation } from 'vs/workbench/contrib/testing/common/testCollection'; - -export const locationsEqual = (a: IRichLocation | undefined, b: IRichLocation | undefined) => { - if (a === undefined || b === undefined) { - return b === a; - } - - return a.uri.toString() === b.uri.toString() && a.range.equalsRange(b.range); -}; - -/** - * Stores and looks up test-item-like-objects by their uri/range. Used to - * implement the 'reveal' action efficiently. - */ -export class TestLocationStore<T extends { location?: IRichLocation, depth: number }> { - private readonly itemsByUri = new Map<string, T[]>(); - - public hasTestInDocument(uri: URI) { - return !!this.itemsByUri.get(uri.toString())?.length; - } - - public getTestAtPosition(uri: URI, position: Position) { - const tests = this.itemsByUri.get(uri.toString()); - if (!tests) { - return; - } - - return tests.find(test => { - const range = test.location?.range; - return range && Range.lift(range).containsPosition(position); - }); - } - - public remove(item: T, fromLocation = item.location) { - if (!fromLocation) { - return; - } - - const key = fromLocation.uri.toString(); - const arr = this.itemsByUri.get(key); - if (!arr) { - return; - } - - for (let i = 0; i < arr.length; i++) { - if (arr[i] === item) { - arr.splice(i, 1); - return; - } - } - } - - public add(item: T) { - if (!item.location) { - return; - } - - const key = item.location.uri.toString(); - const arr = this.itemsByUri.get(key); - if (!arr) { - this.itemsByUri.set(key, [item]); - return; - } - - arr.splice(findFirstInSorted(arr, x => x.depth < item.depth), 0, item); - } -} diff --git a/lib/vscode/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts b/lib/vscode/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts deleted file mode 100644 index e6b54d9e2c0f..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts +++ /dev/null @@ -1,557 +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 dom from 'vs/base/browser/dom'; -import { alert } from 'vs/base/browser/ui/aria/aria'; -import { Codicon } from 'vs/base/common/codicons'; -import { Color } from 'vs/base/common/color'; -import { KeyCode } from 'vs/base/common/keyCodes'; -import { Disposable, IReference, MutableDisposable } from 'vs/base/common/lifecycle'; -import { clamp } from 'vs/base/common/numbers'; -import { count } from 'vs/base/common/strings'; -import { URI } from 'vs/base/common/uri'; -import { ICodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser'; -import { EditorAction2 } from 'vs/editor/browser/editorExtensions'; -import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { EmbeddedCodeEditorWidget, EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; -import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; -import { IEditorContribution } from 'vs/editor/common/editorCommon'; -import { IResolvedTextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; -import { getOuterEditor, IPeekViewService, peekViewTitleBackground, peekViewTitleForeground, peekViewTitleInfoForeground, PeekViewWidget } from 'vs/editor/contrib/peekView/peekView'; -import { localize } from 'vs/nls'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ContextKeyExpr, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; -import { createDecorator, IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService'; -import { EditorModel } from 'vs/workbench/common/editor'; -import { testingPeekBorder } from 'vs/workbench/contrib/testing/browser/theme'; -import { AutoOpenPeekViewWhen, getTestingConfiguration, TestingConfigKeys } from 'vs/workbench/contrib/testing/common/configuration'; -import { Testing } from 'vs/workbench/contrib/testing/common/constants'; -import { ITestItem, ITestMessage, TestResultItem } from 'vs/workbench/contrib/testing/common/testCollection'; -import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys'; -import { isFailedState } from 'vs/workbench/contrib/testing/common/testingStates'; -import { buildTestUri, parseTestUri, TestUriType } from 'vs/workbench/contrib/testing/common/testingUri'; -import { ITestResult, TestResultItemChange, TestResultItemChangeReason } from 'vs/workbench/contrib/testing/common/testResult'; -import { ITestResultService, ResultChangeEvent } from 'vs/workbench/contrib/testing/common/testResultService'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; - -interface ITestDto { - test: ITestItem, - messageIndex: number; - messages: ITestMessage[]; - expectedUri: URI; - actualUri: URI; - messageUri: URI; -} - -export interface ITestingPeekOpener { - _serviceBrand: undefined; - - /** - * Tries to peek the first test error, if the item is in a failed state. - * @returns a boolean indicating whether a peek was opened - */ - tryPeekFirstError(result: ITestResult, test: TestResultItem, options?: Partial<ITextEditorOptions>): Promise<boolean>; -} - -export const ITestingPeekOpener = createDecorator<ITestingPeekOpener>('testingPeekOpener'); - -export class TestingPeekOpener extends Disposable implements ITestingPeekOpener { - declare _serviceBrand: undefined; - - constructor( - @IConfigurationService private readonly configuration: IConfigurationService, - @IEditorService private readonly editorService: IEditorService, - @ICodeEditorService private readonly codeEditorService: ICodeEditorService, - @ITestResultService testResults: ITestResultService, - ) { - super(); - this._register(testResults.onTestChanged(this.openPeekOnFailure, this)); - } - - /** - * Tries to peek the first test error, if the item is in a failed state. - * @returns a boolean if a peek was opened - */ - public async tryPeekFirstError(result: ITestResult, test: TestResultItem, options?: Partial<ITextEditorOptions>) { - const candidate = this.getCandidateMessage(test); - if (!candidate) { - return false; - } - - const message = candidate.message; - const pane = await this.editorService.openEditor({ - resource: message.location!.uri, - options: { selection: message.location!.range, revealIfOpened: true, ...options } - }); - - const control = pane?.getControl(); - if (!isCodeEditor(control)) { - return false; - } - - TestingOutputPeekController.get(control).show(buildTestUri({ - type: TestUriType.ResultMessage, - taskIndex: candidate.taskId, - messageIndex: candidate.index, - resultId: result.id, - testExtId: test.item.extId, - })); - - return true; - } - - /** - * Opens the peek view on a test failure, based on user preferences. - */ - private openPeekOnFailure(evt: TestResultItemChange) { - if (evt.reason !== TestResultItemChangeReason.OwnStateChange) { - return; - } - - const candidate = this.getCandidateMessage(evt.item); - if (!candidate) { - return; - } - - if (evt.result.isAutoRun && !getTestingConfiguration(this.configuration, TestingConfigKeys.AutoOpenPeekViewDuringAutoRun)) { - return; - } - - const editors = this.codeEditorService.listCodeEditors(); - const cfg = getTestingConfiguration(this.configuration, TestingConfigKeys.AutoOpenPeekView); - - // don't show the peek if the user asked to only auto-open peeks for visible tests, - // and this test is not in any of the editors' models. - const testUri = evt.item.item.uri.toString(); - if (cfg === AutoOpenPeekViewWhen.FailureVisible && (!testUri || !editors.some(e => e.getModel()?.uri.toString() === testUri))) { - return; - } - - const controllers = editors.map(TestingOutputPeekController.get); - if (controllers.some(c => c?.isVisible)) { - return; - } - - this.tryPeekFirstError(evt.result, evt.item); - } - - private getCandidateMessage(test: TestResultItem) { - for (let taskId = 0; taskId < test.tasks.length; taskId++) { - const { messages, state } = test.tasks[taskId]; - if (!isFailedState(state)) { - continue; - } - - const index = messages.findIndex(m => !!m.location); - if (index === -1) { - continue; - } - - return { taskId, index, message: messages[index] }; - } - - return undefined; - } -} - -/** - * Adds output/message peek functionality to code editors. - */ -export class TestingOutputPeekController extends Disposable implements IEditorContribution { - /** - * Gets the controller associated with the given code editor. - */ - public static get(editor: ICodeEditor): TestingOutputPeekController { - return editor.getContribution<TestingOutputPeekController>(Testing.OutputPeekContributionId); - } - - /** - * Currently-shown peek view. - */ - private readonly peek = this._register(new MutableDisposable<TestingOutputPeek>()); - - /** - * URI of the currently-visible peek, if any. - */ - private currentPeekUri: URI | undefined; - - /** - * Context key updated when the peek is visible/hidden. - */ - private readonly visible: IContextKey<boolean>; - - /** - * Gets whether a peek is currently shown in the associated editor. - */ - public get isVisible() { - return this.peek.value; - } - - constructor( - private readonly editor: ICodeEditor, - @IInstantiationService private readonly instantiationService: IInstantiationService, - @ITestResultService private readonly testResults: ITestResultService, - @IContextKeyService contextKeyService: IContextKeyService, - ) { - super(); - this.visible = TestingContextKeys.isPeekVisible.bindTo(contextKeyService); - this._register(editor.onDidChangeModel(() => this.peek.clear())); - this._register(testResults.onResultsChanged(this.closePeekOnRunStart, this)); - this._register(testResults.onTestChanged(this.closePeekOnTestChange, this)); - } - - /** - * Toggles peek visibility for the URI. - */ - public toggle(uri: URI) { - if (this.currentPeekUri?.toString() === uri.toString()) { - this.peek.clear(); - } else { - this.show(uri); - } - } - - /** - * Shows a peek for the message in th editor. - */ - public async show(uri: URI) { - const dto = this.retrieveTest(uri); - if (!dto) { - return; - } - - const message = dto.messages[dto.messageIndex]; - if (!message?.location) { - return; - } - - const ctor = message.actualOutput !== undefined && message.expectedOutput !== undefined - ? TestingDiffOutputPeek : TestingMessageOutputPeek; - const isNew = !(this.peek.value instanceof ctor); - if (isNew) { - this.peek.value = this.instantiationService.createInstance(ctor, this.editor); - this.peek.value.onDidClose(() => { - this.visible.set(false); - this.currentPeekUri = undefined; - this.peek.value = undefined; - }); - } - - if (isNew) { - this.visible.set(true); - this.peek.value!.create(); - } - - alert(message.message.toString()); - this.peek.value!.setModel(dto); - this.currentPeekUri = uri; - } - - /** - * Disposes the peek view, if any. - */ - public removePeek() { - this.peek.clear(); - } - - /** - * Removes the peek view if it's being displayed on the given test ID. - */ - public removeIfPeekingForTest(testId: string) { - if (this.peek.value?.currentTest()?.extId === testId) { - this.peek.clear(); - } - } - - /** - * If the test we're currently showing has its state change to something - * else, then clear the peek. - */ - private closePeekOnTestChange(evt: TestResultItemChange) { - if (evt.reason !== TestResultItemChangeReason.OwnStateChange || evt.previous === evt.item.ownComputedState) { - return; - } - - this.removeIfPeekingForTest(evt.item.item.extId); - } - - private closePeekOnRunStart(evt: ResultChangeEvent) { - if ('started' in evt) { - this.peek.clear(); - } - } - - private retrieveTest(uri: URI): ITestDto | undefined { - const parts = parseTestUri(uri); - if (!parts) { - return undefined; - } - - const test = this.testResults.getResult(parts.resultId)?.getStateById(parts.testExtId); - if (!test || !test.tasks[parts.taskIndex]) { - return; - } - - return test && { - test: test.item, - messages: test.tasks[parts.taskIndex].messages, - messageIndex: parts.messageIndex, - expectedUri: buildTestUri({ ...parts, type: TestUriType.ResultExpectedOutput }), - actualUri: buildTestUri({ ...parts, type: TestUriType.ResultActualOutput }), - messageUri: buildTestUri({ ...parts, type: TestUriType.ResultMessage }), - }; - } -} - -abstract class TestingOutputPeek extends PeekViewWidget { - protected model = new MutableDisposable(); - protected dimension?: dom.Dimension; - - constructor( - editor: ICodeEditor, - @IThemeService themeService: IThemeService, - @IPeekViewService peekViewService: IPeekViewService, - @IContextKeyService contextKeyService: IContextKeyService, - @IInstantiationService instantiationService: IInstantiationService, - @ITextModelService protected readonly modelService: ITextModelService, - ) { - super(editor, { showFrame: false, showArrow: true, isResizeable: true, isAccessible: true, className: 'test-output-peek' }, instantiationService); - - TestingContextKeys.isInPeek.bindTo(contextKeyService); - this._disposables.add(themeService.onDidColorThemeChange(this.applyTheme, this)); - this._disposables.add(this.model); - this.applyTheme(themeService.getColorTheme()); - peekViewService.addExclusiveWidget(editor, this); - } - - private applyTheme(theme: IColorTheme) { - const borderColor = theme.getColor(testingPeekBorder) || Color.transparent; - this.style({ - arrowColor: borderColor, - frameColor: borderColor, - headerBackgroundColor: theme.getColor(peekViewTitleBackground) || Color.transparent, - primaryHeadingColor: theme.getColor(peekViewTitleForeground), - secondaryHeadingColor: theme.getColor(peekViewTitleInfoForeground) - }); - } - - /** - * Updates the test to be shown. - */ - public abstract setModel(dto: ITestDto): Promise<void>; - - /** - * Returns the test whose data is currently shown in the peek view. - */ - public abstract currentTest(): ITestItem | undefined; - - /** - * @override - */ - protected override _doLayoutBody(height: number, width: number) { - super._doLayoutBody(height, width); - this.dimension = new dom.Dimension(width, height); - } -} - -const commonEditorOptions: IEditorOptions = { - scrollBeyondLastLine: false, - scrollbar: { - verticalScrollbarSize: 14, - horizontal: 'auto', - useShadows: true, - verticalHasArrows: false, - horizontalHasArrows: false, - alwaysConsumeMouseWheel: false - }, - fixedOverflowWidgets: true, - readOnly: true, - minimap: { - enabled: false - }, -}; - -const diffEditorOptions: IDiffEditorOptions = { - ...commonEditorOptions, - enableSplitViewResizing: true, - isInEmbeddedEditor: true, - renderOverviewRuler: false, - ignoreTrimWhitespace: false, - renderSideBySide: true, - originalAriaLabel: localize('testingOutputExpected', 'Expected result'), - modifiedAriaLabel: localize('testingOutputActual', 'Actual result'), -}; - -class TestingDiffOutputPeek extends TestingOutputPeek { - private readonly diff = this._disposables.add(new MutableDisposable<EmbeddedDiffEditorWidget>()); - private test: ITestItem | undefined; - - /** - * @override - */ - protected _fillBody(containerElement: HTMLElement): void { - const diffContainer = dom.append(containerElement, dom.$('div.preview.inline')); - const preview = this.diff.value = this.instantiationService.createInstance(EmbeddedDiffEditorWidget, diffContainer, diffEditorOptions, this.editor); - - if (this.dimension) { - preview.layout(this.dimension); - } - } - - /** - * @override - */ - public async setModel({ test, messages, messageIndex, expectedUri, actualUri }: ITestDto) { - const message = messages[messageIndex]; - if (!message?.location) { - return; - } - - this.test = test; - this.show(message.location.range, hintDiffPeekHeight(message)); - this.setTitle(message.message.toString().split('\n')[0], test.label); - - const [original, modified] = await Promise.all([ - this.modelService.createModelReference(expectedUri), - this.modelService.createModelReference(actualUri), - ]); - - const model = this.model.value = new SimpleDiffEditorModel(original, modified); - if (!this.diff.value) { - this.model.value = undefined; - } else { - this.diff.value.setModel(model); - } - } - - /** - * @override - */ - public currentTest() { - return this.test; - } - - /** - * @override - */ - protected override _doLayoutBody(height: number, width: number) { - super._doLayoutBody(height, width); - this.diff.value?.layout(this.dimension); - } -} - -class TestingMessageOutputPeek extends TestingOutputPeek { - private readonly preview = this._disposables.add(new MutableDisposable<EmbeddedCodeEditorWidget>()); - private test: ITestItem | undefined; - - /** - * @override - */ - protected _fillBody(containerElement: HTMLElement): void { - const diffContainer = dom.append(containerElement, dom.$('div.preview.inline')); - const preview = this.preview.value = this.instantiationService.createInstance(EmbeddedCodeEditorWidget, diffContainer, commonEditorOptions, this.editor); - - if (this.dimension) { - preview.layout(this.dimension); - } - } - - /** - * @override - */ - public async setModel({ messages, test, messageIndex, messageUri }: ITestDto) { - const message = messages[messageIndex]; - if (!message?.location) { - return; - } - - this.test = test; - this.show(message.location.range, hintPeekStrHeight(message.message.toString())); - this.setTitle(message.message.toString(), test.label); - - const modelRef = this.model.value = await this.modelService.createModelReference(messageUri); - if (this.preview.value) { - this.preview.value.setModel(modelRef.object.textEditorModel); - } else { - this.model.value = undefined; - } - } - - /** - * @override - */ - public currentTest() { - return this.test; - } - - /** - * @override - */ - protected override _doLayoutBody(height: number, width: number) { - super._doLayoutBody(height, width); - this.preview.value?.layout(this.dimension); - } -} - -const hintDiffPeekHeight = (message: ITestMessage) => - Math.max(hintPeekStrHeight(message.actualOutput), hintPeekStrHeight(message.expectedOutput)); - -const hintPeekStrHeight = (str: string | undefined) => clamp(count(str || '', '\n'), 5, 20); - -class SimpleDiffEditorModel extends EditorModel { - public readonly original = this._original.object.textEditorModel; - public readonly modified = this._modified.object.textEditorModel; - - constructor( - private readonly _original: IReference<IResolvedTextEditorModel>, - private readonly _modified: IReference<IResolvedTextEditorModel>, - ) { - super(); - } - - public override dispose() { - super.dispose(); - this._original.dispose(); - this._modified.dispose(); - } -} - -function getOuterEditorFromDiffEditor(accessor: ServicesAccessor): ICodeEditor | null { - const diffEditors = accessor.get(ICodeEditorService).listDiffEditors(); - - for (const diffEditor of diffEditors) { - if (diffEditor.hasTextFocus() && diffEditor instanceof EmbeddedDiffEditorWidget) { - return diffEditor.getParentEditor(); - } - } - - return getOuterEditor(accessor); -} - -export class CloseTestPeek extends EditorAction2 { - constructor() { - super({ - id: 'editor.closeTestPeek', - title: localize('close', 'Close'), - icon: Codicon.close, - precondition: ContextKeyExpr.and( - ContextKeyExpr.or(TestingContextKeys.isInPeek, TestingContextKeys.isPeekVisible), - ContextKeyExpr.not('config.editor.stablePeek') - ), - keybinding: { - weight: KeybindingWeight.EditorContrib - 101, - primary: KeyCode.Escape - } - }); - } - - runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor): void { - const parent = getOuterEditorFromDiffEditor(accessor); - TestingOutputPeekController.get(parent ?? editor).removePeek(); - } -} diff --git a/lib/vscode/src/vs/workbench/contrib/testing/common/getComputedState.ts b/lib/vscode/src/vs/workbench/contrib/testing/common/getComputedState.ts deleted file mode 100644 index e7400f3f7000..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/testing/common/getComputedState.ts +++ /dev/null @@ -1,84 +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 { TestResultState } from 'vs/workbench/api/common/extHostTypes'; -import { maxPriority, statePriority } from 'vs/workbench/contrib/testing/common/testingStates'; - -/** - * Accessor for nodes in get and refresh computed state. - */ -export interface IComputedStateAccessor<T> { - getOwnState(item: T): TestResultState | undefined; - getCurrentComputedState(item: T): TestResultState; - setComputedState(item: T, state: TestResultState): void; - getChildren(item: T): Iterable<T>; - getParents(item: T): Iterable<T>; -} - -/** - * Gets the computed state for the node. - * @param force whether to refresh the computed state for this node, even - * if it was previously set. - */ - -export const getComputedState = <T>(accessor: IComputedStateAccessor<T>, node: T, force = false) => { - let computed = accessor.getCurrentComputedState(node); - if (computed === undefined || force) { - computed = accessor.getOwnState(node) ?? TestResultState.Unset; - for (const child of accessor.getChildren(node)) { - computed = maxPriority(computed, getComputedState(accessor, child)); - } - - accessor.setComputedState(node, computed); - } - - return computed; -}; -/** - * Refreshes the computed state for the node and its parents. Any changes - * elements cause `addUpdated` to be called. - */ - -export const refreshComputedState = <T>( - accessor: IComputedStateAccessor<T>, - node: T, - addUpdated: (node: T) => void, - explicitNewComputedState?: TestResultState, -) => { - const oldState = accessor.getCurrentComputedState(node); - const oldPriority = statePriority[oldState]; - const newState = explicitNewComputedState ?? getComputedState(accessor, node, true); - const newPriority = statePriority[newState]; - if (newPriority === oldPriority) { - return; - } - - accessor.setComputedState(node, newState); - addUpdated(node); - - if (newPriority > oldPriority) { - // Update all parents to ensure they're at least this priority. - for (const parent of accessor.getParents(node)) { - const prev = accessor.getCurrentComputedState(parent); - if (prev !== undefined && statePriority[prev] >= newPriority) { - break; - } - - accessor.setComputedState(parent, newState); - addUpdated(parent); - } - } else if (newPriority < oldPriority) { - // Re-render all parents of this node whose computed priority might have come from this node - for (const parent of accessor.getParents(node)) { - const prev = accessor.getCurrentComputedState(parent); - if (prev === undefined || statePriority[prev] > oldPriority) { - break; - } - - accessor.setComputedState(parent, getComputedState(accessor, parent, true)); - addUpdated(parent); - } - } -}; diff --git a/lib/vscode/src/vs/workbench/contrib/webview/common/webviewUri.ts b/lib/vscode/src/vs/workbench/contrib/webview/common/webviewUri.ts deleted file mode 100644 index a4e9e92e3917..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/webview/common/webviewUri.ts +++ /dev/null @@ -1,25 +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 { URI } from 'vs/base/common/uri'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; - - -export function asWebviewUri( - environmentService: IWorkbenchEnvironmentService, - uuid: string, - resource: URI, -): URI { - const uri = environmentService.webviewResourceRoot - // Make sure we preserve the scheme of the resource but convert it into a normal path segment - // The scheme is important as we need to know if we are requesting a local or a remote resource. - .replace('{{resource}}', resource.scheme + withoutScheme(resource)) - .replace('{{uuid}}', uuid); - return URI.parse(uri); -} - -function withoutScheme(resource: URI): string { - return resource.toString().replace(/^\S+?:/, ''); -} diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/keymaps.png b/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/keymaps.png deleted file mode 100644 index b4027937a3ab6262050ccf79c07ec239fe74105e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49149 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 diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/openVSC.png b/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/openVSC.png deleted file mode 100644 index 9a700e0d4535b58c73281e8d6d9c868d5c59e862..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7282 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 diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/forwardPorts.png b/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/forwardPorts.png deleted file mode 100644 index ae10f31d6f6d10b33cfa1fd9a35d1518e850ee43..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17327 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 M07*qoM6N<$g4){C@&Et; diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/keymaps.png b/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/keymaps.png deleted file mode 100644 index 6105fd0f714736b48b54df920dc0c54247a909d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50010 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 N002ovPDHLkV1my_qC@}y diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/keymaps.png b/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/keymaps.png deleted file mode 100644 index 784f97e43145e6fcdad1e0e4c480c8f151d74292..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49954 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 diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/openVSC.png b/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/openVSC.png deleted file mode 100644 index 95610a5ea4eb360ba59c6f0355ebe1b0502e3da9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17144 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 PQ4<WFu6{1-oD!M<7nvdr diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/pullRequests.png b/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/pullRequests.png deleted file mode 100644 index 77911cafd758f45ebe3985e9541dd20af274e683..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51090 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 diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/remoteTerminal.png b/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/remoteTerminal.png deleted file mode 100644 index 366f16404a497394e6944ed0147159055e63900e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49686 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 X7R67fj*~D1K)jUX)!)|3g2Vp@Is6>c diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/runProject.png b/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/runProject.png deleted file mode 100644 index f90629c6945c526ffc7d99b31a8e8414739a3941..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65764 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 diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts b/lib/vscode/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts deleted file mode 100644 index 5234bdf243ef..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts +++ /dev/null @@ -1,34 +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 { localize } from 'vs/nls'; -import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { WelcomePageContribution, WelcomePageAction, WelcomeInputSerializer, DEFAULT_STARTUP_EDITOR_CONFIG } from 'vs/workbench/contrib/welcome/page/browser/welcomePage'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions, CATEGORIES } from 'vs/workbench/common/actions'; -import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; -import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { IEditorInputFactoryRegistry, EditorExtensions } from 'vs/workbench/common/editor'; -import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; - -Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration) - .registerConfiguration(DEFAULT_STARTUP_EDITOR_CONFIG); - -Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(WelcomePageContribution, LifecyclePhase.Restored); - -Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions) - .registerWorkbenchAction(SyncActionDescriptor.from(WelcomePageAction), 'Help: Welcome', CATEGORIES.Help.value); - -Registry.as<IEditorInputFactoryRegistry>(EditorExtensions.EditorInputFactories).registerEditorInputSerializer(WelcomeInputSerializer.ID, WelcomeInputSerializer); - -MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '1_welcome', - command: { - id: 'workbench.action.showWelcomePage', - title: localize({ key: 'miWelcome', comment: ['&& denotes a mnemonic'] }, "&&Welcome") - }, - order: 1 -}); diff --git a/lib/vscode/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts b/lib/vscode/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts deleted file mode 100644 index 4bdd5fa900ba..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts +++ /dev/null @@ -1,551 +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 'vs/css!./workspaceTrustEditor'; -import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; -import { localize } from 'vs/nls'; -import { Action2, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions'; -import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; -import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { Severity } from 'vs/platform/notification/common/notification'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkspaceTrustManagementService, IWorkspaceTrustRequestService, WorkspaceTrustRequestOptions, workspaceTrustToString } from 'vs/platform/workspace/common/workspaceTrust'; -import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; -import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { Codicon } from 'vs/base/common/codicons'; -import { ThemeColor } from 'vs/workbench/api/common/extHostTypes'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/workbench/services/statusbar/common/statusbar'; -import { IEditorRegistry, EditorDescriptor } from 'vs/workbench/browser/editor'; -import { WorkspaceTrustEditor } from 'vs/workbench/contrib/workspace/browser/workspaceTrustEditor'; -import { WorkspaceTrustEditorInput } from 'vs/workbench/services/workspaces/browser/workspaceTrustEditorInput'; -import { isWorkspaceTrustEnabled, WorkspaceTrustContext, WORKSPACE_TRUST_ENABLED, WORKSPACE_TRUST_STARTUP_PROMPT } from 'vs/workbench/services/workspaces/common/workspaceTrust'; -import { EditorInput, IEditorInputSerializer, IEditorInputFactoryRegistry, EditorExtensions } from 'vs/workbench/common/editor'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { isWeb } from 'vs/base/common/platform'; -import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; -import { dirname, resolve } from 'vs/base/common/path'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import product from 'vs/platform/product/common/product'; -import { MarkdownString } from 'vs/base/common/htmlContent'; -import { isSingleFolderWorkspaceIdentifier, toWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { Schemas } from 'vs/base/common/network'; -import { STATUS_BAR_PROMINENT_ITEM_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_FOREGROUND } from 'vs/workbench/common/theme'; -import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; - -const STARTUP_PROMPT_SHOWN_KEY = 'workspace.trust.startupPrompt.shown'; - - -/* - * Trust Request UX Handler - */ -export class WorkspaceTrustRequestHandler extends Disposable implements IWorkbenchContribution { - - constructor( - @IDialogService private readonly dialogService: IDialogService, - @ICommandService private readonly commandService: ICommandService, - @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, - @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IStorageService private readonly storageService: IStorageService, - @IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService, - ) { - super(); - - if (isWorkspaceTrustEnabled(configurationService)) { - this.registerListeners(); - this.showModalOnStart(); - } - } - - private get startupPromptSetting(): 'always' | 'once' | 'never' { - return this.configurationService.getValue(WORKSPACE_TRUST_STARTUP_PROMPT); - } - - private get useWorkspaceLanguage(): boolean { - return !isSingleFolderWorkspaceIdentifier(toWorkspaceIdentifier(this.workspaceContextService.getWorkspace())); - } - - private get modalTitle(): string { - return this.useWorkspaceLanguage ? - localize('workspaceTrust', "Do you trust the authors of the files in this workspace?") : - localize('folderTrust', "Do you trust the authors of the files in this folder?"); - } - - private async doShowModal(question: string, trustedOption: { label: string, sublabel: string }, untrustedOption: { label: string, sublabel: string }, markdownStrings: string[], trustParentString?: string): Promise<void> { - const result = await this.dialogService.show( - Severity.Info, - question, - [ - trustedOption.label, - untrustedOption.label, - ], - { - checkbox: trustParentString ? { - label: trustParentString - } : undefined, - custom: { - buttonDetails: [ - trustedOption.sublabel, - untrustedOption.sublabel - ], - disableCloseAction: true, - icon: Codicon.shield, - markdownDetails: markdownStrings.map(md => { return { markdown: new MarkdownString(md) }; }) - }, - } - ); - - // Dialog result - switch (result.choice) { - case 0: - if (result.checkboxChecked) { - this.workspaceTrustManagementService.setParentFolderTrust(true); - } else { - this.workspaceTrustRequestService.completeRequest(true); - } - break; - case 1: - this.workspaceTrustRequestService.cancelRequest(); - break; - } - - this.storageService.store(STARTUP_PROMPT_SHOWN_KEY, true, StorageScope.WORKSPACE, StorageTarget.MACHINE); - } - - private showModalOnStart(): void { - if (this.workspaceTrustManagementService.isWorkpaceTrusted()) { - return; - } - - if (this.startupPromptSetting === 'never') { - return; - } - - if (this.startupPromptSetting === 'once' && this.storageService.getBoolean(STARTUP_PROMPT_SHOWN_KEY, StorageScope.WORKSPACE, false)) { - return; - } - - let checkboxText: string | undefined; - const workspaceIdentifier = toWorkspaceIdentifier(this.workspaceContextService.getWorkspace())!; - const isSingleFolderWorkspace = isSingleFolderWorkspaceIdentifier(workspaceIdentifier); - if (isSingleFolderWorkspaceIdentifier(workspaceIdentifier) && workspaceIdentifier.uri.scheme === Schemas.file) { - checkboxText = localize('checkboxString', "I trust the authors of all files in the parent folder"); - } - - // Show Workspace Trust Start Dialog - this.doShowModal( - this.modalTitle, - { label: localize('trustOption', "Yes, I trust the authors"), sublabel: isSingleFolderWorkspace ? localize('trustFolderOptionDescription', "Trust folder and enable all features") : localize('trustWorkspaceOptionDescription', "Trust workspace and enable all features") }, - { label: localize('dontTrustOption', "No, I don't trust the authors"), sublabel: isSingleFolderWorkspace ? localize('dontTrustFolderOptionDescription', "Browse folder in restricted mode") : localize('dontTrustWorkspaceOptionDescription', "Browse workspace in restricted mode") }, - [ - !isSingleFolderWorkspace ? - localize('workspaceStartupTrustDetails', "{0} provides advanced editing features that may automatically execute files in this workspace.", product.nameShort) : - localize('folderStartupTrustDetails', "{0} provides advanced editing features that may automatically execute files in this folder.", product.nameShort), - localize('startupTrustRequestLearnMore', "If you don't trust the authors of these files, we recommend to continue in restricted mode as the files may be malicious. See [our docs](https://aka.ms/vscode-workspace-trust) to learn more.") - ], - checkboxText - ); - } - - private registerListeners(): void { - this._register(this.workspaceTrustRequestService.onDidInitiateWorkspaceTrustRequest(async requestOptions => { - if (requestOptions.modal) { - // Message - const defaultMessage = localize('immediateTrustRequestMessage', "A feature you are trying to use may be a security risk if you do not trust the source of the files or folders you currently have open."); - const message = requestOptions.message ?? defaultMessage; - - // Buttons - const buttons = requestOptions.buttons ?? [ - { label: this.useWorkspaceLanguage ? localize('grantWorkspaceTrustButton', "Trust Workspace & Continue") : localize('grantFolderTrustButton', "Trust Folder & Continue"), type: 'ContinueWithTrust' }, - { label: localize('manageWorkspaceTrustButton', "Manage"), type: 'Manage' } - ]; - // Add Cancel button if not provided - if (!buttons.some(b => b.type === 'Cancel')) { - buttons.push({ label: localize('cancelWorkspaceTrustButton', "Cancel"), type: 'Cancel' }); - } - - // Dialog - const result = await this.dialogService.show( - Severity.Info, - this.modalTitle, - buttons.map(b => b.label), - { - cancelId: buttons.findIndex(b => b.type === 'Cancel'), - custom: { - icon: Codicon.shield, - markdownDetails: [ - { markdown: new MarkdownString(message) }, - { markdown: new MarkdownString(localize('immediateTrustRequestLearnMore', "If you don't trust the authors of these files, we do not recommend continuing as the files may be malicious. See [our docs](https://aka.ms/vscode-workspace-trust) to learn more.")) } - ] - } - } - ); - - // Dialog result - switch (buttons[result.choice].type) { - case 'ContinueWithTrust': - this.workspaceTrustRequestService.completeRequest(true); - break; - case 'ContinueWithoutTrust': - this.workspaceTrustRequestService.completeRequest(undefined); - break; - case 'Manage': - this.workspaceTrustRequestService.cancelRequest(); - await this.commandService.executeCommand('workbench.trust.manage'); - break; - case 'Cancel': - this.workspaceTrustRequestService.cancelRequest(); - break; - } - } - })); - - this._register(this.workspaceContextService.onWillChangeWorkspaceFolders(e => { - if (e.fromCache) { - return; - } - if (!isWorkspaceTrustEnabled(this.configurationService)) { - return; - } - const trusted = this.workspaceTrustManagementService.isWorkpaceTrusted(); - - return e.join(new Promise(async resolve => { - // Workspace is trusted and there are added/changed folders - if (trusted && (e.changes.added.length || e.changes.changed.length)) { - const addedFoldersTrustInfo = e.changes.added.map(folder => this.workspaceTrustManagementService.getFolderTrustInfo(folder.uri)); - if (!addedFoldersTrustInfo.map(i => i.trusted).every(trusted => trusted)) { - const result = await this.dialogService.show( - Severity.Info, - localize('addWorkspaceFolderMessage', "Do you trust the authors of the files in this folder?"), - [localize('yes', 'Yes'), localize('no', 'No')], - { - detail: localize('addWorkspaceFolderDetail', "You are adding files to a trusted workspace that are not currently trusted. Do you trust the authors of these new files?"), - cancelId: 1, - custom: { icon: Codicon.shield } - } - ); - - // Mark added/changed folders as trusted - this.workspaceTrustManagementService.setFoldersTrust(addedFoldersTrustInfo.map(i => i.uri), result.choice === 0); - - resolve(); - } - } - - resolve(); - })); - })); - } -} - -Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceTrustRequestHandler, LifecyclePhase.Ready); - -/* - * Status Bar Entry - */ -class WorkspaceTrustStatusbarItem extends Disposable implements IWorkbenchContribution { - private readonly entryId = `status.workspaceTrust.${this.workspaceService.getWorkspace().id}`; - private readonly statusBarEntryAccessor: MutableDisposable<IStatusbarEntryAccessor>; - private pendingRequestContextKey = WorkspaceTrustContext.PendingRequest.key; - private contextKeys = new Set([this.pendingRequestContextKey]); - - constructor( - @IConfigurationService configurationService: IConfigurationService, - @IStatusbarService private readonly statusbarService: IStatusbarService, - @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService, - @IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService, - @IContextKeyService private readonly contextKeyService: IContextKeyService - ) { - super(); - - this.statusBarEntryAccessor = this._register(new MutableDisposable<IStatusbarEntryAccessor>()); - - if (isWorkspaceTrustEnabled(configurationService)) { - const entry = this.getStatusbarEntry(this.workspaceTrustManagementService.isWorkpaceTrusted()); - this.statusBarEntryAccessor.value = this.statusbarService.addEntry(entry, this.entryId, localize('status.WorkspaceTrust', "Workspace Trust"), StatusbarAlignment.LEFT, 0.99 * Number.MAX_VALUE /* Right of remote indicator */); - this._register(this.workspaceTrustManagementService.onDidChangeTrust(trusted => this.updateStatusbarEntry(trusted))); - this._register(this.contextKeyService.onDidChangeContext((contextChange) => { - if (contextChange.affectsSome(this.contextKeys)) { - this.updateVisibility(this.workspaceTrustManagementService.isWorkpaceTrusted()); - } - })); - - this.updateVisibility(this.workspaceTrustManagementService.isWorkpaceTrusted()); - } - } - - private getStatusbarEntry(trusted: boolean): IStatusbarEntry { - const text = workspaceTrustToString(trusted); - const backgroundColor = new ThemeColor(STATUS_BAR_PROMINENT_ITEM_BACKGROUND); - const color = new ThemeColor(STATUS_BAR_PROMINENT_ITEM_FOREGROUND); - - return { - text: trusted ? `$(shield)` : `$(shield) ${text}`, - ariaLabel: trusted ? localize('status.ariaTrusted', "This workspace is trusted.") : localize('status.ariaUntrusted', "Restricted Mode: Some features are disabled because this workspace is not trusted."), - tooltip: trusted ? localize('status.tooltipTrusted', "This workspace is trusted.") : localize('status.tooltipUntrusted', "Some features are disabled because this workspace is not trusted."), - command: 'workbench.trust.manage', - backgroundColor, - color - }; - } - - private updateVisibility(trusted: boolean): void { - const pendingRequest = this.contextKeyService.getContextKeyValue(this.pendingRequestContextKey) === true; - this.statusbarService.updateEntryVisibility(this.entryId, !trusted || pendingRequest); - } - - private updateStatusbarEntry(trusted: boolean): void { - this.statusBarEntryAccessor.value?.update(this.getStatusbarEntry(trusted)); - this.updateVisibility(trusted); - } -} - -Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution( - WorkspaceTrustStatusbarItem, - LifecyclePhase.Starting -); - -/** - * Trusted Workspace GUI Editor - */ -class WorkspaceTrustEditorInputSerializer implements IEditorInputSerializer { - - canSerialize(editorInput: EditorInput): boolean { - return true; - } - - serialize(input: WorkspaceTrustEditorInput): string { - return '{}'; - } - - deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): WorkspaceTrustEditorInput { - return instantiationService.createInstance(WorkspaceTrustEditorInput); - } -} - -Registry.as<IEditorInputFactoryRegistry>(EditorExtensions.EditorInputFactories) - .registerEditorInputSerializer(WorkspaceTrustEditorInput.ID, WorkspaceTrustEditorInputSerializer); - -Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor( - EditorDescriptor.create( - WorkspaceTrustEditor, - WorkspaceTrustEditor.ID, - localize('workspaceTrustEditor', "Workspace Trust Editor") - ), - [ - new SyncDescriptor(WorkspaceTrustEditorInput) - ] -); - -/* - * Actions - */ - -// Manage Workspace Trust -registerAction2(class extends Action2 { - constructor() { - super({ - id: 'workbench.trust.manage', - title: { - original: 'Manage Workspace Trust', - value: localize('manageWorkspaceTrust', "Manage Workspace Trust") - }, - category: localize('workspacesCategory', "Workspaces"), - menu: { - id: MenuId.GlobalActivity, - group: '6_workspace_trust', - order: 40, - when: ContextKeyExpr.and(IsWebContext.negate(), ContextKeyExpr.equals(`config.${WORKSPACE_TRUST_ENABLED}`, true), WorkspaceTrustContext.PendingRequest.negate()) - }, - }); - } - - run(accessor: ServicesAccessor) { - const editorService = accessor.get(IEditorService); - const instantiationService = accessor.get(IInstantiationService); - - const input = instantiationService.createInstance(WorkspaceTrustEditorInput); - - editorService.openEditor(input, { pinned: true, revealIfOpened: true }); - return; - } -}); - -MenuRegistry.appendMenuItem(MenuId.GlobalActivity, { - command: { - id: 'workbench.trust.manage', - title: localize('manageWorkspaceTrustPending', "Manage Workspace Trust (1)"), - }, - group: '6_workspace_trust', - order: 40, - when: ContextKeyExpr.and(IsWebContext.negate(), ContextKeyExpr.equals(`config.${WORKSPACE_TRUST_ENABLED}`, true), WorkspaceTrustContext.PendingRequest) -}); - -/* - * Configuration - */ -Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration) - .registerConfiguration({ - id: 'security', - scope: ConfigurationScope.APPLICATION, - title: localize('securityConfigurationTitle', "Security"), - type: 'object', - order: 7, - properties: { - [WORKSPACE_TRUST_ENABLED]: { - type: 'boolean', - default: false, - included: !isWeb, - description: localize('workspace.trust.description', "Controls whether or not workspace trust is enabled within VS Code."), - scope: ConfigurationScope.APPLICATION - }, - [WORKSPACE_TRUST_STARTUP_PROMPT]: { - type: 'string', - default: 'once', - included: !isWeb, - description: localize('workspace.trust.startupPrompt.description', "Controls when the startup prompt to trust a workspace is shown."), - scope: ConfigurationScope.APPLICATION, - enum: ['always', 'once', 'never'], - enumDescriptions: [ - localize('workspace.trust.startupPrompt.always', "Ask for trust every time an untrusted workspace is opened."), - localize('workspace.trust.startupPrompt.once', "Ask for trust the first time an untrusted workspace is opened."), - localize('workspace.trust.startupPrompt.never', "Do not ask for trust when an untrusted workspace is opened."), - ] - } - } - }); - -/** - * Telemetry - */ -class WorkspaceTrustTelemetryContribution extends Disposable implements IWorkbenchContribution { - constructor( - @IConfigurationService private readonly configurationService: IConfigurationService, - @IExtensionService private readonly extensionService: IExtensionService, - @ITelemetryService private readonly telemetryService: ITelemetryService, - @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, - @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService, - @IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService - ) { - super(); - - this._register(this.workspaceTrustManagementService.onDidChangeTrust(isTrusted => this.logWorkspaceTrustChangeEvent(isTrusted))); - this._register(this.workspaceTrustRequestService.onDidInitiateWorkspaceTrustRequest(options => this.logWorkspaceTrustRequest(options))); - - this.logInitialWorkspaceTrustInfo(); - } - - private logInitialWorkspaceTrustInfo(): void { - if (!isWorkspaceTrustEnabled(this.configurationService)) { - return; - } - - type WorkspaceTrustInfoEventClassification = { - trustedFoldersCount: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; - }; - - type WorkspaceTrustInfoEvent = { - trustedFoldersCount: number, - }; - - this.telemetryService.publicLog2<WorkspaceTrustInfoEvent, WorkspaceTrustInfoEventClassification>('workspaceTrustFolderCounts', { - trustedFoldersCount: this.workspaceTrustManagementService.getTrustedFolders().length, - }); - } - - private logWorkspaceTrustChangeEvent(isTrusted: boolean): void { - if (!isWorkspaceTrustEnabled(this.configurationService)) { - return; - } - - type WorkspaceTrustStateChangedEvent = { - workspaceId: string, - isTrusted: boolean - }; - - type WorkspaceTrustStateChangedEventClassification = { - workspaceId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - isTrusted: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; - }; - - this.telemetryService.publicLog2<WorkspaceTrustStateChangedEvent, WorkspaceTrustStateChangedEventClassification>('workspaceTrustStateChanged', { - workspaceId: this.workspaceContextService.getWorkspace().id, - isTrusted: isTrusted - }); - - if (isTrusted) { - type WorkspaceTrustFolderInfoEventClassification = { - trustedFolderDepth: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; - workspaceFolderDepth: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; - delta: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; - }; - - type WorkspaceTrustFolderInfoEvent = { - trustedFolderDepth: number, - workspaceFolderDepth: number, - delta: number - }; - - const getDepth = (folder: string): number => { - let resolvedPath = resolve(folder); - - let depth = 0; - while (dirname(resolvedPath) !== resolvedPath && depth < 100) { - resolvedPath = dirname(resolvedPath); - depth++; - } - - return depth; - }; - - for (const folder of this.workspaceContextService.getWorkspace().folders) { - const { trusted, uri } = this.workspaceTrustManagementService.getFolderTrustInfo(folder.uri); - if (!trusted) { - continue; - } - - const workspaceFolderDepth = getDepth(folder.uri.fsPath); - const trustedFolderDepth = getDepth(uri.fsPath); - const delta = workspaceFolderDepth - trustedFolderDepth; - - this.telemetryService.publicLog2<WorkspaceTrustFolderInfoEvent, WorkspaceTrustFolderInfoEventClassification>('workspaceFolderDepthBelowTrustedFolder', { workspaceFolderDepth, trustedFolderDepth, delta }); - } - } - } - - private async logWorkspaceTrustRequest(options: WorkspaceTrustRequestOptions): Promise<void> { - if (!isWorkspaceTrustEnabled(this.configurationService)) { - return; - } - - type WorkspaceTrustRequestedEventClassification = { - modal: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; - workspaceId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - extensions: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - }; - - type WorkspaceTrustRequestedEvent = { - modal: boolean, - workspaceId: string, - extensions: string[] - }; - - this.telemetryService.publicLog2<WorkspaceTrustRequestedEvent, WorkspaceTrustRequestedEventClassification>('workspaceTrustRequested', { - modal: options.modal, - workspaceId: this.workspaceContextService.getWorkspace().id, - extensions: (await this.extensionService.getExtensions()).filter(ext => !!ext.capabilities?.untrustedWorkspaces).map(ext => ext.identifier.value) - }); - } -} - -Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(WorkspaceTrustTelemetryContribution, LifecyclePhase.Restored); diff --git a/lib/vscode/src/vs/workbench/contrib/workspace/browser/workspaceTrustColors.ts b/lib/vscode/src/vs/workbench/contrib/workspace/browser/workspaceTrustColors.ts deleted file mode 100644 index 9260d6261b30..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/workspace/browser/workspaceTrustColors.ts +++ /dev/null @@ -1,14 +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 { localize } from 'vs/nls'; -import { editorErrorForeground, registerColor } from 'vs/platform/theme/common/colorRegistry'; -import { debugIconStartForeground } from 'vs/workbench/contrib/debug/browser/debugColors'; -import { welcomePageTileBackground } from 'vs/workbench/contrib/welcome/page/browser/welcomePageColors'; - -export const trustedForegroundColor = registerColor('workspaceTrust.trustedForegound', { dark: debugIconStartForeground, light: debugIconStartForeground, hc: debugIconStartForeground }, localize('workspaceTrustTrustedColor', 'Color used when indicating a workspace is trusted.')); -export const untrustedForegroundColor = registerColor('workspaceTrust.untrustedForeground', { dark: editorErrorForeground, light: editorErrorForeground, hc: editorErrorForeground }, localize('workspaceTrustUntrustedColor', 'Color used when indicating a workspace is not trusted.')); - -export const trustEditorTileBackgroundColor = registerColor('workspaceTrust.tileBackground', { dark: welcomePageTileBackground, light: welcomePageTileBackground, hc: welcomePageTileBackground }, localize('workspaceTrust.tileBackground', 'Background color for the tiles on the Workspace Trust page.')); diff --git a/lib/vscode/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts b/lib/vscode/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts deleted file mode 100644 index 553260531d9b..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts +++ /dev/null @@ -1,483 +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 { $, append, clearNode, Dimension, EventHelper } from 'vs/base/browser/dom'; -import { ButtonBar } from 'vs/base/browser/ui/button/button'; -import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; -import { Action } from 'vs/base/common/actions'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { Codicon, registerCodicon } from 'vs/base/common/codicons'; -import { Color, RGBA } from 'vs/base/common/color'; -import { debounce } from 'vs/base/common/decorators'; -import { Iterable } from 'vs/base/common/iterator'; -import { splitName } from 'vs/base/common/labels'; -import { DisposableStore } from 'vs/base/common/lifecycle'; -import { parseLinkedText } from 'vs/base/common/linkedText'; -import { Schemas } from 'vs/base/common/network'; -import { isEqual } from 'vs/base/common/resources'; -import { ScrollbarVisibility } from 'vs/base/common/scrollable'; -import { isArray } from 'vs/base/common/types'; -import { URI } from 'vs/base/common/uri'; -import { localize } from 'vs/nls'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { ExtensionUntrustedWorkpaceSupportType } from 'vs/platform/extensions/common/extensions'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IPromptChoiceWithMenu, Severity } from 'vs/platform/notification/common/notification'; -import { Link } from 'vs/platform/opener/browser/link'; -import product from 'vs/platform/product/common/product'; -import { IStorageService } from 'vs/platform/storage/common/storage'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { foreground } from 'vs/platform/theme/common/colorRegistry'; -import { attachButtonStyler, attachLinkStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; -import { IColorTheme, ICssStyleCollector, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; -import { isSingleFolderWorkspaceIdentifier, toWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; -import { EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor'; -import { ChoiceAction } from 'vs/workbench/common/notifications'; -import { ACTIVITY_BAR_BADGE_BACKGROUND } from 'vs/workbench/common/theme'; -import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions'; -import { getInstalledExtensions, IExtensionStatus } from 'vs/workbench/contrib/extensions/common/extensionsUtils'; -import { trustedForegroundColor, untrustedForegroundColor } from 'vs/workbench/contrib/workspace/browser/workspaceTrustColors'; -import { IWorkspaceTrustSettingChangeEvent, WorkspaceTrustSettingArrayRenderer, WorkspaceTrustTree, WorkspaceTrustTreeModel } from 'vs/workbench/contrib/workspace/browser/workspaceTrustTree'; -import { filterSettingsRequireWorkspaceTrust, IWorkbenchConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; -import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; -import { WorkspaceTrustEditorInput } from 'vs/workbench/services/workspaces/browser/workspaceTrustEditorInput'; - -const shieldIcon = registerCodicon('workspace-trust-icon', Codicon.shield); - -const checkListIcon = registerCodicon('workspace-trusted-check-icon', Codicon.check); -const xListIcon = registerCodicon('workspace-trusted-x-icon', Codicon.x); - -export class WorkspaceTrustEditor extends EditorPane { - static readonly ID: string = 'workbench.editor.workspaceTrust'; - private rootElement!: HTMLElement; - - // Header Section - private headerContainer!: HTMLElement; - private headerTitleContainer!: HTMLElement; - private headerTitleIcon!: HTMLElement; - private headerTitleText!: HTMLElement; - private headerDescription!: HTMLElement; - - private bodyScrollBar!: DomScrollableElement; - - // Affected Features Section - private affectedFeaturesContainer!: HTMLElement; - - // Settings Section - private configurationContainer!: HTMLElement; - private trustSettingsTree!: WorkspaceTrustTree; - private workspaceTrustSettingsTreeModel!: WorkspaceTrustTreeModel; - - - constructor( - @ITelemetryService telemetryService: ITelemetryService, - @IThemeService themeService: IThemeService, - @IStorageService storageService: IStorageService, - @IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService, - @IExtensionsWorkbenchService private readonly extensionWorkbenchService: IExtensionsWorkbenchService, - @IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService, - @IInstantiationService private readonly instantiationService: IInstantiationService, - @IContextMenuService private readonly contextMenuService: IContextMenuService, - @IDialogService private readonly dialogService: IDialogService, - @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService, - @IWorkbenchConfigurationService private readonly configurationService: IWorkbenchConfigurationService, - ) { super(WorkspaceTrustEditor.ID, telemetryService, themeService, storageService); } - - protected createEditor(parent: HTMLElement): void { - this.rootElement = append(parent, $('.workspace-trust-editor', { tabindex: '-1' })); - - this.createHeaderElement(this.rootElement); - - const scrollableContent = $('.workspace-trust-editor-body'); - this.bodyScrollBar = this._register(new DomScrollableElement(scrollableContent, { - horizontal: ScrollbarVisibility.Hidden, - vertical: ScrollbarVisibility.Visible, - })); - - append(this.rootElement, this.bodyScrollBar.getDomNode()); - - this.createAffectedFeaturesElement(scrollableContent); - this.createConfigurationElement(scrollableContent); - - this._register(attachStylerCallback(this.themeService, { ACTIVITY_BAR_BADGE_BACKGROUND, trustedForegroundColor, untrustedForegroundColor }, colors => { - this.rootElement.style.setProperty('--workspace-trust-trusted-color', colors.trustedForegroundColor?.toString() || ''); - this.rootElement.style.setProperty('--workspace-trust-untrusted-color', colors.untrustedForegroundColor?.toString() || ''); - this.rootElement.style.setProperty('--workspace-trust-selected-state-color', colors.ACTIVITY_BAR_BADGE_BACKGROUND?.toString() || ''); - })); - - this._register(registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => { - const foregroundColor = theme.getColor(foreground); - if (foregroundColor) { - const fgWithOpacity = new Color(new RGBA(foregroundColor.rgba.r, foregroundColor.rgba.g, foregroundColor.rgba.b, 0.3)); - collector.addRule(`.workspace-trust-editor .workspace-trust-features .workspace-trust-limitations { border: 1px solid ${fgWithOpacity}; margin: 0px 4px; display: flex; flex-direction: column; padding: 10px 40px;}`); - } - })); - } - - override async setInput(input: WorkspaceTrustEditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise<void> { - - await super.setInput(input, options, context, token); - if (token.isCancellationRequested) { return; } - - this.registerListeners(); - this.render(); - } - - private registerListeners(): void { - this._register(this.extensionWorkbenchService.onChange(() => this.render())); - this._register(this.configurationService.onDidChangeRestrictedSettings(() => this.render())); - this._register(this.workspaceTrustManagementService.onDidChangeTrust(() => this.render())); - this._register(this.workspaceTrustManagementService.onDidChangeTrustedFolders(() => this.render())); - } - - private getHeaderContainerClass(trusted: boolean): string { - if (trusted) { - return 'workspace-trust-header workspace-trust-trusted'; - } - - return 'workspace-trust-header workspace-trust-untrusted'; - } - - private useWorkspaceLanguage(): boolean { - return !isSingleFolderWorkspaceIdentifier(toWorkspaceIdentifier(this.workspaceService.getWorkspace())); - } - - private getHeaderTitleText(trusted: boolean): string { - - if (trusted) { - return this.useWorkspaceLanguage() ? localize('trustedHeaderWorkspace', "You trust this workspace") : localize('trustedHeaderFolder', "You trust this folder"); - } - - return this.useWorkspaceLanguage() ? localize('untrustedHeaderWorkspace', "You are in restricted mode") : localize('untrustedHeaderFolder', "You are in Restricted Mode"); - } - - private getHeaderDescriptionText(trusted: boolean): string { - if (trusted) { - return localize('trustedDescription', "All features are enabled because trust has been granted to the workspace. [Learn more](https://aka.ms/vscode-workspace-trust)."); - } - - return localize('untrustedDescription', "{0} is in a restricted mode intended for safe code browsing. [Learn more](https://aka.ms/vscode-workspace-trust).", product.nameShort); - } - - private getHeaderTitleIconClassNames(trusted: boolean): string[] { - return shieldIcon.classNamesArray; - } - - private rendering = false; - private rerenderDisposables: DisposableStore = this._register(new DisposableStore()); - @debounce(100) - private async render() { - if (this.rendering) { - return; - } - - this.rendering = true; - this.rerenderDisposables.clear(); - - const isWorkspaceTrusted = this.workspaceTrustManagementService.isWorkpaceTrusted(); - this.rootElement.classList.toggle('trusted', isWorkspaceTrusted); - this.rootElement.classList.toggle('untrusted', !isWorkspaceTrusted); - - // Header Section - this.headerTitleText.innerText = this.getHeaderTitleText(isWorkspaceTrusted); - this.headerTitleIcon.className = 'workspace-trust-title-icon'; - this.headerTitleIcon.classList.add(...this.getHeaderTitleIconClassNames(isWorkspaceTrusted)); - this.headerDescription.innerText = ''; - - const linkedText = parseLinkedText(this.getHeaderDescriptionText(isWorkspaceTrusted)); - const p = append(this.headerDescription, $('p')); - for (const node of linkedText.nodes) { - if (typeof node === 'string') { - append(p, document.createTextNode(node)); - } else { - const link = this.instantiationService.createInstance(Link, node); - append(p, link.el); - this.rerenderDisposables.add(link); - this.rerenderDisposables.add(attachLinkStyler(link, this.themeService)); - } - } - - this.headerContainer.className = this.getHeaderContainerClass(isWorkspaceTrusted); - - // Settings - const settingsRequiringTrustedWorkspaceCount = filterSettingsRequireWorkspaceTrust(this.configurationService.restrictedSettings.default).length; - - // Features List - const installedExtensions = await this.instantiationService.invokeFunction(getInstalledExtensions); - const onDemandExtensionCount = this.getExtensionCountByUntrustedWorkspaceSupport(installedExtensions, 'limited'); - const onStartExtensionCount = this.getExtensionCountByUntrustedWorkspaceSupport(installedExtensions, false); - - this.renderAffectedFeatures(settingsRequiringTrustedWorkspaceCount, onDemandExtensionCount + onStartExtensionCount); - - // Configuration Tree - this.workspaceTrustSettingsTreeModel.update(this.workspaceTrustManagementService.getTrustedFolders()); - this.trustSettingsTree.setChildren(null, Iterable.map(this.workspaceTrustSettingsTreeModel.settings, s => { return { element: s }; })); - - this.bodyScrollBar.getDomNode().style.height = `calc(100% - ${this.headerContainer.clientHeight}px)`; - this.bodyScrollBar.scanDomNode(); - this.rendering = false; - } - - private getExtensionCountByUntrustedWorkspaceSupport(extensions: IExtensionStatus[], trustRequestType: ExtensionUntrustedWorkpaceSupportType): number { - const filtered = extensions.filter(ext => this.extensionManifestPropertiesService.getExtensionUntrustedWorkspaceSupportType(ext.local.manifest) === trustRequestType); - const set = new Set<string>(); - for (const ext of filtered) { - set.add(ext.identifier.id); - } - - return set.size; - } - - private createHeaderElement(parent: HTMLElement): void { - this.headerContainer = append(parent, $('.workspace-trust-header')); - this.headerTitleContainer = append(this.headerContainer, $('.workspace-trust-title')); - this.headerTitleIcon = append(this.headerTitleContainer, $('.workspace-trust-title-icon')); - this.headerTitleText = append(this.headerTitleContainer, $('.workspace-trust-title-text')); - this.headerDescription = append(this.headerContainer, $('.workspace-trust-description')); - } - - private createConfigurationElement(parent: HTMLElement): void { - this.configurationContainer = append(parent, $('.workspace-trust-settings.settings-editor')); - - const settingsBody = append(this.configurationContainer, $('.workspace-trust-settings-body.settings-body')); - - const workspaceTrustTreeContainer = append(settingsBody, $('.workspace-trust-settings-tree-container.settings-tree-container')); - const renderer = this.instantiationService.createInstance(WorkspaceTrustSettingArrayRenderer,); - - this.trustSettingsTree = this._register(this.instantiationService.createInstance(WorkspaceTrustTree, - workspaceTrustTreeContainer, - [renderer])); - - this.workspaceTrustSettingsTreeModel = this.instantiationService.createInstance(WorkspaceTrustTreeModel); - - this._register(renderer.onDidChangeSetting(e => this.onDidChangeSetting(e))); - } - - private createAffectedFeaturesElement(parent: HTMLElement): void { - this.affectedFeaturesContainer = append(parent, $('.workspace-trust-features')); - } - - private renderAffectedFeatures(numSettings: number, numExtensions: number): void { - clearNode(this.affectedFeaturesContainer); - const trustedContainer = append(this.affectedFeaturesContainer, $('.workspace-trust-limitations.trusted')); - this.renderLimitationsHeaderElement(trustedContainer, - this.useWorkspaceLanguage() ? localize('trustedWorkspace', "In a trusted workspace") : localize('trustedFolder', "In a Trusted Folder"), - this.useWorkspaceLanguage() ? localize('trustedWorkspaceSubtitle', "You trust the authors of the files in the current workspace. All features are enabled:") : localize('trustedFolderSubtitle', "You trust the authors of the files in the current folder. All features are enabled:")); - this.renderLimitationsListElement(trustedContainer, [ - localize('trustedTasks', "Tasks will be allowed to run"), - localize('trustedDebugging', "Debugging will be enabled"), - localize('trustedSettings', "All workspace settings will be applied"), - localize('trustedExtensions', "All extensions will be enabled") - ], checkListIcon.classNamesArray); - - const untrustedContainer = append(this.affectedFeaturesContainer, $('.workspace-trust-limitations.untrusted')); - this.renderLimitationsHeaderElement(untrustedContainer, - localize('untrustedWorkspace', "In Restricted Mode"), - this.useWorkspaceLanguage() ? localize('untrustedWorkspaceSubtitle', "You do not trust the authors of the files in the current workspace. The following features are disabled:") : localize('untrustedFolderSubtitle', "You do not trust the authors of the files in the current folder. The following features are disabled:")); - - this.renderLimitationsListElement(untrustedContainer, [ - localize('untrustedTasks', "Tasks will be disabled"), - localize('untrustedDebugging', "Debugging will be disabled"), - numSettings ? localize('untrustedSettings', "[{0} workspace settings](command:{1}) will not be applied", numSettings, 'settings.filterUntrusted') : localize('no untrustedSettings', "Workspace settings requiring trust will not be applied"), - localize('untrustedExtensions', "[{0} extensions](command:{1}) will be disabled or have limited functionality", numExtensions, 'workbench.extensions.action.listTrustRequiredExtensions') - ], xListIcon.classNamesArray); - - if (!this.workspaceTrustManagementService.isWorkpaceTrusted()) { - this.addTrustButtonToElement(trustedContainer); - } - - if (this.isTrustedExplicitlyOnly()) { - this.addDontTrustButtonToElement(untrustedContainer); - } else { - this.addTrustedTextToElement(untrustedContainer); - } - } - - private isTrustedExplicitlyOnly(): boolean { - // Can only be trusted explicitly in the single folder scenario - const workspaceIdentifier = toWorkspaceIdentifier(this.workspaceService.getWorkspace()); - if (!(isSingleFolderWorkspaceIdentifier(workspaceIdentifier) && workspaceIdentifier.uri.scheme === Schemas.file)) { - return false; - } - - // If the current folder isn't trusted directly, return false - const trustInfo = this.workspaceTrustManagementService.getFolderTrustInfo(workspaceIdentifier.uri); - if (!trustInfo.trusted || !isEqual(workspaceIdentifier.uri, trustInfo.uri)) { - return false; - } - - // Check if the parent is also trusted - if (this.workspaceTrustManagementService.canSetParentFolderTrust()) { - const { parentPath } = splitName(workspaceIdentifier.uri.fsPath); - const parentIsTrusted = this.workspaceTrustManagementService.getFolderTrustInfo(URI.file(parentPath)).trusted; - if (parentIsTrusted) { - return false; - } - } - - return true; - } - - private createButton(parent: HTMLElement, action: Action, enabled?: boolean): void { - const buttonRow = append(parent, $('.workspace-trust-buttons-row')); - const buttonContainer = append(buttonRow, $('.workspace-trust-buttons')); - const buttonBar = this.rerenderDisposables.add(new ButtonBar(buttonContainer)); - - const button = - action instanceof ChoiceAction && action.menu?.length ? - buttonBar.addButtonWithDropdown({ - title: true, - actions: action.menu ?? [], - contextMenuProvider: this.contextMenuService - }) : - buttonBar.addButton(); - - button.label = action.label; - button.enabled = enabled !== undefined ? enabled : action.enabled; - - this.rerenderDisposables.add(button.onDidClick(e => { - if (e) { - EventHelper.stop(e, true); - } - - action.run(); - })); - - this.rerenderDisposables.add(attachButtonStyler(button, this.themeService)); - } - - private addTrustButtonToElement(parent: HTMLElement): void { - if (this.workspaceTrustManagementService.canSetWorkspaceTrust()) { - - const trustUris = async (uris?: URI[]) => { - if (!uris) { - this.workspaceTrustManagementService.setWorkspaceTrust(true); - } else { - this.workspaceTrustManagementService.setFoldersTrust(uris, true); - } - }; - - const trustChoiceWithMenu: IPromptChoiceWithMenu = { - isSecondary: false, - label: localize('trustButton', "Trust"), - menu: [], - run: () => { - trustUris(); - } - }; - - const workspaceIdentifier = toWorkspaceIdentifier(this.workspaceService.getWorkspace()); - if (isSingleFolderWorkspaceIdentifier(workspaceIdentifier) && workspaceIdentifier.uri.scheme === Schemas.file) { - const { parentPath } = splitName(workspaceIdentifier.uri.fsPath); - if (parentPath) { - trustChoiceWithMenu.menu.push({ - label: localize('trustParentButton', "Trust All in Parent Folder"), - run: () => { - trustUris([URI.file(parentPath)]); - } - }); - } - } - - const isWorkspaceTrusted = this.workspaceTrustManagementService.isWorkpaceTrusted(); - this.createButton(parent, new ChoiceAction('workspace.trust.button.action', trustChoiceWithMenu), !isWorkspaceTrusted); - } - } - - private addDontTrustButtonToElement(parent: HTMLElement): void { - if (this.workspaceTrustManagementService.canSetWorkspaceTrust() && this.isTrustedExplicitlyOnly()) { - this.createButton(parent, new Action('workspace.trust.button.action.deny', localize('dontTrustButton', "Don't Trust"), undefined, true, async () => { - await this.workspaceTrustManagementService.setWorkspaceTrust(false); - })); - } - } - - private addTrustedTextToElement(parent: HTMLElement): void { - const isWorkspaceTrusted = this.workspaceTrustManagementService.isWorkpaceTrusted(); - const canSetWorkspaceTrust = this.workspaceTrustManagementService.canSetWorkspaceTrust(); - - if (canSetWorkspaceTrust && isWorkspaceTrusted) { - const textElement = append(parent, $('.workspace-trust-untrusted-description')); - textElement.innerText = this.useWorkspaceLanguage() ? localize('untrustedWorkspaceReason', "This workspace is trusted via one or more of the trusted folders below.") : localize('untrustedFolderReason', "This folder is trusted via one or more of the trusted folders below."); - } - } - - private renderLimitationsHeaderElement(parent: HTMLElement, headerText: string, subtitleText: string): void { - const limitationsHeaderContainer = append(parent, $('.workspace-trust-limitations-header')); - const titleElement = append(limitationsHeaderContainer, $('.workspace-trust-limitations-title')); - const textElement = append(titleElement, $('.workspace-trust-limitations-title-text')); - const subtitleElement = append(limitationsHeaderContainer, $('.workspace-trust-limitations-subtitle')); - - textElement.innerText = headerText; - subtitleElement.innerText = subtitleText; - } - - private renderLimitationsListElement(parent: HTMLElement, limitations: string[], iconClassNames: string[]): void { - const listContainer = append(parent, $('.workspace-trust-limitations-list-container')); - const limitationsList = append(listContainer, $('ul')); - for (const limitation of limitations) { - const limitationListItem = append(limitationsList, $('li')); - const icon = append(limitationListItem, $('.list-item-icon')); - const text = append(limitationListItem, $('.list-item-text')); - - icon.classList.add(...iconClassNames); - - const linkedText = parseLinkedText(limitation); - for (const node of linkedText.nodes) { - if (typeof node === 'string') { - append(text, document.createTextNode(node)); - } else { - const link = this.instantiationService.createInstance(Link, node); - append(text, link.el); - this.rerenderDisposables.add(link); - this.rerenderDisposables.add(attachLinkStyler(link, this.themeService)); - } - } - } - } - - private onDidChangeSetting(change: IWorkspaceTrustSettingChangeEvent) { - const applyChangesWithPrompt = async (showPrompt: boolean, applyChanges: () => void) => { - if (showPrompt) { - const message = localize('workspaceTrustSettingModificationMessage', "Update Workspace Trust Settings"); - const detail = localize('workspaceTrustTransitionDetail', "In order to safely complete this action, all affected windows will have to be reloaded. Are you sure you want to proceed with this action?"); - const primaryButton = localize('workspaceTrustTransitionPrimaryButton', "Yes"); - const secondaryButton = localize('workspaceTrustTransitionSecondaryButton', "No"); - - const result = await this.dialogService.show(Severity.Info, message, [primaryButton, secondaryButton], { cancelId: 1, detail, custom: { icon: Codicon.shield } }); - if (result.choice !== 0) { - return; - } - } - - applyChanges(); - }; - - if (isArray(change.value)) { - if (change.key === 'trustedFolders') { - applyChangesWithPrompt(false, () => this.workspaceTrustManagementService.setTrustedFolders(change.value!)); - } - } - } - - private layoutParticipants: { layout: () => void; }[] = []; - layout(dimension: Dimension): void { - if (!this.isVisible()) { - return; - } - - this.trustSettingsTree.layout(dimension.height, dimension.width); - - this.layoutParticipants.forEach(participant => { - participant.layout(); - }); - - this.bodyScrollBar.scanDomNode(); - } -} diff --git a/lib/vscode/src/vs/workbench/contrib/workspace/browser/workspaceTrustTree.ts b/lib/vscode/src/vs/workbench/contrib/workspace/browser/workspaceTrustTree.ts deleted file mode 100644 index 94f24228f04e..000000000000 --- a/lib/vscode/src/vs/workbench/contrib/workspace/browser/workspaceTrustTree.ts +++ /dev/null @@ -1,624 +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 { addDisposableListener, append, EventType, $, createStyleSheet, trackFocus, addStandardDisposableListener } from 'vs/base/browser/dom'; -import { DefaultStyleController, IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; -import { IList } from 'vs/base/browser/ui/tree/indexTreeModel'; -import { IObjectTreeOptions } from 'vs/base/browser/ui/tree/objectTree'; -import { ITreeModel, ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree'; -import { Color, RGBA } from 'vs/base/common/color'; -import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable, DisposableStore, dispose } from 'vs/base/common/lifecycle'; -import { isArray } from 'vs/base/common/types'; -import { localize } from 'vs/nls'; -import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; -import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { IListService, WorkbenchObjectTree } from 'vs/platform/list/browser/listService'; -import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { editorBackground, errorForeground, focusBorder, foreground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground } from 'vs/platform/theme/common/colorRegistry'; -import { IColorTheme, ICssStyleCollector, IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { NonCollapsibleObjectTreeModel } from 'vs/workbench/contrib/preferences/browser/settingsTree'; -import { AbstractListSettingWidget, focusedRowBackground, focusedRowBorder, ISettingListChangeEvent, rowHoverBackground, settingsHeaderForeground, settingsSelectBackground, settingsTextInputBorder, settingsTextInputForeground } from 'vs/workbench/contrib/preferences/browser/settingsWidgets'; -import { attachButtonStyler, attachInputBoxStyler, attachStyler } from 'vs/platform/theme/common/styler'; -import { CachedListVirtualDelegate } from 'vs/base/browser/ui/list/list'; -import { IAction } from 'vs/base/common/actions'; -import { settingsEditIcon, settingsRemoveIcon } from 'vs/workbench/contrib/preferences/browser/preferencesIcons'; -import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { KeyCode } from 'vs/base/common/keyCodes'; -import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; -import { Button } from 'vs/base/browser/ui/button/button'; -import { disposableTimeout } from 'vs/base/common/async'; -import { URI, UriComponents } from 'vs/base/common/uri'; -import { Schemas } from 'vs/base/common/network'; -import { ILabelService } from 'vs/platform/label/common/label'; - - -export class WorkspaceTrustSettingsTreeEntry { - id: string; - displayLabel: string; - setting: { - key: string; - description: string; - }; - value: URI[]; - - constructor(key: string, displayLabel: string, description: string, value: URI[]) { - this.setting = { key, description }; - this.displayLabel = displayLabel; - this.value = value; - this.id = key; - } -} - -export interface IWorkspaceTrustSettingItemTemplate<T = any> { - onChange?: (value: T, type: WorkspaceTrustSettingListItemChangeType) => void; - - toDispose: DisposableStore; - context?: WorkspaceTrustSettingsTreeEntry; - containerElement: HTMLElement; - labelElement: HTMLElement; - descriptionElement: HTMLElement; - controlElement: HTMLElement; - elementDisposables: DisposableStore; -} - -export interface IWorkspaceTrustUriDataItem extends UriComponents { } - -class WorkspaceTrustFolderSettingWidget extends AbstractListSettingWidget<IWorkspaceTrustUriDataItem> { - constructor( - container: HTMLElement, - @ILabelService protected readonly labelService: ILabelService, - @IThemeService themeService: IThemeService, - @IContextViewService contextViewService: IContextViewService - ) { - super(container, themeService, contextViewService); - } - - protected getEmptyItem(): IWorkspaceTrustUriDataItem { - return URI.file(''); - } - - protected getContainerClasses() { - return ['workspace-trust-uri-setting-widget', 'setting-list-object-widget']; - } - - protected getActionsForItem(item: IWorkspaceTrustUriDataItem, idx: number): IAction[] { - return [ - { - class: ThemeIcon.asClassName(settingsEditIcon), - enabled: true, - id: 'workbench.action.editListItem', - tooltip: this.getLocalizedStrings().editActionTooltip, - run: () => this.editSetting(idx) - }, - { - class: ThemeIcon.asClassName(settingsRemoveIcon), - enabled: true, - id: 'workbench.action.removeListItem', - tooltip: this.getLocalizedStrings().deleteActionTooltip, - run: () => this._onDidChangeList.fire({ originalItem: item, item: undefined, targetIndex: idx }) - } - ] as IAction[]; - } - - protected override renderHeader() { - const header = $('.setting-list-row-header'); - const hostHeader = append(header, $('.setting-list-object-key')); - const pathHeader = append(header, $('.setting-list-object-value')); - const { hostHeaderText, pathHeaderText } = this.getLocalizedStrings(); - - hostHeader.textContent = hostHeaderText; - pathHeader.textContent = pathHeaderText; - - return header; - } - - protected renderItem(item: IWorkspaceTrustUriDataItem): HTMLElement { - const rowElement = $('.setting-list-row'); - rowElement.classList.add('setting-list-object-row'); - - const hostElement = append(rowElement, $('.setting-list-object-key')); - const pathElement = append(rowElement, $('.setting-list-object-value')); - - hostElement.textContent = item.authority ? this.labelService.getHostLabel(item.scheme, item.authority) : localize('localAuthority', "Local"); - pathElement.textContent = item.scheme === Schemas.file ? URI.revive(item).fsPath : item.path; - - return rowElement; - } - - - protected renderEdit(item: IWorkspaceTrustUriDataItem, idx: number): HTMLElement { - const rowElement = $('.setting-list-edit-row'); - - const hostElement = append(rowElement, $('.setting-list-object-key')); - hostElement.textContent = item.authority ? this.labelService.getHostLabel(item.scheme, item.authority) : localize('localAuthority', "Local"); - - const updatedItem = () => { - if (item.scheme === Schemas.file) { - return URI.file(pathInput.value); - } else { - return URI.revive(item).with({ path: pathInput.value }); - } - }; - - const onKeyDown = (e: StandardKeyboardEvent) => { - if (e.equals(KeyCode.Enter)) { - this.handleItemChange(item, updatedItem(), idx); - } else if (e.equals(KeyCode.Escape)) { - this.cancelEdit(); - e.preventDefault(); - } - rowElement?.focus(); - }; - - const pathInput = new InputBox(rowElement, this.contextViewService, { - placeholder: this.getLocalizedStrings().inputPlaceholder - }); - - pathInput.element.classList.add('setting-list-valueInput'); - this.listDisposables.add(attachInputBoxStyler(pathInput, this.themeService, { - inputBackground: settingsSelectBackground, - inputForeground: settingsTextInputForeground, - inputBorder: settingsTextInputBorder - })); - this.listDisposables.add(pathInput); - pathInput.value = item.scheme === Schemas.file ? URI.revive(item).fsPath : item.path; - - this.listDisposables.add( - addStandardDisposableListener(pathInput.inputElement, EventType.KEY_DOWN, onKeyDown) - ); - - const okButton = this._register(new Button(rowElement)); - okButton.label = localize('okButton', "OK"); - okButton.element.classList.add('setting-list-ok-button'); - - this.listDisposables.add(attachButtonStyler(okButton, this.themeService)); - this.listDisposables.add(okButton.onDidClick(() => this.handleItemChange(item, updatedItem(), idx))); - - const cancelButton = this._register(new Button(rowElement)); - cancelButton.label = localize('cancelButton', "Cancel"); - cancelButton.element.classList.add('setting-list-cancel-button'); - - this.listDisposables.add(attachButtonStyler(cancelButton, this.themeService)); - this.listDisposables.add(cancelButton.onDidClick(() => this.cancelEdit())); - - this.listDisposables.add( - disposableTimeout(() => { - pathInput.focus(); - pathInput.select(); - }) - ); - - return rowElement; - } - - protected isItemNew(item: IWorkspaceTrustUriDataItem): boolean { - return item.path === ''; - } - - protected getLocalizedRowTitle(item: IWorkspaceTrustUriDataItem): string { - return localize('trustedRow', "Trusted Path: {0}", this.labelService.getUriLabel(URI.from(item))); - } - - protected getLocalizedStrings() { - return { - deleteActionTooltip: localize('removePath', "Remove Path"), - editActionTooltip: localize('editPath', "Edit Path"), - addButtonLabel: localize('addPath', "Add Path"), - hostHeaderText: localize('hostHeaderText', "Host"), - pathHeaderText: localize('pathHeaderText', "Path"), - inputPlaceholder: localize('pathInputPlaceholder', "Path Item..."), - }; - } -} - -interface IWorkspaceTrustSettingListItemTemplate extends IWorkspaceTrustSettingItemTemplate<URI[] | undefined> { - listWidget: WorkspaceTrustFolderSettingWidget; - validationErrorMessageElement: HTMLElement; -} - -export type WorkspaceTrustSettingListItemChangeType = 'added' | 'removed' | 'changed'; -export interface IWorkspaceTrustSettingChangeEvent { - key: string; - value: URI[] | undefined; // undefined => reset/unconfigure - type: WorkspaceTrustSettingListItemChangeType; -} - - -export class WorkspaceTrustSettingArrayRenderer extends Disposable implements ITreeRenderer<WorkspaceTrustSettingsTreeEntry, never, IWorkspaceTrustSettingListItemTemplate> { - templateId = 'template.setting.array'; - - static readonly CONTROL_CLASS = 'setting-control-focus-target'; - static readonly CONTROL_SELECTOR = '.' + WorkspaceTrustSettingArrayRenderer.CONTROL_CLASS; - static readonly CONTENTS_CLASS = 'setting-item-contents'; - static readonly CONTENTS_SELECTOR = '.' + WorkspaceTrustSettingArrayRenderer.CONTENTS_CLASS; - static readonly ALL_ROWS_SELECTOR = '.monaco-list-row'; - - static readonly SETTING_KEY_ATTR = 'data-key'; - static readonly SETTING_ID_ATTR = 'data-id'; - static readonly ELEMENT_FOCUSABLE_ATTR = 'data-focusable'; - - protected readonly _onDidChangeSetting = this._register(new Emitter<IWorkspaceTrustSettingChangeEvent>()); - readonly onDidChangeSetting: Event<IWorkspaceTrustSettingChangeEvent> = this._onDidChangeSetting.event; - - private readonly _onDidFocusSetting = this._register(new Emitter<WorkspaceTrustSettingsTreeEntry>()); - readonly onDidFocusSetting: Event<WorkspaceTrustSettingsTreeEntry> = this._onDidFocusSetting.event; - - private readonly _onDidChangeIgnoredSettings = this._register(new Emitter<void>()); - readonly onDidChangeIgnoredSettings: Event<void> = this._onDidChangeIgnoredSettings.event; - - constructor( - @IThemeService protected readonly _themeService: IThemeService, - @IContextViewService protected readonly _contextViewService: IContextViewService, - @IOpenerService protected readonly _openerService: IOpenerService, - @IInstantiationService protected readonly _instantiationService: IInstantiationService, - @ICommandService protected readonly _commandService: ICommandService, - @IContextMenuService protected readonly _contextMenuService: IContextMenuService, - @IKeybindingService protected readonly _keybindingService: IKeybindingService, - @IConfigurationService protected readonly _configService: IConfigurationService, - ) { - super(); - } - - renderCommonTemplate(tree: any, _container: HTMLElement, typeClass: string): IWorkspaceTrustSettingItemTemplate { - _container.classList.add('setting-item'); - _container.classList.add('setting-item-' + typeClass); - - const container = append(_container, $(WorkspaceTrustSettingArrayRenderer.CONTENTS_SELECTOR)); - container.classList.add('settings-row-inner-container'); - const titleElement = append(container, $('.setting-item-title')); - const labelCategoryContainer = append(titleElement, $('.setting-item-cat-label-container')); - const labelElement = append(labelCategoryContainer, $('span.setting-item-label')); - const descriptionElement = append(container, $('.setting-item-description')); - const modifiedIndicatorElement = append(container, $('.setting-item-modified-indicator')); - modifiedIndicatorElement.title = localize('modified', "Modified"); - - const valueElement = append(container, $('.setting-item-value')); - const controlElement = append(valueElement, $('div.setting-item-control')); - const toDispose = new DisposableStore(); - - const template: IWorkspaceTrustSettingItemTemplate = { - toDispose, - elementDisposables: new DisposableStore(), - containerElement: container, - labelElement, - descriptionElement, - controlElement - }; - - // Prevent clicks from being handled by list - toDispose.add(addDisposableListener(controlElement, EventType.MOUSE_DOWN, e => e.stopPropagation())); - - toDispose.add(addDisposableListener(titleElement, EventType.MOUSE_ENTER, e => container.classList.add('mouseover'))); - toDispose.add(addDisposableListener(titleElement, EventType.MOUSE_LEAVE, e => container.classList.remove('mouseover'))); - - return template; - } - - addSettingElementFocusHandler(template: IWorkspaceTrustSettingItemTemplate): void { - const focusTracker = trackFocus(template.containerElement); - template.toDispose.add(focusTracker); - focusTracker.onDidBlur(() => { - if (template.containerElement.classList.contains('focused')) { - template.containerElement.classList.remove('focused'); - } - }); - - focusTracker.onDidFocus(() => { - template.containerElement.classList.add('focused'); - - if (template.context) { - this._onDidFocusSetting.fire(template.context); - } - }); - } - - renderTemplate(container: HTMLElement): IWorkspaceTrustSettingListItemTemplate { - const common = this.renderCommonTemplate(null, container, 'list'); - const descriptionElement = common.containerElement.querySelector('.setting-item-description')!; - const validationErrorMessageElement = $('.setting-item-validation-message'); - descriptionElement.after(validationErrorMessageElement); - - const listWidget = this._instantiationService.createInstance(WorkspaceTrustFolderSettingWidget, common.controlElement); - listWidget.domNode.classList.add(WorkspaceTrustSettingArrayRenderer.CONTROL_CLASS); - common.toDispose.add(listWidget); - - const template: IWorkspaceTrustSettingListItemTemplate = { - ...common, - listWidget, - validationErrorMessageElement - }; - - this.addSettingElementFocusHandler(template); - - common.toDispose.add( - listWidget.onDidChangeList(e => { - const { list: newList, changeType } = this.computeNewList(template, e); - if (newList !== null && template.onChange) { - template.onChange(newList, changeType); - } - }) - ); - - return template; - } - - private computeNewList(template: IWorkspaceTrustSettingListItemTemplate, e: ISettingListChangeEvent<IWorkspaceTrustUriDataItem>): { list: URI[] | null, changeType: WorkspaceTrustSettingListItemChangeType } { - if (template.context) { - let newValue: URI[] = []; - - let changeType: WorkspaceTrustSettingListItemChangeType = 'changed'; - if (isArray(template.context.value)) { - newValue = [...template.context.value]; - } - - if (e.targetIndex !== undefined) { - // Delete value - if (!e.item?.path && e.originalItem.path && e.targetIndex > -1) { - newValue.splice(e.targetIndex, 1); - changeType = 'removed'; - } - // Update value - else if (e.item?.path && e.originalItem.path) { - if (e.targetIndex > -1) { - newValue[e.targetIndex] = URI.revive(e.item); - changeType = e.targetIndex < template.context.value.length ? 'changed' : 'added'; - } - // For some reason, we are updating and cannot find original value - // Just append the value in this case - else { - newValue.push(URI.revive(e.item)); - changeType = 'added'; - } - } - // Add value - else if (e.item?.path && !e.originalItem.path && e.targetIndex >= newValue.length) { - newValue.push(URI.revive(e.item)); - changeType = 'added'; - } - } - - return { list: newValue, changeType }; - } - - return { list: null, changeType: 'changed' }; - } - - renderElement(node: ITreeNode<WorkspaceTrustSettingsTreeEntry, never>, index: number, template: IWorkspaceTrustSettingListItemTemplate): void { - const element = node.element; - template.context = element; - - template.containerElement.setAttribute(WorkspaceTrustSettingArrayRenderer.SETTING_KEY_ATTR, element.setting.key); - template.containerElement.setAttribute(WorkspaceTrustSettingArrayRenderer.SETTING_ID_ATTR, element.id); - - template.labelElement.textContent = element.displayLabel; - - template.descriptionElement.innerText = element.setting.description; - - const onChange = (value: any, type: WorkspaceTrustSettingListItemChangeType) => this._onDidChangeSetting.fire({ key: element.setting.key, value, type }); - this.renderValue(element, template, onChange); - } - - protected renderValue(dataElement: WorkspaceTrustSettingsTreeEntry, template: IWorkspaceTrustSettingListItemTemplate, onChange: (value: URI[] | undefined, type: WorkspaceTrustSettingListItemChangeType) => void): void { - const value = getListDisplayValue(dataElement); - template.listWidget.setValue(value); - template.context = dataElement; - - template.onChange = (v, t) => { - onChange(v, t); - renderArrayValidations(dataElement, template, v, false); - }; - - renderArrayValidations(dataElement, template, value.map(v => URI.revive(v)), true); - } - - disposeTemplate(template: IWorkspaceTrustSettingItemTemplate): void { - dispose(template.toDispose); - } - - disposeElement(_element: ITreeNode<WorkspaceTrustSettingsTreeEntry>, _index: number, template: IWorkspaceTrustSettingItemTemplate, _height: number | undefined): void { - if (template.elementDisposables) { - template.elementDisposables.clear(); - } - } -} - -export class WorkspaceTrustTree extends WorkbenchObjectTree<WorkspaceTrustSettingsTreeEntry> { - constructor( - container: HTMLElement, - renderers: ITreeRenderer<any, void, any>[], - @IContextKeyService contextKeyService: IContextKeyService, - @IListService listService: IListService, - @IThemeService themeService: IThemeService, - @IConfigurationService configurationService: IConfigurationService, - @IKeybindingService keybindingService: IKeybindingService, - @IAccessibilityService accessibilityService: IAccessibilityService, - @IInstantiationService instantiationService: IInstantiationService, - ) { - super('WorkspaceTrustTree', container, - new WorkspaceTrustTreeDelegate(), - renderers, - { - horizontalScrolling: false, - alwaysConsumeMouseWheel: false, - supportDynamicHeights: true, - identityProvider: { - getId(e) { - return e.id; - } - }, - accessibilityProvider: new WorkspaceTrustTreeAccessibilityProvider(), - styleController: id => new DefaultStyleController(createStyleSheet(container), id), - smoothScrolling: configurationService.getValue<boolean>('workbench.list.smoothScrolling'), - multipleSelectionSupport: false, - }, - contextKeyService, - listService, - themeService, - configurationService, - keybindingService, - accessibilityService, - ); - - this.disposables.add(registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => { - const foregroundColor = theme.getColor(foreground); - if (foregroundColor) { - // Links appear inside other elements in markdown. CSS opacity acts like a mask. So we have to dynamically compute the description color to avoid - // applying an opacity to the link color. - const fgWithOpacity = new Color(new RGBA(foregroundColor.rgba.r, foregroundColor.rgba.g, foregroundColor.rgba.b, 0.9)); - collector.addRule(`.workspace-trust-editor .workspace-trust-settings .workspace-trust-settings-tree-container .setting-item-contents .setting-item-description { color: ${fgWithOpacity}; }`); - collector.addRule(`.workspace-trust-editor .workspace-trust-settings .settings-toc-container .monaco-list-row:not(.selected) { color: ${fgWithOpacity}; }`); - - // Hack for subpixel antialiasing - collector.addRule(`.workspace-trust-editor .workspace-trust-settings .workspace-trust-settings-tree-container .setting-item-contents .setting-item-title .setting-item-overrides, - .workspace-trust-editor .workspace-trust-settings .workspace-trust-settings-tree-container .setting-item-contents .setting-item-title .setting-item-ignored { color: ${fgWithOpacity}; }`); - } - - const errorColor = theme.getColor(errorForeground); - if (errorColor) { - collector.addRule(`.workspace-trust-editor .workspace-trust-settings .workspace-trust-settings-tree-container .setting-item-contents .setting-item-deprecation-message { color: ${errorColor}; }`); - } - - const invalidInputBackground = theme.getColor(inputValidationErrorBackground); - if (invalidInputBackground) { - collector.addRule(`.workspace-trust-editor .workspace-trust-settings .workspace-trust-settings-tree-container .setting-item-contents .setting-item-validation-message { background-color: ${invalidInputBackground}; }`); - } - - const invalidInputForeground = theme.getColor(inputValidationErrorForeground); - if (invalidInputForeground) { - collector.addRule(`.workspace-trust-editor .workspace-trust-settings .workspace-trust-settings-tree-container .setting-item-contents .setting-item-validation-message { color: ${invalidInputForeground}; }`); - } - - const invalidInputBorder = theme.getColor(inputValidationErrorBorder); - if (invalidInputBorder) { - collector.addRule(`.workspace-trust-editor .workspace-trust-settings .workspace-trust-settings-tree-container .setting-item-contents .setting-item-validation-message { border-style:solid; border-width: 1px; border-color: ${invalidInputBorder}; }`); - collector.addRule(`.workspace-trust-editor .workspace-trust-settings .workspace-trust-settings-tree-container .setting-item.invalid-input .setting-item-control .monaco-inputbox.idle { outline-width: 0; border-style:solid; border-width: 1px; border-color: ${invalidInputBorder}; }`); - } - - const focusedRowBackgroundColor = theme.getColor(focusedRowBackground); - if (focusedRowBackgroundColor) { - collector.addRule(`.workspace-trust-editor .workspace-trust-settings .workspace-trust-settings-tree-container .monaco-list-row.focused .settings-row-inner-container { background-color: ${focusedRowBackgroundColor}; }`); - } - - const rowHoverBackgroundColor = theme.getColor(rowHoverBackground); - if (rowHoverBackgroundColor) { - collector.addRule(`.workspace-trust-editor .workspace-trust-settings .workspace-trust-settings-tree-container .monaco-list-row:not(.focused) .settings-row-inner-container:hover { background-color: ${rowHoverBackgroundColor}; }`); - } - - const focusedRowBorderColor = theme.getColor(focusedRowBorder); - if (focusedRowBorderColor) { - collector.addRule(`.workspace-trust-editor .workspace-trust-settings .workspace-trust-settings-tree-container .monaco-list:focus-within .monaco-list-row.focused .setting-item-contents::before, - .workspace-trust-editor .workspace-trust-settings .workspace-trust-settings-tree-container .monaco-list:focus-within .monaco-list-row.focused .setting-item-contents::after { border-top: 1px solid ${focusedRowBorderColor} }`); - collector.addRule(`.workspace-trust-editor .workspace-trust-settings .workspace-trust-settings-tree-container .monaco-list:focus-within .monaco-list-row.focused .settings-group-title-label::before, - .workspace-trust-editor .workspace-trust-settings .workspace-trust-settings-tree-container .monaco-list:focus-within .monaco-list-row.focused .settings-group-title-label::after { border-top: 1px solid ${focusedRowBorderColor} }`); - } - - const headerForegroundColor = theme.getColor(settingsHeaderForeground); - if (headerForegroundColor) { - collector.addRule(`.workspace-trust-editor .workspace-trust-settings .workspace-trust-settings-tree-container .settings-group-title-label { color: ${headerForegroundColor}; }`); - collector.addRule(`.workspace-trust-editor .workspace-trust-settings .workspace-trust-settings-tree-container .setting-item-label { color: ${headerForegroundColor}; }`); - } - - const focusBorderColor = theme.getColor(focusBorder); - if (focusBorderColor) { - collector.addRule(`.workspace-trust-editor .workspace-trust-settings .workspace-trust-settings-tree-container .setting-item-contents .setting-item-markdown a:focus { outline-color: ${focusBorderColor} }`); - } - })); - - this.getHTMLElement().classList.add('settings-editor-tree'); - - this.disposables.add(attachStyler(themeService, { - listBackground: editorBackground, - listActiveSelectionBackground: editorBackground, - listActiveSelectionForeground: foreground, - listFocusAndSelectionBackground: editorBackground, - listFocusAndSelectionForeground: foreground, - listFocusBackground: editorBackground, - listFocusForeground: foreground, - listHoverForeground: foreground, - listHoverBackground: editorBackground, - listHoverOutline: editorBackground, - listFocusOutline: editorBackground, - listInactiveSelectionBackground: editorBackground, - listInactiveSelectionForeground: foreground, - listInactiveFocusBackground: editorBackground, - listInactiveFocusOutline: editorBackground - }, colors => { - this.style(colors); - })); - - this.disposables.add(configurationService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration('workbench.list.smoothScrolling')) { - this.updateOptions({ - smoothScrolling: configurationService.getValue<boolean>('workbench.list.smoothScrolling') - }); - } - })); - } - - protected override createModel(user: string, view: IList<ITreeNode<WorkspaceTrustSettingsTreeEntry>>, options: IObjectTreeOptions<WorkspaceTrustSettingsTreeEntry>): ITreeModel<WorkspaceTrustSettingsTreeEntry | null, void, WorkspaceTrustSettingsTreeEntry | null> { - return new NonCollapsibleObjectTreeModel<WorkspaceTrustSettingsTreeEntry>(user, view, options); - } -} - -export class WorkspaceTrustTreeModel { - - settings: WorkspaceTrustSettingsTreeEntry[] = []; - - update(trustedFolders: URI[]): void { - this.settings = []; - this.settings.push(new WorkspaceTrustSettingsTreeEntry( - 'trustedFolders', - localize('trustedFolders', "Trusted Folders"), - localize('trustedFoldersDescription', "You trust the following folders and their children: "), - trustedFolders)); - } -} - -class WorkspaceTrustTreeAccessibilityProvider implements IListAccessibilityProvider<WorkspaceTrustSettingsTreeEntry> { - getAriaLabel(element: WorkspaceTrustSettingsTreeEntry) { - if (element instanceof WorkspaceTrustSettingsTreeEntry) { - return `element.displayLabel`; - } - - return null; - } - - getWidgetAriaLabel() { - return localize('settings', "Workspace Trust Setting"); - } -} - -class WorkspaceTrustTreeDelegate extends CachedListVirtualDelegate<WorkspaceTrustSettingsTreeEntry> { - - getTemplateId(element: WorkspaceTrustSettingsTreeEntry): string { - return 'template.setting.array'; - } - - hasDynamicHeight(element: WorkspaceTrustSettingsTreeEntry): boolean { - return true; - } - - protected estimateHeight(element: WorkspaceTrustSettingsTreeEntry): number { - return 104; - } -} - -function getListDisplayValue(element: WorkspaceTrustSettingsTreeEntry): IWorkspaceTrustUriDataItem[] { - if (!element.value || !isArray(element.value)) { - return []; - } - - return element.value; -} - -function renderArrayValidations(dataElement: WorkspaceTrustSettingsTreeEntry, template: IWorkspaceTrustSettingListItemTemplate, v: URI[] | undefined, arg3: boolean) { -} - diff --git a/lib/vscode/src/vs/workbench/electron-sandbox/actions/windowActions.ts b/lib/vscode/src/vs/workbench/electron-sandbox/actions/windowActions.ts deleted file mode 100644 index 12cf59e82819..000000000000 --- a/lib/vscode/src/vs/workbench/electron-sandbox/actions/windowActions.ts +++ /dev/null @@ -1,254 +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 'vs/css!./media/actions'; -import { URI } from 'vs/base/common/uri'; -import { Action } from 'vs/base/common/actions'; -import { localize } from 'vs/nls'; -import { applyZoom } from 'vs/platform/windows/electron-sandbox/window'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { getZoomLevel } from 'vs/base/browser/browser'; -import { FileKind } from 'vs/platform/files/common/files'; -import { IModelService } from 'vs/editor/common/services/modelService'; -import { IModeService } from 'vs/editor/common/services/modeService'; -import { IQuickInputService, IQuickInputButton } from 'vs/platform/quickinput/common/quickInput'; -import { getIconClasses } from 'vs/editor/common/services/getIconClasses'; -import { ICommandHandler } from 'vs/platform/commands/common/commands'; -import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; -import { Codicon } from 'vs/base/common/codicons'; -import { isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; - -export class CloseCurrentWindowAction extends Action { - - static readonly ID = 'workbench.action.closeWindow'; - static readonly LABEL = localize('closeWindow', "Close Window"); - - constructor( - id: string, - label: string, - @INativeHostService private readonly nativeHostService: INativeHostService - ) { - super(id, label); - } - - override async run(): Promise<void> { - this.nativeHostService.closeWindow(); - } -} - -export abstract class BaseZoomAction extends Action { - - private static readonly SETTING_KEY = 'window.zoomLevel'; - - private static readonly MAX_ZOOM_LEVEL = 9; - private static readonly MIN_ZOOM_LEVEL = -8; - - constructor( - id: string, - label: string, - @IConfigurationService private readonly configurationService: IConfigurationService - ) { - super(id, label); - } - - protected async setConfiguredZoomLevel(level: number): Promise<void> { - level = Math.round(level); // when reaching smallest zoom, prevent fractional zoom levels - - if (level > BaseZoomAction.MAX_ZOOM_LEVEL || level < BaseZoomAction.MIN_ZOOM_LEVEL) { - return; // https://github.com/microsoft/vscode/issues/48357 - } - - await this.configurationService.updateValue(BaseZoomAction.SETTING_KEY, level); - - applyZoom(level); - } -} - -export class ZoomInAction extends BaseZoomAction { - - static readonly ID = 'workbench.action.zoomIn'; - static readonly LABEL = localize('zoomIn', "Zoom In"); - - constructor( - id: string, - label: string, - @IConfigurationService configurationService: IConfigurationService - ) { - super(id, label, configurationService); - } - - override async run(): Promise<void> { - this.setConfiguredZoomLevel(getZoomLevel() + 1); - } -} - -export class ZoomOutAction extends BaseZoomAction { - - static readonly ID = 'workbench.action.zoomOut'; - static readonly LABEL = localize('zoomOut', "Zoom Out"); - - constructor( - id: string, - label: string, - @IConfigurationService configurationService: IConfigurationService - ) { - super(id, label, configurationService); - } - - override async run(): Promise<void> { - this.setConfiguredZoomLevel(getZoomLevel() - 1); - } -} - -export class ZoomResetAction extends BaseZoomAction { - - static readonly ID = 'workbench.action.zoomReset'; - static readonly LABEL = localize('zoomReset', "Reset Zoom"); - - constructor( - id: string, - label: string, - @IConfigurationService configurationService: IConfigurationService - ) { - super(id, label, configurationService); - } - - override async run(): Promise<void> { - this.setConfiguredZoomLevel(0); - } -} - -export abstract class BaseSwitchWindow extends Action { - - private readonly closeWindowAction: IQuickInputButton = { - iconClass: Codicon.removeClose.classNames, - tooltip: localize('close', "Close Window") - }; - - private readonly closeDirtyWindowAction: IQuickInputButton = { - iconClass: 'dirty-window ' + Codicon.closeDirty, - tooltip: localize('close', "Close Window"), - alwaysVisible: true - }; - - constructor( - id: string, - label: string, - private readonly quickInputService: IQuickInputService, - private readonly keybindingService: IKeybindingService, - private readonly modelService: IModelService, - private readonly modeService: IModeService, - private readonly nativeHostService: INativeHostService - ) { - super(id, label); - } - - protected abstract isQuickNavigate(): boolean; - - override async run(): Promise<void> { - const currentWindowId = this.nativeHostService.windowId; - - const windows = await this.nativeHostService.getWindows(); - const placeHolder = localize('switchWindowPlaceHolder', "Select a window to switch to"); - const picks = windows.map(window => { - const resource = window.filename ? URI.file(window.filename) : isSingleFolderWorkspaceIdentifier(window.workspace) ? window.workspace.uri : isWorkspaceIdentifier(window.workspace) ? window.workspace.configPath : undefined; - const fileKind = window.filename ? FileKind.FILE : isSingleFolderWorkspaceIdentifier(window.workspace) ? FileKind.FOLDER : isWorkspaceIdentifier(window.workspace) ? FileKind.ROOT_FOLDER : FileKind.FILE; - return { - payload: window.id, - label: window.title, - ariaLabel: window.dirty ? localize('windowDirtyAriaLabel', "{0}, dirty window", window.title) : window.title, - iconClasses: getIconClasses(this.modelService, this.modeService, resource, fileKind), - description: (currentWindowId === window.id) ? localize('current', "Current Window") : undefined, - buttons: currentWindowId !== window.id ? window.dirty ? [this.closeDirtyWindowAction] : [this.closeWindowAction] : undefined - }; - }); - const autoFocusIndex = (picks.indexOf(picks.filter(pick => pick.payload === currentWindowId)[0]) + 1) % picks.length; - - const pick = await this.quickInputService.pick(picks, { - contextKey: 'inWindowsPicker', - activeItem: picks[autoFocusIndex], - placeHolder, - quickNavigate: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : undefined, - onDidTriggerItemButton: async context => { - await this.nativeHostService.closeWindowById(context.item.payload); - context.removeItem(); - } - }); - - if (pick) { - this.nativeHostService.focusWindow({ windowId: pick.payload }); - } - } -} - -export class SwitchWindow extends BaseSwitchWindow { - - static readonly ID = 'workbench.action.switchWindow'; - static readonly LABEL = localize('switchWindow', "Switch Window..."); - - constructor( - id: string, - label: string, - @IQuickInputService quickInputService: IQuickInputService, - @IKeybindingService keybindingService: IKeybindingService, - @IModelService modelService: IModelService, - @IModeService modeService: IModeService, - @INativeHostService nativeHostService: INativeHostService - ) { - super(id, label, quickInputService, keybindingService, modelService, modeService, nativeHostService); - } - - protected isQuickNavigate(): boolean { - return false; - } -} - -export class QuickSwitchWindow extends BaseSwitchWindow { - - static readonly ID = 'workbench.action.quickSwitchWindow'; - static readonly LABEL = localize('quickSwitchWindow', "Quick Switch Window..."); - - constructor( - id: string, - label: string, - @IQuickInputService quickInputService: IQuickInputService, - @IKeybindingService keybindingService: IKeybindingService, - @IModelService modelService: IModelService, - @IModeService modeService: IModeService, - @INativeHostService nativeHostService: INativeHostService - ) { - super(id, label, quickInputService, keybindingService, modelService, modeService, nativeHostService); - } - - protected isQuickNavigate(): boolean { - return true; - } -} - -export const NewWindowTabHandler: ICommandHandler = function (accessor: ServicesAccessor) { - return accessor.get(INativeHostService).newWindowTab(); -}; - -export const ShowPreviousWindowTabHandler: ICommandHandler = function (accessor: ServicesAccessor) { - return accessor.get(INativeHostService).showPreviousWindowTab(); -}; - -export const ShowNextWindowTabHandler: ICommandHandler = function (accessor: ServicesAccessor) { - return accessor.get(INativeHostService).showNextWindowTab(); -}; - -export const MoveWindowTabToNewWindowHandler: ICommandHandler = function (accessor: ServicesAccessor) { - return accessor.get(INativeHostService).moveWindowTabToNewWindow(); -}; - -export const MergeWindowTabsHandlerHandler: ICommandHandler = function (accessor: ServicesAccessor) { - return accessor.get(INativeHostService).mergeAllWindowTabs(); -}; - -export const ToggleWindowTabsBarHandler: ICommandHandler = function (accessor: ServicesAccessor) { - return accessor.get(INativeHostService).toggleWindowTabsBar(); -}; diff --git a/lib/vscode/src/vs/workbench/services/localizations/browser/localizationsService.ts b/lib/vscode/src/vs/workbench/services/localizations/browser/localizationsService.ts deleted file mode 100644 index 721a233b295e..000000000000 --- a/lib/vscode/src/vs/workbench/services/localizations/browser/localizationsService.ts +++ /dev/null @@ -1,23 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Coder Technologies. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; -import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; - -// @ts-ignore: interface is implemented via proxy -export class LocalizationsService implements ILocalizationsService { - - declare readonly _serviceBrand: undefined; - - constructor( - @IRemoteAgentService remoteAgentService: IRemoteAgentService, - ) { - return ProxyChannel.toService<ILocalizationsService>(remoteAgentService.getConnection()!.getChannel('localizations')); - } -} - -registerSingleton(ILocalizationsService, LocalizationsService, true); diff --git a/lib/vscode/src/vs/workbench/services/textfile/browser/browserTextFileService.ts b/lib/vscode/src/vs/workbench/services/textfile/browser/browserTextFileService.ts deleted file mode 100644 index ade0b17718f2..000000000000 --- a/lib/vscode/src/vs/workbench/services/textfile/browser/browserTextFileService.ts +++ /dev/null @@ -1,28 +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 { AbstractTextFileService } from 'vs/workbench/services/textfile/browser/textFileService'; -import { ITextFileService, TextFileEditorModelState } from 'vs/workbench/services/textfile/common/textfiles'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; - -export class BrowserTextFileService extends AbstractTextFileService { - - protected override registerListeners(): void { - super.registerListeners(); - - // Lifecycle - this.lifecycleService.onBeforeShutdown(event => event.veto(this.onBeforeShutdown(), 'veto.textFiles')); - } - - private onBeforeShutdown(): boolean { - if (this.files.models.some(model => model.hasState(TextFileEditorModelState.PENDING_SAVE))) { - return true; // files are pending to be saved: veto (as there is no support for long running operations on shutdown) - } - - return false; - } -} - -registerSingleton(ITextFileService, BrowserTextFileService); diff --git a/lib/vscode/src/vs/workbench/services/workingCopy/common/legacyBackupRestorer.ts b/lib/vscode/src/vs/workbench/services/workingCopy/common/legacyBackupRestorer.ts deleted file mode 100644 index 99ef284a33bf..000000000000 --- a/lib/vscode/src/vs/workbench/services/workingCopy/common/legacyBackupRestorer.ts +++ /dev/null @@ -1,136 +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 { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/common/workingCopyBackup'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IResourceEditorInput } from 'vs/platform/editor/common/editor'; -import { Schemas } from 'vs/base/common/network'; -import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { IUntitledTextResourceEditorInput, IEditorInput, IEditorInputFactoryRegistry, EditorExtensions, IEditorInputWithOptions } from 'vs/workbench/common/editor'; -import { toLocalResource, isEqual } from 'vs/base/common/resources'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IPathService } from 'vs/workbench/services/path/common/pathService'; -import { ILogService } from 'vs/platform/log/common/log'; -import { Promises } from 'vs/base/common/async'; -import { IWorkingCopyIdentifier } from 'vs/workbench/services/workingCopy/common/workingCopy'; - -/** - * @deprecated TODO@bpasero remove me once all backups are handled properly - */ -export class LegacyWorkingCopyBackupRestorer implements IWorkbenchContribution { - - private static readonly UNTITLED_REGEX = /Untitled-\d+/; - - private readonly editorInputFactories = Registry.as<IEditorInputFactoryRegistry>(EditorExtensions.EditorInputFactories); - - constructor( - @IEditorService private readonly editorService: IEditorService, - @IWorkingCopyBackupService private readonly workingCopyBackupService: IWorkingCopyBackupService, - @ILifecycleService private readonly lifecycleService: ILifecycleService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, - @IInstantiationService private readonly instantiationService: IInstantiationService, - @IPathService private readonly pathService: IPathService, - @ILogService private readonly logService: ILogService - ) { - this.restoreLegacyBackups(); - } - - private restoreLegacyBackups(): void { - this.lifecycleService.when(LifecyclePhase.Restored).then(() => this.doRestoreLegacyBackups()); - } - - protected async doRestoreLegacyBackups(): Promise<void> { - - // Resolve all backup resources that exist for this window - // that have not yet adopted the working copy editor handler - // - any working copy without `typeId` - // - not `search-edior:/` (supports migration to typeId) - const backups = (await this.workingCopyBackupService.getBackups()) - .filter(backup => backup.typeId.length === 0) - .filter(backup => backup.resource.scheme !== 'search-editor'); - - // Trigger `resolve` in each opened editor that can be found - // for the given resource and keep track of backups that are - // not opened. - const unresolvedBackups = await this.resolveOpenedBackupEditors(backups); - - // For remaining unresolved backups, explicitly open an editor - if (unresolvedBackups.length > 0) { - try { - await this.openEditors(unresolvedBackups); - } catch (error) { - this.logService.error(error); - } - - // Finally trigger `resolve` in the newly opened editors - await this.resolveOpenedBackupEditors(unresolvedBackups); - } - } - - private async resolveOpenedBackupEditors(backups: readonly IWorkingCopyIdentifier[]): Promise<IWorkingCopyIdentifier[]> { - const unresolvedBackups: IWorkingCopyIdentifier[] = []; - - await Promises.settled(backups.map(async backup => { - const openedEditor = this.findOpenedEditor(backup); - if (openedEditor) { - try { - await openedEditor.resolve(); - } catch (error) { - unresolvedBackups.push(backup); // ignore error and remember as unresolved - } - } else { - unresolvedBackups.push(backup); - } - })); - - return unresolvedBackups; - } - - private findOpenedEditor(backup: IWorkingCopyIdentifier): IEditorInput | undefined { - for (const editor of this.editorService.editors) { - const customFactory = this.editorInputFactories.getCustomEditorInputFactory(backup.resource.scheme); - if (customFactory?.canResolveBackup(editor, backup.resource) || isEqual(editor.resource, backup.resource)) { - return editor; - } - } - - return undefined; - } - - private async openEditors(backups: IWorkingCopyIdentifier[]): Promise<void> { - const hasOpenedEditors = this.editorService.visibleEditors.length > 0; - const editors = await Promises.settled(backups.map((backup, index) => this.resolveEditor(backup, index, hasOpenedEditors))); - - await this.editorService.openEditors(editors); - } - - private async resolveEditor(backup: IWorkingCopyIdentifier, index: number, hasOpenedEditors: boolean): Promise<IResourceEditorInput | IUntitledTextResourceEditorInput | IEditorInputWithOptions> { - - // Set editor as `inactive` if we have other editors - const options = { pinned: true, preserveFocus: true, inactive: index > 0 || hasOpenedEditors }; - - // This is a (weak) strategy to find out if the untitled input had - // an associated file path or not by just looking at the path. and - // if so, we must ensure to restore the local resource it had. - if (backup.resource.scheme === Schemas.untitled && !LegacyWorkingCopyBackupRestorer.UNTITLED_REGEX.test(backup.resource.path)) { - return { resource: toLocalResource(backup.resource, this.environmentService.remoteAuthority, this.pathService.defaultUriScheme), options, forceUntitled: true }; - } - - // Handle custom editors by asking the custom editor input factory - // to create the input. - const customFactory = this.editorInputFactories.getCustomEditorInputFactory(backup.resource.scheme); - if (customFactory) { - const editor = await customFactory.createCustomEditorInput(backup.resource, this.instantiationService); - - return { editor, options }; - } - - // Finally return with a simple resource based input - return { resource: backup.resource, options }; - } -} diff --git a/lib/vscode/src/vs/workbench/services/workingCopy/test/browser/legacyBackupRestorer.test.ts b/lib/vscode/src/vs/workbench/services/workingCopy/test/browser/legacyBackupRestorer.test.ts deleted file mode 100644 index 42e4490556b6..000000000000 --- a/lib/vscode/src/vs/workbench/services/workingCopy/test/browser/legacyBackupRestorer.test.ts +++ /dev/null @@ -1,113 +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 assert from 'assert'; -import { isWindows } from 'vs/base/common/platform'; -import { URI } from 'vs/base/common/uri'; -import { bufferToReadable, VSBuffer } from 'vs/base/common/buffer'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { EditorService } from 'vs/workbench/services/editor/browser/editorService'; -import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/common/workingCopyBackup'; -import { Schemas } from 'vs/base/common/network'; -import { isEqual } from 'vs/base/common/resources'; -import { createEditorPart, InMemoryTestWorkingCopyBackupService, registerTestResourceEditor, TestServiceAccessor, toUntypedWorkingCopyId, workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices'; -import { LegacyWorkingCopyBackupRestorer } from 'vs/workbench/services/workingCopy/common/legacyBackupRestorer'; -import { BrowserWorkingCopyBackupTracker } from 'vs/workbench/services/workingCopy/browser/workingCopyBackupTracker'; -import { DisposableStore } from 'vs/base/common/lifecycle'; - -suite('LegacyWorkingCopyBackupRestorer', () => { - - class TestBackupRestorer extends LegacyWorkingCopyBackupRestorer { - override async doRestoreLegacyBackups(): Promise<void> { - return super.doRestoreLegacyBackups(); - } - } - - let accessor: TestServiceAccessor; - let disposables = new DisposableStore(); - - const fooFile = URI.file(isWindows ? 'c:\\Foo' : '/Foo'); - const barFile = URI.file(isWindows ? 'c:\\Bar' : '/Bar'); - const untitledFile1 = URI.from({ scheme: Schemas.untitled, path: 'Untitled-1' }); - const untitledFile2 = URI.from({ scheme: Schemas.untitled, path: 'Untitled-2' }); - - setup(() => { - disposables.add(registerTestResourceEditor()); - }); - - teardown(() => { - disposables.clear(); - }); - - test('Restore backups', async function () { - const workingCopyBackupService = new InMemoryTestWorkingCopyBackupService(); - const instantiationService = workbenchInstantiationService(); - instantiationService.stub(IWorkingCopyBackupService, workingCopyBackupService); - - const part = await createEditorPart(instantiationService, disposables); - - instantiationService.stub(IEditorGroupsService, part); - - const editorService: EditorService = instantiationService.createInstance(EditorService); - instantiationService.stub(IEditorService, editorService); - - accessor = instantiationService.createInstance(TestServiceAccessor); - - disposables.add(instantiationService.createInstance(BrowserWorkingCopyBackupTracker)); - const restorer = instantiationService.createInstance(TestBackupRestorer); - - // Backup 2 normal files and 2 untitled files - await workingCopyBackupService.backup(toUntypedWorkingCopyId(untitledFile1), bufferToReadable(VSBuffer.fromString('untitled-1'))); - await workingCopyBackupService.backup(toUntypedWorkingCopyId(untitledFile2), bufferToReadable(VSBuffer.fromString('untitled-2'))); - await workingCopyBackupService.backup(toUntypedWorkingCopyId(fooFile), bufferToReadable(VSBuffer.fromString('fooFile'))); - await workingCopyBackupService.backup(toUntypedWorkingCopyId(barFile), bufferToReadable(VSBuffer.fromString('barFile'))); - - // Verify backups restored and opened as dirty - await restorer.doRestoreLegacyBackups(); - assert.strictEqual(editorService.count, 4); - assert.ok(editorService.editors.every(editor => editor.isDirty())); - - let counter = 0; - for (const editor of editorService.editors) { - const resource = editor.resource; - if (isEqual(resource, untitledFile1)) { - const model = await accessor.textFileService.untitled.resolve({ untitledResource: resource }); - if (model.textEditorModel?.getValue() !== 'untitled-1') { - const backupContents = await workingCopyBackupService.getBackupContents(model); - assert.fail(`Unable to restore backup for resource ${untitledFile1.toString()}. Backup contents: ${backupContents}`); - } - model.dispose(); - counter++; - } else if (isEqual(resource, untitledFile2)) { - const model = await accessor.textFileService.untitled.resolve({ untitledResource: resource }); - if (model.textEditorModel?.getValue() !== 'untitled-2') { - const backupContents = await workingCopyBackupService.getBackupContents(model); - assert.fail(`Unable to restore backup for resource ${untitledFile2.toString()}. Backup contents: ${backupContents}`); - } - model.dispose(); - counter++; - } else if (isEqual(resource, fooFile)) { - const model = accessor.textFileService.files.get(fooFile); - await model?.resolve(); - if (model?.textEditorModel?.getValue() !== 'fooFile') { - const backupContents = await workingCopyBackupService.getBackupContents(model!); - assert.fail(`Unable to restore backup for resource ${fooFile.toString()}. Backup contents: ${backupContents}`); - } - counter++; - } else { - const model = accessor.textFileService.files.get(barFile); - await model?.resolve(); - if (model?.textEditorModel?.getValue() !== 'barFile') { - const backupContents = await workingCopyBackupService.getBackupContents(model!); - assert.fail(`Unable to restore backup for resource ${barFile.toString()}. Backup contents: ${backupContents}`); - } - counter++; - } - } - - assert.strictEqual(counter, 4); - }); -}); diff --git a/lib/vscode/src/vs/workbench/services/workspaces/common/workspaceTrust.ts b/lib/vscode/src/vs/workbench/services/workspaces/common/workspaceTrust.ts deleted file mode 100644 index ac0463e5590c..000000000000 --- a/lib/vscode/src/vs/workbench/services/workspaces/common/workspaceTrust.ts +++ /dev/null @@ -1,378 +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 { Emitter } from 'vs/base/common/event'; -import { splitName } from 'vs/base/common/labels'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { Schemas } from 'vs/base/common/network'; -import { isWeb } from 'vs/base/common/platform'; -import { dirname } from 'vs/base/common/resources'; -import { URI } from 'vs/base/common/uri'; -import { localize } from 'vs/nls'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; -import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { WorkspaceTrustRequestOptions, IWorkspaceTrustManagementService, IWorkspaceTrustInfo, IWorkspaceTrustUriInfo, IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust'; -import { isSingleFolderWorkspaceIdentifier, isUntitledWorkspace, toWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; - -export const WORKSPACE_TRUST_ENABLED = 'security.workspace.trust.enabled'; -export const WORKSPACE_TRUST_STARTUP_PROMPT = 'security.workspace.trust.startupPrompt'; -export const WORKSPACE_TRUST_EXTENSION_SUPPORT = 'extensions.supportUntrustedWorkspaces'; -export const WORKSPACE_TRUST_STORAGE_KEY = 'content.trust.model.key'; - -export const WorkspaceTrustContext = { - PendingRequest: new RawContextKey<boolean>('workspaceTrustPendingRequest', false), - IsTrusted: new RawContextKey<boolean>('isWorkspaceTrusted', false, localize('workspaceTrustCtx', "Whether the current workspace has been trusted by the user.")) -}; - -export function isWorkspaceTrustEnabled(configurationService: IConfigurationService): boolean { - if (isWeb) { - return false; - } - - return configurationService.inspect<boolean>(WORKSPACE_TRUST_ENABLED).userValue ?? false; -} - -export class WorkspaceTrustManagementService extends Disposable implements IWorkspaceTrustManagementService { - - _serviceBrand: undefined; - - private readonly storageKey = WORKSPACE_TRUST_STORAGE_KEY; - - private readonly _onDidChangeTrust = this._register(new Emitter<boolean>()); - readonly onDidChangeTrust = this._onDidChangeTrust.event; - - private readonly _onDidChangeTrustedFolders = this._register(new Emitter<void>()); - readonly onDidChangeTrustedFolders = this._onDidChangeTrustedFolders.event; - - private _isWorkspaceTrusted: boolean = false; - private _trustStateInfo: IWorkspaceTrustInfo; - - constructor( - @IConfigurationService readonly configurationService: IConfigurationService, - @IEnvironmentService private readonly environmentService: IEnvironmentService, - @IStorageService private readonly storageService: IStorageService, - @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, - @IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService - ) { - super(); - - this._trustStateInfo = this.loadTrustInfo(); - this._isWorkspaceTrusted = this.calculateWorkspaceTrust(); - - this.registerListeners(); - } - - private set currentTrustState(trusted: boolean) { - if (this._isWorkspaceTrusted === trusted) { return; } - this._isWorkspaceTrusted = trusted; - - this._onDidChangeTrust.fire(trusted); - } - - private registerListeners(): void { - this._register(this.workspaceService.onDidChangeWorkspaceFolders(() => this.currentTrustState = this.calculateWorkspaceTrust())); - this._register(this.workspaceService.onDidChangeWorkbenchState(() => this.currentTrustState = this.calculateWorkspaceTrust())); - this._register(this.storageService.onDidChangeValue(changeEvent => { - if (changeEvent.key === this.storageKey) { - this._trustStateInfo = this.loadTrustInfo(); - this.currentTrustState = this.calculateWorkspaceTrust(); - - this._onDidChangeTrustedFolders.fire(); - } - })); - } - - private loadTrustInfo(): IWorkspaceTrustInfo { - const infoAsString = this.storageService.get(this.storageKey, StorageScope.GLOBAL); - - let result: IWorkspaceTrustInfo | undefined; - try { - if (infoAsString) { - result = JSON.parse(infoAsString); - } - } catch { } - - if (!result) { - result = { - uriTrustInfo: [] - }; - } - - if (!result.uriTrustInfo) { - result.uriTrustInfo = []; - } - - result.uriTrustInfo = result.uriTrustInfo.map(info => { return { uri: URI.revive(info.uri), trusted: info.trusted }; }); - result.uriTrustInfo = result.uriTrustInfo.filter(info => info.trusted); - - return result; - } - - private saveTrustInfo(): void { - this.storageService.store(this.storageKey, JSON.stringify(this._trustStateInfo), StorageScope.GLOBAL, StorageTarget.MACHINE); - } - - private calculateWorkspaceTrust(): boolean { - if (!isWorkspaceTrustEnabled(this.configurationService)) { - return true; - } - - if (this.environmentService.extensionTestsLocationURI) { - return true; // trust running tests with vscode-test - } - - if (this.workspaceService.getWorkbenchState() === WorkbenchState.EMPTY) { - return true; - } - - const workspaceFolders = this.getWorkspaceFolders(); - const trusted = this.getFoldersTrust(workspaceFolders); - - return trusted; - } - - private getFoldersTrust(folders: URI[]): boolean { - let state = true; - for (const folder of folders) { - const { trusted } = this.getFolderTrustInfo(folder); - - if (!trusted) { - state = trusted; - return state; - } - } - - return state; - } - - private getWorkspaceFolders(): URI[] { - const folderURIs = this.workspaceService.getWorkspace().folders.map(f => f.uri); - const workspaceConfiguration = this.workspaceService.getWorkspace().configuration; - if (workspaceConfiguration && !isUntitledWorkspace(workspaceConfiguration, this.environmentService)) { - folderURIs.push(dirname(workspaceConfiguration)); - } - - return folderURIs; - } - - public getFolderTrustInfo(folder: URI): IWorkspaceTrustUriInfo { - let resultState = false; - let maxLength = -1; - - let resultUri = folder; - - for (const trustInfo of this._trustStateInfo.uriTrustInfo) { - if (this.uriIdentityService.extUri.isEqualOrParent(folder, trustInfo.uri)) { - const fsPath = trustInfo.uri.fsPath; - if (fsPath.length > maxLength) { - maxLength = fsPath.length; - resultState = trustInfo.trusted; - resultUri = trustInfo.uri; - } - } - } - - return { trusted: resultState, uri: resultUri }; - } - - setFoldersTrust(folders: URI[], trusted: boolean): void { - let changed = false; - - for (const folder of folders) { - if (trusted) { - const foundItem = this._trustStateInfo.uriTrustInfo.find(trustInfo => this.uriIdentityService.extUri.isEqual(trustInfo.uri, folder)); - if (!foundItem) { - this._trustStateInfo.uriTrustInfo.push({ uri: folder, trusted: true }); - changed = true; - } - } else { - const previousLength = this._trustStateInfo.uriTrustInfo.length; - this._trustStateInfo.uriTrustInfo = this._trustStateInfo.uriTrustInfo.filter(trustInfo => !this.uriIdentityService.extUri.isEqual(trustInfo.uri, folder)); - if (previousLength !== this._trustStateInfo.uriTrustInfo.length) { - changed = true; - } - } - } - - if (changed) { - this.saveTrustInfo(); - } - } - - canSetWorkspaceTrust(): boolean { - return this.workspaceService.getWorkbenchState() !== WorkbenchState.EMPTY; - } - - canSetParentFolderTrust(): boolean { - const workspaceIdentifier = toWorkspaceIdentifier(this.workspaceService.getWorkspace()); - return isSingleFolderWorkspaceIdentifier(workspaceIdentifier) && workspaceIdentifier.uri.scheme === Schemas.file; - } - - isWorkpaceTrusted(): boolean { - return this._isWorkspaceTrusted; - } - - setParentFolderTrust(trusted: boolean): void { - const workspaceIdentifier = toWorkspaceIdentifier(this.workspaceService.getWorkspace()); - if (isSingleFolderWorkspaceIdentifier(workspaceIdentifier) && workspaceIdentifier.uri.scheme === Schemas.file) { - const { parentPath } = splitName(workspaceIdentifier.uri.fsPath); - - this.setFoldersTrust([URI.file(parentPath)], trusted); - } - } - - setWorkspaceTrust(trusted: boolean): void { - const workspaceFolders = this.getWorkspaceFolders(); - this.setFoldersTrust(workspaceFolders, trusted); - } - - getTrustedFolders(): URI[] { - return this._trustStateInfo.uriTrustInfo.map(info => info.uri); - } - - setTrustedFolders(folders: URI[]): void { - this._trustStateInfo.uriTrustInfo = []; - for (const folder of folders) { - this._trustStateInfo.uriTrustInfo.push({ - trusted: true, - uri: folder - }); - } - - this.saveTrustInfo(); - } -} - -export class WorkspaceTrustRequestService extends Disposable implements IWorkspaceTrustRequestService { - _serviceBrand: undefined; - - private _trusted!: boolean; - private _trustRequestPromise?: Promise<boolean>; - private _trustRequestResolver?: (trusted: boolean) => void; - private _modalTrustRequestPromise?: Promise<boolean | undefined>; - private _modalTrustRequestResolver?: (trusted: boolean | undefined) => void; - private readonly _ctxWorkspaceTrustState: IContextKey<boolean>; - private readonly _ctxWorkspaceTrustPendingRequest: IContextKey<boolean>; - - private readonly _onDidInitiateWorkspaceTrustRequest = this._register(new Emitter<WorkspaceTrustRequestOptions>()); - readonly onDidInitiateWorkspaceTrustRequest = this._onDidInitiateWorkspaceTrustRequest.event; - - private readonly _onDidCompleteWorkspaceTrustRequest = this._register(new Emitter<boolean>()); - readonly onDidCompleteWorkspaceTrustRequest = this._onDidCompleteWorkspaceTrustRequest.event; - - constructor( - @IContextKeyService contextKeyService: IContextKeyService, - @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService, - ) { - super(); - - this._register(this.workspaceTrustManagementService.onDidChangeTrust(trusted => this.onTrustStateChanged(trusted))); - - this._ctxWorkspaceTrustState = WorkspaceTrustContext.IsTrusted.bindTo(contextKeyService); - this._ctxWorkspaceTrustPendingRequest = WorkspaceTrustContext.PendingRequest.bindTo(contextKeyService); - - this.trusted = this.workspaceTrustManagementService.isWorkpaceTrusted(); - } - - private get trusted(): boolean { - return this._trusted; - } - - private set trusted(trusted: boolean) { - this._trusted = trusted; - this._ctxWorkspaceTrustState.set(trusted); - } - - private onTrustStateChanged(trusted: boolean): void { - // Resolve any pending soft requests for workspace trust - if (this._trustRequestResolver) { - this._trustRequestResolver(trusted); - - this._trustRequestResolver = undefined; - this._trustRequestPromise = undefined; - } - - // Update context if there are no pending requests - if (!this._modalTrustRequestPromise && !this._trustRequestPromise) { - this._ctxWorkspaceTrustPendingRequest.set(false); - } - - this.trusted = trusted; - } - - cancelRequest(): void { - if (this._modalTrustRequestResolver) { - this._modalTrustRequestResolver(undefined); - - this._modalTrustRequestResolver = undefined; - this._modalTrustRequestPromise = undefined; - } - } - - completeRequest(trusted?: boolean): void { - if (this._modalTrustRequestResolver) { - this._modalTrustRequestResolver(trusted ?? this.trusted); - - this._modalTrustRequestResolver = undefined; - this._modalTrustRequestPromise = undefined; - } - if (this._trustRequestResolver) { - this._trustRequestResolver(trusted ?? this.trusted); - - this._trustRequestResolver = undefined; - this._trustRequestPromise = undefined; - } - - if (trusted === undefined) { - return; - } - - this.workspaceTrustManagementService.setWorkspaceTrust(trusted); - this._onDidCompleteWorkspaceTrustRequest.fire(trusted); - } - - async requestWorkspaceTrust(options: WorkspaceTrustRequestOptions = { modal: false }): Promise<boolean | undefined> { - // Trusted workspace - if (this.trusted) { - return this.trusted; - } - - if (options.modal) { - // Modal request - if (!this._modalTrustRequestPromise) { - // Create promise - this._modalTrustRequestPromise = new Promise(resolve => { - this._modalTrustRequestResolver = resolve; - }); - } else { - // Return existing promise - return this._modalTrustRequestPromise; - } - } else { - // Soft request - if (!this._trustRequestPromise) { - // Create promise - this._trustRequestPromise = new Promise(resolve => { - this._trustRequestResolver = resolve; - }); - } else { - // Return existing promise - return this._trustRequestPromise; - } - } - - this._ctxWorkspaceTrustPendingRequest.set(true); - this._onDidInitiateWorkspaceTrustRequest.fire(options); - - return options.modal ? this._modalTrustRequestPromise! : this._trustRequestPromise!; - } -} - -registerSingleton(IWorkspaceTrustRequestService, WorkspaceTrustRequestService); diff --git a/lib/vscode/src/vs/workbench/test/browser/api/extHostNotebookKernel2.test.ts b/lib/vscode/src/vs/workbench/test/browser/api/extHostNotebookKernel2.test.ts deleted file mode 100644 index 1af0ca885cc3..000000000000 --- a/lib/vscode/src/vs/workbench/test/browser/api/extHostNotebookKernel2.test.ts +++ /dev/null @@ -1,96 +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 assert from 'assert'; -import { TestRPCProtocol } from 'vs/workbench/test/browser/api/testRPCProtocol'; -import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook'; -import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; -import { mock } from 'vs/workbench/test/common/workbenchTestServices'; -import { INotebookKernelDto2, MainContext, MainThreadCommandsShape, MainThreadNotebookKernelsShape } from 'vs/workbench/api/common/extHost.protocol'; -import { ExtHostNotebookKernels } from 'vs/workbench/api/common/extHostNotebookKernels'; -import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; -import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; - -suite('NotebookKernel', function () { - - let rpcProtocol: TestRPCProtocol; - let extHostNotebookKernels: ExtHostNotebookKernels; - - const kernelData = new Map<number, INotebookKernelDto2>(); - - setup(async function () { - - kernelData.clear(); - - rpcProtocol = new TestRPCProtocol(); - rpcProtocol.set(MainContext.MainThreadCommands, new class extends mock<MainThreadCommandsShape>() { - override $registerCommand() { } - }); - rpcProtocol.set(MainContext.MainThreadNotebookKernels, new class extends mock<MainThreadNotebookKernelsShape>() { - override async $addKernel(handle: number, data: INotebookKernelDto2): Promise<void> { - kernelData.set(handle, data); - } - override $removeKernel(handle: number) { - kernelData.delete(handle); - } - override $updateKernel(handle: number, data: Partial<INotebookKernelDto2>) { - assert.strictEqual(kernelData.has(handle), true); - kernelData.set(handle, { ...kernelData.get(handle)!, ...data, }); - } - }); - - extHostNotebookKernels = new ExtHostNotebookKernels( - rpcProtocol, - new class extends mock<IExtHostInitDataService>() { }, - new class extends mock<ExtHostNotebookController>() { } - ); - }); - - test('create/dispose kernel', async function () { - - const kernel = extHostNotebookKernels.createNotebookController(nullExtensionDescription, 'foo', '*', 'Foo'); - - assert.throws(() => (<any>kernel).id = 'dd'); - assert.throws(() => (<any>kernel).viewType = 'dd'); - - assert.ok(kernel); - assert.strictEqual(kernel.id, 'foo'); - assert.strictEqual(kernel.label, 'Foo'); - assert.strictEqual(kernel.viewType, '*'); - - await rpcProtocol.sync(); - assert.strictEqual(kernelData.size, 1); - - let [first] = kernelData.values(); - assert.strictEqual(first.id, 'nullExtensionDescription/foo'); - assert.strictEqual(ExtensionIdentifier.equals(first.extensionId, nullExtensionDescription.identifier), true); - assert.strictEqual(first.label, 'Foo'); - assert.strictEqual(first.viewType, '*'); - - kernel.dispose(); - await rpcProtocol.sync(); - assert.strictEqual(kernelData.size, 0); - }); - - test('update kernel', async function () { - - const kernel = extHostNotebookKernels.createNotebookController(nullExtensionDescription, 'foo', '*', 'Foo'); - - await rpcProtocol.sync(); - assert.ok(kernel); - - let [first] = kernelData.values(); - assert.strictEqual(first.id, 'nullExtensionDescription/foo'); - assert.strictEqual(first.label, 'Foo'); - - kernel.label = 'Far'; - assert.strictEqual(kernel.label, 'Far'); - - await rpcProtocol.sync(); - [first] = kernelData.values(); - assert.strictEqual(first.id, 'nullExtensionDescription/foo'); - assert.strictEqual(first.label, 'Far'); - }); -}); diff --git a/lib/vscode/src/vs/workbench/test/browser/parts/editor/resourceEditorInput.test.ts b/lib/vscode/src/vs/workbench/test/browser/parts/editor/resourceEditorInput.test.ts deleted file mode 100644 index 09baace30db9..000000000000 --- a/lib/vscode/src/vs/workbench/test/browser/parts/editor/resourceEditorInput.test.ts +++ /dev/null @@ -1,54 +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 assert from 'assert'; -import { URI } from 'vs/base/common/uri'; -import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; -import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { workbenchInstantiationService, TestServiceAccessor } from 'vs/workbench/test/browser/workbenchTestServices'; -import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; -import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; - -suite('Resource text editors', () => { - - let instantiationService: IInstantiationService; - let accessor: TestServiceAccessor; - - setup(() => { - instantiationService = workbenchInstantiationService(); - accessor = instantiationService.createInstance(TestServiceAccessor); - }); - - test('basics', async () => { - const resource = URI.from({ scheme: 'inmemory', authority: null!, path: 'thePath' }); - accessor.modelService.createModel('function test() {}', accessor.modeService.create('text'), resource); - - const input: ResourceEditorInput = instantiationService.createInstance(ResourceEditorInput, resource, 'The Name', 'The Description', undefined); - - const model = await input.resolve(); - - assert.ok(model); - assert.strictEqual(snapshotToString(((model as ResourceEditorModel).createSnapshot()!)), 'function test() {}'); - }); - - test('custom mode', async () => { - ModesRegistry.registerLanguage({ - id: 'resource-input-test', - }); - - const resource = URI.from({ scheme: 'inmemory', authority: null!, path: 'thePath' }); - accessor.modelService.createModel('function test() {}', accessor.modeService.create('text'), resource); - - const input: ResourceEditorInput = instantiationService.createInstance(ResourceEditorInput, resource, 'The Name', 'The Description', 'resource-input-test'); - - const model = await input.resolve(); - assert.ok(model); - assert.strictEqual(model.textEditorModel?.getModeId(), 'resource-input-test'); - - input.setMode('text'); - assert.strictEqual(model.textEditorModel?.getModeId(), PLAINTEXT_MODE_ID); - }); -}); diff --git a/lib/vscode/yarn.lock b/lib/vscode/yarn.lock deleted file mode 100644 index b812f49d6dc4..000000000000 --- a/lib/vscode/yarn.lock +++ /dev/null @@ -1,9823 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"7zip@0.0.6": - version "0.0.6" - resolved "https://registry.yarnpkg.com/7zip/-/7zip-0.0.6.tgz#9cafb171af82329490353b4816f03347aa150a30" - integrity sha1-nK+xca+CMpSQNTtIFvAzR6oVCjA= - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" - integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== - dependencies: - "@babel/highlight" "^7.12.13" - -"@babel/compat-data@^7.13.15": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.0.tgz#a901128bce2ad02565df95e6ecbf195cf9465919" - integrity sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q== - -"@babel/core@^7.7.5": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.0.tgz#47299ff3ec8d111b493f1a9d04bf88c04e728d88" - integrity sha512-8YqpRig5NmIHlMLw09zMlPTvUVMILjqCOtVgu+TVNWEBvy9b5I3RRyhqnrV4hjgEK7n8P9OqvkWJAFmEL6Wwfw== - dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.14.0" - "@babel/helper-compilation-targets" "^7.13.16" - "@babel/helper-module-transforms" "^7.14.0" - "@babel/helpers" "^7.14.0" - "@babel/parser" "^7.14.0" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.14.0" - "@babel/types" "^7.14.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.1.2" - semver "^6.3.0" - source-map "^0.5.0" - -"@babel/generator@^7.14.0": - version "7.14.1" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.1.tgz#1f99331babd65700183628da186f36f63d615c93" - integrity sha512-TMGhsXMXCP/O1WtQmZjpEYDhCYC9vFhayWZPJSZCGkPJgUqX0rF0wwtrYvnzVxIjcF80tkUertXVk5cwqi5cAQ== - dependencies: - "@babel/types" "^7.14.1" - jsesc "^2.5.1" - source-map "^0.5.0" - -"@babel/helper-compilation-targets@^7.13.16": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz#6e91dccf15e3f43e5556dffe32d860109887563c" - integrity sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA== - dependencies: - "@babel/compat-data" "^7.13.15" - "@babel/helper-validator-option" "^7.12.17" - browserslist "^4.14.5" - semver "^6.3.0" - -"@babel/helper-function-name@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz#93ad656db3c3c2232559fd7b2c3dbdcbe0eb377a" - integrity sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA== - dependencies: - "@babel/helper-get-function-arity" "^7.12.13" - "@babel/template" "^7.12.13" - "@babel/types" "^7.12.13" - -"@babel/helper-get-function-arity@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz#bc63451d403a3b3082b97e1d8b3fe5bd4091e583" - integrity sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg== - dependencies: - "@babel/types" "^7.12.13" - -"@babel/helper-member-expression-to-functions@^7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz#dfe368f26d426a07299d8d6513821768216e6d72" - integrity sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw== - dependencies: - "@babel/types" "^7.13.12" - -"@babel/helper-module-imports@^7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977" - integrity sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA== - dependencies: - "@babel/types" "^7.13.12" - -"@babel/helper-module-transforms@^7.14.0": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.14.0.tgz#8fcf78be220156f22633ee204ea81f73f826a8ad" - integrity sha512-L40t9bxIuGOfpIGA3HNkJhU9qYrf4y5A5LUSw7rGMSn+pcG8dfJ0g6Zval6YJGd2nEjI7oP00fRdnhLKndx6bw== - dependencies: - "@babel/helper-module-imports" "^7.13.12" - "@babel/helper-replace-supers" "^7.13.12" - "@babel/helper-simple-access" "^7.13.12" - "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/helper-validator-identifier" "^7.14.0" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.14.0" - "@babel/types" "^7.14.0" - -"@babel/helper-optimise-call-expression@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz#5c02d171b4c8615b1e7163f888c1c81c30a2aaea" - integrity sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA== - dependencies: - "@babel/types" "^7.12.13" - -"@babel/helper-replace-supers@^7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz#6442f4c1ad912502481a564a7386de0c77ff3804" - integrity sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.13.12" - "@babel/helper-optimise-call-expression" "^7.12.13" - "@babel/traverse" "^7.13.0" - "@babel/types" "^7.13.12" - -"@babel/helper-simple-access@^7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz#dd6c538afb61819d205a012c31792a39c7a5eaf6" - integrity sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA== - dependencies: - "@babel/types" "^7.13.12" - -"@babel/helper-split-export-declaration@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz#e9430be00baf3e88b0e13e6f9d4eaf2136372b05" - integrity sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg== - dependencies: - "@babel/types" "^7.12.13" - -"@babel/helper-validator-identifier@^7.14.0": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" - integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== - -"@babel/helper-validator-option@^7.12.17": - version "7.12.17" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" - integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw== - -"@babel/helpers@^7.14.0": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.14.0.tgz#ea9b6be9478a13d6f961dbb5f36bf75e2f3b8f62" - integrity sha512-+ufuXprtQ1D1iZTO/K9+EBRn+qPWMJjZSw/S0KlFrxCw4tkrzv9grgpDHkY9MeQTjTY8i2sp7Jep8DfU6tN9Mg== - dependencies: - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.14.0" - "@babel/types" "^7.14.0" - -"@babel/highlight@^7.12.13": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.0.tgz#3197e375711ef6bf834e67d0daec88e4f46113cf" - integrity sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg== - dependencies: - "@babel/helper-validator-identifier" "^7.14.0" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.12.13", "@babel/parser@^7.14.0": - version "7.14.1" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.1.tgz#1bd644b5db3f5797c4479d89ec1817fe02b84c47" - integrity sha512-muUGEKu8E/ftMTPlNp+mc6zL3E9zKWmF5sDHZ5MSsoTP9Wyz64AhEf9kD08xYJ7w6Hdcu8H550ircnPyWSIF0Q== - -"@babel/template@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327" - integrity sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA== - dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/parser" "^7.12.13" - "@babel/types" "^7.12.13" - -"@babel/traverse@^7.13.0", "@babel/traverse@^7.14.0": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.0.tgz#cea0dc8ae7e2b1dec65f512f39f3483e8cc95aef" - integrity sha512-dZ/a371EE5XNhTHomvtuLTUyx6UEoJmYX+DT5zBCQN3McHemsuIaKKYqsc/fs26BEkHs/lBZy0J571LP5z9kQA== - dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.14.0" - "@babel/helper-function-name" "^7.12.13" - "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/parser" "^7.14.0" - "@babel/types" "^7.14.0" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/types@^7.12.13", "@babel/types@^7.13.12", "@babel/types@^7.14.0", "@babel/types@^7.14.1": - version "7.14.1" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.1.tgz#095bd12f1c08ab63eff6e8f7745fa7c9cc15a9db" - integrity sha512-S13Qe85fzLs3gYRUnrpyeIrBJIMYv33qSTg1qoBwiG6nPKwUWAD9odSzWhEedpwOIzSEI6gbdQIWEMiCI42iBA== - dependencies: - "@babel/helper-validator-identifier" "^7.14.0" - to-fast-properties "^2.0.0" - -"@coder/logger@^1.1.16": - version "1.1.16" - resolved "https://registry.yarnpkg.com/@coder/logger/-/logger-1.1.16.tgz#ee5b1b188f680733f35c11b065bbd139d618c1e1" - integrity sha512-X6VB1++IkosYY6amRAiMvuvCf12NA4+ooX+gOuu5bJIkdjmh4Lz7QpJcWRdgxesvo1msriDDr9E/sDbIWf6vsQ== - -"@electron/get@^1.12.4": - version "1.12.4" - resolved "https://registry.yarnpkg.com/@electron/get/-/get-1.12.4.tgz#a5971113fc1bf8fa12a8789dc20152a7359f06ab" - integrity sha512-6nr9DbJPUR9Xujw6zD3y+rS95TyItEVM0NVjt1EehY2vUWfIgPiIPVHxCvaTS0xr2B+DRxovYVKbuOWqC35kjg== - dependencies: - debug "^4.1.1" - env-paths "^2.2.0" - fs-extra "^8.1.0" - got "^9.6.0" - progress "^2.0.3" - semver "^6.2.0" - sumchecker "^3.0.1" - optionalDependencies: - global-agent "^2.0.2" - global-tunnel-ng "^2.7.1" - -"@gulp-sourcemaps/identity-map@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/identity-map/-/identity-map-2.0.1.tgz#a6e8b1abec8f790ec6be2b8c500e6e68037c0019" - integrity sha512-Tb+nSISZku+eQ4X1lAkevcQa+jknn/OVUgZ3XCxEKIsLsqYuPoJwJOPQeaOk75X3WPftb29GWY1eqE7GLsXb1Q== - dependencies: - acorn "^6.4.1" - normalize-path "^3.0.0" - postcss "^7.0.16" - source-map "^0.6.0" - through2 "^3.0.1" - -"@gulp-sourcemaps/map-sources@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz#890ae7c5d8c877f6d384860215ace9d7ec945bda" - integrity sha1-iQrnxdjId/bThIYCFazp1+yUW9o= - dependencies: - normalize-path "^2.0.1" - through2 "^2.0.3" - -"@istanbuljs/schema@^0.1.2": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" - integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== - -"@nodelib/fs.scandir@2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69" - integrity sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA== - dependencies: - "@nodelib/fs.stat" "2.0.4" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.4", "@nodelib/fs.stat@^2.0.2": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz#a3f2dd61bab43b8db8fa108a121cfffe4c676655" - integrity sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.6" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz#cce9396b30aa5afe9e3756608f5831adcb53d063" - integrity sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow== - dependencies: - "@nodelib/fs.scandir" "2.1.4" - fastq "^1.6.0" - -"@npmcli/move-file@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" - integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== - dependencies: - mkdirp "^1.0.4" - rimraf "^3.0.2" - -"@octokit/auth-token@^2.4.4": - version "2.4.5" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.5.tgz#568ccfb8cb46f36441fac094ce34f7a875b197f3" - integrity sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA== - dependencies: - "@octokit/types" "^6.0.3" - -"@octokit/core@^3.2.3": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.4.0.tgz#b48aa27d755b339fe7550548b340dcc2b513b742" - integrity sha512-6/vlKPP8NF17cgYXqucdshWqmMZGXkuvtcrWCgU5NOI0Pl2GjlmZyWgBMrU8zJ3v2MJlM6++CiB45VKYmhiWWg== - dependencies: - "@octokit/auth-token" "^2.4.4" - "@octokit/graphql" "^4.5.8" - "@octokit/request" "^5.4.12" - "@octokit/request-error" "^2.0.5" - "@octokit/types" "^6.0.3" - before-after-hook "^2.2.0" - universal-user-agent "^6.0.0" - -"@octokit/endpoint@^6.0.1": - version "6.0.11" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.11.tgz#082adc2aebca6dcefa1fb383f5efb3ed081949d1" - integrity sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ== - dependencies: - "@octokit/types" "^6.0.3" - is-plain-object "^5.0.0" - universal-user-agent "^6.0.0" - -"@octokit/graphql@^4.5.8": - version "4.6.1" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.6.1.tgz#f975486a46c94b7dbe58a0ca751935edc7e32cc9" - integrity sha512-2lYlvf4YTDgZCTXTW4+OX+9WTLFtEUc6hGm4qM1nlZjzxj+arizM4aHWzBVBCxY9glh7GIs0WEuiSgbVzv8cmA== - dependencies: - "@octokit/request" "^5.3.0" - "@octokit/types" "^6.0.3" - universal-user-agent "^6.0.0" - -"@octokit/openapi-types@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-7.0.0.tgz#0f6992db9854af15eca77d71ab0ec7fad2f20411" - integrity sha512-gV/8DJhAL/04zjTI95a7FhQwS6jlEE0W/7xeYAzuArD0KVAVWDLP2f3vi98hs3HLTczxXdRK/mF0tRoQPpolEw== - -"@octokit/plugin-paginate-rest@^2.6.2": - version "2.13.3" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.3.tgz#f0f1792230805108762d87906fb02d573b9e070a" - integrity sha512-46lptzM9lTeSmIBt/sVP/FLSTPGx6DCzAdSX3PfeJ3mTf4h9sGC26WpaQzMEq/Z44cOcmx8VsOhO+uEgE3cjYg== - dependencies: - "@octokit/types" "^6.11.0" - -"@octokit/plugin-request-log@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.3.tgz#70a62be213e1edc04bb8897ee48c311482f9700d" - integrity sha512-4RFU4li238jMJAzLgAwkBAw+4Loile5haQMQr+uhFq27BmyJXcXSKvoQKqh0agsZEiUlW6iSv3FAgvmGkur7OQ== - -"@octokit/plugin-rest-endpoint-methods@5.0.1": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.0.1.tgz#631b8d4edc6798b03489911252a25f2a4e58c594" - integrity sha512-vvWbPtPqLyIzJ7A4IPdTl+8IeuKAwMJ4LjvmqWOOdfSuqWQYZXq2CEd0hsnkidff2YfKlguzujHs/reBdAx8Sg== - dependencies: - "@octokit/types" "^6.13.1" - deprecation "^2.3.1" - -"@octokit/request-error@^2.0.0", "@octokit/request-error@^2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.0.5.tgz#72cc91edc870281ad583a42619256b380c600143" - integrity sha512-T/2wcCFyM7SkXzNoyVNWjyVlUwBvW3igM3Btr/eKYiPmucXTtkxt2RBsf6gn3LTzaLSLTQtNmvg+dGsOxQrjZg== - dependencies: - "@octokit/types" "^6.0.3" - deprecation "^2.0.0" - once "^1.4.0" - -"@octokit/request@^5.3.0", "@octokit/request@^5.4.12": - version "5.4.15" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.15.tgz#829da413dc7dd3aa5e2cdbb1c7d0ebe1f146a128" - integrity sha512-6UnZfZzLwNhdLRreOtTkT9n57ZwulCve8q3IT/Z477vThu6snfdkBuhxnChpOKNGxcQ71ow561Qoa6uqLdPtag== - dependencies: - "@octokit/endpoint" "^6.0.1" - "@octokit/request-error" "^2.0.0" - "@octokit/types" "^6.7.1" - is-plain-object "^5.0.0" - node-fetch "^2.6.1" - universal-user-agent "^6.0.0" - -"@octokit/rest@^18.0.14": - version "18.5.3" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.5.3.tgz#6a2e6006a87ebbc34079c419258dd29ec9ff659d" - integrity sha512-KPAsUCr1DOdLVbZJgGNuE/QVLWEaVBpFQwDAz/2Cnya6uW2wJ/P5RVGk0itx7yyN1aGa8uXm2pri4umEqG1JBA== - dependencies: - "@octokit/core" "^3.2.3" - "@octokit/plugin-paginate-rest" "^2.6.2" - "@octokit/plugin-request-log" "^1.0.2" - "@octokit/plugin-rest-endpoint-methods" "5.0.1" - -"@octokit/types@^6.0.3", "@octokit/types@^6.11.0", "@octokit/types@^6.13.1", "@octokit/types@^6.7.1": - version "6.14.2" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.14.2.tgz#64c9457f38fb8522bdbba3c8cc814590a2d61bf5" - integrity sha512-wiQtW9ZSy4OvgQ09iQOdyXYNN60GqjCL/UdMsepDr1Gr0QzpW6irIKbH3REuAHXAhxkEk9/F2a3Gcs1P6kW5jA== - dependencies: - "@octokit/openapi-types" "^7.0.0" - -"@sindresorhus/is@^0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" - integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== - -"@szmarczak/http-timer@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" - integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== - dependencies: - defer-to-connect "^1.0.1" - -"@tootallnate/once@1", "@tootallnate/once@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - -"@ts-morph/common@~0.9.0": - version "0.9.1" - resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.9.1.tgz#3afe35aa96831bbe5ad7a7465daf26157a244d80" - integrity sha512-NkSf6P5cPxzgOuhGOK6AZgGq1M5C3EoicEVfXfqnJ0ntmA3lHDs6hzdh61zmO22b6FMpbq/m2Sj9JNqeiLEmBw== - dependencies: - fast-glob "^3.2.5" - minimatch "^3.0.4" - mkdirp "^1.0.4" - path-browserify "^1.0.1" - -"@types/anymatch@*": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" - integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== - -"@types/applicationinsights@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@types/applicationinsights/-/applicationinsights-0.20.0.tgz#fa7b36dc954f635fa9037cad27c378446b1048fb" - integrity sha512-dQ3Hb58ERe5YNKFVyvU9BrEvpgKeb6Ht9HkCyBvsOZxhx6yKSwF3e+xml3PJQ3JiVOvf6gM/PmE3MdWDl1L6aA== - dependencies: - applicationinsights "*" - -"@types/chokidar@2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@types/chokidar/-/chokidar-2.1.3.tgz#123ab795dba6d89be04bf076e6aecaf8620db674" - integrity sha512-6qK3xoLLAhQVTucQGHTySwOVA1crHRXnJeLwqK6KIFkkKa2aoMFXh+WEi8PotxDtvN6MQJLyYN9ag9P6NLV81w== - dependencies: - chokidar "*" - -"@types/cookie@^0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.3.3.tgz#85bc74ba782fb7aa3a514d11767832b0e3bc6803" - integrity sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow== - -"@types/copy-webpack-plugin@^6.0.3": - version "6.4.2" - resolved "https://registry.yarnpkg.com/@types/copy-webpack-plugin/-/copy-webpack-plugin-6.4.2.tgz#b2ec2bed52068110e2f71ab673e062763254809d" - integrity sha512-pjEkbOxQLxKdNRJHf2MI8Rx66WK67NQao1ruLeaHizsu6F25gjW5LQL6Xc8lmMRhu9KIJ3WO4KyxP5Oy0tCUjg== - dependencies: - "@types/webpack" "^4" - -"@types/cssnano@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/cssnano/-/cssnano-4.0.0.tgz#f1bb29d6d0813861a3d87e02946b2988d0110d4e" - integrity sha512-BC/2ibKZfPIaBLBNzkitdW1IvvX/LKW6/QXGc4Su/tAJ7mQ3f2CKBuGCCKaqGAnoKwzfuC7G/recpkARwdOwuA== - dependencies: - postcss "5 - 7" - -"@types/debug@4.1.5": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd" - integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ== - -"@types/eslint-visitor-keys@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" - integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== - -"@types/expect@^1.20.4": - version "1.20.4" - resolved "https://registry.yarnpkg.com/@types/expect/-/expect-1.20.4.tgz#8288e51737bf7e3ab5d7c77bfa695883745264e5" - integrity sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg== - -"@types/glob@^7.1.1": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" - integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w== - dependencies: - "@types/minimatch" "*" - "@types/node" "*" - -"@types/graceful-fs@4.1.2": - version "4.1.2" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.2.tgz#fbc9575dbcc6d1d91dd768d30c5fc0c19f6c50bd" - integrity sha512-epDhsJAVxJsWfeqpzEDFhLnhHMbHie/VMFY+2Hvt5p7FemeW5ELM+6gcVYL/ZsUwdu3zrWpDE3VUTddXW+EMYg== - dependencies: - "@types/node" "*" - -"@types/gulp-postcss@^8.0.0": - version "8.0.0" - resolved "https://registry.yarnpkg.com/@types/gulp-postcss/-/gulp-postcss-8.0.0.tgz#f7e86d45e4999fd43e6d8c55b00504c88a67ad61" - integrity sha512-AVgjA03bpkYONKZpzuJviB9PzaNbDzrovYPbenj8/XxivUc35C/dIzJanyaQv7CFqfLLPLsqSalmtP3GLq6iag== - dependencies: - "@types/node" "*" - "@types/vinyl" "*" - -"@types/http-proxy-agent@^2.0.1": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@types/http-proxy-agent/-/http-proxy-agent-2.0.2.tgz#942c1f35c7e1f0edd1b6ffae5d0f9051cfb32be1" - integrity sha512-2S6IuBRhqUnH1/AUx9k8KWtY3Esg4eqri946MnxTG5HwehF1S5mqLln8fcyMiuQkY72p2gH3W+rIPqp5li0LyQ== - dependencies: - "@types/node" "*" - -"@types/json-schema@^7.0.3", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6": - version "7.0.7" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" - integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== - -"@types/minimatch@*": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21" - integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA== - -"@types/minimist@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.1.tgz#283f669ff76d7b8260df8ab7a4262cc83d988256" - integrity sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg== - -"@types/mocha@^8.2.0": - version "8.2.2" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.2.tgz#91daa226eb8c2ff261e6a8cbf8c7304641e095e0" - integrity sha512-Lwh0lzzqT5Pqh6z61P3c3P5nm6fzQK/MMHl9UKeneAeInVflBSz1O2EkX6gM6xfJd7FBXBY5purtLx7fUiZ7Hw== - -"@types/node@*": - version "15.0.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.2.tgz#51e9c0920d1b45936ea04341aa3e2e58d339fb67" - integrity sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA== - -"@types/node@^14.14.37": - version "14.14.44" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.44.tgz#df7503e6002847b834371c004b372529f3f85215" - integrity sha512-+gaugz6Oce6ZInfI/tK4Pq5wIIkJMEJUu92RB3Eu93mtj4wjjjz9EB5mLp5s1pSsLXdC/CPut/xF20ZzAQJbTA== - -"@types/q@^1.5.1": - version "1.5.4" - resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24" - integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug== - -"@types/sinon@^1.16.36": - version "1.16.36" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-1.16.36.tgz#74bb6ed7928597c1b3fb1b009005e94dc6eae357" - integrity sha1-dLtu15KFl8Gz+xsAkAXpTcbq41c= - -"@types/source-list-map@*": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" - integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== - -"@types/tapable@^1": - version "1.0.7" - resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.7.tgz#545158342f949e8fd3bfd813224971ecddc3fac4" - integrity sha512-0VBprVqfgFD7Ehb2vd8Lh9TG3jP98gvr8rgehQqzztZNI7o8zS8Ad4jyZneKELphpuE212D8J70LnSNQSyO6bQ== - -"@types/trusted-types@^1.0.6": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-1.0.6.tgz#569b8a08121d3203398290d602d84d73c8dcf5da" - integrity sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw== - -"@types/uglify-js@*": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.13.0.tgz#1cad8df1fb0b143c5aba08de5712ea9d1ff71124" - integrity sha512-EGkrJD5Uy+Pg0NUR8uA4bJ5WMfljyad0G+784vLCNUkD+QwOJXUbBYExXfVGf7YtyzdQp3L/XMYcliB987kL5Q== - dependencies: - source-map "^0.6.1" - -"@types/vinyl@*": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/vinyl/-/vinyl-2.0.4.tgz#9a7a8071c8d14d3a95d41ebe7135babe4ad5995a" - integrity sha512-2o6a2ixaVI2EbwBPg1QYLGQoHK56p/8X/sGfKbFC8N6sY9lfjsMf/GprtkQkSya0D4uRiutRZ2BWj7k3JvLsAQ== - dependencies: - "@types/expect" "^1.20.4" - "@types/node" "*" - -"@types/vscode-windows-registry@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/vscode-windows-registry/-/vscode-windows-registry-1.0.0.tgz#333eea7fd5743fa4c99dff13af16de2c08a586d0" - integrity sha512-gyq9tIMbxry5GL2gY7J30E6R3EUx0cAin/k3wfsQez4C5uDWVJmJw142x6KFXtYX7xYQL/IXmm4cRqi4ghg05A== - -"@types/webpack-sources@*": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-2.1.0.tgz#8882b0bd62d1e0ce62f183d0d01b72e6e82e8c10" - integrity sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg== - dependencies: - "@types/node" "*" - "@types/source-list-map" "*" - source-map "^0.7.3" - -"@types/webpack@^4", "@types/webpack@^4.41.25": - version "4.41.28" - resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.28.tgz#0069a2159b7ad4d83d0b5801942c17d54133897b" - integrity sha512-Nn84RAiJjKRfPFFCVR8LC4ueTtTdfWAMZ03THIzZWRJB+rX24BD3LqPSFnbMscWauEsT4segAsylPDIaZyZyLQ== - dependencies: - "@types/anymatch" "*" - "@types/node" "*" - "@types/tapable" "^1" - "@types/uglify-js" "*" - "@types/webpack-sources" "*" - source-map "^0.6.0" - -"@types/wicg-file-system-access@^2020.9.1": - version "2020.9.1" - resolved "https://registry.yarnpkg.com/@types/wicg-file-system-access/-/wicg-file-system-access-2020.9.1.tgz#ae1f420b0ca70f545c8621a9b63ed29270ef724a" - integrity sha512-hEN/YpLwvDjhRJrKoBiyiKtIh2zNkmJ/GY9VWIXNgjy7TBZNM9upfb/rnWDGpOoLomnEQtlTBjFBFCDra1oxOQ== - -"@types/windows-foreground-love@^0.3.0": - version "0.3.0" - resolved "https://registry.yarnpkg.com/@types/windows-foreground-love/-/windows-foreground-love-0.3.0.tgz#26bc230b2568aa7ab7c56d35bb5653c0a6965a42" - integrity sha512-tFUVA/fiofNqOh6lZlymvQiQYPY+cZXZPR9mn9wN6/KS8uwx0zgH4Ij/jmFyRYr+x+DGZWEIeknS2BMi7FZJAQ== - -"@types/windows-mutex@^0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@types/windows-mutex/-/windows-mutex-0.4.0.tgz#d27070418aa26047c6c860c704952ff26aeb961b" - integrity sha512-zUMH4nutIURLARU6f10Ls6XcZWhUkwmzVEALs26dt1ZbaLv/qxsGdYiePUbwhQmrQUp3EPZ1HxopWpzzC8ot5A== - -"@types/windows-process-tree@^0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@types/windows-process-tree/-/windows-process-tree-0.2.0.tgz#2fa205c838a8ef0a07697cd747c954653978d22c" - integrity sha512-vQAnkWpMX4HUPjubkxKta4Rfh2EDy2ksalnr37gFHNrmk+uxx50PRH+/fM5nTsEBCi4ESFT/7t7Za3jGqyTZ4g== - -"@types/winreg@^1.2.30": - version "1.2.30" - resolved "https://registry.yarnpkg.com/@types/winreg/-/winreg-1.2.30.tgz#91d6710e536d345b9c9b017c574cf6a8da64c518" - integrity sha1-kdZxDlNtNFucmwF8V0z2qNpkxRg= - -"@types/yauzl@^2.9.1": - version "2.9.1" - resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.1.tgz#d10f69f9f522eef3cf98e30afb684a1e1ec923af" - integrity sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA== - dependencies: - "@types/node" "*" - -"@types/yazl@^2.4.2": - version "2.4.2" - resolved "https://registry.yarnpkg.com/@types/yazl/-/yazl-2.4.2.tgz#d5f8a4752261badbf1a36e8b49e042dc18ec84bc" - integrity sha512-T+9JH8O2guEjXNxqmybzQ92mJUh2oCwDDMSSimZSe1P+pceZiFROZLYmcbqkzV5EUwz6VwcKXCO2S2yUpra6XQ== - dependencies: - "@types/node" "*" - -"@typescript-eslint/eslint-plugin@3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.2.0.tgz#7fb997f391af32ae6ca1dbe56bcefe4dd30bda14" - integrity sha512-t9RTk/GyYilIXt6BmZurhBzuMT9kLKw3fQoJtK9ayv0tXTlznXEAnx07sCLXdkN3/tZDep1s1CEV95CWuARYWA== - dependencies: - "@typescript-eslint/experimental-utils" "3.2.0" - functional-red-black-tree "^1.0.1" - regexpp "^3.0.0" - semver "^7.3.2" - tsutils "^3.17.1" - -"@typescript-eslint/experimental-utils@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.10.1.tgz#e179ffc81a80ebcae2ea04e0332f8b251345a686" - integrity sha512-DewqIgscDzmAfd5nOGe4zm6Bl7PKtMG2Ad0KG8CUZAHlXfAKTF9Ol5PXhiMh39yRL2ChRH1cuuUGOcVyyrhQIw== - dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/types" "3.10.1" - "@typescript-eslint/typescript-estree" "3.10.1" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - -"@typescript-eslint/experimental-utils@3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.2.0.tgz#4dab8fc9f44f059ec073470a81bb4d7d7d51e6c5" - integrity sha512-UbJBsk+xO9dIFKtj16+m42EvUvsjZbbgQ2O5xSTSfVT1Z3yGkL90DVu0Hd3029FZ5/uBgl+F3Vo8FAcEcqc6aQ== - dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "3.2.0" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - -"@typescript-eslint/parser@^3.3.0": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-3.10.1.tgz#1883858e83e8b442627e1ac6f408925211155467" - integrity sha512-Ug1RcWcrJP02hmtaXVS3axPPTTPnZjupqhgj+NnZ6BCkwSImWk/283347+x9wN+lqOdK9Eo3vsyiyDHgsmiEJw== - dependencies: - "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "3.10.1" - "@typescript-eslint/types" "3.10.1" - "@typescript-eslint/typescript-estree" "3.10.1" - eslint-visitor-keys "^1.1.0" - -"@typescript-eslint/types@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.10.1.tgz#1d7463fa7c32d8a23ab508a803ca2fe26e758727" - integrity sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ== - -"@typescript-eslint/typescript-estree@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.10.1.tgz#fd0061cc38add4fad45136d654408569f365b853" - integrity sha512-QbcXOuq6WYvnB3XPsZpIwztBoquEYLXh2MtwVU+kO8jgYCiv4G5xrSP/1wg4tkvrEE+esZVquIPX/dxPlePk1w== - dependencies: - "@typescript-eslint/types" "3.10.1" - "@typescript-eslint/visitor-keys" "3.10.1" - debug "^4.1.1" - glob "^7.1.6" - is-glob "^4.0.1" - lodash "^4.17.15" - semver "^7.3.2" - tsutils "^3.17.1" - -"@typescript-eslint/typescript-estree@3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.2.0.tgz#c735f1ca6b4d3cd671f30de8c9bde30843e7ead8" - integrity sha512-uh+Y2QO7dxNrdLw7mVnjUqkwO/InxEqwN0wF+Za6eo3coxls9aH9kQ/5rSvW2GcNanebRTmsT5w1/92lAOb1bA== - dependencies: - debug "^4.1.1" - eslint-visitor-keys "^1.1.0" - glob "^7.1.6" - is-glob "^4.0.1" - lodash "^4.17.15" - semver "^7.3.2" - tsutils "^3.17.1" - -"@typescript-eslint/visitor-keys@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-3.10.1.tgz#cd4274773e3eb63b2e870ac602274487ecd1e931" - integrity sha512-9JgC82AaQeglebjZMgYR5wgmfUdUc+EitGUUMW8u2nDckaeimzW+VsoLV6FoimPv2id3VQzfjwBxEMVz08ameQ== - dependencies: - eslint-visitor-keys "^1.1.0" - -"@ungap/promise-all-settled@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" - integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== - -"@webassemblyjs/ast@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" - integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA== - dependencies: - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" - -"@webassemblyjs/floating-point-hex-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4" - integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA== - -"@webassemblyjs/helper-api-error@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2" - integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw== - -"@webassemblyjs/helper-buffer@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00" - integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA== - -"@webassemblyjs/helper-code-frame@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27" - integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA== - dependencies: - "@webassemblyjs/wast-printer" "1.9.0" - -"@webassemblyjs/helper-fsm@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8" - integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw== - -"@webassemblyjs/helper-module-context@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07" - integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g== - dependencies: - "@webassemblyjs/ast" "1.9.0" - -"@webassemblyjs/helper-wasm-bytecode@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790" - integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw== - -"@webassemblyjs/helper-wasm-section@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346" - integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - -"@webassemblyjs/ieee754@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4" - integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg== - dependencies: - "@xtuc/ieee754" "^1.2.0" - -"@webassemblyjs/leb128@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95" - integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw== - dependencies: - "@xtuc/long" "4.2.2" - -"@webassemblyjs/utf8@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab" - integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w== - -"@webassemblyjs/wasm-edit@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf" - integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/helper-wasm-section" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-opt" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - "@webassemblyjs/wast-printer" "1.9.0" - -"@webassemblyjs/wasm-gen@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c" - integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" - -"@webassemblyjs/wasm-opt@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61" - integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - -"@webassemblyjs/wasm-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e" - integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" - -"@webassemblyjs/wast-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914" - integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/floating-point-hex-parser" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-code-frame" "1.9.0" - "@webassemblyjs/helper-fsm" "1.9.0" - "@xtuc/long" "4.2.2" - -"@webassemblyjs/wast-printer@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899" - integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" - "@xtuc/long" "4.2.2" - -"@xtuc/ieee754@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" - integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== - -"@xtuc/long@4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" - integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - -acorn-jsx@^5.0.0, acorn-jsx@^5.2.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" - integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== - -acorn@^6.0.7, acorn@^6.4.1: - version "6.4.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" - integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== - -acorn@^7.1.1: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -agent-base@4, agent-base@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" - integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== - dependencies: - es6-promisify "^5.0.0" - -agent-base@5: - version "5.1.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c" - integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g== - -agent-base@6, agent-base@^6.0.0, agent-base@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - -aggregate-error@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" - integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - -ajv-errors@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" - integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== - -ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" - integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== - -ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.9.1: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -alphanum-sort@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" - integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= - -amdefine@>=0.0.4: - version "1.0.1" - resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" - integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= - -ansi-colors@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - -ansi-colors@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9" - integrity sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA== - dependencies: - ansi-wrap "^0.1.0" - -ansi-colors@^3.2.3: - version "3.2.4" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" - integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== - -ansi-cyan@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ansi-cyan/-/ansi-cyan-0.1.1.tgz#538ae528af8982f28ae30d86f2f17456d2609873" - integrity sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM= - dependencies: - ansi-wrap "0.1.0" - -ansi-escapes@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - -ansi-escapes@^4.2.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-gray@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" - integrity sha1-KWLPVOyXksSFEKPetSRDaGHvclE= - dependencies: - ansi-wrap "0.1.0" - -ansi-red@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c" - integrity sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw= - dependencies: - ansi-wrap "0.1.0" - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-wrap@0.1.0, ansi-wrap@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" - integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768= - -any-promise@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= - -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - -anymatch@~3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== - 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" - integrity sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE= - dependencies: - buffer-equal "^1.0.0" - -applicationinsights@*: - version "1.8.10" - resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.8.10.tgz#fffa482cd1519880fb888536a87081ac05130667" - integrity sha512-ZLDA7mShh4mP2Z/HlFolmvhBPX1LfnbIWXrselyYVA7EKjHhri1fZzpu2EiWAmfbRxNBY6fRjoPJWbx5giKy4A== - dependencies: - cls-hooked "^4.2.2" - continuation-local-storage "^3.2.1" - diagnostic-channel "0.3.1" - diagnostic-channel-publishers "0.4.4" - -applicationinsights@1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.8.tgz#db6e3d983cf9f9405fe1ee5ba30ac6e1914537b5" - integrity sha512-KzOOGdphOS/lXWMFZe5440LUdFbrLpMvh2SaRxn7BmiI550KAoSb2gIhiq6kJZ9Ir3AxRRztjhzif+e5P5IXIg== - dependencies: - diagnostic-channel "0.2.0" - diagnostic-channel-publishers "0.2.1" - zone.js "0.7.6" - -aproba@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== - -archy@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" - integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -arr-diff@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-1.1.0.tgz#687c32758163588fef7de7b36fabe495eb1a399a" - integrity sha1-aHwydYFjWI/vfeezb6vklesaOZo= - dependencies: - arr-flatten "^1.0.1" - array-slice "^0.2.3" - -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-filter@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/arr-filter/-/arr-filter-1.1.2.tgz#43fdddd091e8ef11aa4c45d9cdc18e2dff1711ee" - integrity sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4= - dependencies: - make-iterator "^1.0.0" - -arr-flatten@^1.0.1, 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-map@^2.0.0, arr-map@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/arr-map/-/arr-map-2.0.2.tgz#3a77345ffc1cf35e2a91825601f9e58f2e24cac4" - integrity sha1-Onc0X/wc814qkYJWAfnljy4kysQ= - dependencies: - make-iterator "^1.0.0" - -arr-union@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-2.1.0.tgz#20f9eab5ec70f5c7d215b1077b1c39161d292c7d" - integrity sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0= - -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-back@^3.0.1: - version "3.1.0" - resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" - integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== - -array-differ@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" - integrity sha1-7/UuN1gknTO+QCuLuOVkuytdQDE= - -array-each@^1.0.0, array-each@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f" - integrity sha1-p5SvDAWrF1KEbudTofIRoFugxE8= - -array-filter@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" - integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM= - -array-initial@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/array-initial/-/array-initial-1.1.0.tgz#2fa74b26739371c3947bd7a7adc73be334b3d795" - integrity sha1-L6dLJnOTccOUe9enrcc74zSz15U= - dependencies: - array-slice "^1.0.0" - is-number "^4.0.0" - -array-last@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/array-last/-/array-last-1.3.0.tgz#7aa77073fec565ddab2493f5f88185f404a9d336" - integrity sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg== - dependencies: - is-number "^4.0.0" - -array-slice@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" - integrity sha1-3Tz7gO15c6dRF82sabC5nshhhvU= - -array-slice@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.1.0.tgz#e368ea15f89bc7069f7ffb89aec3a6c7d4ac22d4" - integrity sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w== - -array-sort@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-sort/-/array-sort-1.0.0.tgz#e4c05356453f56f53512a7d1d6123f2c54c0a88a" - integrity sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg== - dependencies: - default-compare "^1.0.0" - get-value "^2.0.6" - kind-of "^5.0.2" - -array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= - dependencies: - array-uniq "^1.0.1" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - -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= - -arrify@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= - -asar@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/asar/-/asar-3.0.3.tgz#1fef03c2d6d2de0cbad138788e4f7ae03b129c7b" - integrity sha512-k7zd+KoR+n8pl71PvgElcoKHrVNiSXtw7odKbyNpmgKe7EGRF9Pnu3uLOukD37EvavKwVFxOUpqXTIZC5B5Pmw== - dependencies: - chromium-pickle-js "^0.2.0" - commander "^5.0.0" - glob "^7.1.6" - minimatch "^3.0.4" - optionalDependencies: - "@types/glob" "^7.1.1" - -asn1.js@^5.2.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" - integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - safer-buffer "^2.1.0" - -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - -assert@^1.1.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" - integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== - dependencies: - object-assign "^4.1.1" - util "0.10.3" - -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= - -ast-types@^0.13.2: - version "0.13.4" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" - integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w== - dependencies: - tslib "^2.0.1" - -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - -async-done@^1.2.0, async-done@^1.2.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/async-done/-/async-done-1.3.2.tgz#5e15aa729962a4b07414f528a88cdf18e0b290a2" - integrity sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.2" - process-nextick-args "^2.0.0" - stream-exhaust "^1.0.1" - -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== - -async-hook-jl@^1.7.6: - version "1.7.6" - resolved "https://registry.yarnpkg.com/async-hook-jl/-/async-hook-jl-1.7.6.tgz#4fd25c2f864dbaf279c610d73bf97b1b28595e68" - integrity sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg== - dependencies: - stack-chain "^1.3.7" - -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - -async-listener@^0.6.0: - version "0.6.10" - resolved "https://registry.yarnpkg.com/async-listener/-/async-listener-0.6.10.tgz#a7c97abe570ba602d782273c0de60a51e3e17cbc" - integrity sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw== - dependencies: - semver "^5.3.0" - shimmer "^1.1.0" - -async-settle@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/async-settle/-/async-settle-1.0.0.tgz#1d0a914bb02575bec8a8f3a74e5080f72b2c0c6b" - integrity sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs= - dependencies: - async-done "^1.2.2" - -async@^2.1.5: - version "2.6.3" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" - integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== - dependencies: - lodash "^4.17.14" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -atob@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -available-typed-arrays@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5" - integrity sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ== - dependencies: - array-filter "^1.0.0" - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" - integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== - -azure-storage@^2.10.2: - version "2.10.3" - resolved "https://registry.yarnpkg.com/azure-storage/-/azure-storage-2.10.3.tgz#c5966bf929d87587d78f6847040ea9a4b1d4a50a" - integrity sha512-IGLs5Xj6kO8Ii90KerQrrwuJKexLgSwYC4oLWmc11mzKe7Jt2E5IVg+ZQ8K53YWZACtVTMBNO3iGuA+4ipjJxQ== - dependencies: - browserify-mime "~1.2.9" - extend "^3.0.2" - json-edm-parser "0.1.2" - md5.js "1.3.4" - readable-stream "~2.0.0" - request "^2.86.0" - underscore "~1.8.3" - uuid "^3.0.0" - validator "~9.4.1" - xml2js "0.2.8" - xmlbuilder "^9.0.7" - -bach@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/bach/-/bach-1.2.0.tgz#4b3ce96bf27134f79a1b414a51c14e34c3bd9880" - integrity sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA= - dependencies: - arr-filter "^1.1.1" - arr-flatten "^1.0.1" - arr-map "^2.0.0" - array-each "^1.0.0" - array-initial "^1.0.0" - array-last "^1.1.1" - async-done "^1.2.2" - async-settle "^1.0.0" - now-and-later "^2.0.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base64-js@^1.0.2, base64-js@^1.3.1, base64-js@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -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" - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - -before-after-hook@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.1.tgz#73540563558687586b52ed217dad6a802ab1549c" - integrity sha512-/6FKxSTWoJdbsLDF8tdIjaRiFXiE6UHsEHE3OPI/cwPURCVi1ukP0gmLn7XWEiFk5TcwQjjY5PWsU+j+tgXgmw== - -big.js@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" - integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== - -binary-extensions@^1.0.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" - integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== - -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - -binaryextensions@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-1.0.1.tgz#1e637488b35b58bda5f4774bf96a5212a8c90755" - integrity sha1-HmN0iLNbWL2l9HdL+WpSEqjJB1U= - -bindings@^1.2.1, bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - -bl@^4.0.2: - version "4.1.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" - integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" - -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= - dependencies: - inherits "~2.0.0" - -bluebird@^3.5.5: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.0.0, bn.js@^5.1.1: - version "5.2.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" - integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== - -boolbase@^1.0.0, boolbase@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= - -boolean@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.0.3.tgz#0fee0c9813b66bef25a8a6a904bb46736d05f024" - integrity sha512-EqrTKXQX6Z3A2nRmMEIlAIfjQOgFnVO2nqZGpbcsPnYGWBwpFqzlrozU1dy+S2iqfYDLh26ef4KrgTxu9xQrxA== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -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== - 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" - -braces@^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, brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - -"browser-request@>= 0.3.1 < 0.4.0": - version "0.3.3" - resolved "https://registry.yarnpkg.com/browser-request/-/browser-request-0.3.3.tgz#9ece5b5aca89a29932242e18bf933def9876cc17" - integrity sha1-ns5bWsqJopkyJC4Yv5M975h2zBc= - -browser-stdout@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-mime@~1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/browserify-mime/-/browserify-mime-1.2.9.tgz#aeb1af28de6c0d7a6a2ce40adb68ff18422af31f" - integrity sha1-rrGvKN5sDXpqLOQK22j/GEIq8x8= - -browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" - integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== - dependencies: - bn.js "^5.0.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" - integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== - dependencies: - bn.js "^5.1.1" - browserify-rsa "^4.0.1" - create-hash "^1.2.0" - create-hmac "^1.1.7" - elliptic "^6.5.3" - inherits "^2.0.4" - parse-asn1 "^5.1.5" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -browserify-zlib@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== - dependencies: - pako "~1.0.5" - -browserslist@^4.0.0, browserslist@^4.14.5: - version "4.16.6" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" - integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ== - dependencies: - caniuse-lite "^1.0.30001219" - colorette "^1.2.2" - electron-to-chromium "^1.3.723" - escalade "^3.1.1" - node-releases "^1.1.71" - -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= - -buffer-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe" - integrity sha1-WWFrSYME1Var1GaWayLu2j7KX74= - -buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= - -buffer@^4.3.0: - version "4.9.2" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" - integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - -buffer@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - -builtin-status-codes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= - -bytes@3.1.0, bytes@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== - -cacache@^12.0.2: - version "12.0.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" - integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== - dependencies: - bluebird "^3.5.5" - chownr "^1.1.1" - figgy-pudding "^3.5.1" - glob "^7.1.4" - graceful-fs "^4.1.15" - infer-owner "^1.0.3" - lru-cache "^5.1.1" - mississippi "^3.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.3" - ssri "^6.0.1" - unique-filename "^1.1.1" - y18n "^4.0.0" - -cacache@^15.0.5: - version "15.0.6" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.0.6.tgz#65a8c580fda15b59150fb76bf3f3a8e45d583099" - integrity sha512-g1WYDMct/jzW+JdWEyjaX2zoBkZ6ZT9VpOyp2I/VMtDsNLffNat3kqPFfi1eDRSK9/SuKGyORDHcQMcPF8sQ/w== - dependencies: - "@npmcli/move-file" "^1.0.1" - chownr "^2.0.0" - fs-minipass "^2.0.0" - glob "^7.1.4" - infer-owner "^1.0.4" - lru-cache "^6.0.0" - minipass "^3.1.1" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.2" - mkdirp "^1.0.3" - p-map "^4.0.0" - promise-inflight "^1.0.1" - rimraf "^3.0.2" - ssri "^8.0.1" - tar "^6.0.2" - unique-filename "^1.1.1" - -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== - 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" - -cacheable-request@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" - integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^3.0.0" - lowercase-keys "^2.0.0" - normalize-url "^4.1.0" - responselike "^1.0.2" - -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - -caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= - dependencies: - callsites "^2.0.0" - -caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= - dependencies: - caller-callsite "^2.0.0" - -callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camelcase@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" - integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= - -camelcase@^5.0.0, camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -camelcase@^6.0.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" - integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== - -caniuse-api@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" - integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== - dependencies: - browserslist "^4.0.0" - caniuse-lite "^1.0.0" - lodash.memoize "^4.1.2" - lodash.uniq "^4.5.0" - -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001219: - version "1.0.30001222" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001222.tgz#2789b8487282cbbe1700924f53951303d28086a9" - integrity sha512-rPmwUK0YMjfMlZVmH6nVB5U3YJ5Wnx3vmT5lnRO3nIKO8bJ+TRWMbGuuiSugDJqESy/lz+1hSrlQEagCtoOAWQ== - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" - integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - -charenc@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" - integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= - -chokidar@*, chokidar@3.5.1, chokidar@^3.4.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" - integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== - dependencies: - anymatch "~3.1.1" - braces "~3.0.2" - glob-parent "~5.1.0" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.5.0" - optionalDependencies: - fsevents "~2.3.1" - -chokidar@^2.0.0, chokidar@^2.1.8: - version "2.1.8" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" - integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== - dependencies: - anymatch "^2.0.0" - 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" - optionalDependencies: - fsevents "^1.2.7" - -chownr@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== - -chownr@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" - integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== - -chrome-remote-interface@0.26.1: - version "0.26.1" - resolved "https://registry.yarnpkg.com/chrome-remote-interface/-/chrome-remote-interface-0.26.1.tgz#6c7d4479742b6d236752d716a9bc2d322d7d8ad2" - integrity sha512-ela482aJK0riFu05sl+zdbnb3ezMiqzwsqf/f/27HngWds+Fat3vcZWpIoDoeQuWMid/+LfKAteAYWaWPqsweg== - dependencies: - commander "2.11.x" - ws "^3.3.3" - -chrome-trace-event@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" - integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== - -chromium-pickle-js@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz#04a106672c18b085ab774d983dfa3ea138f22205" - integrity sha1-BKEGZywYsIWrd02YPfo+oTjyIgU= - -ci-info@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" - integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== - -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -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" - -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= - dependencies: - restore-cursor "^2.0.0" - -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-width@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" - integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== - -cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== - -cliui@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" - integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi "^2.0.0" - -cliui@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" - integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== - dependencies: - string-width "^3.1.0" - strip-ansi "^5.2.0" - wrap-ansi "^5.1.0" - -cliui@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" - integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^6.2.0" - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -clone-buffer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" - integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg= - -clone-response@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" - integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= - dependencies: - mimic-response "^1.0.0" - -clone-stats@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" - integrity sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE= - -clone-stats@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" - integrity sha1-s3gt/4u1R04Yuba/D9/ngvh3doA= - -clone@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= - -clone@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= - -cloneable-readable@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.3.tgz#120a00cb053bfb63a222e709f9683ea2e11d8cec" - integrity sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ== - dependencies: - inherits "^2.0.1" - process-nextick-args "^2.0.0" - readable-stream "^2.3.5" - -cls-hooked@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/cls-hooked/-/cls-hooked-4.2.2.tgz#ad2e9a4092680cdaffeb2d3551da0e225eae1908" - integrity sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw== - dependencies: - async-hook-jl "^1.7.6" - emitter-listener "^1.0.1" - semver "^5.4.1" - -coa@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" - integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== - dependencies: - "@types/q" "^1.5.1" - chalk "^2.4.1" - q "^1.1.2" - -code-block-writer@^10.1.1: - version "10.1.1" - resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-10.1.1.tgz#ad5684ed4bfb2b0783c8b131281ae84ee640a42f" - integrity sha512-67ueh2IRGst/51p0n6FvPrnRjAGHY5F8xdjkgrYE7DDzpJe6qA07RYQ9VcoUeo5ATOjSOiWpSL3SWBRRbempMw== - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - -coffee-script@^1.10.0: - version "1.12.7" - resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.7.tgz#c05dae0cb79591d05b3070a8433a98c9a89ccc53" - integrity sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw== - -collection-map@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-map/-/collection-map-1.0.0.tgz#aea0f06f8d26c780c2b75494385544b2255af18c" - integrity sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw= - dependencies: - arr-map "^2.0.2" - for-own "^1.0.0" - make-iterator "^1.0.0" - -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" - -color-convert@^1.9.0, color-convert@^1.9.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@^1.0.0, color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -color-string@^1.5.4: - version "1.5.5" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.5.tgz#65474a8f0e7439625f3d27a6a19d89fc45223014" - integrity sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg== - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - -color-support@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" - integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== - -color@^3.0.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/color/-/color-3.1.3.tgz#ca67fb4e7b97d611dcde39eceed422067d91596e" - integrity sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ== - dependencies: - color-convert "^1.9.1" - color-string "^1.5.4" - -colorette@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" - integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== - -combined-stream@^1.0.6, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -command-line-args@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.1.1.tgz#88e793e5bb3ceb30754a86863f0401ac92fd369a" - integrity sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg== - dependencies: - array-back "^3.0.1" - find-replace "^3.0.0" - lodash.camelcase "^4.3.0" - typical "^4.0.0" - -commander@2.11.x: - version "2.11.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" - integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== - -commander@^2.19.0, commander@^2.20.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commander@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" - integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== - -commander@^6.1.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" - integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== - -commandpost@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/commandpost/-/commandpost-1.4.0.tgz#89218012089dfc9b67a337ba162f15c88e0f1048" - integrity sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ== - -comment-parser@^0.7.2: - version "0.7.6" - resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-0.7.6.tgz#0e743a53c8e646c899a1323db31f6cd337b10f12" - integrity sha512-GKNxVA7/iuTnAqGADlTWX4tkhzxZKXp5fLJqKTlQLHkE65XDUKutZ3BHaJC5IGcper2tT3QRD1xr4o3jNpgXXg== - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - -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== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -concat-stream@^1.5.0, concat-stream@^1.6.0: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -concat-with-sourcemaps@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e" - integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg== - dependencies: - source-map "^0.6.1" - -config-chain@^1.1.11, config-chain@^1.1.12: - version "1.1.12" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" - integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - -console-browserify@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" - integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== - -constants-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= - -continuation-local-storage@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz#11f613f74e914fe9b34c92ad2d28fe6ae1db7ffb" - integrity sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA== - dependencies: - async-listener "^0.6.0" - emitter-listener "^1.1.1" - -convert-source-map@^1.0.0, convert-source-map@^1.5.0, convert-source-map@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== - dependencies: - safe-buffer "~5.1.1" - -copy-concurrently@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" - integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== - dependencies: - aproba "^1.1.1" - fs-write-stream-atomic "^1.0.8" - iferr "^0.1.5" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.0" - -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= - -copy-props@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/copy-props/-/copy-props-2.0.5.tgz#03cf9ae328d4ebb36f8f1d804448a6af9ee3f2d2" - integrity sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw== - dependencies: - each-props "^1.3.2" - is-plain-object "^5.0.0" - -copy-webpack-plugin@^6.0.3: - version "6.4.1" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-6.4.1.tgz#138cd9b436dbca0a6d071720d5414848992ec47e" - integrity sha512-MXyPCjdPVx5iiWyl40Va3JGh27bKzOTNY3NjUTrosD2q7dR/cLD0013uqJ3BpFbUjyONINjb6qI7nDIJujrMbA== - dependencies: - cacache "^15.0.5" - fast-glob "^3.2.4" - find-cache-dir "^3.3.1" - glob-parent "^5.1.1" - globby "^11.0.1" - loader-utils "^2.0.0" - normalize-path "^3.0.0" - p-limit "^3.0.2" - schema-utils "^3.0.0" - serialize-javascript "^5.0.1" - webpack-sources "^1.4.3" - -core-js@^3.6.5: - version "3.11.2" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.11.2.tgz#af087a43373fc6e72942917c4a4c3de43ed574d6" - integrity sha512-3tfrrO1JpJSYGKnd9LKTBPqgUES/UYiCzMKeqwR1+jF16q4kD1BY2NvqkfuzXwQ6+CIWm55V9cjD7PQd+hijdw== - -core-util-is@1.0.2, 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= - -cosmiconfig@^5.0.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" - integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== - dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" - -create-ecdh@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" - integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== - dependencies: - bn.js "^4.1.0" - elliptic "^6.5.3" - -create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -crypt@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" - integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= - -crypto-browserify@^3.11.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - -cson-parser@^1.3.3: - version "1.3.5" - resolved "https://registry.yarnpkg.com/cson-parser/-/cson-parser-1.3.5.tgz#7ec675e039145533bf2a6a856073f1599d9c2d24" - integrity sha1-fsZ14DkUVTO/KmqFYHPxWZ2cLSQ= - dependencies: - coffee-script "^1.10.0" - -css-color-names@0.0.4, css-color-names@^0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" - integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA= - -css-declaration-sorter@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz#c198940f63a76d7e36c1e71018b001721054cb22" - integrity sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA== - dependencies: - postcss "^7.0.1" - timsort "^0.3.0" - -css-loader@^3.2.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.6.0.tgz#2e4b2c7e6e2d27f8c8f28f61bffcd2e6c91ef645" - integrity sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ== - dependencies: - camelcase "^5.3.1" - cssesc "^3.0.0" - icss-utils "^4.1.1" - loader-utils "^1.2.3" - normalize-path "^3.0.0" - postcss "^7.0.32" - postcss-modules-extract-imports "^2.0.0" - postcss-modules-local-by-default "^3.0.2" - postcss-modules-scope "^2.2.0" - postcss-modules-values "^3.0.0" - postcss-value-parser "^4.1.0" - schema-utils "^2.7.0" - semver "^6.3.0" - -css-select-base-adapter@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" - integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== - -css-select@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" - integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== - dependencies: - boolbase "^1.0.0" - css-what "^3.2.1" - domutils "^1.7.0" - nth-check "^1.0.2" - -css-tree@1.0.0-alpha.37: - version "1.0.0-alpha.37" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" - integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== - dependencies: - mdn-data "2.0.4" - source-map "^0.6.1" - -css-tree@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" - integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== - dependencies: - mdn-data "2.0.14" - source-map "^0.6.1" - -css-what@^3.2.1: - version "3.4.2" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" - integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== - -css@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/css/-/css-3.0.0.tgz#4447a4d58fdd03367c516ca9f64ae365cee4aa5d" - integrity sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ== - dependencies: - inherits "^2.0.4" - source-map "^0.6.1" - source-map-resolve "^0.6.0" - -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - -cssnano-preset-default@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz#920622b1fc1e95a34e8838203f1397a504f2d3ff" - integrity sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ== - dependencies: - css-declaration-sorter "^4.0.1" - cssnano-util-raw-cache "^4.0.1" - postcss "^7.0.0" - postcss-calc "^7.0.1" - postcss-colormin "^4.0.3" - postcss-convert-values "^4.0.1" - postcss-discard-comments "^4.0.2" - postcss-discard-duplicates "^4.0.2" - postcss-discard-empty "^4.0.1" - postcss-discard-overridden "^4.0.1" - postcss-merge-longhand "^4.0.11" - postcss-merge-rules "^4.0.3" - postcss-minify-font-values "^4.0.2" - postcss-minify-gradients "^4.0.2" - postcss-minify-params "^4.0.2" - postcss-minify-selectors "^4.0.2" - postcss-normalize-charset "^4.0.1" - postcss-normalize-display-values "^4.0.2" - postcss-normalize-positions "^4.0.2" - postcss-normalize-repeat-style "^4.0.2" - postcss-normalize-string "^4.0.2" - postcss-normalize-timing-functions "^4.0.2" - postcss-normalize-unicode "^4.0.1" - postcss-normalize-url "^4.0.1" - postcss-normalize-whitespace "^4.0.2" - postcss-ordered-values "^4.1.2" - postcss-reduce-initial "^4.0.3" - postcss-reduce-transforms "^4.0.2" - postcss-svgo "^4.0.3" - postcss-unique-selectors "^4.0.1" - -cssnano-util-get-arguments@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" - integrity sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8= - -cssnano-util-get-match@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" - integrity sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0= - -cssnano-util-raw-cache@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz#b26d5fd5f72a11dfe7a7846fb4c67260f96bf282" - integrity sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA== - dependencies: - postcss "^7.0.0" - -cssnano-util-same-parent@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz#574082fb2859d2db433855835d9a8456ea18bbf3" - integrity sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q== - -cssnano@^4.1.11: - version "4.1.11" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.11.tgz#c7b5f5b81da269cb1fd982cb960c1200910c9a99" - integrity sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g== - dependencies: - cosmiconfig "^5.0.0" - cssnano-preset-default "^4.0.8" - is-resolvable "^1.0.0" - postcss "^7.0.0" - -csso@^4.0.2: - version "4.2.0" - resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" - integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== - dependencies: - css-tree "^1.1.2" - -cssom@0.3.x, "cssom@>= 0.3.0 < 0.4.0": - version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" - integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== - -"cssstyle@>= 0.2.21 < 0.3.0": - version "0.2.37" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54" - integrity sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ= - dependencies: - cssom "0.3.x" - -cyclist@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" - integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= - -d@1, d@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" - integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== - dependencies: - es5-ext "^0.10.50" - type "^1.0.1" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - -data-uri-to-buffer@3: - version "3.0.1" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636" - integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og== - -debounce@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" - integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== - -debug-fabulous@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/debug-fabulous/-/debug-fabulous-1.1.0.tgz#af8a08632465224ef4174a9f06308c3c2a1ebc8e" - integrity sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg== - dependencies: - debug "3.X" - memoizee "0.4.X" - object-assign "4.X" - -debug@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - -debug@3.X, debug@^3.1.0: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -debug@4, debug@4.3.1, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== - dependencies: - ms "2.1.2" - -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" - -decamelize@^1.1.1, decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - -decamelize@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" - integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== - -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= - -decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= - dependencies: - mimic-response "^1.0.0" - -deemon@^1.4.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/deemon/-/deemon-1.6.0.tgz#4eff868e44e684a224c7cb65a32bb8142f2dabc5" - integrity sha512-6GN9m4o9c+PVcGuTPgcJ/UMbyoFgQBsFalityPDfJ5Fk5/hjKET67DAPVsM3+4uSHBfkDN+AW6BHQx852cJGvg== - dependencies: - bl "^4.0.2" - tree-kill "^1.2.2" - -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - -deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - -default-compare@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/default-compare/-/default-compare-1.0.0.tgz#cb61131844ad84d84788fb68fd01681ca7781a2f" - integrity sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ== - dependencies: - kind-of "^5.0.2" - -default-resolution@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/default-resolution/-/default-resolution-2.0.0.tgz#bcb82baa72ad79b426a76732f1a81ad6df26d684" - integrity sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ= - -defer-to-connect@^1.0.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" - integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== - -define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -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" - -degenerator@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-2.2.0.tgz#49e98c11fa0293c5b26edfbb52f15729afcdb254" - integrity sha512-aiQcQowF01RxFI4ZLFMpzyotbQonhNpBao6dkI8JPk5a+hmSjR5ErHp2CQySmQe8os3VBqLCIh87nDBgZXvsmg== - dependencies: - ast-types "^0.13.2" - escodegen "^1.8.1" - esprima "^4.0.0" - -delayed-stream@0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.6.tgz#a2646cb7ec3d5d7774614670a7a65de0c173edbc" - integrity sha1-omRst+w9XXd0YUZwp6Zd4MFz7bw= - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - -deprecation@^2.0.0, deprecation@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" - integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== - -des.js@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" - integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -detect-file@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" - integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= - -detect-indent@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.0.0.tgz#0abd0f549f69fc6659a254fe96786186b6f528fd" - integrity sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA== - -detect-newline@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" - integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= - -detect-node@^2.0.4: - version "2.0.5" - resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.5.tgz#9d270aa7eaa5af0b72c4c9d9b814e7f4ce738b79" - integrity sha512-qi86tE6hRcFHy8jI1m2VG+LaPUR1LhqDa5G8tVjuUXmOrpuAgqsA1pN0+ldgr3aKUH+QLI9hCY/OcRYisERejw== - -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" - integrity sha1-ji1geottef6IC1SLxYzGvrKIxPM= - -diagnostic-channel-publishers@0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.4.4.tgz#57c3b80b7e7f576f95be3a257d5e94550f0082d6" - integrity sha512-l126t01d2ZS9EreskvEtZPrcgstuvH3rbKy82oUhUrVmBaGx4hO9wECdl3cvZbKDYjMF3QJDB5z5dL9yWAjvZQ== - -diagnostic-channel@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz#cc99af9612c23fb1fff13612c72f2cbfaa8d5a17" - integrity sha1-zJmvlhLCP7H/8TYSxy8sv6qNWhc= - dependencies: - semver "^5.3.0" - -diagnostic-channel@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-0.3.1.tgz#7faa143e107f861be3046539eb4908faab3f53fd" - integrity sha512-6eb9YRrimz8oTr5+JDzGmSYnXy5V7YnK5y/hd8AUDK1MssHjQKm9LlD6NSrHx4vMDF3+e/spI2hmWTviElgWZA== - dependencies: - semver "^5.3.0" - -diff@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" - integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== - -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -dom-serializer@0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" - integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== - dependencies: - domelementtype "^2.0.1" - entities "^2.0.0" - -domain-browser@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" - integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== - -domelementtype@1, domelementtype@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" - integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== - -domelementtype@^2.0.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" - integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== - -domhandler@^2.3.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" - integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== - dependencies: - domelementtype "1" - -domutils@^1.5.1, domutils@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" - integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== - dependencies: - dom-serializer "0" - domelementtype "1" - -dot-prop@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" - integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== - dependencies: - is-obj "^2.0.0" - -duplexer3@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= - -duplexer@^0.1.1, duplexer@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" - integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== - -duplexify@^3.4.2, duplexify@^3.6.0: - version "3.7.1" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" - integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - -each-props@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/each-props/-/each-props-1.3.2.tgz#ea45a414d16dd5cfa419b1a81720d5ca06892333" - integrity sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA== - dependencies: - is-plain-object "^2.0.1" - object.defaults "^1.1.0" - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -editorconfig@^0.15.0, editorconfig@^0.15.3: - version "0.15.3" - resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.3.tgz#bef84c4e75fb8dcb0ce5cee8efd51c15999befc5" - integrity sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g== - dependencies: - commander "^2.19.0" - lru-cache "^4.1.5" - semver "^5.6.0" - sigmund "^1.0.1" - -electron-to-chromium@^1.3.723: - version "1.3.726" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.726.tgz#6d3c577e5f5a48904ba891464740896c05e3bdb1" - integrity sha512-dw7WmrSu/JwtACiBzth8cuKf62NKL1xVJuNvyOg0jvruN/n4NLtGYoTzciQquCPNaS2eR+BT5GrxHbslfc/w1w== - -elliptic@^6.5.3: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -emitter-listener@^1.0.1, emitter-listener@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8" - integrity sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ== - dependencies: - shimmer "^1.2.0" - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -emojis-list@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" - integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== - -encodeurl@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= - -end-of-stream@^1.0.0, end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - -enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.1, enhanced-resolve@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" - integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg== - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.5.0" - tapable "^1.0.0" - -entities@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" - integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== - -entities@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" - integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== - -env-paths@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" - integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== - -errno@^0.1.3, errno@~0.1.7: - version "0.1.8" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" - integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== - dependencies: - prr "~1.0.1" - -error-ex@^1.2.0, error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.17.2, es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2: - version "1.18.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0.tgz#ab80b359eecb7ede4c298000390bc5ac3ec7b5a4" - integrity sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw== - dependencies: - call-bind "^1.0.2" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - get-intrinsic "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.2" - is-callable "^1.2.3" - is-negative-zero "^2.0.1" - is-regex "^1.1.2" - is-string "^1.0.5" - object-inspect "^1.9.0" - object-keys "^1.1.1" - object.assign "^4.1.2" - string.prototype.trimend "^1.0.4" - string.prototype.trimstart "^1.0.4" - unbox-primitive "^1.0.0" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: - version "0.10.53" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" - integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q== - dependencies: - es6-iterator "~2.0.3" - es6-symbol "~3.1.3" - next-tick "~1.0.0" - -es6-error@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" - integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== - -es6-iterator@^2.0.1, es6-iterator@^2.0.3, es6-iterator@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-promise@^4.0.3: - version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" - integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== - -es6-promisify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= - dependencies: - es6-promise "^4.0.3" - -es6-symbol@^3.1.1, es6-symbol@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" - integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== - dependencies: - d "^1.0.1" - ext "^1.1.2" - -es6-weak-map@^2.0.1, es6-weak-map@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.3.tgz#b6da1f16cc2cc0d9be43e6bdbfc5e7dfcdf31d53" - integrity sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA== - dependencies: - d "1" - es5-ext "^0.10.46" - es6-iterator "^2.0.3" - es6-symbol "^3.1.1" - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -escodegen@^1.8.1: - version "1.14.3" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" - integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== - dependencies: - esprima "^4.0.1" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - -eslint-plugin-jsdoc@^19.1.0: - version "19.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-19.2.0.tgz#f522b970878ae402b28ce62187305b33dfe2c834" - integrity sha512-QdNifBFLXCDGdy+26RXxcrqzEZarFWNybCZQVqJQYEYPlxd6lm+LPkrs6mCOhaGc2wqC6zqpedBQFX8nQJuKSw== - dependencies: - comment-parser "^0.7.2" - debug "^4.1.1" - jsdoctypeparser "^6.1.0" - lodash "^4.17.15" - object.entries-ponyfill "^1.0.1" - regextras "^0.7.0" - semver "^6.3.0" - spdx-expression-parse "^3.0.0" - -eslint-scope@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" - integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-scope@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-utils@^1.3.1, eslint-utils@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-utils@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint@6.8.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" - integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.10.0" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^5.0.0" - eslint-utils "^1.4.3" - eslint-visitor-keys "^1.1.0" - espree "^6.1.2" - esquery "^1.0.1" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^7.0.0" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.14" - minimatch "^3.0.4" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.3" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^6.1.2" - strip-ansi "^5.2.0" - strip-json-comments "^3.0.1" - table "^5.2.3" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -eslint@^5.0.1: - version "5.16.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" - integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.9.1" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^4.0.3" - eslint-utils "^1.3.1" - eslint-visitor-keys "^1.0.0" - espree "^5.0.1" - esquery "^1.0.1" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.7.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^6.2.2" - js-yaml "^3.13.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.11" - minimatch "^3.0.4" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^5.5.1" - strip-ansi "^4.0.0" - strip-json-comments "^2.0.1" - table "^5.2.3" - text-table "^0.2.0" - -espree@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" - integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== - dependencies: - acorn "^6.0.7" - acorn-jsx "^5.0.0" - eslint-visitor-keys "^1.0.0" - -espree@^6.1.2: - version "6.2.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" - integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== - dependencies: - acorn "^7.1.1" - acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" - -esprima@^4.0.0, esprima@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.0.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.1.0, esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1, estraverse@^4.2.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -event-emitter@^0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" - integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk= - dependencies: - d "1" - es5-ext "~0.10.14" - -event-stream@3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" - integrity sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE= - dependencies: - duplexer "~0.1.1" - from "~0" - map-stream "~0.1.0" - pause-stream "0.0.11" - split "0.3" - stream-combiner "~0.0.4" - through "~2.3.1" - -event-stream@^3.3.4, event-stream@~3.3.4: - version "3.3.5" - resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.5.tgz#e5dd8989543630d94c6cf4d657120341fa31636b" - integrity sha512-vyibDcu5JL20Me1fP734QBH/kenBGLZap2n0+XXM7mvuUPzJ20Ydqj1aKcIeMdri1p+PU+4yAKugjN8KCVst+g== - dependencies: - duplexer "^0.1.1" - from "^0.1.7" - map-stream "0.0.7" - pause-stream "^0.0.11" - split "^1.0.1" - stream-combiner "^0.2.2" - through "^2.3.8" - -events@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -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" - -expand-tilde@^2.0.0, expand-tilde@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" - integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= - dependencies: - homedir-polyfill "^1.0.1" - -ext@^1.1.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" - integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A== - dependencies: - type "^2.0.0" - -extend-shallow@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-1.1.4.tgz#19d6bf94dfc09d76ba711f39b872d21ff4dd9071" - integrity sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE= - dependencies: - kind-of "^1.1.0" - -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" - -extend@^3.0.0, extend@^3.0.2, extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -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" - -extract-zip@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" - integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== - dependencies: - debug "^4.1.1" - get-stream "^5.1.0" - yauzl "^2.10.0" - optionalDependencies: - "@types/yauzl" "^2.9.1" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= - -fancy-log@^1.3.2, fancy-log@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.3.tgz#dbc19154f558690150a23953a0adbd035be45fc7" - integrity sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw== - dependencies: - ansi-gray "^0.1.1" - color-support "^1.1.3" - parse-node-version "^1.0.0" - time-stamp "^1.0.0" - -fast-deep-equal@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-glob@^3.1.1, fast-glob@^3.2.4, fast-glob@^3.2.5: - version "3.2.5" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" - integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.0" - merge2 "^1.3.0" - micromatch "^4.0.2" - picomatch "^2.2.1" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz#e6a754cc8f15e58987aa9cbd27af66fd6f4e5af9" - integrity sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk= - -fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -fast-plist@0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/fast-plist/-/fast-plist-0.1.2.tgz#a45aff345196006d406ca6cdcd05f69051ef35b8" - integrity sha1-pFr/NFGWAG1AbKbNzQX2kFHvNbg= - -fastq@^1.6.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.11.0.tgz#bb9fb955a07130a918eb63c1f5161cc32a5d0858" - integrity sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g== - dependencies: - reusify "^1.0.4" - -fd-slicer@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" - integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= - dependencies: - pend "~1.2.0" - -figgy-pudding@^3.5.1: - version "3.5.2" - resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" - integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== - -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= - dependencies: - escape-string-regexp "^1.0.5" - -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" - -file-loader@^4.2.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-4.3.0.tgz#780f040f729b3d18019f20605f723e844b8a58af" - integrity sha512-aKrYPYjF1yG3oX0kWRrqrSMfgftm7oJW5M+m4owoldH5C51C0RkIwB++JbRvEW3IU6/ZG5n8UvEcdgwOt2UOWA== - dependencies: - loader-utils "^1.2.3" - schema-utils "^2.5.0" - -file-uri-to-path@1.0.0: - version "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== - -file-uri-to-path@2: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz#7b415aeba227d575851e0a5b0c640d7656403fba" - integrity sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg== - -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= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.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" - -find-cache-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" - integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== - dependencies: - commondir "^1.0.1" - make-dir "^2.0.0" - pkg-dir "^3.0.0" - -find-cache-dir@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" - integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== - dependencies: - commondir "^1.0.1" - make-dir "^3.0.2" - pkg-dir "^4.1.0" - -find-parent-dir@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/find-parent-dir/-/find-parent-dir-0.3.0.tgz#33c44b429ab2b2f0646299c5f9f718f376ff8d54" - integrity sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ= - -find-replace@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38" - integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== - dependencies: - array-back "^3.0.1" - -find-up@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - -find-up@^4.0.0, find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -findup-sync@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" - integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw= - dependencies: - detect-file "^1.0.0" - is-glob "^3.1.0" - micromatch "^3.0.4" - resolve-dir "^1.0.1" - -findup-sync@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1" - integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg== - dependencies: - detect-file "^1.0.0" - is-glob "^4.0.0" - micromatch "^3.0.4" - resolve-dir "^1.0.1" - -fined@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fined/-/fined-1.2.0.tgz#d00beccf1aa2b475d16d423b0238b713a2c4a37b" - integrity sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng== - dependencies: - expand-tilde "^2.0.2" - is-plain-object "^2.0.3" - object.defaults "^1.1.0" - object.pick "^1.2.0" - parse-filepath "^1.0.1" - -flagged-respawn@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-1.0.1.tgz#e7de6f1279ddd9ca9aac8a5971d618606b3aab41" - integrity sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q== - -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - -flat@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== - -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== - -flush-write-stream@^1.0.0, flush-write-stream@^1.0.2: - version "1.1.1" - resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" - integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== - dependencies: - inherits "^2.0.3" - readable-stream "^2.3.6" - -for-in@^1.0.1, 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= - -for-own@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" - integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs= - dependencies: - for-in "^1.0.1" - -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -formatio@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/formatio/-/formatio-1.1.1.tgz#5ed3ccd636551097383465d996199100e86161e9" - integrity sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek= - dependencies: - samsam "~1.1" - -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" - -from2@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - -from@^0.1.7, from@~0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" - integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= - -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-minipass@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" - integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== - dependencies: - minipass "^3.0.0" - -fs-mkdirp-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz#0b7815fc3201c6a69e14db98ce098c16935259eb" - integrity sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes= - dependencies: - graceful-fs "^4.1.11" - through2 "^2.0.3" - -fs-write-stream-atomic@^1.0.8: - version "1.0.10" - resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" - integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= - dependencies: - graceful-fs "^4.1.2" - iferr "^0.1.5" - imurmurhash "^0.1.4" - readable-stream "1 || 2" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@^1.2.7: - version "1.2.13" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" - integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== - dependencies: - bindings "^1.5.0" - nan "^2.12.1" - -fsevents@~2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -fstream@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" - integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" - -ftp@^0.3.10: - version "0.3.10" - resolved "https://registry.yarnpkg.com/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d" - integrity sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0= - dependencies: - readable-stream "1.1.x" - xregexp "2.0.0" - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== - -get-caller-file@^2.0.1, get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - -get-stream@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - -get-stream@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" - integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== - dependencies: - pump "^3.0.0" - -get-uri@3, get-uri@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c" - integrity sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg== - dependencies: - "@tootallnate/once" "1" - data-uri-to-buffer "3" - debug "4" - file-uri-to-path "2" - fs-extra "^8.1.0" - ftp "^0.3.10" - -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= - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - -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= - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - -glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@^5.1.1, glob-parent@~5.1.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob-stream@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-6.1.0.tgz#7045c99413b3eb94888d83ab46d0b404cc7bdde4" - integrity sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ= - dependencies: - extend "^3.0.0" - glob "^7.1.1" - glob-parent "^3.1.0" - is-negated-glob "^1.0.0" - ordered-read-streams "^1.0.0" - pumpify "^1.3.5" - readable-stream "^2.1.5" - remove-trailing-separator "^1.0.1" - to-absolute-glob "^2.0.0" - unique-stream "^2.0.2" - -glob-watcher@^5.0.3: - version "5.0.5" - resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-5.0.5.tgz#aa6bce648332924d9a8489be41e3e5c52d4186dc" - integrity sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw== - dependencies: - anymatch "^2.0.0" - async-done "^1.2.0" - chokidar "^2.0.0" - is-negated-glob "^1.0.0" - just-debounce "^1.0.0" - normalize-path "^3.0.0" - object.defaults "^1.1.0" - -glob@7.1.6, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^5.0.13: - version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - -global-agent@^2.0.2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/global-agent/-/global-agent-2.2.0.tgz#566331b0646e6bf79429a16877685c4a1fbf76dc" - integrity sha512-+20KpaW6DDLqhG7JDiJpD1JvNvb8ts+TNl7BPOYcURqCrXqnN1Vf+XVOrkKJAFPqfX+oEhsdzOj1hLWkBTdNJg== - dependencies: - boolean "^3.0.1" - core-js "^3.6.5" - es6-error "^4.1.1" - matcher "^3.0.0" - roarr "^2.15.3" - semver "^7.3.2" - serialize-error "^7.0.1" - -global-modules@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" - integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== - dependencies: - global-prefix "^1.0.1" - is-windows "^1.0.1" - resolve-dir "^1.0.0" - -global-modules@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" - integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== - dependencies: - global-prefix "^3.0.0" - -global-prefix@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" - integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4= - dependencies: - expand-tilde "^2.0.2" - homedir-polyfill "^1.0.1" - ini "^1.3.4" - is-windows "^1.0.1" - which "^1.2.14" - -global-prefix@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" - integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== - dependencies: - ini "^1.3.5" - kind-of "^6.0.2" - which "^1.3.1" - -global-tunnel-ng@^2.7.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz#d03b5102dfde3a69914f5ee7d86761ca35d57d8f" - integrity sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg== - dependencies: - encodeurl "^1.0.2" - lodash "^4.17.10" - npm-conf "^1.1.3" - tunnel "^0.0.6" - -globals@^11.1.0, globals@^11.7.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== - dependencies: - type-fest "^0.8.1" - -globalthis@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.2.tgz#2a235d34f4d8036219f7e34929b5de9e18166b8b" - integrity sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ== - dependencies: - define-properties "^1.1.3" - -globby@^11.0.1: - version "11.0.3" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.3.tgz#9b1f0cb523e171dd1ad8c7b2a9fb4b644b9593cb" - integrity sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" - -glogg@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.2.tgz#2d7dd702beda22eb3bffadf880696da6d846313f" - integrity sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA== - dependencies: - sparkles "^1.0.0" - -got@^9.6.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" - integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== - dependencies: - "@sindresorhus/is" "^0.14.0" - "@szmarczak/http-timer" "^1.1.2" - cacheable-request "^6.0.0" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^4.1.0" - lowercase-keys "^1.0.1" - mimic-response "^1.0.1" - p-cancelable "^1.0.0" - to-readable-stream "^1.0.0" - url-parse-lax "^3.0.0" - -graceful-fs@4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" - integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== - -graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: - version "4.2.6" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" - integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== - -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== - -gulp-atom-electron@^1.30.1: - version "1.31.0" - resolved "https://registry.yarnpkg.com/gulp-atom-electron/-/gulp-atom-electron-1.31.0.tgz#40c1b2c3cfb6e4d35551e1ba07d6fd7b3fef05d6" - integrity sha512-sL5VcAjNFpWDgPYGqlr4CotNIhGzwzsII/vg8J5ROZ83mPB5iEF7boT8ADPKm9MuJ0q9uLHEcQFiuMZ4xk5hJg== - dependencies: - "@electron/get" "^1.12.4" - "@octokit/rest" "^18.0.14" - event-stream "3.3.4" - gulp-filter "^5.1.0" - gulp-rename "1.2.2" - gulp-symdest "^1.2.0" - gulp-vinyl-zip "^2.1.2" - mkdirp "^0.5.1" - plist "^3.0.1" - progress "^1.1.8" - rcedit "^0.3.0" - rimraf "^2.4.2" - semver "^4.3.4" - temp "^0.8.3" - vinyl "^2.2.0" - vinyl-fs "^3.0.3" - -gulp-azure-storage@^0.11.1: - version "0.11.1" - resolved "https://registry.yarnpkg.com/gulp-azure-storage/-/gulp-azure-storage-0.11.1.tgz#0e5f5d0f789da11206f1e5a9311a6cf7107877d7" - integrity sha512-csOwItwZV1P9GLsORVQy+CFwjYDdHNrBol89JlHdlhGx0fTgJBc1COTRZbjGRyRjgdUuVguo3YLl4ToJ10/SIQ== - dependencies: - azure-storage "^2.10.2" - delayed-stream "0.0.6" - event-stream "3.3.4" - mime "^1.3.4" - progress "^1.1.8" - queue "^3.0.10" - streamifier "^0.1.1" - vinyl "^2.2.0" - vinyl-fs "^3.0.3" - yargs "^15.3.0" - -gulp-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/gulp-bom/-/gulp-bom-3.0.0.tgz#b2f1ab0ef304ff5e593665b776ba517ef7ffb4ad" - integrity sha512-iw/J94F+MVlxG64Q17BSkHsyjpY17qHl3N3A/jDdrL77zQBkhKtTiKLqM4di9CUX/qFToyyeDsOWwH+rESBgmA== - dependencies: - plugin-error "^1.0.1" - through2 "^3.0.1" - -gulp-buffer@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/gulp-buffer/-/gulp-buffer-0.0.2.tgz#af81b4346101736b49942ec6c9fa867ffe737036" - integrity sha1-r4G0NGEBc2tJlC7GyfqGf/5zcDY= - dependencies: - through2 "~0.4.0" - -gulp-cli@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/gulp-cli/-/gulp-cli-2.3.0.tgz#ec0d380e29e52aa45e47977f0d32e18fd161122f" - integrity sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A== - dependencies: - ansi-colors "^1.0.1" - archy "^1.0.0" - array-sort "^1.0.0" - color-support "^1.1.3" - concat-stream "^1.6.0" - copy-props "^2.0.1" - fancy-log "^1.3.2" - gulplog "^1.0.0" - interpret "^1.4.0" - isobject "^3.0.1" - liftoff "^3.1.0" - matchdep "^2.0.0" - mute-stdout "^1.0.0" - pretty-hrtime "^1.0.0" - replace-homedir "^1.0.0" - semver-greatest-satisfied-range "^1.1.0" - v8flags "^3.2.0" - yargs "^7.1.0" - -gulp-concat@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/gulp-concat/-/gulp-concat-2.6.1.tgz#633d16c95d88504628ad02665663cee5a4793353" - integrity sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M= - dependencies: - concat-with-sourcemaps "^1.0.0" - through2 "^2.0.0" - vinyl "^2.0.0" - -gulp-eslint@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/gulp-eslint/-/gulp-eslint-5.0.0.tgz#2a2684095f774b2cf79310262078c56cc7a12b52" - integrity sha512-9GUqCqh85C7rP9120cpxXuZz2ayq3BZc85pCTuPJS03VQYxne0aWPIXWx6LSvsGPa3uRqtSO537vaugOh+5cXg== - dependencies: - eslint "^5.0.1" - fancy-log "^1.3.2" - plugin-error "^1.0.1" - -gulp-filter@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/gulp-filter/-/gulp-filter-5.1.0.tgz#a05e11affb07cf7dcf41a7de1cb7b63ac3783e73" - integrity sha1-oF4Rr/sHz33PQafeHLe2OsN4PnM= - dependencies: - multimatch "^2.0.0" - plugin-error "^0.1.2" - streamfilter "^1.0.5" - -gulp-flatmap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/gulp-flatmap/-/gulp-flatmap-1.0.2.tgz#b515ae6081d66af99daf56c612e2d92502720133" - integrity sha512-xm+Ax2vPL/xiMBqLFI++wUyPtncm3b55ztGHewmRcoG/sYb0OUTatjSacOud3fee77rnk+jOgnDEHhwBtMHgFA== - dependencies: - plugin-error "0.1.2" - through2 "2.0.3" - -gulp-gunzip@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/gulp-gunzip/-/gulp-gunzip-1.1.0.tgz#56f81b4ed8106ba3c905e310661ee7f11eb5ac03" - integrity sha512-3INeprGyz5fUtAs75k6wVslGuRZIjKAoQp39xA7Bz350ReqkrfYaLYqjZ67XyIfLytRXdzeX04f+DnBduYhQWw== - dependencies: - through2 "~2.0.3" - vinyl "~2.0.1" - -gulp-gzip@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/gulp-gzip/-/gulp-gzip-1.4.2.tgz#0422a94014248655b5b1a9eea1c2abee1d4f4337" - integrity sha512-ZIxfkUwk2XmZPTT9pPHrHUQlZMyp9nPhg2sfoeN27mBGpi7OaHnOD+WCN41NXjfJQ69lV1nQ9LLm1hYxx4h3UQ== - dependencies: - ansi-colors "^1.0.1" - bytes "^3.0.0" - fancy-log "^1.3.2" - plugin-error "^1.0.0" - stream-to-array "^2.3.0" - through2 "^2.0.3" - -gulp-json-editor@^2.5.0: - version "2.5.5" - resolved "https://registry.yarnpkg.com/gulp-json-editor/-/gulp-json-editor-2.5.5.tgz#7aac10e999a93c70eddb9592db5ac40541eb715c" - integrity sha512-YnPwdUP+tsrGumc78vgKXYYkxNavv7pZakXLfOsm9e8v+eDdo+zWFV2n2wwHHGcSuRsBfarruZ9SUvR5DNtCEQ== - dependencies: - deepmerge "^4.2.2" - detect-indent "^6.0.0" - js-beautify "^1.13.5" - plugin-error "^1.0.1" - through2 "^4.0.2" - -gulp-plumber@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/gulp-plumber/-/gulp-plumber-1.2.1.tgz#d38700755a300b9d372318e4ffb5ff7ced0b2c84" - integrity sha512-mctAi9msEAG7XzW5ytDVZ9PxWMzzi1pS2rBH7lA095DhMa6KEXjm+St0GOCc567pJKJ/oCvosVAZEpAey0q2eQ== - dependencies: - chalk "^1.1.3" - fancy-log "^1.3.2" - plugin-error "^0.1.2" - through2 "^2.0.3" - -gulp-postcss@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/gulp-postcss/-/gulp-postcss-9.0.0.tgz#2ade18809ab475dae743a88bd6501af0b04ee54e" - integrity sha512-5mSQ9CK8salSagrXgrVyILfEMy6I5rUGPRiR9rVjgJV9m/rwdZYUhekMr+XxDlApfc5ZdEJ8gXNZrU/TsgT5dQ== - dependencies: - fancy-log "^1.3.3" - plugin-error "^1.0.1" - postcss-load-config "^2.1.1" - vinyl-sourcemaps-apply "^0.2.1" - -gulp-remote-retry-src@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/gulp-remote-retry-src/-/gulp-remote-retry-src-0.6.0.tgz#fdcb5d5c9e67c31ae378a2a886ddad3d47913bb1" - integrity sha512-lFxpwwbM/GEIdYiNumxiUcPHZUROFJaF1zTBne1H8b3Pwx6Te6O9uEYp++JZPP62jdheOWcHUTBREiMkpdbm4Q== - dependencies: - event-stream "3.3.4" - node.extend "~1.1.2" - request "^2.88.0" - requestretry "^4.0.0" - through2 "~2.0.3" - vinyl "~2.0.1" - -gulp-rename@1.2.2, gulp-rename@~1.2.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/gulp-rename/-/gulp-rename-1.2.2.tgz#3ad4428763f05e2764dec1c67d868db275687817" - integrity sha1-OtRCh2PwXidk3sHGfYaNsnVoeBc= - -gulp-replace@^0.5.4: - version "0.5.4" - resolved "https://registry.yarnpkg.com/gulp-replace/-/gulp-replace-0.5.4.tgz#69a67914bbd13c562bff14f504a403796aa0daa9" - integrity sha1-aaZ5FLvRPFYr/xT1BKQDeWqg2qk= - dependencies: - istextorbinary "1.0.2" - readable-stream "^2.0.1" - replacestream "^4.0.0" - -gulp-shell@^0.6.5: - version "0.6.5" - resolved "https://registry.yarnpkg.com/gulp-shell/-/gulp-shell-0.6.5.tgz#f07b204ad8ad1c2659f7a1b6d76efa16d416a759" - integrity sha512-f3m1WcS0o2B72/PGj1Jbv9zYR9rynBh/EQJv64n01xQUo7j7anols0eww9GG/WtDTzGVQLrupVDYkifRFnj5Zg== - dependencies: - async "^2.1.5" - chalk "^2.3.0" - fancy-log "^1.3.2" - lodash "^4.17.4" - lodash.template "^4.4.0" - plugin-error "^0.1.2" - through2 "^2.0.3" - -gulp-sourcemaps@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-3.0.0.tgz#2e154e1a2efed033c0e48013969e6f30337b2743" - integrity sha512-RqvUckJkuYqy4VaIH60RMal4ZtG0IbQ6PXMNkNsshEGJ9cldUPRb/YCgboYae+CLAs1HQNb4ADTKCx65HInquQ== - dependencies: - "@gulp-sourcemaps/identity-map" "^2.0.1" - "@gulp-sourcemaps/map-sources" "^1.0.0" - acorn "^6.4.1" - convert-source-map "^1.0.0" - css "^3.0.0" - debug-fabulous "^1.0.0" - detect-newline "^2.0.0" - graceful-fs "^4.0.0" - source-map "^0.6.0" - strip-bom-string "^1.0.0" - through2 "^2.0.0" - -gulp-symdest@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/gulp-symdest/-/gulp-symdest-1.2.0.tgz#bda30559a7a65ff3a31038ba539c63ca4c2d3259" - integrity sha512-8AdxdZUKzSyzSYJ86S8FPb10DRtT9Vh80d5vloRDOwByWgPVP0a0UDu85R0RZGYOuX1wOFjhYlSKshCskU5E2A== - dependencies: - event-stream "3.3.4" - mkdirp "^0.5.1" - mocha "^8.3.0" - queue "^3.1.0" - vinyl-fs "^3.0.3" - -gulp-tsb@4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/gulp-tsb/-/gulp-tsb-4.0.6.tgz#526f07a2c74e1d2f8932b1500316f2a64b33363c" - integrity sha512-55HSu1zvOOq7D+OqPScvGQaJPKveLbM1T5jEnSJUhbcbwX1Kx0SWv4UVe7MfFcBwFe3wMiWSkKoajNONEv5E9g== - dependencies: - ansi-colors "^1.0.1" - fancy-log "^1.3.2" - through "^2.3.6" - vinyl "^2.1.0" - -gulp-untar@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/gulp-untar/-/gulp-untar-0.0.7.tgz#92067d79e0fa1e92d60562a100233a44a5aa08b4" - integrity sha512-0QfbCH2a1k2qkTLWPqTX+QO4qNsHn3kC546YhAP3/n0h+nvtyGITDuDrYBMDZeW4WnFijmkOvBWa5HshTic1tw== - dependencies: - event-stream "~3.3.4" - streamifier "~0.1.1" - tar "^2.2.1" - through2 "~2.0.3" - vinyl "^1.2.0" - -gulp-vinyl-zip@^2.1.2: - version "2.2.1" - resolved "https://registry.yarnpkg.com/gulp-vinyl-zip/-/gulp-vinyl-zip-2.2.1.tgz#24a60230afeb3b88b1efba06d31653ef7145dfd8" - integrity sha512-9lwCZUkrENzP649hVQB2r+8GgeGtVrqA2fEeVDX6aYr6+yJjdczWu0r1C6WvbZdzhXcA61MtR5MEyjR9a3D7cw== - dependencies: - queue "^4.2.1" - through "^2.3.8" - through2 "^2.0.3" - vinyl "^2.0.2" - vinyl-fs "^3.0.3" - yauzl "^2.2.1" - yazl "^2.2.1" - -gulp@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/gulp/-/gulp-4.0.2.tgz#543651070fd0f6ab0a0650c6a3e6ff5a7cb09caa" - integrity sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA== - dependencies: - glob-watcher "^5.0.3" - gulp-cli "^2.2.0" - undertaker "^1.2.1" - vinyl-fs "^3.0.0" - -gulplog@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5" - integrity sha1-4oxNRdBey77YGDY86PnFkmIp/+U= - dependencies: - glogg "^1.0.0" - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - -har-validator@~5.1.3: - version "5.1.5" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" - integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== - dependencies: - ajv "^6.12.3" - har-schema "^2.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - -has-bigints@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" - integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-symbols@^1.0.1, has-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" - integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== - -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" - -has@^1.0.0, has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -he@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - -hex-color-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" - integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== - -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -homedir-polyfill@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" - integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== - dependencies: - parse-passwd "^1.0.0" - -hosted-git-info@^2.1.4: - version "2.8.9" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" - integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== - -hsl-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" - integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4= - -hsla-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" - integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= - -html-escaper@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - -"htmlparser2@>= 3.7.3 < 4.0.0": - version "3.10.1" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" - integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== - dependencies: - domelementtype "^1.3.1" - domhandler "^2.3.0" - domutils "^1.5.1" - entities "^1.1.1" - inherits "^2.0.1" - readable-stream "^3.1.1" - -http-cache-semantics@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" - integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== - -http-errors@1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" - integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.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" - integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== - dependencies: - agent-base "4" - debug "3.1.0" - -http-proxy-agent@^4.0.0, http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -https-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= - -https-proxy-agent@5, https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== - dependencies: - agent-base "6" - debug "4" - -https-proxy-agent@^2.2.3: - version "2.2.4" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" - integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== - dependencies: - agent-base "^4.3.0" - debug "^3.1.0" - -https-proxy-agent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b" - integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg== - dependencies: - agent-base "5" - debug "4" - -husky@^0.13.1: - version "0.13.4" - resolved "https://registry.yarnpkg.com/husky/-/husky-0.13.4.tgz#48785c5028de3452a51c48c12c4f94b2124a1407" - integrity sha1-SHhcUCjeNFKlHEjBLE+UshJKFAc= - dependencies: - chalk "^1.1.3" - find-parent-dir "^0.3.0" - is-ci "^1.0.9" - normalize-path "^1.0.0" - -iconv-lite-umd@0.6.8: - version "0.6.8" - resolved "https://registry.yarnpkg.com/iconv-lite-umd/-/iconv-lite-umd-0.6.8.tgz#5ad310ec126b260621471a2d586f7f37b9958ec0" - integrity sha512-zvXJ5gSwMC9JD3wDzH8CoZGc1pbiJn12Tqjk8BXYCnYz3hYL5GRjHW8LEykjXhV9WgNGI4rgpgHcbIiBfrRq6A== - -iconv-lite@0.4.24, iconv-lite@^0.4.19, iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -icss-utils@^4.0.0, icss-utils@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" - integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA== - dependencies: - postcss "^7.0.14" - -ieee754@^1.1.13, ieee754@^1.1.4: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -iferr@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" - integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.1.4: - version "5.1.8" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== - -import-cwd@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" - integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk= - dependencies: - import-from "^2.1.0" - -import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" - -import-fresh@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -import-from@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" - integrity sha1-M1238qev/VOqpHHUuAId7ja387E= - dependencies: - resolve-from "^3.0.0" - -import-local@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" - integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== - dependencies: - pkg-dir "^3.0.0" - resolve-cwd "^2.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - -indexes-of@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" - integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= - -infer-owner@^1.0.3, infer-owner@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" - integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, 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.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= - -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -ini@^1.3.4, ini@^1.3.5: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - -innosetup@6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/innosetup/-/innosetup-6.0.5.tgz#3001e54c638e4e19edd9ebdc6b1855b9ba8b0bbf" - integrity sha512-XRvidEN0dcxe7NrGXBjl/clfNRfmyakSDtgKaJgvZ3ciKE5ArQOVGqUJcLyPhllqHhMzYGpbUF3ZTZvtKVDP2g== - -inquirer@^6.2.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" - integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== - dependencies: - ansi-escapes "^3.2.0" - chalk "^2.4.2" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^3.0.3" - figures "^2.0.0" - lodash "^4.17.12" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^6.4.0" - string-width "^2.1.0" - strip-ansi "^5.1.0" - through "^2.3.6" - -inquirer@^7.0.0: - version "7.3.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - -interpret@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" - integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== - -invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= - -ip@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" - integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= - -is-absolute-url@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" - integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY= - -is-absolute@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576" - integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA== - dependencies: - is-relative "^1.0.0" - is-windows "^1.0.1" - -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= - dependencies: - kind-of "^3.0.2" - -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-arguments@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.0.tgz#62353031dfbee07ceb34656a6bde59efecae8dd9" - integrity sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg== - dependencies: - call-bind "^1.0.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - -is-arrayish@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" - integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== - -is-bigint@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.2.tgz#ffb381442503235ad245ea89e45b3dbff040ee5a" - integrity sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA== - -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-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-boolean-object@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.0.tgz#e2aaad3a3a8fca34c28f6eee135b156ed2587ff0" - integrity sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA== - dependencies: - call-bind "^1.0.0" - -is-buffer@^1.1.5, is-buffer@~1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - -is-callable@^1.1.4, is-callable@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" - integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== - -is-ci@^1.0.9: - version "1.2.1" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c" - integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg== - dependencies: - ci-info "^1.5.0" - -is-color-stop@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" - integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U= - dependencies: - css-color-names "^0.0.4" - hex-color-regex "^1.1.0" - hsl-regex "^1.0.0" - hsla-regex "^1.0.0" - rgb-regex "^1.0.1" - rgba-regex "^1.0.0" - -is-core-module@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.3.0.tgz#d341652e3408bca69c4671b79a0954a3d349f887" - integrity sha512-xSphU2KG9867tsYdLD4RWQ1VqdFl4HTO9Thf3I/3dLEfr0dbPTWKsuCKrgqMljg4nPE+Gq0VCnzT3gr0CyBmsw== - dependencies: - has "^1.0.3" - -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-date-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" - integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== - -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-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= - -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: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-generator-function@^1.0.7: - version "1.0.8" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.8.tgz#dfb5c2b120e02b0a8d9d2c6806cd5621aa922f7b" - integrity sha512-2Omr/twNtufVZFr1GhxjOMFPAj2sjc/dKaIqBhvo4qciXfJmITGH6ZGd8eZYNHza8t1y0e01AuqRhJwfWp26WQ== - -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, 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-negated-glob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2" - integrity sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI= - -is-negative-zero@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" - integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== - -is-number-object@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" - integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== - -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-number@^4.0.0: - version "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-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" - integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== - -is-plain-obj@^1.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - -is-plain-obj@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - -is-plain-object@^2.0.1, 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-plain-object@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" - integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== - -is-promise@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" - integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== - -is-regex@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.2.tgz#81c8ebde4db142f2cf1c53fc86d6a45788266251" - integrity sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg== - dependencies: - call-bind "^1.0.2" - has-symbols "^1.0.1" - -is-relative@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d" - integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA== - dependencies: - is-unc-path "^1.0.0" - -is-resolvable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== - -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - -is-string@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" - integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" - integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== - dependencies: - has-symbols "^1.0.1" - -is-typed-array@^1.1.3: - version "1.1.5" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.5.tgz#f32e6e096455e329eb7b423862456aa213f0eb4e" - integrity sha512-S+GRDgJlR3PyEbsX/Fobd9cqpZBuvUS+8asRqYDMLCb2qMzt1oz5m5oxQCxOgUDxiWsOVNi4yaF+/uvdlHlYug== - dependencies: - available-typed-arrays "^1.0.2" - call-bind "^1.0.2" - es-abstract "^1.18.0-next.2" - foreach "^2.0.5" - has-symbols "^1.0.1" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -is-unc-path@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d" - integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ== - dependencies: - unc-path-regex "^0.1.2" - -is-utf8@^0.2.0, is-utf8@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= - -is-valid-glob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-1.0.0.tgz#29bf3eff701be2d4d315dbacc39bc39fe8f601aa" - integrity sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao= - -is-windows@^1.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== - -is-wsl@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= - -is@^3.1.0, is@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/is/-/is-3.3.0.tgz#61cff6dd3c4193db94a3d62582072b44e5645d79" - integrity sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg== - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - -isarray@1.0.0, 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= - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -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= - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -istanbul-lib-coverage@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" - integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== - -istanbul-lib-instrument@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" - integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== - dependencies: - "@babel/core" "^7.7.5" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.0.0" - semver "^6.3.0" - -istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" - integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" - supports-color "^7.1.0" - -istanbul-lib-source-maps@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" - integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^3.0.0" - source-map "^0.6.1" - -istanbul-reports@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" - integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - -istextorbinary@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-1.0.2.tgz#ace19354d1a9a0173efeb1084ce0f87b0ad7decf" - integrity sha1-rOGTVNGpoBc+/rEITOD4ewrX3s8= - dependencies: - binaryextensions "~1.0.0" - textextensions "~1.0.0" - -jpeg-js@^0.4.2: - version "0.4.3" - resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.3.tgz#6158e09f1983ad773813704be80680550eff977b" - integrity sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q== - -js-beautify@^1.13.5: - version "1.13.13" - resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.13.13.tgz#756907d1728f329f2b84c42efd56ad17514620bf" - integrity sha512-oH+nc0U5mOAqX8M5JO1J0Pw/7Q35sAdOsM5W3i87pir9Ntx6P/5Gx1xLNoK+MGyvHk4rqqRCE4Oq58H6xl2W7A== - dependencies: - config-chain "^1.1.12" - editorconfig "^0.15.3" - glob "^7.1.3" - mkdirp "^1.0.4" - nopt "^5.0.0" - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.0.0.tgz#f426bc0ff4b4051926cd588c71113183409a121f" - integrity sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q== - dependencies: - argparse "^2.0.1" - -js-yaml@^3.13.0, js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -jschardet@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.3.0.tgz#06e2636e16c8ada36feebbdc08aa34e6a9b3ff75" - integrity sha512-6I6xT7XN/7sBB7q8ObzKbmv5vN+blzLcboDE1BNEsEfmRXJValMxO6OIRT69ylPBRemS3rw6US+CMCar0OBc9g== - -jsdoctypeparser@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsdoctypeparser/-/jsdoctypeparser-6.1.0.tgz#acfb936c26300d98f1405cb03e20b06748e512a8" - integrity sha512-UCQBZ3xCUBv/PLfwKAJhp6jmGOSLFNKzrotXGNgbKhWvz27wPsCsVeP7gIcHPElQw2agBmynAitXqhxR58XAmA== - -jsdom-no-contextify@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/jsdom-no-contextify/-/jsdom-no-contextify-3.1.0.tgz#0d8beaf610c2ff23894f54dfa7f89dd22fd0f7ab" - integrity sha1-DYvq9hDC/yOJT1Tfp/id0i/Q96s= - dependencies: - browser-request ">= 0.3.1 < 0.4.0" - cssom ">= 0.3.0 < 0.4.0" - cssstyle ">= 0.2.21 < 0.3.0" - htmlparser2 ">= 3.7.3 < 4.0.0" - nwmatcher ">= 1.3.4 < 2.0.0" - parse5 ">= 1.3.1 < 2.0.0" - request ">= 2.44.0 < 3.0.0" - xml-name-validator "^1.0.0" - xmlhttprequest ">= 1.6.0 < 2.0.0" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json-buffer@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" - integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= - -json-edm-parser@0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/json-edm-parser/-/json-edm-parser-0.1.2.tgz#1e60b0fef1bc0af67bc0d146dfdde5486cd615b4" - integrity sha1-HmCw/vG8CvZ7wNFG393lSGzWFbQ= - dependencies: - jsonparse "~1.2.0" - -json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - -json5@^2.1.2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - -jsonparse@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.2.0.tgz#5c0c5685107160e72fe7489bddea0b44c2bc67bd" - integrity sha1-XAxWhRBxYOcv50ib3eoLRMK8Z70= - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -just-debounce@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.1.0.tgz#2f81a3ad4121a76bc7cb45dbf704c0d76a8e5ddf" - integrity sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ== - -keyv@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" - integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== - dependencies: - json-buffer "3.0.0" - -kind-of@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44" - integrity sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ= - -kind-of@^3.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, kind-of@^5.0.2: - 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.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - -last-run@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/last-run/-/last-run-1.1.1.tgz#45b96942c17b1c79c772198259ba943bebf8ca5b" - integrity sha1-RblpQsF7HHnHchmCWbqUO+v4yls= - dependencies: - default-resolution "^2.0.0" - es6-weak-map "^2.0.1" - -lazy.js@^0.4.2: - version "0.4.3" - resolved "https://registry.yarnpkg.com/lazy.js/-/lazy.js-0.4.3.tgz#87f67a07ad36555121e4fff1520df31be66786d8" - integrity sha1-h/Z6B602VVEh5P/xUg3zG+Znhtg= - -lazystream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" - integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ= - dependencies: - readable-stream "^2.0.5" - -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= - dependencies: - invert-kv "^1.0.0" - -lead@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lead/-/lead-1.0.0.tgz#6f14f99a37be3a9dd784f5495690e5903466ee42" - integrity sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI= - dependencies: - flush-write-stream "^1.0.2" - -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -liftoff@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-3.1.0.tgz#c9ba6081f908670607ee79062d700df062c52ed3" - integrity sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog== - dependencies: - extend "^3.0.0" - findup-sync "^3.0.0" - fined "^1.0.1" - flagged-respawn "^1.0.0" - is-plain-object "^2.0.4" - object.map "^1.0.0" - rechoir "^0.6.2" - resolve "^1.1.7" - -load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - -load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - -loader-runner@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" - integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== - -loader-utils@^1.0.2, loader-utils@^1.2.3, loader-utils@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" - integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^1.0.1" - -loader-utils@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" - integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^2.1.2" - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= - -lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= - -lodash.clone@^4.3.2: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6" - integrity sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y= - -lodash.memoize@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= - -lodash.some@^4.2.2: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" - integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0= - -lodash.template@^4.4.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" - integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.templatesettings "^4.0.0" - -lodash.templatesettings@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" - integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== - dependencies: - lodash._reinterpolate "^3.0.0" - -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= - -lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log-symbols@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" - integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA== - dependencies: - chalk "^4.0.0" - -lolex@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.3.2.tgz#7c3da62ffcb30f0f5a80a2566ca24e45d8a01f31" - integrity sha1-fD2mL/yzDw9agKJWbKJORdigHzE= - -lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== - -lowercase-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" - integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== - -lru-cache@^4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -lru-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" - integrity sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM= - dependencies: - es5-ext "~0.10.2" - -make-dir@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - -make-dir@^3.0.0, make-dir@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -make-iterator@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/make-iterator/-/make-iterator-1.0.1.tgz#29b33f312aa8f547c4a5e490f56afcec99133ad6" - integrity sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw== - dependencies: - kind-of "^6.0.2" - -map-cache@^0.2.0, 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-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.0.7.tgz#8a1f07896d82b10926bd3744a2420009f88974a8" - integrity sha1-ih8HiW2CsQkmvTdEokIACfiJdKg= - -map-stream@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" - integrity sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ= - -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" - -matchdep@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/matchdep/-/matchdep-2.0.0.tgz#c6f34834a0d8dbc3b37c27ee8bbcb27c7775582e" - integrity sha1-xvNINKDY28OzfCfui7yyfHd1WC4= - dependencies: - findup-sync "^2.0.0" - micromatch "^3.0.4" - resolve "^1.4.0" - stack-trace "0.0.10" - -matcher@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca" - integrity sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng== - dependencies: - escape-string-regexp "^4.0.0" - -md5.js@1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" - integrity sha1-6b296UogpawYsENA/Fdk1bCdkB0= - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -md5@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" - integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== - dependencies: - charenc "0.0.2" - crypt "0.0.2" - is-buffer "~1.1.6" - -mdn-data@2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" - integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== - -mdn-data@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" - integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== - -memoizee@0.4.X: - version "0.4.15" - resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.15.tgz#e6f3d2da863f318d02225391829a6c5956555b72" - integrity sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ== - dependencies: - d "^1.0.1" - es5-ext "^0.10.53" - es6-weak-map "^2.0.3" - event-emitter "^0.3.5" - is-promise "^2.2.2" - lru-queue "^0.1.0" - next-tick "^1.1.0" - timers-ext "^0.1.7" - -memory-fs@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" - integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - -memory-fs@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" - integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - -memorystream@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" - integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI= - -merge-options@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-options/-/merge-options-1.0.1.tgz#2a64b24457becd4e4dc608283247e94ce589aa32" - integrity sha512-iuPV41VWKWBIOpBsjoxjDZw8/GbSfZ2mk7N1453bwMrfzdrIk7EzBd+8UVR6rkw67th7xnk9Dytl3J+lHPdxvg== - dependencies: - is-plain-obj "^1.1" - -merge2@^1.3.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: - 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" - -micromatch@^4.0.0, micromatch@^4.0.2: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== - dependencies: - braces "^3.0.1" - picomatch "^2.2.3" - -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -mime-db@1.47.0: - version "1.47.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.47.0.tgz#8cb313e59965d3c05cfbf898915a267af46a335c" - integrity sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw== - -mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.30" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.30.tgz#6e7be8b4c479825f85ed6326695db73f9305d62d" - integrity sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg== - dependencies: - mime-db "1.47.0" - -mime@^1.3.4, mime@^1.4.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -mime@^2.4.6: - version "2.5.2" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" - integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg== - -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -mimic-response@^1.0.0, mimic-response@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" - integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - -"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.3, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -minipass-collect@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" - integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== - dependencies: - minipass "^3.0.0" - -minipass-flush@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" - integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== - dependencies: - minipass "^3.0.0" - -minipass-pipeline@^1.2.2: - version "1.2.4" - resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" - integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== - dependencies: - minipass "^3.0.0" - -minipass@^3.0.0, minipass@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" - integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg== - dependencies: - yallist "^4.0.0" - -minizlib@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" - integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== - dependencies: - minipass "^3.0.0" - yallist "^4.0.0" - -mississippi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" - integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== - dependencies: - concat-stream "^1.5.0" - duplexify "^3.4.2" - end-of-stream "^1.1.0" - flush-write-stream "^1.0.0" - from2 "^2.1.0" - parallel-transform "^1.1.0" - pump "^3.0.0" - pumpify "^1.3.3" - stream-each "^1.1.0" - through2 "^2.0.0" - -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 0", mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@~0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - -mkdirp@^1.0.3, mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -mocha-junit-reporter@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-2.0.0.tgz#3bf990fce7a42c0d2b718f188553a25d9f24b9a2" - integrity sha512-20HoWh2HEfhqmigfXOKUhZQyX23JImskc37ZOhIjBKoBEsb+4cAFRJpAVhFpnvsztLklW/gFVzsrobjLwmX4lA== - dependencies: - debug "^2.2.0" - md5 "^2.1.0" - mkdirp "~0.5.1" - strip-ansi "^4.0.0" - xml "^1.0.0" - -mocha-multi-reporters@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/mocha-multi-reporters/-/mocha-multi-reporters-1.5.1.tgz#c73486bed5519e1d59c9ce39ac7a9792600e5676" - integrity sha512-Yb4QJOaGLIcmB0VY7Wif5AjvLMUFAdV57D2TWEva1Y0kU/3LjKpeRVmlMIfuO1SVbauve459kgtIizADqxMWPg== - dependencies: - debug "^4.1.1" - lodash "^4.17.15" - -mocha@^8.2.1, mocha@^8.3.0: - version "8.3.2" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.3.2.tgz#53406f195fa86fbdebe71f8b1c6fb23221d69fcc" - integrity sha512-UdmISwr/5w+uXLPKspgoV7/RXZwKRTiTjJ2/AC5ZiEztIoOYdfKb19+9jNmEInzx5pBsCyJQzarAxqIGBNYJhg== - dependencies: - "@ungap/promise-all-settled" "1.1.2" - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.5.1" - debug "4.3.1" - diff "5.0.0" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "7.1.6" - growl "1.10.5" - he "1.2.0" - js-yaml "4.0.0" - log-symbols "4.0.0" - minimatch "3.0.4" - ms "2.1.3" - nanoid "3.1.20" - serialize-javascript "5.0.1" - strip-json-comments "3.1.1" - supports-color "8.1.1" - which "2.0.2" - wide-align "1.1.3" - workerpool "6.1.0" - yargs "16.2.0" - yargs-parser "20.2.4" - yargs-unparser "2.0.0" - -move-concurrently@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" - integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= - dependencies: - aproba "^1.1.1" - copy-concurrently "^1.0.0" - fs-write-stream-atomic "^1.0.8" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.3" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3, ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -multimatch@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b" - integrity sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis= - dependencies: - array-differ "^1.0.0" - array-union "^1.0.1" - arrify "^1.0.0" - minimatch "^3.0.0" - -mute-stdout@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mute-stdout/-/mute-stdout-1.0.1.tgz#acb0300eb4de23a7ddeec014e3e96044b3472331" - integrity sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg== - -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= - -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - -nan@^2.12.1, nan@^2.13.2, nan@^2.14.0: - version "2.14.2" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" - integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== - -nanoid@3.1.20: - version "3.1.20" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788" - integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw== - -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-is-elevated@0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/native-is-elevated/-/native-is-elevated-0.4.3.tgz#f1071c4a821acc71d43f36ff8051d3816d832e1c" - integrity sha512-bHS3sCoh+raqFGIxmL/plER3eBQ+IEBy4RH/4uahhToZneTvqNKQrL0PgOTtnpL55XjBd3dy0pNtZMkCk0J48g== - -native-watchdog@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/native-watchdog/-/native-watchdog-1.3.0.tgz#88cee94c9dc766b85c8506eda14c8bd8c9618e27" - integrity sha512-WOjGRNGkYZ5MXsntcvCYrKtSYMaewlbCFplbcUVo9bE80LPVt8TAVFHYWB8+a6fWCGYheq21+Wtt6CJrUaCJhw== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -neo-async@^2.5.0, neo-async@^2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - -netmask@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" - integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== - -next-tick@1, next-tick@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" - integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== - -next-tick@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" - integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -node-addon-api@*, node-addon-api@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.1.0.tgz#98b21931557466c6729e51cb77cd39c965f42239" - integrity sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw== - -node-fetch@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== - -node-libs-browser@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" - integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== - dependencies: - assert "^1.1.1" - browserify-zlib "^0.2.0" - buffer "^4.3.0" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - crypto-browserify "^3.11.0" - domain-browser "^1.1.1" - events "^3.0.0" - https-browserify "^1.0.0" - os-browserify "^0.3.0" - path-browserify "0.0.1" - process "^0.11.10" - punycode "^1.2.4" - querystring-es3 "^0.2.0" - readable-stream "^2.3.3" - stream-browserify "^2.0.1" - stream-http "^2.7.2" - string_decoder "^1.0.0" - timers-browserify "^2.0.4" - tty-browserify "0.0.0" - url "^0.11.0" - util "^0.11.0" - vm-browserify "^1.0.1" - -node-pty@0.10.1: - version "0.10.1" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.1.tgz#cd05d03a2710315ec40221232ec04186f6ac2c6d" - integrity sha512-JTdtUS0Im/yRsWJSx7yiW9rtpfmxqxolrtnyKwPLI+6XqTAPW/O2MjS8FYL4I5TsMbH2lVgDb2VMjp+9LoQGNg== - dependencies: - nan "^2.14.0" - -node-releases@^1.1.71: - version "1.1.71" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb" - integrity sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg== - -node.extend@~1.1.2: - version "1.1.8" - resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-1.1.8.tgz#0aab3e63789f4e6d68b42bc00073ad1881243cf0" - integrity sha512-L/dvEBwyg3UowwqOUTyDsGBU6kjBQOpOhshio9V3i3BMPv5YUb9+mWNN8MK0IbWqT0AqaTSONZf0aTuMMahWgA== - dependencies: - has "^1.0.3" - is "^3.2.1" - -nopt@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" - integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== - dependencies: - abbrev "1" - -normalize-package-data@^2.3.2: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-path@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379" - integrity sha1-MtDkcvkf80VwHBWoMRAY07CpA3k= - -normalize-path@^2.0.1, normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -normalize-url@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" - integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== - -normalize-url@^4.1.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" - integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ== - -now-and-later@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/now-and-later/-/now-and-later-2.0.1.tgz#8e579c8685764a7cc02cb680380e94f43ccb1f7c" - integrity sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ== - dependencies: - once "^1.3.2" - -npm-conf@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" - integrity sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw== - dependencies: - config-chain "^1.1.11" - pify "^3.0.0" - -npm-run-all@^4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" - integrity sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ== - dependencies: - ansi-styles "^3.2.1" - chalk "^2.4.1" - cross-spawn "^6.0.5" - memorystream "^0.3.1" - minimatch "^3.0.4" - pidtree "^0.3.0" - read-pkg "^3.0.0" - shell-quote "^1.6.1" - string.prototype.padend "^3.0.0" - -nsfw@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/nsfw/-/nsfw-2.1.2.tgz#4fa841e7f7122b60b2e1f61187d1b57ad3403428" - integrity sha512-zGPdt32aJ5b1laK9rvgXQmXGAagrx3VkcMt0JePtu6wBfzC1o4xLCM3kq7FxZxUnxyxYhODyBYzpt3H16FhaGA== - dependencies: - node-addon-api "*" - -nth-check@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" - integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== - dependencies: - boolbase "~1.0.0" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - -"nwmatcher@>= 1.3.4 < 2.0.0", nwmatcher@^1.4.4: - version "1.4.4" - resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.4.tgz#2285631f34a95f0d0395cd900c96ed39b58f346e" - integrity sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ== - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - -object-assign@4.X, object-assign@^4.0.1, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -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-inspect@^1.9.0: - version "1.10.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.2.tgz#b6385a3e2b7cae0b5eafcf90cddf85d128767f30" - integrity sha512-gz58rdPpadwztRrPjZE9DZLOABUpTGdcANUgOwBFO1C+HZZhePoP83M65WGDmbpwFYJSWqavbl4SgDn4k8RYTA== - -object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object-keys@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" - integrity sha1-KKaq50KN0sOpLz2V8hM13SBOAzY= - -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.assign@^4.0.4, object.assign@^4.1.0, object.assign@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - -object.defaults@^1.0.0, object.defaults@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/object.defaults/-/object.defaults-1.1.0.tgz#3a7f868334b407dea06da16d88d5cd29e435fecf" - integrity sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8= - dependencies: - array-each "^1.0.1" - array-slice "^1.0.0" - for-own "^1.0.0" - isobject "^3.0.0" - -object.entries-ponyfill@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object.entries-ponyfill/-/object.entries-ponyfill-1.0.1.tgz#29abdf77cbfbd26566dd1aa24e9d88f65433d256" - integrity sha1-Kavfd8v70mVm3RqiTp2I9lQz0lY= - -object.getownpropertydescriptors@^2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz#1bd63aeacf0d5d2d2f31b5e393b03a7c601a23f7" - integrity sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - -object.map@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object.map/-/object.map-1.0.1.tgz#cf83e59dc8fcc0ad5f4250e1f78b3b81bd801d37" - integrity sha1-z4Plncj8wK1fQlDh94s7gb2AHTc= - dependencies: - for-own "^1.0.0" - make-iterator "^1.0.0" - -object.pick@^1.2.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" - -object.reduce@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object.reduce/-/object.reduce-1.0.1.tgz#6fe348f2ac7fa0f95ca621226599096825bb03ad" - integrity sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60= - dependencies: - for-own "^1.0.0" - make-iterator "^1.0.0" - -object.values@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.3.tgz#eaa8b1e17589f02f698db093f7c62ee1699742ee" - integrity sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - has "^1.0.3" - -once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= - dependencies: - mimic-fn "^1.0.0" - -onetime@^5.1.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -opn@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/opn/-/opn-6.0.0.tgz#3c5b0db676d5f97da1233d1ed42d182bc5a27d2d" - integrity sha512-I9PKfIZC+e4RXZ/qr1RhgyCnGgYX0UEIlXgWnCOVACIvFgaC9rz6Won7xbdhoHrd8IIhV7YEpHjreNUNkqCGkQ== - dependencies: - is-wsl "^1.1.0" - -optimist@0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.3.5.tgz#03654b52417030312d109f39b159825b60309304" - integrity sha1-A2VLUkFwMDEtEJ85sVmCW2AwkwQ= - dependencies: - wordwrap "~0.0.2" - -optionator@^0.8.1, optionator@^0.8.2, optionator@^0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - -ordered-read-streams@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz#77c0cb37c41525d64166d990ffad7ec6a0e1363e" - integrity sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4= - dependencies: - readable-stream "^2.0.1" - -os-browserify@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= - -os-locale@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" - integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= - dependencies: - lcid "^1.0.0" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -p-all@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-all/-/p-all-1.0.0.tgz#93bdf53a55a23821fdfa98b4174a99bf7f31df8d" - integrity sha1-k731OlWiOCH9+pi0F0qZv38x340= - dependencies: - p-map "^1.0.0" - -p-cancelable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" - integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== - -p-limit@^2.0.0, p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-limit@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -p-map@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" - integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA== - -p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== - dependencies: - aggregate-error "^3.0.0" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -pac-proxy-agent@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-4.1.0.tgz#66883eeabadc915fc5e95457324cb0f0ac78defb" - integrity sha512-ejNgYm2HTXSIYX9eFlkvqFp8hyJ374uDf0Zq5YUAifiSh1D6fo+iBivQZirGvVv8dCYUsLhmLBRhlAYvBKI5+Q== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - get-uri "3" - http-proxy-agent "^4.0.1" - https-proxy-agent "5" - pac-resolver "^4.1.0" - raw-body "^2.2.0" - socks-proxy-agent "5" - -pac-resolver@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-4.2.0.tgz#b82bcb9992d48166920bc83c7542abb454bd9bdd" - integrity sha512-rPACZdUyuxT5Io/gFKUeeZFfE5T7ve7cAkE5TUZRRfuKP0u5Hocwe48X7ZEm6mYB+bTB0Qf+xlVlA/RM/i6RCQ== - dependencies: - degenerator "^2.2.0" - ip "^1.1.5" - netmask "^2.0.1" - -pako@~1.0.5: - version "1.0.11" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" - integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== - -parallel-transform@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" - integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== - dependencies: - cyclist "^1.0.1" - inherits "^2.0.3" - readable-stream "^2.1.5" - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-asn1@^5.0.0, parse-asn1@^5.1.5: - version "5.1.6" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" - integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== - dependencies: - asn1.js "^5.2.0" - browserify-aes "^1.0.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - -parse-filepath@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891" - integrity sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE= - dependencies: - is-absolute "^1.0.0" - map-cache "^0.2.0" - path-root "^0.1.1" - -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= - dependencies: - error-ex "^1.2.0" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -parse-node-version@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" - integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== - -parse-passwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" - integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= - -"parse5@>= 1.3.1 < 2.0.0": - version "1.5.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94" - integrity sha1-m387DeMr543CQBsXVzzK8Pb1nZQ= - -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-browserify@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" - integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== - -path-browserify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" - integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== - -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-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= - dependencies: - pinkie-promise "^2.0.0" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -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= - -path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= - -path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== - -path-root-regex@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" - integrity sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0= - -path-root@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7" - integrity sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc= - dependencies: - path-root-regex "^0.1.0" - -path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= - dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -pause-stream@0.0.11, pause-stream@^0.0.11: - version "0.0.11" - resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" - integrity sha1-/lo0sMvOErWqaitAPuLnO2AvFEU= - dependencies: - through "~2.3" - -pbkdf2@^3.0.3: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" - integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d" - integrity sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg== - -pidtree@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" - integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== - -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - -pkg-dir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" - integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== - dependencies: - find-up "^3.0.0" - -pkg-dir@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -playwright@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.8.0.tgz#8eca2250967ee892b9fdfec44e2358455ab0f8e3" - integrity sha512-urMJDLX92KawbkWKrt3chVVBPQsuuNwlS5St7I5YQENXAEItoyUqX7FjiYaoPgXifKqe1+BKC+7pBAq1QUkgSw== - dependencies: - commander "^6.1.0" - debug "^4.1.1" - extract-zip "^2.0.1" - https-proxy-agent "^5.0.0" - jpeg-js "^0.4.2" - mime "^2.4.6" - pngjs "^5.0.0" - progress "^2.0.3" - proper-lockfile "^4.1.1" - proxy-from-env "^1.1.0" - rimraf "^3.0.2" - ws "^7.3.1" - -plist@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.2.tgz#74bbf011124b90421c22d15779cee60060ba95bc" - integrity sha512-MSrkwZBdQ6YapHy87/8hDU8MnIcyxBKjeF+McXnr5A9MtffPewTs7G3hlpodT5TacyfIyFTaJEhh3GGcmasTgQ== - dependencies: - base64-js "^1.5.1" - xmlbuilder "^9.0.7" - xmldom "^0.5.0" - -plugin-error@0.1.2, plugin-error@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace" - integrity sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4= - dependencies: - ansi-cyan "^0.1.1" - ansi-red "^0.1.1" - arr-diff "^1.0.1" - arr-union "^2.0.1" - extend-shallow "^1.1.2" - -plugin-error@^1.0.0, plugin-error@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-1.0.1.tgz#77016bd8919d0ac377fdcdd0322328953ca5781c" - integrity sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA== - dependencies: - ansi-colors "^1.0.1" - arr-diff "^4.0.0" - arr-union "^3.1.0" - extend-shallow "^3.0.2" - -pngjs@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" - integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw== - -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= - -postcss-calc@^7.0.1: - version "7.0.5" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-7.0.5.tgz#f8a6e99f12e619c2ebc23cf6c486fdc15860933e" - integrity sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg== - dependencies: - postcss "^7.0.27" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.0.2" - -postcss-colormin@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.3.tgz#ae060bce93ed794ac71264f08132d550956bd381" - integrity sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw== - dependencies: - browserslist "^4.0.0" - color "^3.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-convert-values@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz#ca3813ed4da0f812f9d43703584e449ebe189a7f" - integrity sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-discard-comments@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz#1fbabd2c246bff6aaad7997b2b0918f4d7af4033" - integrity sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg== - dependencies: - postcss "^7.0.0" - -postcss-discard-duplicates@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz#3fe133cd3c82282e550fc9b239176a9207b784eb" - integrity sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ== - dependencies: - postcss "^7.0.0" - -postcss-discard-empty@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz#c8c951e9f73ed9428019458444a02ad90bb9f765" - integrity sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w== - dependencies: - postcss "^7.0.0" - -postcss-discard-overridden@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz#652aef8a96726f029f5e3e00146ee7a4e755ff57" - integrity sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg== - dependencies: - postcss "^7.0.0" - -postcss-load-config@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.2.tgz#c5ea504f2c4aef33c7359a34de3573772ad7502a" - integrity sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw== - dependencies: - cosmiconfig "^5.0.0" - import-cwd "^2.0.0" - -postcss-merge-longhand@^4.0.11: - version "4.0.11" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz#62f49a13e4a0ee04e7b98f42bb16062ca2549e24" - integrity sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw== - dependencies: - css-color-names "0.0.4" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - stylehacks "^4.0.0" - -postcss-merge-rules@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz#362bea4ff5a1f98e4075a713c6cb25aefef9a650" - integrity sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ== - dependencies: - browserslist "^4.0.0" - caniuse-api "^3.0.0" - cssnano-util-same-parent "^4.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - vendors "^1.0.0" - -postcss-minify-font-values@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz#cd4c344cce474343fac5d82206ab2cbcb8afd5a6" - integrity sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-minify-gradients@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz#93b29c2ff5099c535eecda56c4aa6e665a663471" - integrity sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q== - dependencies: - cssnano-util-get-arguments "^4.0.0" - is-color-stop "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-minify-params@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz#6b9cef030c11e35261f95f618c90036d680db874" - integrity sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg== - dependencies: - alphanum-sort "^1.0.0" - browserslist "^4.0.0" - cssnano-util-get-arguments "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - uniqs "^2.0.0" - -postcss-minify-selectors@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz#e2e5eb40bfee500d0cd9243500f5f8ea4262fbd8" - integrity sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g== - dependencies: - alphanum-sort "^1.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - -postcss-modules-extract-imports@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" - integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ== - dependencies: - postcss "^7.0.5" - -postcss-modules-local-by-default@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz#bb14e0cc78279d504dbdcbfd7e0ca28993ffbbb0" - integrity sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw== - dependencies: - icss-utils "^4.1.1" - postcss "^7.0.32" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.1.0" - -postcss-modules-scope@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz#385cae013cc7743f5a7d7602d1073a89eaae62ee" - integrity sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ== - dependencies: - postcss "^7.0.6" - postcss-selector-parser "^6.0.0" - -postcss-modules-values@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10" - integrity sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg== - dependencies: - icss-utils "^4.0.0" - postcss "^7.0.6" - -postcss-normalize-charset@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4" - integrity sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g== - dependencies: - postcss "^7.0.0" - -postcss-normalize-display-values@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz#0dbe04a4ce9063d4667ed2be476bb830c825935a" - integrity sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ== - dependencies: - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-positions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz#05f757f84f260437378368a91f8932d4b102917f" - integrity sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA== - dependencies: - cssnano-util-get-arguments "^4.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-repeat-style@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz#c4ebbc289f3991a028d44751cbdd11918b17910c" - integrity sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q== - dependencies: - cssnano-util-get-arguments "^4.0.0" - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-string@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz#cd44c40ab07a0c7a36dc5e99aace1eca4ec2690c" - integrity sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA== - dependencies: - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-timing-functions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz#8e009ca2a3949cdaf8ad23e6b6ab99cb5e7d28d9" - integrity sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A== - dependencies: - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-unicode@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz#841bd48fdcf3019ad4baa7493a3d363b52ae1cfb" - integrity sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg== - dependencies: - browserslist "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-url@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz#10e437f86bc7c7e58f7b9652ed878daaa95faae1" - integrity sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA== - dependencies: - is-absolute-url "^2.0.0" - normalize-url "^3.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-whitespace@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz#bf1d4070fe4fcea87d1348e825d8cc0c5faa7d82" - integrity sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-ordered-values@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz#0cf75c820ec7d5c4d280189559e0b571ebac0eee" - integrity sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw== - dependencies: - cssnano-util-get-arguments "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-reduce-initial@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df" - integrity sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA== - dependencies: - browserslist "^4.0.0" - caniuse-api "^3.0.0" - has "^1.0.0" - postcss "^7.0.0" - -postcss-reduce-transforms@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz#17efa405eacc6e07be3414a5ca2d1074681d4e29" - integrity sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg== - dependencies: - cssnano-util-get-match "^4.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-selector-parser@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz#b310f5c4c0fdaf76f94902bbaa30db6aa84f5270" - integrity sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA== - dependencies: - dot-prop "^5.2.0" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: - version "6.0.5" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.5.tgz#042d74e137db83e6f294712096cb413f5aa612c4" - integrity sha512-aFYPoYmXbZ1V6HZaSvat08M97A8HqO6Pjz+PiNpw/DhuRrC72XWAdp3hL6wusDCN31sSmcZyMGa2hZEuX+Xfhg== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - -postcss-svgo@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.3.tgz#343a2cdbac9505d416243d496f724f38894c941e" - integrity sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - svgo "^1.0.0" - -postcss-unique-selectors@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz#9446911f3289bfd64c6d680f073c03b1f9ee4bac" - integrity sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg== - dependencies: - alphanum-sort "^1.0.0" - postcss "^7.0.0" - uniqs "^2.0.0" - -postcss-value-parser@^3.0.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" - integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== - -postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" - integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== - -"postcss@5 - 7", postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.27, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: - version "7.0.35" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.35.tgz#d2be00b998f7f211d8a276974079f2e92b970e24" - integrity sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg== - dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - -prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= - -pretty-hrtime@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" - integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= - -process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -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= - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - -progress@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" - integrity sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74= - -progress@^2.0.0, progress@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -promise-inflight@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" - integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= - -proper-lockfile@^4.1.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" - integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA== - dependencies: - graceful-fs "^4.2.4" - retry "^0.12.0" - signal-exit "^3.0.2" - -proto-list@~1.2.1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" - integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= - -proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-4.0.1.tgz#326c3250776c7044cd19655ccbfadf2e065a045c" - integrity sha512-ODnQnW2jc/FUVwHHuaZEfN5otg/fMbvMxz9nMSUQfJ9JU7q2SZvSULSsjLloVgJOiv9yhc8GlNMKc4GkFmcVEA== - dependencies: - agent-base "^6.0.0" - debug "4" - http-proxy-agent "^4.0.0" - https-proxy-agent "^5.0.0" - lru-cache "^5.1.1" - pac-proxy-agent "^4.1.0" - proxy-from-env "^1.0.0" - socks-proxy-agent "^5.0.0" - -proxy-from-env@^1.0.0, proxy-from-env@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== - -prr@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" - integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= - -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - -psl@^1.1.28: - version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== - -public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - -pump@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" - integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pump@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" - integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pumpify@^1.3.3, pumpify@^1.3.5: - version "1.5.1" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" - integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== - dependencies: - duplexify "^3.6.0" - inherits "^2.0.3" - pump "^2.0.0" - -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - -punycode@^1.2.4: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -q@^1.1.2: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= - -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== - -querystring-es3@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= - -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -queue@3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/queue/-/queue-3.0.6.tgz#66c0ffd0a1d9d28045adebda966a2d3946ab9f13" - integrity sha1-ZsD/0KHZ0oBFrevalmotOUarnxM= - dependencies: - inherits "~2.0.0" - -queue@^3.0.10, queue@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/queue/-/queue-3.1.0.tgz#6c49d01f009e2256788789f2bffac6b8b9990585" - integrity sha1-bEnQHwCeIlZ4h4nyv/rGuLmZBYU= - dependencies: - inherits "~2.0.0" - -queue@^4.2.1: - version "4.5.1" - resolved "https://registry.yarnpkg.com/queue/-/queue-4.5.1.tgz#6e4290a2d7e99dc75b34494431633fe5437b0dac" - integrity sha512-AMD7w5hRXcFSb8s9u38acBZ+309u6GsiibP4/0YacJeaurRshogB7v/ZcVPxP5gD5+zIw6ixRHdutiYUJfwKHw== - dependencies: - inherits "~2.0.0" - -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - -raw-body@^2.2.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.1.tgz#30ac82f98bb5ae8c152e67149dac8d55153b168c" - integrity sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA== - dependencies: - bytes "3.1.0" - http-errors "1.7.3" - iconv-lite "0.4.24" - unpipe "1.0.0" - -rcedit@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/rcedit/-/rcedit-0.3.0.tgz#cb5eee185e546f9eda597c248c9906186fa96bce" - integrity sha1-y17uGF5Ub57aWXwkjJkGGG+pa84= - -rcedit@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/rcedit/-/rcedit-1.1.2.tgz#7a28edf981953f75b5f3e5d4cbc1f9ffa0abbc78" - integrity sha512-z2ypB4gbINhI6wVe0JJMmdpmOpmNc4g90sE6/6JSuch5kYnjfz9CxvVPqqhShgR6GIkmtW3W2UlfiXhWljA0Fw== - -read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= - dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" - -read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - -read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@1.1.x: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -"readable-stream@2 || 3", readable-stream@3, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readable-stream@~1.0.17: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@~2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" - integrity sha1-j5A0HmilPMySh4jaz80Rs265t44= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - 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" - -readdirp@~3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" - integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== - dependencies: - picomatch "^2.2.1" - -rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= - dependencies: - resolve "^1.1.6" - -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" - -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - -regexpp@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" - integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== - -regextras@^0.7.0: - version "0.7.1" - resolved "https://registry.yarnpkg.com/regextras/-/regextras-0.7.1.tgz#be95719d5f43f9ef0b9fa07ad89b7c606995a3b2" - integrity sha512-9YXf6xtW+qzQ+hcMQXx95MOvfqXFgsKDZodX3qZB0x2n5Z94ioetIITsBtvJbiOyxa/6s9AtyweBLCdPmPko/w== - -remove-bom-buffer@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53" - integrity sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ== - dependencies: - is-buffer "^1.1.5" - is-utf8 "^0.2.1" - -remove-bom-stream@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz#05f1a593f16e42e1fb90ebf59de8e569525f9523" - integrity sha1-BfGlk/FuQuH7kOv1nejlaVJflSM= - dependencies: - remove-bom-buffer "^3.0.0" - safe-buffer "^5.1.0" - through2 "^2.0.3" - -remove-trailing-separator@^1.0.1, remove-trailing-separator@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - -repeat-element@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" - integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== - -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= - -replace-ext@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" - integrity sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ= - -replace-ext@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a" - integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw== - -replace-homedir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/replace-homedir/-/replace-homedir-1.0.0.tgz#e87f6d513b928dde808260c12be7fec6ff6e798c" - integrity sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw= - dependencies: - homedir-polyfill "^1.0.1" - is-absolute "^1.0.0" - remove-trailing-separator "^1.1.0" - -replacestream@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/replacestream/-/replacestream-4.0.3.tgz#3ee5798092be364b1cdb1484308492cb3dff2f36" - integrity sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA== - dependencies: - escape-string-regexp "^1.0.3" - object-assign "^4.0.1" - readable-stream "^2.0.2" - -"request@>= 2.44.0 < 3.0.0", request@^2.85.0, request@^2.86.0, request@^2.88.0: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - -requestretry@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/requestretry/-/requestretry-4.1.2.tgz#f5975c0c3be9e352e25038c9fed482d5cc51978e" - integrity sha512-N1WAp+8eOy8NfsVBChcSxNCKvPY1azOpliQ4Sby4WDe0HFEhdKywlNZeROMBQ+BI3Jpc0eNOT1KVFGREawtahA== - dependencies: - extend "^3.0.2" - lodash "^4.17.15" - when "^3.7.7" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - -resolve-cwd@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" - integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= - dependencies: - resolve-from "^3.0.0" - -resolve-dir@^1.0.0, resolve-dir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" - integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M= - dependencies: - expand-tilde "^2.0.0" - global-modules "^1.0.0" - -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha1-six699nWiBvItuZTM17rywoYh0g= - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-options@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/resolve-options/-/resolve-options-1.1.0.tgz#32bb9e39c06d67338dc9378c0d6d6074566ad131" - integrity sha1-MrueOcBtZzONyTeMDW1gdFZq0TE= - dependencies: - value-or-function "^3.0.0" - -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= - -resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.4.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" - integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== - dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" - -responselike@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" - integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= - dependencies: - lowercase-keys "^1.0.0" - -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - -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== - -retry@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" - integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rgb-regex@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" - integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= - -rgba-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" - integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= - -rimraf@2, rimraf@^2.4.2, rimraf@^2.5.4, rimraf@^2.6.3: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - -rimraf@2.6.3, rimraf@~2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -roarr@^2.15.3: - version "2.15.4" - resolved "https://registry.yarnpkg.com/roarr/-/roarr-2.15.4.tgz#f5fe795b7b838ccfe35dc608e0282b9eba2e7afd" - integrity sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A== - dependencies: - boolean "^3.0.1" - detect-node "^2.0.4" - globalthis "^1.0.1" - json-stringify-safe "^5.0.1" - semver-compare "^1.0.0" - sprintf-js "^1.1.2" - -run-async@^2.2.0, run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -run-queue@^1.0.0, run-queue@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" - integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= - dependencies: - aproba "^1.1.1" - -rxjs@^6.4.0, rxjs@^6.6.0: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== - dependencies: - tslib "^1.9.0" - -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -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" - -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -samsam@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.1.2.tgz#bec11fdc83a9fda063401210e40176c3024d1567" - integrity sha1-vsEf3IOp/aBjQBIQ5AF2wwJNFWc= - -samsam@~1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.1.3.tgz#9f5087419b4d091f232571e7fa52e90b0f552621" - integrity sha1-n1CHQZtNCR8jJXHn+lLpCw9VJiE= - -sax@0.5.x: - version "0.5.8" - resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1" - integrity sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE= - -sax@>=0.6.0, sax@~1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -schema-utils@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" - integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== - dependencies: - ajv "^6.1.0" - ajv-errors "^1.0.0" - ajv-keywords "^3.1.0" - -schema-utils@^2.5.0, schema-utils@^2.7.0: - version "2.7.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" - integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== - dependencies: - "@types/json-schema" "^7.0.5" - ajv "^6.12.4" - ajv-keywords "^3.5.2" - -schema-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.0.0.tgz#67502f6aa2b66a2d4032b4279a2944978a0913ef" - integrity sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA== - dependencies: - "@types/json-schema" "^7.0.6" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - -semver-compare@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" - integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= - -semver-greatest-satisfied-range@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz#13e8c2658ab9691cb0cd71093240280d36f77a5b" - integrity sha1-E+jCZYq5aRywzXEJMkAoDTb3els= - dependencies: - sver-compat "^1.5.0" - -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@^4.3.4: - version "4.3.6" - resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" - integrity sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto= - -semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.3.2: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - -serialize-error@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18" - integrity sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw== - dependencies: - type-fest "^0.13.1" - -serialize-javascript@5.0.1, serialize-javascript@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" - integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== - dependencies: - randombytes "^2.1.0" - -serialize-javascript@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" - integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== - dependencies: - randombytes "^2.1.0" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -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" - -setimmediate@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= - -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== - -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -shell-quote@^1.6.1: - version "1.7.2" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" - integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== - -shimmer@^1.1.0, shimmer@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" - integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== - -sigmund@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" - integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= - -signal-exit@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== - -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= - dependencies: - is-arrayish "^0.3.1" - -sinon@^1.17.2: - version "1.17.7" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-1.17.7.tgz#4542a4f49ba0c45c05eb2e9dd9d203e2b8efe0bf" - integrity sha1-RUKk9JugxFwF6y6d2dID4rjv4L8= - dependencies: - formatio "1.1.1" - lolex "1.3.2" - samsam "1.1.2" - util ">=0.10.3 <1" - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - -smart-buffer@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.1.0.tgz#91605c25d91652f4661ea69ccf45f1b331ca21ba" - integrity sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw== - -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@5, socks-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.0.tgz#7c0f364e7b1cf4a7a437e71253bed72e9004be60" - integrity sha512-lEpa1zsWCChxiynk+lCycKuC502RxDWLKJZoIhnxrWNjLSDGYRFflHA1/228VkRcnv9TIb8w98derGbpKxJRgA== - dependencies: - agent-base "6" - debug "4" - socks "^2.3.3" - -socks@^2.3.3: - version "2.6.1" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.1.tgz#989e6534a07cf337deb1b1c94aaa44296520d30e" - integrity sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA== - dependencies: - ip "^1.1.5" - smart-buffer "^4.1.0" - -source-list-map@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" - integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== - -source-map-resolve@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" - integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-resolve@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.6.0.tgz#3d9df87e236b53f16d01e58150fc7711138e5ed2" - integrity sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - -source-map-support@^0.3.2: - version "0.3.3" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.3.3.tgz#34900977d5ba3f07c7757ee72e73bb1a9b53754f" - integrity sha1-NJAJd9W6PwfHdX7nLnO7GptTdU8= - dependencies: - source-map "0.1.32" - -source-map-support@~0.5.12: - version "0.5.19" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" - integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-url@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" - integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== - -source-map@0.1.32: - version "0.1.32" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" - integrity sha1-yLbBZ3l7pHQKjqMyUhYv8IWRsmY= - dependencies: - amdefine ">=0.0.4" - -source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@^0.5.0, source-map@^0.5.1, 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= - -source-map@^0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - -sparkles@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.1.tgz#008db65edce6c50eec0c5e228e1945061dd0437c" - integrity sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw== - -spdlog@^0.11.1: - version "0.11.1" - resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.11.1.tgz#29721b31018a5fe6a3ce2531f9d8d43e0bd6b825" - integrity sha512-M+sg9/Tnr0lrfnW2/hqgpoc4Z8Jzq7W8NUn35iiSslj+1uj1pgutI60MCpulDP2QyFzOpC8VsJmYD6Fub7wHoA== - dependencies: - bindings "^1.5.0" - mkdirp "^0.5.1" - nan "^2.14.0" - -spdx-correct@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" - integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" - integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.7" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz#e9c18a410e5ed7e12442a549fbd8afa767038d65" - integrity sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ== - -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== - dependencies: - extend-shallow "^3.0.0" - -split@0.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" - integrity sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8= - dependencies: - through "2" - -split@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" - integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== - dependencies: - through "2" - -sprintf-js@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" - integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -ssri@^6.0.1: - version "6.0.2" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5" - integrity sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q== - dependencies: - figgy-pudding "^3.5.1" - -ssri@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" - integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== - dependencies: - minipass "^3.1.1" - -stable@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" - integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== - -stack-chain@^1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/stack-chain/-/stack-chain-1.3.7.tgz#d192c9ff4ea6a22c94c4dd459171e3f00cea1285" - integrity sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU= - -stack-trace@0.0.10: - version "0.0.10" - resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" - integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= - -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" - -"statuses@>= 1.5.0 < 2": - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - -stream-browserify@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" - integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== - dependencies: - inherits "~2.0.1" - readable-stream "^2.0.2" - -stream-combiner@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.2.2.tgz#aec8cbac177b56b6f4fa479ced8c1912cee52858" - integrity sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg= - dependencies: - duplexer "~0.1.1" - through "~2.3.4" - -stream-combiner@~0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" - integrity sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ= - dependencies: - duplexer "~0.1.1" - -stream-each@^1.1.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" - integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== - dependencies: - end-of-stream "^1.1.0" - stream-shift "^1.0.0" - -stream-exhaust@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/stream-exhaust/-/stream-exhaust-1.0.2.tgz#acdac8da59ef2bc1e17a2c0ccf6c320d120e555d" - integrity sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw== - -stream-http@^2.7.2: - version "2.8.3" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" - integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.1" - readable-stream "^2.3.6" - to-arraybuffer "^1.0.0" - xtend "^4.0.0" - -stream-shift@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" - integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== - -stream-to-array@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/stream-to-array/-/stream-to-array-2.3.0.tgz#bbf6b39f5f43ec30bc71babcb37557acecf34353" - integrity sha1-u/azn19D7DC8cbq8s3VXrOzzQ1M= - dependencies: - any-promise "^1.1.0" - -streamfilter@^1.0.5: - version "1.0.7" - resolved "https://registry.yarnpkg.com/streamfilter/-/streamfilter-1.0.7.tgz#ae3e64522aa5a35c061fd17f67620c7653c643c9" - integrity sha512-Gk6KZM+yNA1JpW0KzlZIhjo3EaBJDkYfXtYSbOwNIQ7Zd6006E6+sCFlW1NDvFG/vnXhKmw6TJJgiEQg/8lXfQ== - dependencies: - readable-stream "^2.0.2" - -streamifier@^0.1.1, streamifier@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/streamifier/-/streamifier-0.1.1.tgz#97e98d8fa4d105d62a2691d1dc07e820db8dfc4f" - integrity sha1-l+mNj6TRBdYqJpHR3AfoINuN/E8= - -string-width@^1.0.1, string-width@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -"string-width@^1.0.2 || 2", string-width@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string-width@^3.0.0, string-width@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" - integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -string.prototype.padend@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.2.tgz#6858ca4f35c5268ebd5e8615e1327d55f59ee311" - integrity sha512-/AQFLdYvePENU3W5rgurfWSMU6n+Ww8n/3cUt7E+vPBB/D7YDG8x+qjoFs4M/alR2bW7Qg6xMjVwWUOvuQ0XpQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - -string.prototype.trimend@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" - integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string.prototype.trimstart@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" - integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string_decoder@^1.0.0, string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== - dependencies: - ansi-regex "^5.0.0" - -strip-bom-string@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" - integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI= - -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= - dependencies: - is-utf8 "^0.2.0" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - -strip-json-comments@3.1.1, strip-json-comments@^3.0.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -strip-json-comments@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -style-loader@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.3.0.tgz#828b4a3b3b7e7aa5847ce7bae9e874512114249e" - integrity sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q== - dependencies: - loader-utils "^2.0.0" - schema-utils "^2.7.0" - -stylehacks@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" - integrity sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g== - dependencies: - browserslist "^4.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - -sudo-prompt@9.2.1: - version "9.2.1" - resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-9.2.1.tgz#77efb84309c9ca489527a4e749f287e6bdd52afd" - integrity sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw== - -sumchecker@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-3.0.1.tgz#6377e996795abb0b6d348e9b3e1dfb24345a8e42" - integrity sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg== - dependencies: - debug "^4.1.0" - -supports-color@8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -supports-color@^5.3.0, supports-color@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -sver-compat@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/sver-compat/-/sver-compat-1.5.0.tgz#3cf87dfeb4d07b4a3f14827bc186b3fd0c645cd8" - integrity sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg= - dependencies: - es6-iterator "^2.0.1" - es6-symbol "^3.1.1" - -svgo@^1.0.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" - integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== - dependencies: - chalk "^2.4.1" - coa "^2.0.2" - css-select "^2.0.0" - css-select-base-adapter "^0.1.1" - css-tree "1.0.0-alpha.37" - csso "^4.0.2" - js-yaml "^3.13.1" - mkdirp "~0.5.1" - object.values "^1.1.0" - sax "~1.2.4" - stable "^0.1.8" - unquote "~1.1.1" - util.promisify "~1.0.0" - -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - -tapable@^1.0.0, tapable@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" - integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== - -tar@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40" - integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA== - dependencies: - block-stream "*" - fstream "^1.0.12" - inherits "2" - -tar@^6.0.2: - version "6.1.0" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.0.tgz#d1724e9bcc04b977b18d5c573b333a2207229a83" - integrity sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA== - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^3.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - -tas-client-umd@0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/tas-client-umd/-/tas-client-umd-0.1.4.tgz#49db4130dd63a8342fabf77185a740fc6a7bea80" - integrity sha512-1hFqJeLD3ryNikniIaO7TItlXhS5vx7bJ+wbPDf8o+IifgwwOWK2ARisdEM9SnJd0ccfcwNPG6Po+RiKn5L2hg== - -temp@^0.8.3: - version "0.8.4" - resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.4.tgz#8c97a33a4770072e0a05f919396c7665a7dd59f2" - integrity sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg== - dependencies: - rimraf "~2.6.2" - -terser-webpack-plugin@^1.4.3: - version "1.4.5" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b" - integrity sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw== - dependencies: - cacache "^12.0.2" - find-cache-dir "^2.1.0" - is-wsl "^1.1.0" - schema-utils "^1.0.0" - serialize-javascript "^4.0.0" - source-map "^0.6.1" - terser "^4.1.2" - webpack-sources "^1.4.0" - worker-farm "^1.7.0" - -terser@^4.1.2: - version "4.8.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" - integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== - dependencies: - commander "^2.20.0" - source-map "~0.6.1" - source-map-support "~0.5.12" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -textextensions@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-1.0.2.tgz#65486393ee1f2bb039a60cbba05b0b68bd9501d2" - integrity sha1-ZUhjk+4fK7A5pgy7oFsLaL2VAdI= - -through2-filter@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254" - integrity sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA== - dependencies: - through2 "~2.0.0" - xtend "~4.0.0" - -through2@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" - integrity sha1-AARWmzfHx0ujnEPzzteNGtlBQL4= - dependencies: - readable-stream "^2.1.5" - xtend "~4.0.1" - -through2@^2.0.0, through2@^2.0.3, through2@~2.0.0, through2@~2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - -through2@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4" - integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ== - dependencies: - inherits "^2.0.4" - readable-stream "2 || 3" - -through2@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" - integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== - dependencies: - readable-stream "3" - -through2@~0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/through2/-/through2-0.4.2.tgz#dbf5866031151ec8352bb6c4db64a2292a840b9b" - integrity sha1-2/WGYDEVHsg1K7bE22SiKSqEC5s= - dependencies: - readable-stream "~1.0.17" - xtend "~2.1.1" - -through@2, through@^2.3.6, through@^2.3.8, through@~2.3, through@~2.3.1, through@~2.3.4: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -time-stamp@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" - integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM= - -timers-browserify@^2.0.4: - version "2.0.12" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" - integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== - dependencies: - setimmediate "^1.0.4" - -timers-ext@^0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.7.tgz#6f57ad8578e07a3fb9f91d9387d65647555e25c6" - integrity sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ== - dependencies: - es5-ext "~0.10.46" - next-tick "1" - -timsort@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" - integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -to-absolute-glob@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz#1865f43d9e74b0822db9f145b78cff7d0f7c849b" - integrity sha1-GGX0PZ50sIItufFFt4z/fQ98hJs= - dependencies: - is-absolute "^1.0.0" - is-negated-glob "^1.0.0" - -to-arraybuffer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -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-readable-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" - integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== - -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-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" - 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" - -to-through@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-through/-/to-through-2.0.0.tgz#fc92adaba072647bc0b67d6b03664aa195093af6" - integrity sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY= - dependencies: - through2 "^2.0.3" - -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== - -tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - -tree-kill@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" - integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== - -ts-loader@^6.2.1: - version "6.2.2" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-6.2.2.tgz#dffa3879b01a1a1e0a4b85e2b8421dc0dfff1c58" - integrity sha512-HDo5kXZCBml3EUPcc7RlZOV/JGlLHwppTLEHb3SHnr5V7NXD4klMEkrhJe5wgRbaWsSXi+Y1SIBN/K9B6zWGWQ== - dependencies: - chalk "^2.3.0" - enhanced-resolve "^4.0.0" - loader-utils "^1.0.2" - micromatch "^4.0.0" - semver "^6.0.0" - -ts-morph@^10.0.2: - version "10.0.2" - resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-10.0.2.tgz#292418207db467326231b2be92828b5e295e7946" - integrity sha512-TVuIfEqtr9dW25K3Jajqpqx7t/zLRFxKu2rXQZSDjTm4MO4lfmuj1hn8WEryjeDDBFcNOCi+yOmYUYR4HucrAg== - dependencies: - "@ts-morph/common" "~0.9.0" - code-block-writer "^10.1.1" - -tsec@0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/tsec/-/tsec-0.1.4.tgz#dc8743c28ad01230ea4692e326866e0d54487f3f" - integrity sha512-7r6m7gmRE11si2FeM0pPoLfGV3AZTRcJJxx2bS5MYtvwaEMNqq2QlaVAEYaH1RqICeN3ODe2jVBJkC+JYQ/gtQ== - dependencies: - glob "^7.1.1" - minimatch "^3.0.3" - -tslib@^1.8.1, tslib@^1.9.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^2.0.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" - integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== - -tsutils@^3.17.1: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - -tty-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tunnel@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" - integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - -type-fest@^0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934" - integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg== - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -type@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" - integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== - -type@^2.0.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/type/-/type-2.5.0.tgz#0a2e78c2e77907b252abe5f298c1b01c63f0db3d" - integrity sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw== - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - -typescript-formatter@7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/typescript-formatter/-/typescript-formatter-7.1.0.tgz#dd1b5547de211065221f765263e15f18c84c66b8" - integrity sha512-XgPUSZ3beF7Xx2ZIEngIonWpDTS0XzWqV0vjtcm6nOPONug4WFXQYjbvulCzY2T0+knceZn5CFQjVUShNkIdLA== - dependencies: - commandpost "^1.0.0" - editorconfig "^0.15.0" - -typescript@^3.9.5: - version "3.9.9" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.9.tgz#e69905c54bc0681d0518bd4d587cc6f2d0b1a674" - integrity sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w== - -typescript@^4.3.0-dev.20210426: - version "4.3.0-dev.20210504" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.0-dev.20210504.tgz#e5c75b63cf9a3eb70c326e763784aab3cdb4b435" - integrity sha512-1ROBt+Q/fOQTyCYh5tKRJV5IXeuIMWNU9K2NxoNghwfUwUF+tbAYWdToYLo23zIt7OUAsF/I/sWAImmQM6XUSA== - -typical@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" - integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== - -ultron@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" - integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== - -unbox-primitive@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" - integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== - dependencies: - function-bind "^1.1.1" - has-bigints "^1.0.1" - has-symbols "^1.0.2" - which-boxed-primitive "^1.0.2" - -unc-path-regex@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" - integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo= - -underscore@^1.8.2: - version "1.13.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.1.tgz#0c1c6bd2df54b6b69f2314066d65b6cde6fcf9d1" - integrity sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g== - -underscore@~1.8.3: - version "1.8.3" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" - integrity sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI= - -undertaker-registry@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/undertaker-registry/-/undertaker-registry-1.0.1.tgz#5e4bda308e4a8a2ae584f9b9a4359a499825cc50" - integrity sha1-XkvaMI5KiirlhPm5pDWaSZglzFA= - -undertaker@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/undertaker/-/undertaker-1.3.0.tgz#363a6e541f27954d5791d6fa3c1d321666f86d18" - integrity sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg== - dependencies: - arr-flatten "^1.0.1" - arr-map "^2.0.0" - bach "^1.0.0" - collection-map "^1.0.0" - es6-weak-map "^2.0.1" - fast-levenshtein "^1.0.0" - last-run "^1.1.0" - object.defaults "^1.0.0" - object.reduce "^1.0.0" - undertaker-registry "^1.0.0" - -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" - -uniq@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" - integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= - -uniqs@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" - integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= - -unique-filename@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" - integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== - dependencies: - unique-slug "^2.0.0" - -unique-slug@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" - integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== - dependencies: - imurmurhash "^0.1.4" - -unique-stream@^2.0.2: - version "2.3.1" - resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.3.1.tgz#c65d110e9a4adf9a6c5948b28053d9a8d04cbeac" - integrity sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A== - dependencies: - json-stable-stringify-without-jsonify "^1.0.1" - through2-filter "^3.0.0" - -universal-user-agent@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" - integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== - -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== - -unpipe@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - -unquote@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" - integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= - -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.2.0" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" - integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -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= - -url-parse-lax@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" - integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= - dependencies: - prepend-http "^2.0.0" - -url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= - dependencies: - punycode "1.3.2" - querystring "0.2.0" - -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, util-deprecate@^1.0.2, 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= - -util.promisify@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" - integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.2" - has-symbols "^1.0.1" - object.getownpropertydescriptors "^2.1.0" - -util@0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= - dependencies: - inherits "2.0.1" - -"util@>=0.10.3 <1": - version "0.12.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.12.3.tgz#971bb0292d2cc0c892dab7c6a5d37c2bec707888" - integrity sha512-I8XkoQwE+fPQEhy9v012V+TSdH2kp9ts29i20TaaDUXsg7x/onePbhFJUExBfv/2ay1ZOp/Vsm3nDlmnFGSAog== - dependencies: - inherits "^2.0.3" - is-arguments "^1.0.4" - is-generator-function "^1.0.7" - is-typed-array "^1.1.3" - safe-buffer "^5.1.2" - which-typed-array "^1.1.2" - -util@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" - integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== - dependencies: - inherits "2.0.3" - -uuid@^3.0.0, uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - -v8-compile-cache@^2.0.3, v8-compile-cache@^2.1.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -v8-inspect-profiler@^0.0.20: - version "0.0.20" - resolved "https://registry.yarnpkg.com/v8-inspect-profiler/-/v8-inspect-profiler-0.0.20.tgz#f7ad0f8178dcea2f1504334e8844ef38181792ab" - integrity sha512-AFLVT7GLCvTcw0HszhwxD1GCBboIeZSxqlk0myNXVLIfjelLl8rybm8KmRjoYcWH7uXqMC0qwhKk7Vj4wppiFQ== - dependencies: - chrome-remote-interface "0.26.1" - -v8flags@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.2.0.tgz#b243e3b4dfd731fa774e7492128109a0fe66d656" - integrity sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg== - dependencies: - homedir-polyfill "^1.0.1" - -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -validator@~9.4.1: - version "9.4.1" - resolved "https://registry.yarnpkg.com/validator/-/validator-9.4.1.tgz#abf466d398b561cd243050112c6ff1de6cc12663" - integrity sha512-YV5KjzvRmSyJ1ee/Dm5UED0G+1L4GZnLN3w6/T+zZm8scVua4sOhYKWTUrKa0H/tMiJyO9QLHMPN+9mB/aMunA== - -value-or-function@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-3.0.0.tgz#1c243a50b595c1be54a754bfece8563b9ff8d813" - integrity sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM= - -vendors@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" - integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -vinyl-fs@^3.0.0, vinyl-fs@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-3.0.3.tgz#c85849405f67428feabbbd5c5dbdd64f47d31bc7" - integrity sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng== - dependencies: - fs-mkdirp-stream "^1.0.0" - glob-stream "^6.1.0" - graceful-fs "^4.0.0" - is-valid-glob "^1.0.0" - lazystream "^1.0.0" - lead "^1.0.0" - object.assign "^4.0.4" - pumpify "^1.3.5" - readable-stream "^2.3.3" - remove-bom-buffer "^3.0.0" - remove-bom-stream "^1.2.0" - resolve-options "^1.1.0" - through2 "^2.0.0" - to-through "^2.0.0" - value-or-function "^3.0.0" - vinyl "^2.0.0" - vinyl-sourcemap "^1.1.0" - -vinyl-sourcemap@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz#92a800593a38703a8cdb11d8b300ad4be63b3e16" - integrity sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY= - dependencies: - append-buffer "^1.0.2" - convert-source-map "^1.5.0" - graceful-fs "^4.1.6" - normalize-path "^2.1.1" - now-and-later "^2.0.0" - remove-bom-buffer "^3.0.0" - vinyl "^2.0.0" - -vinyl-sourcemaps-apply@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz#ab6549d61d172c2b1b87be5c508d239c8ef87705" - integrity sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU= - dependencies: - source-map "^0.5.1" - -vinyl@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" - integrity sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ= - dependencies: - clone "^1.0.0" - clone-stats "^0.0.1" - replace-ext "0.0.1" - -vinyl@^2.0.0, vinyl@^2.0.2, vinyl@^2.1.0, vinyl@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.1.tgz#23cfb8bbab5ece3803aa2c0a1eb28af7cbba1974" - integrity sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw== - dependencies: - clone "^2.1.1" - clone-buffer "^1.0.0" - clone-stats "^1.0.0" - cloneable-readable "^1.0.0" - remove-trailing-separator "^1.0.1" - replace-ext "^1.0.0" - -vinyl@~2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.0.2.tgz#0a3713d8d4e9221c58f10ca16c0116c9e25eda7c" - integrity sha1-CjcT2NTpIhxY8QyhbAEWyeJe2nw= - dependencies: - clone "^1.0.0" - clone-buffer "^1.0.0" - clone-stats "^1.0.0" - cloneable-readable "^1.0.0" - is-stream "^1.1.0" - remove-trailing-separator "^1.0.1" - replace-ext "^1.0.0" - -vm-browserify@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" - integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== - -vscode-debugprotocol@1.47.0: - version "1.47.0" - resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.47.0.tgz#700055bea38633a9530a5a552fb3ea314d76b73f" - integrity sha512-ii7oCz3Wfr/SGtFr5AYop5dJm0dUmpg0hq2lTzTBdaht8nSheYMMjPntxULBR+2TUxXLcCKFZkF2UEJQduYsIQ== - -vscode-nls-dev@^3.3.1: - version "3.3.2" - resolved "https://registry.yarnpkg.com/vscode-nls-dev/-/vscode-nls-dev-3.3.2.tgz#f15e0b627f948224a96dc0288da3c3b9c6dfae81" - integrity sha512-/YJY/LegZ0jsWFd8BforDmXpwWKprM7L3rL0kLEvjQxOJw6qtmnoUJorLIv0ZXjebeyhI3mc8hjmQr479ykLIQ== - dependencies: - ansi-colors "^3.2.3" - clone "^2.1.1" - event-stream "^3.3.4" - fancy-log "^1.3.3" - glob "^7.1.2" - iconv-lite "^0.4.19" - is "^3.2.1" - source-map "^0.6.1" - typescript "^3.9.5" - vinyl "^2.1.0" - xml2js "^0.4.19" - yargs "^13.2.4" - -vscode-oniguruma@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.3.1.tgz#e2383879c3485b19f533ec34efea9d7a2b14be8f" - integrity sha512-gz6ZBofA7UXafVA+m2Yt2zHKgXC2qedArprIsHAPKByTkwq9l5y/izAGckqxYml7mSbYxTRTfdRwsFq3cwF4LQ== - -vscode-proxy-agent@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.11.0.tgz#9dc8d2bb9d448f1e33bb1caef97a741289660f2f" - integrity sha512-Y5mHjDGq/OKOvKG0IwCYfj25cvQ2cLEil8ce8n55IZHRAP9RF3e1sKU4ZUNDB8X2NIpKwyltrWpK9tFFE/kc3g== - dependencies: - "@tootallnate/once" "^1.1.2" - agent-base "^6.0.2" - debug "^4.3.1" - get-uri "^3.0.2" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - socks-proxy-agent "^5.0.0" - optionalDependencies: - vscode-windows-ca-certs "^0.3.0" - -vscode-regexpp@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/vscode-regexpp/-/vscode-regexpp-3.1.0.tgz#42d059b6fffe99bd42939c0d013f632f0cad823f" - integrity sha512-pqtN65VC1jRLawfluX4Y80MMG0DHJydWhe5ZwMHewZD6sys4LbU6lHwFAHxeuaVE6Y6+xZOtAw+9hvq7/0ejkg== - -vscode-ripgrep@^1.11.2, vscode-ripgrep@^1.11.3: - version "1.11.3" - resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.11.3.tgz#a997f4f4535dfeb9d775f04053c1247454d7a37a" - integrity sha512-fdD+BciXiEO1iWTrV/S3sAthlK/tHRBjHF+aJIZDxUMD/q9wpNq+YPFEiLCrW+8epahfR19241DeVHHgX/I4Ww== - dependencies: - https-proxy-agent "^4.0.0" - proxy-from-env "^1.1.0" - -vscode-sqlite3@4.0.11: - version "4.0.11" - resolved "https://registry.yarnpkg.com/vscode-sqlite3/-/vscode-sqlite3-4.0.11.tgz#8f41ec8f4c03e24a284a74c5fad322ea39141f15" - integrity sha512-45oylZEr8sWJFWRoVE9iXI8RQhk7XDeIpwWYdtOAXFnCfmI74n0CwSqZOLfVsMLgtpU9/JZ1CA6s45tgKktSVQ== - dependencies: - nan "^2.14.0" - -vscode-telemetry-extractor@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/vscode-telemetry-extractor/-/vscode-telemetry-extractor-1.7.0.tgz#f99b1a90a4cad0f75454f2f57615a155e55eb960" - integrity sha512-UC/N/uqPuQIuNnXg52XJnejeId2+Nuq04rj4H1rSZsqj9a56pigs6ogLPdZSi+OVLI21LU9PnJ/ZKrBrLm1roA== - dependencies: - command-line-args "^5.1.1" - ts-morph "^10.0.2" - vscode-ripgrep "^1.11.2" - -vscode-textmate@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e" - integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ== - -vscode-windows-ca-certs@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/vscode-windows-ca-certs/-/vscode-windows-ca-certs-0.3.0.tgz#324e1f8ba842bbf048a39e7c0ee8fe655e9adfcc" - integrity sha512-CYrpCEKmAFQJoZNReOrelNL+VKyebOVRCqL9evrBlVcpWQDliliJgU5RggGS8FPGtQ3jAKLQt9frF0qlxYYPKA== - dependencies: - node-addon-api "^3.0.2" - -vscode-windows-registry@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/vscode-windows-registry/-/vscode-windows-registry-1.0.3.tgz#377e9a8bf75c0acac81a188282a4f16f748ecd47" - integrity sha512-IXCwNAm+H5yPCn6JBz89T9AAMgy5xEN2LxbxrvHPlErmyQqCYtpCCjvisfgT2dCuaJ2T9FfiqIeIrOpDm2Jc4Q== - -watchpack-chokidar2@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" - integrity sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww== - dependencies: - chokidar "^2.1.8" - -watchpack@^1.7.4: - version "1.7.5" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453" - integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ== - dependencies: - graceful-fs "^4.1.2" - neo-async "^2.5.0" - optionalDependencies: - chokidar "^3.4.1" - watchpack-chokidar2 "^2.0.1" - -webpack-cli@^3.3.12: - version "3.3.12" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.12.tgz#94e9ada081453cd0aa609c99e500012fd3ad2d4a" - integrity sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag== - dependencies: - chalk "^2.4.2" - cross-spawn "^6.0.5" - enhanced-resolve "^4.1.1" - findup-sync "^3.0.0" - global-modules "^2.0.0" - import-local "^2.0.0" - interpret "^1.4.0" - loader-utils "^1.4.0" - supports-color "^6.1.0" - v8-compile-cache "^2.1.1" - yargs "^13.3.2" - -webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" - integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - -webpack-stream@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/webpack-stream/-/webpack-stream-5.2.1.tgz#35c992161399fe8cad9c10d4a5c258f022629b39" - integrity sha512-WvyVU0K1/VB1NZ7JfsaemVdG0PXAQUqbjUNW4A58th4pULvKMQxG+y33HXTL02JvD56ko2Cub+E2NyPwrLBT/A== - dependencies: - fancy-log "^1.3.3" - lodash.clone "^4.3.2" - lodash.some "^4.2.2" - memory-fs "^0.4.1" - plugin-error "^1.0.1" - supports-color "^5.5.0" - through "^2.3.8" - vinyl "^2.1.0" - webpack "^4.26.1" - -webpack@^4.26.1, webpack@^4.43.0: - version "4.46.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" - integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/wasm-edit" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - acorn "^6.4.1" - ajv "^6.10.2" - ajv-keywords "^3.4.1" - chrome-trace-event "^1.0.2" - enhanced-resolve "^4.5.0" - eslint-scope "^4.0.3" - json-parse-better-errors "^1.0.2" - loader-runner "^2.4.0" - loader-utils "^1.2.3" - memory-fs "^0.4.1" - micromatch "^3.1.10" - mkdirp "^0.5.3" - neo-async "^2.6.1" - node-libs-browser "^2.2.1" - schema-utils "^1.0.0" - tapable "^1.1.3" - terser-webpack-plugin "^1.4.3" - watchpack "^1.7.4" - webpack-sources "^1.4.1" - -when@^3.7.7: - version "3.7.8" - resolved "https://registry.yarnpkg.com/when/-/when-3.7.8.tgz#c7130b6a7ea04693e842cdc9e7a1f2aa39a39f82" - integrity sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I= - -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" - integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - -which-typed-array@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.4.tgz#8fcb7d3ee5adf2d771066fba7cf37e32fe8711ff" - integrity sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA== - dependencies: - available-typed-arrays "^1.0.2" - call-bind "^1.0.0" - es-abstract "^1.18.0-next.1" - foreach "^2.0.5" - function-bind "^1.1.1" - has-symbols "^1.0.1" - is-typed-array "^1.1.3" - -which@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -which@^1.2.14, which@^1.2.9, which@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -wide-align@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - -windows-foreground-love@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/windows-foreground-love/-/windows-foreground-love-0.2.0.tgz#b291832d8a02a966bc046ba0e498cc789809076b" - integrity sha512-72ZDshnt8Q3/ImLMt4wxsY8eVnUd1KDb5QfvZX09AxJJJa0hGdyzPfd/ms0pKSYYwKlEhB1ri+WDKNvdIpJknQ== - -windows-mutex@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/windows-mutex/-/windows-mutex-0.3.0.tgz#2f51a0c97b3979c98952b23c086035f1f3715fab" - integrity sha512-IDWzyHOEpQr7m590pT90jMbCYNe525d7BgP6F80TjispEu2gWMvTIoSuO6Sy4atIEhvs3ys7DVlKdLzIAyRviQ== - dependencies: - bindings "^1.2.1" - nan "^2.14.0" - -windows-process-tree@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/windows-process-tree/-/windows-process-tree-0.3.0.tgz#cf0d9291b22fba2a7f5a687c8272866e28fbcafd" - integrity sha512-0bKI4gcd5MOsOpn2TdStCSlnjThtH6BdHrocekY9qCgTqgEtdaUs0B5BaqyzF9jXoTSwz38NMdE1F55o4fgv9Q== - dependencies: - nan "^2.13.2" - -word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= - -worker-farm@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" - integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== - dependencies: - errno "~0.1.7" - -workerpool@6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.0.tgz#a8e038b4c94569596852de7a8ea4228eefdeb37b" - integrity sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg== - -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== - dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" - -wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - -ws@^3.3.3: - version "3.3.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" - integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== - dependencies: - async-limiter "~1.0.0" - safe-buffer "~5.1.0" - ultron "~1.1.0" - -ws@^7.3.1: - version "7.4.5" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.5.tgz#a484dd851e9beb6fdb420027e3885e8ce48986c1" - integrity sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g== - -xml-name-validator@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-1.0.0.tgz#dcf82ee092322951ef8cc1ba596c9cbfd14a83f1" - integrity sha1-3Pgu4JIyKVHvjMG6WWycv9FKg/E= - -xml2js@0.2.8: - version "0.2.8" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.2.8.tgz#9b81690931631ff09d1957549faf54f4f980b3c2" - integrity sha1-m4FpCTFjH/CdGVdUn69U9PmAs8I= - dependencies: - sax "0.5.x" - -xml2js@^0.4.17, xml2js@^0.4.19: - version "0.4.23" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" - integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - -xml@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" - integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= - -xmlbuilder@^9.0.7: - version "9.0.7" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" - integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= - -xmlbuilder@~11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" - integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== - -xmldom@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.5.0.tgz#193cb96b84aa3486127ea6272c4596354cb4962e" - integrity sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA== - -"xmlhttprequest@>= 1.6.0 < 2.0.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" - integrity sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw= - -xregexp@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943" - integrity sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM= - -xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -xtend@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" - integrity sha1-bv7MKk2tjmlixJAbM3znuoe10os= - dependencies: - object-keys "~0.4.0" - -xterm-addon-search@0.9.0-beta.2: - version "0.9.0-beta.2" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.2.tgz#46de7c7d5f1d0ae546b84552c08182916d83025d" - integrity sha512-Ljg+O8HcGx1z2RjpV+nX070zpSjmefU09SFPBVWAHjGT983y6b5yoqG7AVVZdirsJ0zGiccAZL9Kila1CQN6nQ== - -xterm-addon-unicode11@0.3.0-beta.5: - version "0.3.0-beta.5" - resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.3.0-beta.5.tgz#7e490799d530d3b301125c7a4e92317c161761c4" - integrity sha512-SgDDL3PoMH1G48JO6T45whKAex4NPxi80UzUVitnrqyd8dFQP+oF6cxqUutULgm9HSGk62qy3mrZvIMGO5VXog== - -xterm-addon-webgl@0.11.0-beta.8: - version "0.11.0-beta.8" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.11.0-beta.8.tgz#8cb4925d67c31beb8144275daf46358f42eff9fe" - integrity sha512-udRmQ/jgH8cL8VQOZweytkToIROevVeiA7WY0tIe878Wt2zKY+AYHZV8js3c1W9wHDu5G90BhmzTidJ5UwZK3Q== - -xterm@4.12.0-beta.26: - version "4.12.0-beta.26" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.12.0-beta.26.tgz#57c75b732808795398a66bc1a3e06d09eaff2ada" - integrity sha512-yZB1kMBXQu2G0G1ch7TUi6f893iTZC+tmfjw/PQNZTmN46b4oX1l7rplc3sFcdrICHtmQ0Q5n1u0d6WUAdq1Kw== - -y18n@^3.2.1: - version "3.2.2" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696" - integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ== - -y18n@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" - integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yargs-parser@20.2.4: - version "20.2.4" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" - integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== - -yargs-parser@^13.1.2: - version "13.1.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" - integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-parser@^18.1.2: - version "18.1.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" - integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-parser@^20.2.2: - version "20.2.7" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a" - integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw== - -yargs-parser@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.1.tgz#7ede329c1d8cdbbe209bd25cdb990e9b1ebbb394" - integrity sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA== - dependencies: - camelcase "^3.0.0" - object.assign "^4.1.0" - -yargs-unparser@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" - integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== - dependencies: - camelcase "^6.0.0" - decamelize "^4.0.0" - flat "^5.0.2" - is-plain-obj "^2.1.0" - -yargs@16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yargs@^13.2.4, yargs@^13.3.2: - version "13.3.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" - integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.2" - -yargs@^15.3.0: - version "15.4.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" - integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== - dependencies: - cliui "^6.0.0" - decamelize "^1.2.0" - find-up "^4.1.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^4.2.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^18.1.2" - -yargs@^7.1.0: - version "7.1.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.2.tgz#63a0a5d42143879fdbb30370741374e0641d55db" - integrity sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA== - dependencies: - camelcase "^3.0.0" - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - os-locale "^1.4.0" - read-pkg-up "^1.0.1" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^1.0.2" - which-module "^1.0.0" - y18n "^3.2.1" - yargs-parser "^5.0.1" - -yaserver@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/yaserver/-/yaserver-0.2.0.tgz#56393027dc13f3c1bb89d20e0bd17269aa927802" - integrity sha512-onsELrl7Y42M4P3T9R0N/ZJNJRu4cGwzhDyOWIFRMJvPUIrGKInYGh+DJBefrbr1qoyDu7DSCLl9BL5hSSVfDA== - -yauzl@^2.10.0, yauzl@^2.2.1, yauzl@^2.9.2: - version "2.10.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" - integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.1.0" - -yazl@^2.2.1, yazl@^2.4.3: - version "2.5.1" - resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.5.1.tgz#a3d65d3dd659a5b0937850e8609f22fffa2b5c35" - integrity sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw== - dependencies: - buffer-crc32 "~0.2.3" - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -zone.js@0.7.6: - version "0.7.6" - resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009" - integrity sha1-+7w50+AmHQmG8boGMG6zrrDSIAk= diff --git a/package.json b/package.json index 300b49e51983..3c2b3b89dc09 100644 --- a/package.json +++ b/package.json @@ -1,165 +1,223 @@ { - "name": "code-server", - "license": "MIT", - "version": "3.9.3", - "description": "Run VS Code on a remote server.", - "homepage": "https://github.com/cdr/code-server", - "bugs": { - "url": "https://github.com/cdr/code-server/issues" + "name": "code-oss-dev", + "version": "1.57.0", + "distro": "90b97e4e10fb8a1ab3cd4846f4dc56bfea8ea620", + "author": { + "name": "Microsoft Corporation" }, - "repository": "https://github.com/cdr/code-server", + "license": "MIT", + "main": "./out/main", + "private": true, "scripts": { - "clean": "./ci/build/clean.sh", - "build": "./ci/build/build-code-server.sh", - "build:vscode": "./ci/build/build-vscode.sh", - "release": "./ci/build/build-release.sh", - "release:standalone": "./ci/build/build-standalone-release.sh", - "release:github-draft": "./ci/build/release-github-draft.sh", - "release:github-assets": "./ci/build/release-github-assets.sh", - "release:prep": "./ci/build/release-prep.sh", - "test:e2e": "./ci/dev/test-e2e.sh", - "test:standalone-release": "./ci/build/test-standalone-release.sh", - "test:unit": "./ci/dev/test-unit.sh", - "package": "./ci/build/build-packages.sh", - "postinstall": "./ci/dev/postinstall.sh", - "update:vscode": "./ci/dev/update-vscode.sh", - "_____": "", - "_audit": "./ci/dev/audit.sh", - "fmt": "./ci/dev/fmt.sh", - "lint": "./ci/dev/lint.sh", - "test": "echo 'Run yarn test:unit or yarn test:e2e' && exit 1", - "ci": "./ci/dev/ci.sh", - "watch": "VSCODE_IPC_HOOK_CLI= NODE_OPTIONS=--max_old_space_size=32384 ts-node ./ci/dev/watch.ts", - "icons": "./ci/dev/gen_icons.sh", - "coverage": "codecov" + "test": "mocha", + "test-browser": "node test/unit/browser/index.js", + "preinstall": "node build/npm/preinstall.js", + "postinstall": "node build/npm/postinstall.js", + "compile": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js compile", + "watch": "npm-run-all -lp watch-client watch-extensions", + "watchd": "deemon yarn watch", + "watch-webd": "deemon yarn watch-web", + "kill-watchd": "deemon --kill yarn watch", + "kill-watch-webd": "deemon --kill yarn watch-web", + "restart-watchd": "deemon --restart yarn watch", + "restart-watch-webd": "deemon --restart yarn watch-web", + "watch-client": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js watch-client", + "watch-clientd": "deemon yarn watch-client", + "kill-watch-clientd": "deemon --kill yarn watch-client", + "watch-extensions": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js watch-extensions watch-extension-media", + "watch-extensionsd": "deemon yarn watch-extensions", + "kill-watch-extensionsd": "deemon --kill yarn watch-extensions", + "mocha": "mocha test/unit/node/all.js --delay", + "precommit": "node build/hygiene.js", + "gulp": "node --max_old_space_size=8192 ./node_modules/gulp/bin/gulp.js", + "electron": "node build/lib/electron", + "7z": "7z", + "update-grammars": "node build/npm/update-all-grammars.js", + "update-localization-extension": "node build/npm/update-localization-extension.js", + "smoketest": "cd test/smoke && yarn compile && node test/index.js", + "smoketest-no-compile": "cd test/smoke && node test/index.js", + "download-builtin-extensions": "node build/lib/builtInExtensions.js", + "download-builtin-extensions-cg": "node build/lib/builtInExtensionsCG.js", + "monaco-compile-check": "tsc -p src/tsconfig.monaco.json --noEmit", + "tsec-compile-check": "node node_modules/tsec/bin/tsec -p src/tsconfig.tsec.json", + "valid-layers-check": "node build/lib/layersChecker.js", + "update-distro": "node build/npm/update-distro.js", + "web": "node resources/web/code-web.js", + "compile-web": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js compile-web", + "watch-web": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js watch-web", + "eslint": "node build/eslint", + "playwright-install": "node build/azure-pipelines/common/installPlaywright.js", + "compile-build": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js compile-build", + "compile-extensions-build": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js compile-extensions-build", + "minify-vscode": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js minify-vscode", + "minify-vscode-reh": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js minify-vscode-reh", + "minify-vscode-reh-web": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js minify-vscode-reh-web", + "hygiene": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js hygiene", + "core-ci": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js core-ci", + "extensions-ci": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js extensions-ci" }, - "main": "out/node/entry.js", - "devDependencies": { - "@schemastore/package": "^0.0.6", - "@types/body-parser": "^1.19.0", - "@types/compression": "^1.7.0", - "@types/cookie-parser": "^1.4.2", - "@types/express": "^4.17.8", - "@types/http-proxy": "^1.17.4", - "@types/js-yaml": "^4.0.0", - "@types/node": "~12.20.7", - "@types/parcel-bundler": "^1.12.1", - "@types/pem": "^1.9.5", - "@types/proxy-from-env": "^1.0.1", - "@types/safe-compare": "^1.1.0", - "@types/semver": "^7.1.0", - "@types/split2": "^3.2.0", - "@types/tar-fs": "^2.0.0", - "@types/tar-stream": "^2.1.0", - "@types/ws": "^7.2.6", - "@types/wtfnode": "^0.7.0", - "@typescript-eslint/eslint-plugin": "^4.7.0", - "@typescript-eslint/parser": "^4.7.0", - "audit-ci": "^4.0.0", - "codecov": "^3.8.1", - "doctoc": "^2.0.0", - "eslint": "^7.7.0", - "eslint-config-prettier": "^8.1.0", - "eslint-import-resolver-alias": "^1.1.2", - "eslint-plugin-import": "^2.18.2", - "eslint-plugin-prettier": "^3.1.0", - "leaked-handles": "^5.2.0", - "parcel-bundler": "^1.12.5", - "prettier": "^2.2.1", - "prettier-plugin-sh": "^0.6.0", - "shellcheck": "^1.0.0", - "stylelint": "^13.0.0", - "stylelint-config-recommended": "^5.0.0", - "ts-node": "^9.1.1", - "typescript": "^4.1.3", - "wtfnode": "^0.8.4" + "dependencies": { + "applicationinsights": "1.0.8", + "chokidar": "3.5.1", + "graceful-fs": "4.2.6", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.3", + "iconv-lite-umd": "0.6.8", + "jschardet": "3.0.0", + "keytar": "7.2.0", + "minimist": "^1.2.5", + "native-is-elevated": "0.4.3", + "native-keymap": "2.2.1", + "native-watchdog": "1.3.0", + "node-pty": "0.11.0-beta7", + "nsfw": "2.1.2", + "spdlog": "^0.13.0", + "sudo-prompt": "9.2.1", + "tas-client-umd": "0.1.4", + "v8-inspect-profiler": "^0.0.20", + "vscode-oniguruma": "1.5.1", + "vscode-proxy-agent": "^0.11.0", + "vscode-regexpp": "^3.1.0", + "vscode-ripgrep": "^1.11.3", + "vscode-sqlite3": "4.0.11", + "vscode-textmate": "5.4.0", + "xterm": "4.13.0-beta.1", + "xterm-addon-search": "0.9.0-beta.2", + "xterm-addon-unicode11": "0.3.0-beta.5", + "xterm-addon-webgl": "0.11.1", + "yauzl": "^2.9.2", + "yazl": "^2.4.3" }, - "resolutions": { - "safe-buffer": "^5.1.1", - "vfile-message": "^2.0.2" + "devDependencies": { + "7zip": "0.0.6", + "@types/applicationinsights": "0.20.0", + "@types/chokidar": "2.1.3", + "@types/cookie": "^0.3.3", + "@types/copy-webpack-plugin": "^6.0.3", + "@types/cssnano": "^4.0.0", + "@types/debug": "4.1.5", + "@types/graceful-fs": "4.1.2", + "@types/gulp-postcss": "^8.0.0", + "@types/http-proxy-agent": "^2.0.1", + "@types/keytar": "^4.4.0", + "@types/minimist": "^1.2.1", + "@types/mocha": "^8.2.0", + "@types/node": "14.x", + "@types/sinon": "^1.16.36", + "@types/trusted-types": "^1.0.6", + "@types/vscode-windows-registry": "^1.0.0", + "@types/webpack": "^4.41.25", + "@types/wicg-file-system-access": "^2020.9.1", + "@types/windows-foreground-love": "^0.3.0", + "@types/windows-mutex": "^0.4.0", + "@types/windows-process-tree": "^0.2.0", + "@types/winreg": "^1.2.30", + "@types/yauzl": "^2.9.1", + "@types/yazl": "^2.4.2", + "@typescript-eslint/eslint-plugin": "3.2.0", + "@typescript-eslint/parser": "^3.3.0", + "ansi-colors": "^3.2.3", + "asar": "^3.0.3", + "chromium-pickle-js": "^0.2.0", + "copy-webpack-plugin": "^6.0.3", + "cson-parser": "^1.3.3", + "css-loader": "^3.2.0", + "cssnano": "^4.1.11", + "debounce": "^1.0.0", + "deemon": "^1.4.0", + "electron": "12.0.9", + "eslint": "6.8.0", + "eslint-plugin-jsdoc": "^19.1.0", + "event-stream": "3.3.4", + "fancy-log": "^1.3.3", + "fast-plist": "0.1.2", + "file-loader": "^4.2.0", + "glob": "^5.0.13", + "gulp": "^4.0.0", + "gulp-atom-electron": "^1.30.1", + "gulp-azure-storage": "^0.11.1", + "gulp-bom": "^3.0.0", + "gulp-buffer": "0.0.2", + "gulp-concat": "^2.6.1", + "gulp-eslint": "^5.0.0", + "gulp-filter": "^5.1.0", + "gulp-flatmap": "^1.0.2", + "gulp-gunzip": "^1.0.0", + "gulp-gzip": "^1.4.2", + "gulp-json-editor": "^2.5.0", + "gulp-plumber": "^1.2.0", + "gulp-postcss": "^9.0.0", + "gulp-remote-retry-src": "^0.6.0", + "gulp-rename": "^1.2.0", + "gulp-replace": "^0.5.4", + "gulp-shell": "^0.6.5", + "gulp-sourcemaps": "^3.0.0", + "gulp-tsb": "4.0.6", + "gulp-untar": "^0.0.7", + "gulp-vinyl-zip": "^2.1.2", + "husky": "^0.13.1", + "innosetup": "6.0.5", + "is": "^3.1.0", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.0", + "jsdom-no-contextify": "^3.1.0", + "lazy.js": "^0.4.2", + "merge-options": "^1.0.1", + "mime": "^1.4.1", + "minimatch": "^3.0.4", + "minimist": "^1.2.5", + "mkdirp": "^1.0.4", + "mocha": "^8.2.1", + "mocha-junit-reporter": "^2.0.0", + "mocha-multi-reporters": "^1.5.1", + "npm-run-all": "^4.1.5", + "opn": "^6.0.0", + "optimist": "0.3.5", + "p-all": "^1.0.0", + "playwright": "1.8.0", + "pump": "^1.0.1", + "queue": "3.0.6", + "rcedit": "^1.1.0", + "request": "^2.85.0", + "rimraf": "^2.2.8", + "sinon": "^1.17.2", + "source-map": "0.6.1", + "source-map-support": "^0.3.2", + "style-loader": "^1.0.0", + "ts-loader": "^6.2.1", + "tsec": "0.1.4", + "typescript": "^4.4.0-dev.20210528", + "typescript-formatter": "7.1.0", + "underscore": "^1.12.1", + "vinyl": "^2.0.0", + "vinyl-fs": "^3.0.0", + "vscode-debugprotocol": "1.47.0", + "vscode-nls-dev": "^3.3.1", + "vscode-telemetry-extractor": "^1.7.0", + "webpack": "^4.43.0", + "webpack-cli": "^3.3.12", + "webpack-stream": "^5.2.1", + "xml2js": "^0.4.17", + "yaserver": "^0.2.0" }, - "dependencies": { - "@coder/logger": "1.1.16", - "body-parser": "^1.19.0", - "compression": "^1.7.4", - "cookie-parser": "^1.4.5", - "env-paths": "^2.2.0", - "express": "^5.0.0-alpha.8", - "http-proxy": "^1.18.0", - "httpolyglot": "^0.1.2", - "js-yaml": "^4.0.0", - "limiter": "^1.1.5", - "node-fetch": "^2.6.1", - "pem": "^1.14.2", - "proxy-agent": "^4.0.0", - "proxy-from-env": "^1.1.0", - "qs": "6.7.0", - "rotating-file-stream": "^2.1.1", - "safe-buffer": "^5.1.1", - "safe-compare": "^1.1.4", - "semver": "^7.1.3", - "split2": "^3.2.2", - "tar-fs": "^2.0.0", - "tar-stream": "^2.2.0", - "ws": "^7.2.0", - "xdg-basedir": "^4.0.0", - "yarn": "^1.22.4" + "repository": { + "type": "git", + "url": "https://github.com/microsoft/vscode.git" }, - "bin": { - "code-server": "out/node/entry.js" + "bugs": { + "url": "https://github.com/microsoft/vscode/issues" }, - "keywords": [ - "vscode", - "development", - "ide", - "coder", - "vscode-remote", - "browser-ide" - ], - "engines": { - "node": ">= 12 <= 14" + "optionalDependencies": { + "vscode-windows-registry": "1.0.3", + "windows-foreground-love": "0.4.0", + "windows-mutex": "0.4.1", + "windows-process-tree": "0.3.0" }, - "jest": { - "transform": { - "^.+\\.ts$": "<rootDir>/test/node_modules/ts-jest" - }, - "testEnvironment": "node", - "testPathIgnorePatterns": [ - "/node_modules/", - "/lib/", - "/out/", - "test/e2e" - ], - "collectCoverage": true, - "collectCoverageFrom": [ - "<rootDir>/src/**/*.ts" - ], - "coverageDirectory": "<rootDir>/coverage", - "coverageReporters": [ - "json", - "json-summary", - "text", - "clover" - ], - "coveragePathIgnorePatterns": [ - "out" - ], - "coverageThreshold": { - "global": { - "lines": 40 - } - }, - "modulePathIgnorePatterns": [ - "<rootDir>/lib/vscode", - "<rootDir>/release-packages", - "<rootDir>/release", - "<rootDir>/release-standalone", - "<rootDir>/release-npm-package", - "<rootDir>/release-gcp", - "<rootDir>/release-images" - ], - "moduleNameMapper": { - "^.+\\.(css|less)$": "<rootDir>/test/utils/cssStub.ts" - } + "resolutions": { + "elliptic": "^6.5.3", + "nwmatcher": "^1.4.4" } } diff --git a/lib/vscode/product.json b/product.json similarity index 67% rename from lib/vscode/product.json rename to product.json index df09a299f097..9010521ca351 100644 --- a/lib/vscode/product.json +++ b/product.json @@ -1,6 +1,6 @@ { - "nameShort": "code-server", - "nameLong": "code-server", + "nameShort": "Code - OSS", + "nameLong": "Code - OSS", "applicationName": "code-oss", "dataFolderName": ".vscode-oss", "win32MutexName": "vscodeoss", @@ -20,20 +20,21 @@ "darwinBundleIdentifier": "com.visualstudio.code.oss", "linuxIconName": "com.visualstudio.code.oss", "licenseFileName": "LICENSE.txt", - "reportIssueUrl": "https://github.com/cdr/code-server/issues/new", + "reportIssueUrl": "https://github.com/microsoft/vscode/issues/new", "urlProtocol": "code-oss", + "webviewContentExternalBaseUrlTemplate": "https://{{uuid}}.vscode-webview.net/{{quality}}/{{commit}}/out/vs/workbench/contrib/webview/browser/pre/", "extensionAllowedProposedApi": [ "ms-vscode.vscode-js-profile-flame", "ms-vscode.vscode-js-profile-table", - "ms-vscode.github-browser", - "ms-vscode.github-richnav", "ms-vscode.remotehub", - "ms-vscode.remotehub-insiders" + "ms-vscode.remotehub-insiders", + "GitHub.remotehub", + "GitHub.remotehub-insiders" ], "builtInExtensions": [ { "name": "ms-vscode.node-debug", - "version": "1.44.27", + "version": "1.44.28", "repo": "https://github.com/microsoft/vscode-node-debug", "metadata": { "id": "b6ded8fb-a0a0-4c1c-acbd-ab2a3bc995a6", @@ -48,7 +49,7 @@ }, { "name": "ms-vscode.node-debug2", - "version": "1.42.6", + "version": "1.42.7", "repo": "https://github.com/microsoft/vscode-node-debug2", "metadata": { "id": "36d19e17-7569-4841-a001-947eb18602b2", @@ -93,7 +94,7 @@ }, { "name": "ms-vscode.js-debug", - "version": "1.56.2", + "version": "1.57.0", "repo": "https://github.com/microsoft/vscode-js-debug", "metadata": { "id": "25629058-ddac-4e17-abba-74678e126c5d", @@ -120,47 +121,6 @@ }, "publisherDisplayName": "Microsoft" } - }, - { - "name": "ms-vscode.remotehub", - "version": "0.5.3", - "repo": "https://github.com/microsoft/vscode-remotehub", - "metadata": { - "id": "ed0ffe1d-36f0-49a0-bafe-da68355eb33a", - "publisherId": { - "publisherId": "5f5636e7-69ed-4afe-b5d6-8d231fb3d3ee", - "publisherName": "ms-vscode", - "displayName": "Microsoft", - "flags": "verified" - }, - "publisherDisplayName": "Microsoft" - } - } - ], - "webBuiltInExtensions": [ - { - "name": "ms-vscode.remotehub", - "version": "0.5.3", - "repo": "https://github.com/microsoft/vscode-remotehub", - "metadata": { - "id": "ed0ffe1d-36f0-49a0-bafe-da68355eb33a", - "publisherId": { - "publisherId": "5f5636e7-69ed-4afe-b5d6-8d231fb3d3ee", - "publisherName": "ms-vscode", - "displayName": "Microsoft", - "flags": "verified" - }, - "publisherDisplayName": "Microsoft" - } } - ], - - "//": "https://github.com/VSCodium/vscodium/pull/155/files", - "documentationUrl": "https://go.microsoft.com/fwlink/?LinkID=533484#vscode", - "keyboardShortcutsUrlMac": "https://go.microsoft.com/fwlink/?linkid=832143", - "keyboardShortcutsUrlLinux": "https://go.microsoft.com/fwlink/?linkid=832144", - "keyboardShortcutsUrlWin": "https://go.microsoft.com/fwlink/?linkid=832145", - "introductoryVideosUrl": "https://go.microsoft.com/fwlink/?linkid=832146", - "tipsAndTricksUrl": "https://go.microsoft.com/fwlink/?linkid=852118", - "newsletterSignupUrl": "https://www.research.net/r/vsc-newsletter" + ] } diff --git a/lib/vscode/remote/.yarnrc b/remote/.yarnrc similarity index 100% rename from lib/vscode/remote/.yarnrc rename to remote/.yarnrc diff --git a/lib/vscode/remote/package.json b/remote/package.json similarity index 67% rename from lib/vscode/remote/package.json rename to remote/package.json index ff56643c0c83..df17e646d37a 100644 --- a/lib/vscode/remote/package.json +++ b/remote/package.json @@ -6,31 +6,31 @@ "applicationinsights": "1.0.8", "chokidar": "3.5.1", "cookie": "^0.4.0", - "graceful-fs": "4.2.3", + "graceful-fs": "4.2.6", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.3", "iconv-lite-umd": "0.6.8", - "jschardet": "2.3.0", + "jschardet": "3.0.0", "minimist": "^1.2.5", "native-watchdog": "1.3.0", - "node-pty": "0.10.1", + "node-pty": "0.11.0-beta7", "nsfw": "2.1.2", - "spdlog": "^0.11.1", + "spdlog": "^0.13.0", "tas-client-umd": "0.1.4", - "vscode-oniguruma": "1.3.1", + "vscode-oniguruma": "1.5.1", "vscode-proxy-agent": "^0.11.0", "vscode-regexpp": "^3.1.0", "vscode-ripgrep": "^1.11.3", - "vscode-textmate": "5.2.0", - "xterm": "4.12.0-beta.26", + "vscode-textmate": "5.4.0", + "xterm": "4.13.0-beta.1", "xterm-addon-search": "0.9.0-beta.2", "xterm-addon-unicode11": "0.3.0-beta.5", - "xterm-addon-webgl": "0.11.0-beta.8", + "xterm-addon-webgl": "0.11.1", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, "optionalDependencies": { - "vscode-windows-registry": "1.0.2", - "windows-process-tree": "0.2.4" + "vscode-windows-registry": "1.0.3", + "windows-process-tree": "0.3.0" } } diff --git a/lib/vscode/remote/web/package.json b/remote/web/package.json similarity index 59% rename from lib/vscode/remote/web/package.json rename to remote/web/package.json index 317ccc0dcd2d..63e52d40495b 100644 --- a/lib/vscode/remote/web/package.json +++ b/remote/web/package.json @@ -4,13 +4,13 @@ "private": true, "dependencies": { "iconv-lite-umd": "0.6.8", - "jschardet": "2.3.0", + "jschardet": "3.0.0", "tas-client-umd": "0.1.4", - "vscode-oniguruma": "1.3.1", - "vscode-textmate": "5.2.0", - "xterm": "4.12.0-beta.26", + "vscode-oniguruma": "1.5.1", + "vscode-textmate": "5.4.0", + "xterm": "4.13.0-beta.1", "xterm-addon-search": "0.9.0-beta.2", "xterm-addon-unicode11": "0.3.0-beta.5", - "xterm-addon-webgl": "0.11.0-beta.8" + "xterm-addon-webgl": "0.11.1" } } diff --git a/lib/vscode/remote/web/yarn.lock b/remote/web/yarn.lock similarity index 54% rename from lib/vscode/remote/web/yarn.lock rename to remote/web/yarn.lock index 6f88d68228b0..31c8ed1e6996 100644 --- a/lib/vscode/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -7,25 +7,25 @@ iconv-lite-umd@0.6.8: resolved "https://registry.yarnpkg.com/iconv-lite-umd/-/iconv-lite-umd-0.6.8.tgz#5ad310ec126b260621471a2d586f7f37b9958ec0" integrity sha512-zvXJ5gSwMC9JD3wDzH8CoZGc1pbiJn12Tqjk8BXYCnYz3hYL5GRjHW8LEykjXhV9WgNGI4rgpgHcbIiBfrRq6A== -jschardet@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.3.0.tgz#06e2636e16c8ada36feebbdc08aa34e6a9b3ff75" - integrity sha512-6I6xT7XN/7sBB7q8ObzKbmv5vN+blzLcboDE1BNEsEfmRXJValMxO6OIRT69ylPBRemS3rw6US+CMCar0OBc9g== +jschardet@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-3.0.0.tgz#898d2332e45ebabbdb6bf2feece9feea9a99e882" + integrity sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ== tas-client-umd@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/tas-client-umd/-/tas-client-umd-0.1.4.tgz#49db4130dd63a8342fabf77185a740fc6a7bea80" integrity sha512-1hFqJeLD3ryNikniIaO7TItlXhS5vx7bJ+wbPDf8o+IifgwwOWK2ARisdEM9SnJd0ccfcwNPG6Po+RiKn5L2hg== -vscode-oniguruma@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.3.1.tgz#e2383879c3485b19f533ec34efea9d7a2b14be8f" - integrity sha512-gz6ZBofA7UXafVA+m2Yt2zHKgXC2qedArprIsHAPKByTkwq9l5y/izAGckqxYml7mSbYxTRTfdRwsFq3cwF4LQ== +vscode-oniguruma@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.5.1.tgz#9ca10cd3ada128bd6380344ea28844243d11f695" + integrity sha512-JrBZH8DCC262TEYcYdeyZusiETu0Vli0xFgdRwNJjDcObcRjbmJP+IFcA3ScBwIXwgFHYKbAgfxtM/Cl+3Spjw== -vscode-textmate@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e" - integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ== +vscode-textmate@5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.4.0.tgz#4b25ffc1f14ac3a90faf9a388c67a01d24257cd7" + integrity sha512-c0Q4zYZkcLizeYJ3hNyaVUM2AA8KDhNCA3JvXY8CeZSJuBdAy3bAvSbv46RClC4P3dSO9BdwhnKEx2zOo6vP/w== xterm-addon-search@0.9.0-beta.2: version "0.9.0-beta.2" @@ -37,12 +37,12 @@ xterm-addon-unicode11@0.3.0-beta.5: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.3.0-beta.5.tgz#7e490799d530d3b301125c7a4e92317c161761c4" integrity sha512-SgDDL3PoMH1G48JO6T45whKAex4NPxi80UzUVitnrqyd8dFQP+oF6cxqUutULgm9HSGk62qy3mrZvIMGO5VXog== -xterm-addon-webgl@0.11.0-beta.8: - version "0.11.0-beta.8" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.11.0-beta.8.tgz#8cb4925d67c31beb8144275daf46358f42eff9fe" - integrity sha512-udRmQ/jgH8cL8VQOZweytkToIROevVeiA7WY0tIe878Wt2zKY+AYHZV8js3c1W9wHDu5G90BhmzTidJ5UwZK3Q== +xterm-addon-webgl@0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.11.1.tgz#33dd250ab52e9f51d2ff52396447962e6f53e24c" + integrity sha512-xF6DnEoV+rPtzetMBXBZVe1kLKtus7AKdEcyfq2eMHQzhaRvC+pfnU+XiCXC85kueguqu2UkBHXZs5mihK9jOQ== -xterm@4.12.0-beta.26: - version "4.12.0-beta.26" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.12.0-beta.26.tgz#57c75b732808795398a66bc1a3e06d09eaff2ada" - integrity sha512-yZB1kMBXQu2G0G1ch7TUi6f893iTZC+tmfjw/PQNZTmN46b4oX1l7rplc3sFcdrICHtmQ0Q5n1u0d6WUAdq1Kw== +xterm@4.13.0-beta.1: + version "4.13.0-beta.1" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.13.0-beta.1.tgz#ad2ad321c69a4add6e878c890f278a1da74fd7d0" + integrity sha512-gAMGqBglESTxQWph1uKVyd1jO/6eKsbicNG+Mr/YAsj06TjFVcLw839Iqu6P+DVFEV7lLLspcOb8fwX6qMBH/Q== diff --git a/lib/vscode/remote/yarn.lock b/remote/yarn.lock similarity index 89% rename from lib/vscode/remote/yarn.lock rename to remote/yarn.lock index 2a0d2ccc6c6f..efeb6c53ebcd 100644 --- a/lib/vscode/remote/yarn.lock +++ b/remote/yarn.lock @@ -214,12 +214,7 @@ glob-parent@~5.1.0: dependencies: is-glob "^4.0.1" -graceful-fs@4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" - integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== - -graceful-fs@^4.1.6, graceful-fs@^4.2.0: +graceful-fs@4.2.6, graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.6" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== @@ -309,10 +304,10 @@ isarray@0.0.1: resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= -jschardet@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.3.0.tgz#06e2636e16c8ada36feebbdc08aa34e6a9b3ff75" - integrity sha512-6I6xT7XN/7sBB7q8ObzKbmv5vN+blzLcboDE1BNEsEfmRXJValMxO6OIRT69ylPBRemS3rw6US+CMCar0OBc9g== +jschardet@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-3.0.0.tgz#898d2332e45ebabbdb6bf2feece9feea9a99e882" + integrity sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ== jsonfile@^4.0.0: version "4.0.0" @@ -326,7 +321,7 @@ minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== -mkdirp@^0.5.1: +mkdirp@^0.5.5: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== @@ -343,16 +338,11 @@ ms@2.1.2, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -nan@^2.13.2: +nan@^2.13.2, nan@^2.14.0: version "2.14.2" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== -nan@^2.14.0: - version "2.14.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" - integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== - native-watchdog@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/native-watchdog/-/native-watchdog-1.3.0.tgz#88cee94c9dc766b85c8506eda14c8bd8c9618e27" @@ -363,10 +353,10 @@ node-addon-api@*, node-addon-api@^3.0.2: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.1.0.tgz#98b21931557466c6729e51cb77cd39c965f42239" integrity sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw== -node-pty@0.10.1: - version "0.10.1" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.1.tgz#cd05d03a2710315ec40221232ec04186f6ac2c6d" - integrity sha512-JTdtUS0Im/yRsWJSx7yiW9rtpfmxqxolrtnyKwPLI+6XqTAPW/O2MjS8FYL4I5TsMbH2lVgDb2VMjp+9LoQGNg== +node-pty@0.11.0-beta7: + version "0.11.0-beta7" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.11.0-beta7.tgz#aed0888b5032d96c54d8473455e6adfae3bbebbe" + integrity sha512-uApPGLglZRiHQcUMWakbZOrBo8HVWvhzIqNnrWvBGJOvc6m/S5lCdbbg93BURyJqHFmBS0GV+4hwiMNDuGRbSA== dependencies: nan "^2.14.0" @@ -446,13 +436,13 @@ socks@^2.3.3: ip "^1.1.5" smart-buffer "^4.1.0" -spdlog@^0.11.1: - version "0.11.1" - resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.11.1.tgz#29721b31018a5fe6a3ce2531f9d8d43e0bd6b825" - integrity sha512-M+sg9/Tnr0lrfnW2/hqgpoc4Z8Jzq7W8NUn35iiSslj+1uj1pgutI60MCpulDP2QyFzOpC8VsJmYD6Fub7wHoA== +spdlog@^0.13.0: + version "0.13.5" + resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.13.5.tgz#a31027dcccbe032e9a53579f42cb45428af08bad" + integrity sha512-D1xA5tRXw7eZOoFBCAnOxCxLN3JpHVDjpPJG/xjJ0nFZvtfOUTAzK66MVxJCDht/ZFwjLcBAltvzjfz4JTuSEw== dependencies: bindings "^1.5.0" - mkdirp "^0.5.1" + mkdirp "^0.5.5" nan "^2.14.0" string_decoder@~0.10.x: @@ -477,10 +467,10 @@ universalify@^0.1.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== -vscode-oniguruma@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.3.1.tgz#e2383879c3485b19f533ec34efea9d7a2b14be8f" - integrity sha512-gz6ZBofA7UXafVA+m2Yt2zHKgXC2qedArprIsHAPKByTkwq9l5y/izAGckqxYml7mSbYxTRTfdRwsFq3cwF4LQ== +vscode-oniguruma@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.5.1.tgz#9ca10cd3ada128bd6380344ea28844243d11f695" + integrity sha512-JrBZH8DCC262TEYcYdeyZusiETu0Vli0xFgdRwNJjDcObcRjbmJP+IFcA3ScBwIXwgFHYKbAgfxtM/Cl+3Spjw== vscode-proxy-agent@^0.11.0: version "0.11.0" @@ -510,10 +500,10 @@ vscode-ripgrep@^1.11.3: https-proxy-agent "^4.0.0" proxy-from-env "^1.1.0" -vscode-textmate@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e" - integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ== +vscode-textmate@5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.4.0.tgz#4b25ffc1f14ac3a90faf9a388c67a01d24257cd7" + integrity sha512-c0Q4zYZkcLizeYJ3hNyaVUM2AA8KDhNCA3JvXY8CeZSJuBdAy3bAvSbv46RClC4P3dSO9BdwhnKEx2zOo6vP/w== vscode-windows-ca-certs@^0.3.0: version "0.3.0" @@ -522,15 +512,15 @@ vscode-windows-ca-certs@^0.3.0: dependencies: node-addon-api "^3.0.2" -vscode-windows-registry@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/vscode-windows-registry/-/vscode-windows-registry-1.0.2.tgz#b863e704a6a69c50b3098a55fbddbe595b0c124a" - integrity sha512-/CLLvuOSM2Vme2z6aNyB+4Omd7hDxpf4Thrt8ImxnXeQtxzel2bClJpFQvQqK/s4oaXlkBKS7LqVLeZM+uSVIA== +vscode-windows-registry@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/vscode-windows-registry/-/vscode-windows-registry-1.0.3.tgz#377e9a8bf75c0acac81a188282a4f16f748ecd47" + integrity sha512-IXCwNAm+H5yPCn6JBz89T9AAMgy5xEN2LxbxrvHPlErmyQqCYtpCCjvisfgT2dCuaJ2T9FfiqIeIrOpDm2Jc4Q== -windows-process-tree@0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/windows-process-tree/-/windows-process-tree-0.2.4.tgz#747af587b54cc6c996f2be0836cc8a8fd0dc038f" - integrity sha512-9gag9AHm3Iin/4YC1EwoIfZlqW/rG2eV7rJZ4Fy5NnAMGdewmnwsie5Rz+CJo2vSolqzzfw7hPeu3oOdniNejg== +windows-process-tree@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/windows-process-tree/-/windows-process-tree-0.3.0.tgz#cf0d9291b22fba2a7f5a687c8272866e28fbcafd" + integrity sha512-0bKI4gcd5MOsOpn2TdStCSlnjThtH6BdHrocekY9qCgTqgEtdaUs0B5BaqyzF9jXoTSwz38NMdE1F55o4fgv9Q== dependencies: nan "^2.13.2" @@ -549,15 +539,15 @@ xterm-addon-unicode11@0.3.0-beta.5: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.3.0-beta.5.tgz#7e490799d530d3b301125c7a4e92317c161761c4" integrity sha512-SgDDL3PoMH1G48JO6T45whKAex4NPxi80UzUVitnrqyd8dFQP+oF6cxqUutULgm9HSGk62qy3mrZvIMGO5VXog== -xterm-addon-webgl@0.11.0-beta.8: - version "0.11.0-beta.8" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.11.0-beta.8.tgz#8cb4925d67c31beb8144275daf46358f42eff9fe" - integrity sha512-udRmQ/jgH8cL8VQOZweytkToIROevVeiA7WY0tIe878Wt2zKY+AYHZV8js3c1W9wHDu5G90BhmzTidJ5UwZK3Q== +xterm-addon-webgl@0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.11.1.tgz#33dd250ab52e9f51d2ff52396447962e6f53e24c" + integrity sha512-xF6DnEoV+rPtzetMBXBZVe1kLKtus7AKdEcyfq2eMHQzhaRvC+pfnU+XiCXC85kueguqu2UkBHXZs5mihK9jOQ== -xterm@4.12.0-beta.26: - version "4.12.0-beta.26" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.12.0-beta.26.tgz#57c75b732808795398a66bc1a3e06d09eaff2ada" - integrity sha512-yZB1kMBXQu2G0G1ch7TUi6f893iTZC+tmfjw/PQNZTmN46b4oX1l7rplc3sFcdrICHtmQ0Q5n1u0d6WUAdq1Kw== +xterm@4.13.0-beta.1: + version "4.13.0-beta.1" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.13.0-beta.1.tgz#ad2ad321c69a4add6e878c890f278a1da74fd7d0" + integrity sha512-gAMGqBglESTxQWph1uKVyd1jO/6eKsbicNG+Mr/YAsj06TjFVcLw839Iqu6P+DVFEV7lLLspcOb8fwX6qMBH/Q== yauzl@^2.9.2: version "2.10.0" diff --git a/lib/vscode/resources/completions/bash/code b/resources/completions/bash/code similarity index 100% rename from lib/vscode/resources/completions/bash/code rename to resources/completions/bash/code diff --git a/lib/vscode/resources/completions/zsh/_code b/resources/completions/zsh/_code similarity index 100% rename from lib/vscode/resources/completions/zsh/_code rename to resources/completions/zsh/_code diff --git a/lib/vscode/resources/darwin/bat.icns b/resources/darwin/bat.icns similarity index 100% rename from lib/vscode/resources/darwin/bat.icns rename to resources/darwin/bat.icns diff --git a/lib/vscode/resources/darwin/bin/code.sh b/resources/darwin/bin/code.sh similarity index 100% rename from lib/vscode/resources/darwin/bin/code.sh rename to resources/darwin/bin/code.sh diff --git a/lib/vscode/resources/darwin/bower.icns b/resources/darwin/bower.icns similarity index 100% rename from lib/vscode/resources/darwin/bower.icns rename to resources/darwin/bower.icns diff --git a/lib/vscode/resources/darwin/c.icns b/resources/darwin/c.icns similarity index 100% rename from lib/vscode/resources/darwin/c.icns rename to resources/darwin/c.icns diff --git a/lib/vscode/resources/darwin/code.icns b/resources/darwin/code.icns similarity index 100% rename from lib/vscode/resources/darwin/code.icns rename to resources/darwin/code.icns diff --git a/lib/vscode/resources/darwin/config.icns b/resources/darwin/config.icns similarity index 100% rename from lib/vscode/resources/darwin/config.icns rename to resources/darwin/config.icns diff --git a/lib/vscode/resources/darwin/cpp.icns b/resources/darwin/cpp.icns similarity index 100% rename from lib/vscode/resources/darwin/cpp.icns rename to resources/darwin/cpp.icns diff --git a/lib/vscode/resources/darwin/csharp.icns b/resources/darwin/csharp.icns similarity index 100% rename from lib/vscode/resources/darwin/csharp.icns rename to resources/darwin/csharp.icns diff --git a/lib/vscode/resources/darwin/css.icns b/resources/darwin/css.icns similarity index 100% rename from lib/vscode/resources/darwin/css.icns rename to resources/darwin/css.icns diff --git a/lib/vscode/resources/darwin/default.icns b/resources/darwin/default.icns similarity index 100% rename from lib/vscode/resources/darwin/default.icns rename to resources/darwin/default.icns diff --git a/lib/vscode/resources/darwin/go.icns b/resources/darwin/go.icns similarity index 100% rename from lib/vscode/resources/darwin/go.icns rename to resources/darwin/go.icns diff --git a/lib/vscode/resources/darwin/html.icns b/resources/darwin/html.icns similarity index 100% rename from lib/vscode/resources/darwin/html.icns rename to resources/darwin/html.icns diff --git a/lib/vscode/resources/darwin/jade.icns b/resources/darwin/jade.icns similarity index 100% rename from lib/vscode/resources/darwin/jade.icns rename to resources/darwin/jade.icns diff --git a/lib/vscode/resources/darwin/java.icns b/resources/darwin/java.icns similarity index 100% rename from lib/vscode/resources/darwin/java.icns rename to resources/darwin/java.icns diff --git a/lib/vscode/resources/darwin/javascript.icns b/resources/darwin/javascript.icns similarity index 100% rename from lib/vscode/resources/darwin/javascript.icns rename to resources/darwin/javascript.icns diff --git a/lib/vscode/resources/darwin/json.icns b/resources/darwin/json.icns similarity index 100% rename from lib/vscode/resources/darwin/json.icns rename to resources/darwin/json.icns diff --git a/lib/vscode/resources/darwin/less.icns b/resources/darwin/less.icns similarity index 100% rename from lib/vscode/resources/darwin/less.icns rename to resources/darwin/less.icns diff --git a/lib/vscode/resources/darwin/markdown.icns b/resources/darwin/markdown.icns similarity index 100% rename from lib/vscode/resources/darwin/markdown.icns rename to resources/darwin/markdown.icns diff --git a/lib/vscode/resources/darwin/php.icns b/resources/darwin/php.icns similarity index 100% rename from lib/vscode/resources/darwin/php.icns rename to resources/darwin/php.icns diff --git a/lib/vscode/resources/darwin/powershell.icns b/resources/darwin/powershell.icns similarity index 100% rename from lib/vscode/resources/darwin/powershell.icns rename to resources/darwin/powershell.icns diff --git a/lib/vscode/resources/darwin/python.icns b/resources/darwin/python.icns similarity index 100% rename from lib/vscode/resources/darwin/python.icns rename to resources/darwin/python.icns diff --git a/lib/vscode/resources/darwin/react.icns b/resources/darwin/react.icns similarity index 100% rename from lib/vscode/resources/darwin/react.icns rename to resources/darwin/react.icns diff --git a/lib/vscode/resources/darwin/ruby.icns b/resources/darwin/ruby.icns similarity index 100% rename from lib/vscode/resources/darwin/ruby.icns rename to resources/darwin/ruby.icns diff --git a/lib/vscode/resources/darwin/sass.icns b/resources/darwin/sass.icns similarity index 100% rename from lib/vscode/resources/darwin/sass.icns rename to resources/darwin/sass.icns diff --git a/lib/vscode/resources/darwin/shell.icns b/resources/darwin/shell.icns similarity index 100% rename from lib/vscode/resources/darwin/shell.icns rename to resources/darwin/shell.icns diff --git a/lib/vscode/resources/darwin/sql.icns b/resources/darwin/sql.icns similarity index 100% rename from lib/vscode/resources/darwin/sql.icns rename to resources/darwin/sql.icns diff --git a/lib/vscode/resources/darwin/typescript.icns b/resources/darwin/typescript.icns similarity index 100% rename from lib/vscode/resources/darwin/typescript.icns rename to resources/darwin/typescript.icns diff --git a/lib/vscode/resources/darwin/vue.icns b/resources/darwin/vue.icns similarity index 100% rename from lib/vscode/resources/darwin/vue.icns rename to resources/darwin/vue.icns diff --git a/lib/vscode/resources/darwin/xml.icns b/resources/darwin/xml.icns similarity index 100% rename from lib/vscode/resources/darwin/xml.icns rename to resources/darwin/xml.icns diff --git a/lib/vscode/resources/darwin/yaml.icns b/resources/darwin/yaml.icns similarity index 100% rename from lib/vscode/resources/darwin/yaml.icns rename to resources/darwin/yaml.icns diff --git a/lib/vscode/resources/linux/bin/code.sh b/resources/linux/bin/code.sh similarity index 100% rename from lib/vscode/resources/linux/bin/code.sh rename to resources/linux/bin/code.sh diff --git a/lib/vscode/resources/linux/code-url-handler.desktop b/resources/linux/code-url-handler.desktop similarity index 87% rename from lib/vscode/resources/linux/code-url-handler.desktop rename to resources/linux/code-url-handler.desktop index b85525fbd042..7106e0e0969b 100644 --- a/lib/vscode/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@@ --no-sandbox --open-url %U +Exec=@@EXEC@@ --open-url %U Icon=@@ICON@@ Type=Application NoDisplay=true diff --git a/lib/vscode/resources/linux/code-workspace.xml b/resources/linux/code-workspace.xml similarity index 100% rename from lib/vscode/resources/linux/code-workspace.xml rename to resources/linux/code-workspace.xml diff --git a/lib/vscode/resources/linux/code.appdata.xml b/resources/linux/code.appdata.xml similarity index 100% rename from lib/vscode/resources/linux/code.appdata.xml rename to resources/linux/code.appdata.xml diff --git a/lib/vscode/resources/linux/code.desktop b/resources/linux/code.desktop similarity index 82% rename from lib/vscode/resources/linux/code.desktop rename to resources/linux/code.desktop index 62d6bfc47b46..ab3b79a011b7 100755 --- a/lib/vscode/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@@ --no-sandbox --unity-launch %F +Exec=@@EXEC@@ --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@@ --no-sandbox --new-window %F +Exec=@@EXEC@@ --new-window %F Icon=@@ICON@@ diff --git a/lib/vscode/resources/linux/code.png b/resources/linux/code.png similarity index 100% rename from lib/vscode/resources/linux/code.png rename to resources/linux/code.png diff --git a/lib/vscode/resources/linux/debian/control.template b/resources/linux/debian/control.template similarity index 100% rename from lib/vscode/resources/linux/debian/control.template rename to resources/linux/debian/control.template diff --git a/lib/vscode/resources/linux/debian/postinst.template b/resources/linux/debian/postinst.template similarity index 100% rename from lib/vscode/resources/linux/debian/postinst.template rename to resources/linux/debian/postinst.template diff --git a/lib/vscode/resources/linux/debian/postrm.template b/resources/linux/debian/postrm.template similarity index 100% rename from lib/vscode/resources/linux/debian/postrm.template rename to resources/linux/debian/postrm.template diff --git a/lib/vscode/resources/linux/debian/prerm.template b/resources/linux/debian/prerm.template similarity index 100% rename from lib/vscode/resources/linux/debian/prerm.template rename to resources/linux/debian/prerm.template diff --git a/lib/vscode/resources/linux/rpm/code.spec.template b/resources/linux/rpm/code.spec.template similarity index 100% rename from lib/vscode/resources/linux/rpm/code.spec.template rename to resources/linux/rpm/code.spec.template diff --git a/lib/vscode/resources/linux/rpm/code.xpm b/resources/linux/rpm/code.xpm similarity index 100% rename from lib/vscode/resources/linux/rpm/code.xpm rename to resources/linux/rpm/code.xpm diff --git a/lib/vscode/resources/linux/rpm/dependencies.json b/resources/linux/rpm/dependencies.json similarity index 100% rename from lib/vscode/resources/linux/rpm/dependencies.json rename to resources/linux/rpm/dependencies.json diff --git a/lib/vscode/resources/linux/snap/electron-launch b/resources/linux/snap/electron-launch similarity index 100% rename from lib/vscode/resources/linux/snap/electron-launch rename to resources/linux/snap/electron-launch diff --git a/lib/vscode/resources/linux/snap/snapcraft.yaml b/resources/linux/snap/snapcraft.yaml similarity index 100% rename from lib/vscode/resources/linux/snap/snapcraft.yaml rename to resources/linux/snap/snapcraft.yaml diff --git a/lib/vscode/resources/web/callback.html b/resources/web/callback.html similarity index 100% rename from lib/vscode/resources/web/callback.html rename to resources/web/callback.html diff --git a/lib/vscode/resources/web/code-web.js b/resources/web/code-web.js similarity index 100% rename from lib/vscode/resources/web/code-web.js rename to resources/web/code-web.js diff --git a/lib/vscode/resources/win32/VisualElementsManifest.xml b/resources/win32/VisualElementsManifest.xml similarity index 100% rename from lib/vscode/resources/win32/VisualElementsManifest.xml rename to resources/win32/VisualElementsManifest.xml diff --git a/lib/vscode/resources/win32/bin/code.cmd b/resources/win32/bin/code.cmd similarity index 100% rename from lib/vscode/resources/win32/bin/code.cmd rename to resources/win32/bin/code.cmd diff --git a/lib/vscode/resources/win32/bin/code.sh b/resources/win32/bin/code.sh similarity index 100% rename from lib/vscode/resources/win32/bin/code.sh rename to resources/win32/bin/code.sh diff --git a/lib/vscode/resources/win32/bower.ico b/resources/win32/bower.ico similarity index 100% rename from lib/vscode/resources/win32/bower.ico rename to resources/win32/bower.ico diff --git a/lib/vscode/resources/win32/c.ico b/resources/win32/c.ico similarity index 100% rename from lib/vscode/resources/win32/c.ico rename to resources/win32/c.ico diff --git a/lib/vscode/resources/win32/code.ico b/resources/win32/code.ico similarity index 100% rename from lib/vscode/resources/win32/code.ico rename to resources/win32/code.ico diff --git a/lib/vscode/resources/win32/code_150x150.png b/resources/win32/code_150x150.png similarity index 100% rename from lib/vscode/resources/win32/code_150x150.png rename to resources/win32/code_150x150.png diff --git a/lib/vscode/resources/win32/code_70x70.png b/resources/win32/code_70x70.png similarity index 100% rename from lib/vscode/resources/win32/code_70x70.png rename to resources/win32/code_70x70.png diff --git a/lib/vscode/resources/win32/config.ico b/resources/win32/config.ico similarity index 100% rename from lib/vscode/resources/win32/config.ico rename to resources/win32/config.ico diff --git a/lib/vscode/resources/win32/cpp.ico b/resources/win32/cpp.ico similarity index 100% rename from lib/vscode/resources/win32/cpp.ico rename to resources/win32/cpp.ico diff --git a/lib/vscode/resources/win32/csharp.ico b/resources/win32/csharp.ico similarity index 100% rename from lib/vscode/resources/win32/csharp.ico rename to resources/win32/csharp.ico diff --git a/lib/vscode/resources/win32/css.ico b/resources/win32/css.ico similarity index 100% rename from lib/vscode/resources/win32/css.ico rename to resources/win32/css.ico diff --git a/lib/vscode/resources/win32/default.ico b/resources/win32/default.ico similarity index 100% rename from lib/vscode/resources/win32/default.ico rename to resources/win32/default.ico diff --git a/lib/vscode/resources/win32/go.ico b/resources/win32/go.ico similarity index 100% rename from lib/vscode/resources/win32/go.ico rename to resources/win32/go.ico diff --git a/lib/vscode/resources/win32/html.ico b/resources/win32/html.ico similarity index 100% rename from lib/vscode/resources/win32/html.ico rename to resources/win32/html.ico diff --git a/lib/vscode/resources/win32/inno-big-100.bmp b/resources/win32/inno-big-100.bmp similarity index 100% rename from lib/vscode/resources/win32/inno-big-100.bmp rename to resources/win32/inno-big-100.bmp diff --git a/lib/vscode/resources/win32/inno-big-125.bmp b/resources/win32/inno-big-125.bmp similarity index 100% rename from lib/vscode/resources/win32/inno-big-125.bmp rename to resources/win32/inno-big-125.bmp diff --git a/lib/vscode/resources/win32/inno-big-150.bmp b/resources/win32/inno-big-150.bmp similarity index 100% rename from lib/vscode/resources/win32/inno-big-150.bmp rename to resources/win32/inno-big-150.bmp diff --git a/lib/vscode/resources/win32/inno-big-175.bmp b/resources/win32/inno-big-175.bmp similarity index 100% rename from lib/vscode/resources/win32/inno-big-175.bmp rename to resources/win32/inno-big-175.bmp diff --git a/lib/vscode/resources/win32/inno-big-200.bmp b/resources/win32/inno-big-200.bmp similarity index 100% rename from lib/vscode/resources/win32/inno-big-200.bmp rename to resources/win32/inno-big-200.bmp diff --git a/lib/vscode/resources/win32/inno-big-225.bmp b/resources/win32/inno-big-225.bmp similarity index 100% rename from lib/vscode/resources/win32/inno-big-225.bmp rename to resources/win32/inno-big-225.bmp diff --git a/lib/vscode/resources/win32/inno-big-250.bmp b/resources/win32/inno-big-250.bmp similarity index 100% rename from lib/vscode/resources/win32/inno-big-250.bmp rename to resources/win32/inno-big-250.bmp diff --git a/lib/vscode/resources/win32/inno-small-100.bmp b/resources/win32/inno-small-100.bmp similarity index 100% rename from lib/vscode/resources/win32/inno-small-100.bmp rename to resources/win32/inno-small-100.bmp diff --git a/lib/vscode/resources/win32/inno-small-125.bmp b/resources/win32/inno-small-125.bmp similarity index 100% rename from lib/vscode/resources/win32/inno-small-125.bmp rename to resources/win32/inno-small-125.bmp diff --git a/lib/vscode/resources/win32/inno-small-150.bmp b/resources/win32/inno-small-150.bmp similarity index 100% rename from lib/vscode/resources/win32/inno-small-150.bmp rename to resources/win32/inno-small-150.bmp diff --git a/lib/vscode/resources/win32/inno-small-175.bmp b/resources/win32/inno-small-175.bmp similarity index 100% rename from lib/vscode/resources/win32/inno-small-175.bmp rename to resources/win32/inno-small-175.bmp diff --git a/lib/vscode/resources/win32/inno-small-200.bmp b/resources/win32/inno-small-200.bmp similarity index 100% rename from lib/vscode/resources/win32/inno-small-200.bmp rename to resources/win32/inno-small-200.bmp diff --git a/lib/vscode/resources/win32/inno-small-225.bmp b/resources/win32/inno-small-225.bmp similarity index 100% rename from lib/vscode/resources/win32/inno-small-225.bmp rename to resources/win32/inno-small-225.bmp diff --git a/lib/vscode/resources/win32/inno-small-250.bmp b/resources/win32/inno-small-250.bmp similarity index 100% rename from lib/vscode/resources/win32/inno-small-250.bmp rename to resources/win32/inno-small-250.bmp diff --git a/lib/vscode/resources/win32/jade.ico b/resources/win32/jade.ico similarity index 100% rename from lib/vscode/resources/win32/jade.ico rename to resources/win32/jade.ico diff --git a/lib/vscode/resources/win32/java.ico b/resources/win32/java.ico similarity index 100% rename from lib/vscode/resources/win32/java.ico rename to resources/win32/java.ico diff --git a/lib/vscode/resources/win32/javascript.ico b/resources/win32/javascript.ico similarity index 100% rename from lib/vscode/resources/win32/javascript.ico rename to resources/win32/javascript.ico diff --git a/lib/vscode/resources/win32/json.ico b/resources/win32/json.ico similarity index 100% rename from lib/vscode/resources/win32/json.ico rename to resources/win32/json.ico diff --git a/lib/vscode/resources/win32/less.ico b/resources/win32/less.ico similarity index 100% rename from lib/vscode/resources/win32/less.ico rename to resources/win32/less.ico diff --git a/lib/vscode/resources/win32/markdown.ico b/resources/win32/markdown.ico similarity index 100% rename from lib/vscode/resources/win32/markdown.ico rename to resources/win32/markdown.ico diff --git a/lib/vscode/resources/win32/php.ico b/resources/win32/php.ico similarity index 100% rename from lib/vscode/resources/win32/php.ico rename to resources/win32/php.ico diff --git a/lib/vscode/resources/win32/powershell.ico b/resources/win32/powershell.ico similarity index 100% rename from lib/vscode/resources/win32/powershell.ico rename to resources/win32/powershell.ico diff --git a/lib/vscode/resources/win32/python.ico b/resources/win32/python.ico similarity index 100% rename from lib/vscode/resources/win32/python.ico rename to resources/win32/python.ico diff --git a/lib/vscode/resources/win32/react.ico b/resources/win32/react.ico similarity index 100% rename from lib/vscode/resources/win32/react.ico rename to resources/win32/react.ico diff --git a/lib/vscode/resources/win32/ruby.ico b/resources/win32/ruby.ico similarity index 100% rename from lib/vscode/resources/win32/ruby.ico rename to resources/win32/ruby.ico diff --git a/lib/vscode/resources/win32/sass.ico b/resources/win32/sass.ico similarity index 100% rename from lib/vscode/resources/win32/sass.ico rename to resources/win32/sass.ico diff --git a/lib/vscode/resources/win32/shell.ico b/resources/win32/shell.ico similarity index 100% rename from lib/vscode/resources/win32/shell.ico rename to resources/win32/shell.ico diff --git a/lib/vscode/resources/win32/sql.ico b/resources/win32/sql.ico similarity index 100% rename from lib/vscode/resources/win32/sql.ico rename to resources/win32/sql.ico diff --git a/lib/vscode/resources/win32/typescript.ico b/resources/win32/typescript.ico similarity index 100% rename from lib/vscode/resources/win32/typescript.ico rename to resources/win32/typescript.ico diff --git a/lib/vscode/resources/win32/vue.ico b/resources/win32/vue.ico similarity index 100% rename from lib/vscode/resources/win32/vue.ico rename to resources/win32/vue.ico diff --git a/lib/vscode/resources/win32/xml.ico b/resources/win32/xml.ico similarity index 100% rename from lib/vscode/resources/win32/xml.ico rename to resources/win32/xml.ico diff --git a/lib/vscode/resources/win32/yaml.ico b/resources/win32/yaml.ico similarity index 100% rename from lib/vscode/resources/win32/yaml.ico rename to resources/win32/yaml.ico diff --git a/lib/vscode/scripts/code-cli.bat b/scripts/code-cli.bat similarity index 100% rename from lib/vscode/scripts/code-cli.bat rename to scripts/code-cli.bat diff --git a/lib/vscode/scripts/code-cli.sh b/scripts/code-cli.sh similarity index 100% rename from lib/vscode/scripts/code-cli.sh rename to scripts/code-cli.sh diff --git a/lib/vscode/scripts/code.bat b/scripts/code.bat similarity index 100% rename from lib/vscode/scripts/code.bat rename to scripts/code.bat diff --git a/lib/vscode/scripts/code.sh b/scripts/code.sh similarity index 98% rename from lib/vscode/scripts/code.sh rename to scripts/code.sh index 3095f3897bf7..713040b5a27b 100755 --- a/lib/vscode/scripts/code.sh +++ b/scripts/code.sh @@ -43,7 +43,7 @@ function code() { export ELECTRON_ENABLE_LOGGING=1 # Launch Code - exec "$CODE" . --no-sandbox "$@" + exec "$CODE" . "$@" } function code-wsl() diff --git a/lib/vscode/scripts/generate-definitelytyped.sh b/scripts/generate-definitelytyped.sh similarity index 100% rename from lib/vscode/scripts/generate-definitelytyped.sh rename to scripts/generate-definitelytyped.sh diff --git a/lib/vscode/scripts/node-electron.bat b/scripts/node-electron.bat similarity index 100% rename from lib/vscode/scripts/node-electron.bat rename to scripts/node-electron.bat diff --git a/lib/vscode/scripts/node-electron.sh b/scripts/node-electron.sh similarity index 100% rename from lib/vscode/scripts/node-electron.sh rename to scripts/node-electron.sh diff --git a/lib/vscode/scripts/npm.bat b/scripts/npm.bat similarity index 100% rename from lib/vscode/scripts/npm.bat rename to scripts/npm.bat diff --git a/lib/vscode/scripts/npm.sh b/scripts/npm.sh similarity index 100% rename from lib/vscode/scripts/npm.sh rename to scripts/npm.sh diff --git a/lib/vscode/scripts/test-documentation.bat b/scripts/test-documentation.bat similarity index 100% rename from lib/vscode/scripts/test-documentation.bat rename to scripts/test-documentation.bat diff --git a/lib/vscode/scripts/test-documentation.sh b/scripts/test-documentation.sh similarity index 100% rename from lib/vscode/scripts/test-documentation.sh rename to scripts/test-documentation.sh diff --git a/lib/vscode/scripts/test-integration.bat b/scripts/test-integration.bat similarity index 100% rename from lib/vscode/scripts/test-integration.bat rename to scripts/test-integration.bat diff --git a/lib/vscode/scripts/test-integration.sh b/scripts/test-integration.sh similarity index 91% rename from lib/vscode/scripts/test-integration.sh rename to scripts/test-integration.sh index c6c116c2f679..0b2fe97b17d2 100755 --- a/lib/vscode/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -6,8 +6,10 @@ if [[ "$OSTYPE" == "darwin"* ]]; then ROOT=$(dirname $(dirname $(realpath "$0"))) else ROOT=$(dirname $(dirname $(readlink -f $0))) - # Electron 6 introduces a chrome-sandbox that requires root to run. This can fail. Disable sandbox via --no-sandbox. - LINUX_EXTRA_ARGS="--no-sandbox" + # --disable-setuid-sandbox: setuid sandboxes requires root and is used in containers so we disable this + # --disable-dev-shm-usage --use-gl=swiftshader: when run on docker containers where size of /dev/shm + # partition < 64MB which causes OOM failure for chromium compositor that uses the partition for shared memory + LINUX_EXTRA_ARGS="--disable-setuid-sandbox --disable-dev-shm-usage --use-gl=swiftshader" fi VSCODEUSERDATADIR=`mktemp -d 2>/dev/null` @@ -44,13 +46,6 @@ else export ELECTRON_ENABLE_STACK_DUMPING=1 export ELECTRON_ENABLE_LOGGING=1 - # Production builds are run on docker containers where size of /dev/shm partition < 64MB which causes OOM failure - # for chromium compositor that uses the partition for shared memory - if [ "$LINUX_EXTRA_ARGS" ] - then - LINUX_EXTRA_ARGS="$LINUX_EXTRA_ARGS --disable-dev-shm-usage --use-gl=swiftshader" - fi - echo "Storing crash reports into '$VSCODECRASHDIR'." echo "Running integration tests with '$INTEGRATION_TEST_ELECTRON_PATH' as build." fi diff --git a/lib/vscode/scripts/test.bat b/scripts/test.bat similarity index 95% rename from lib/vscode/scripts/test.bat rename to scripts/test.bat index b37aa32e0ad0..7232c26193ce 100644 --- a/lib/vscode/scripts/test.bat +++ b/scripts/test.bat @@ -12,7 +12,7 @@ set NAMESHORT=%NAMESHORT:"=%.exe set CODE=".build\electron\%NAMESHORT%" :: Download Electron if needed -node build\lib\electron.js +call node build\lib\electron.js if %errorlevel% neq 0 node .\node_modules\gulp\bin\gulp.js electron :: Run tests diff --git a/lib/vscode/scripts/test.sh b/scripts/test.sh similarity index 67% rename from lib/vscode/scripts/test.sh rename to scripts/test.sh index 7594af3d9762..68f75db60d8e 100755 --- a/lib/vscode/scripts/test.sh +++ b/scripts/test.sh @@ -6,8 +6,10 @@ if [[ "$OSTYPE" == "darwin"* ]]; then ROOT=$(dirname $(dirname $(realpath "$0"))) else ROOT=$(dirname $(dirname $(readlink -f $0))) - # Electron 6 introduces a chrome-sandbox that requires root to run. This can fail. Disable sandbox via --no-sandbox. - LINUX_EXTRA_ARGS="--no-sandbox --disable-dev-shm-usage --use-gl=swiftshader" + # --disable-setuid-sandbox: setuid sandboxes requires root and is used in containers so we disable this + # --disable-dev-shm-usage --use-gl=swiftshader: when run on docker containers where size of /dev/shm + # partition < 64MB which causes OOM failure for chromium compositor that uses the partition for shared memory + LINUX_EXTRA_ARGS="--disable-setuid-sandbox --disable-dev-shm-usage --use-gl=swiftshader" fi cd $ROOT diff --git a/lib/vscode/src/bootstrap-amd.js b/src/bootstrap-amd.js similarity index 100% rename from lib/vscode/src/bootstrap-amd.js rename to src/bootstrap-amd.js diff --git a/lib/vscode/src/bootstrap-fork.js b/src/bootstrap-fork.js similarity index 100% rename from lib/vscode/src/bootstrap-fork.js rename to src/bootstrap-fork.js diff --git a/lib/vscode/src/bootstrap-node.js b/src/bootstrap-node.js similarity index 98% rename from lib/vscode/src/bootstrap-node.js rename to src/bootstrap-node.js index b9cc3f67b84f..9a57b93333cc 100644 --- a/lib/vscode/src/bootstrap-node.js +++ b/src/bootstrap-node.js @@ -11,6 +11,7 @@ // - Posix: allow to change the current working dir via `VSCODE_CWD` if defined // - all OS: store the `process.cwd()` inside `VSCODE_CWD` for consistent lookups // TODO@bpasero revisit if chdir() on Windows is needed in the future still +// (find all users of `chdir` in code, there are more locations) function setupCurrentWorkingDirectory() { const path = require('path'); diff --git a/lib/vscode/src/bootstrap-window.js b/src/bootstrap-window.js similarity index 96% rename from lib/vscode/src/bootstrap-window.js rename to src/bootstrap-window.js index ec6693603214..270dda4cd681 100644 --- a/lib/vscode/src/bootstrap-window.js +++ b/src/bootstrap-window.js @@ -57,6 +57,11 @@ const configuration = await preloadGlobals.context.resolveConfiguration(); performance.mark('code/didWaitForWindowConfig'); + // Signal DOM modifications are now OK + if (typeof options?.canModifyDOM === 'function') { + options.canModifyDOM(configuration); + } + // Developer settings const { forceDisableShowDevtoolsOnError, @@ -79,11 +84,6 @@ // Enable ASAR support globalThis.MonacoBootstrap.enableASARSupport(configuration.appRoot); - // Signal DOM modifications are now OK - if (typeof options?.canModifyDOM === 'function') { - options.canModifyDOM(configuration); - } - // Get the nls configuration into the process.env as early as possible const nlsConfig = globalThis.MonacoBootstrap.setupNLS(); @@ -179,13 +179,6 @@ require(modulePaths, async result => { try { - // Wait for process environment being fully resolved - performance.mark('code/willWaitForShellEnv'); - if (!safeProcess.env['VSCODE_SKIP_PROCESS_ENV_PATCHING'] /* TODO@bpasero for https://github.com/microsoft/vscode/issues/108804 */) { - await safeProcess.shellEnv(); - } - performance.mark('code/didWaitForShellEnv'); - // Callback only after process environment is resolved const callbackResult = resultCallback(result, configuration); if (callbackResult instanceof Promise) { diff --git a/lib/vscode/src/bootstrap.js b/src/bootstrap.js similarity index 100% rename from lib/vscode/src/bootstrap.js rename to src/bootstrap.js diff --git a/src/browser/favicon.afdesign b/src/browser/favicon.afdesign deleted file mode 100644 index b654f32e82b1..000000000000 --- a/src/browser/favicon.afdesign +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:625d2049c38ae27df0613fa533020e889fa98affd603050f46d3748be7b90d0b -size 38675 diff --git a/src/browser/media/favicon-dark-support.svg b/src/browser/media/favicon-dark-support.svg deleted file mode 100644 index 06f1fa00d62c..000000000000 --- a/src/browser/media/favicon-dark-support.svg +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 2250 2250" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><style> -@media (prefers-color-scheme: dark) { - * { - fill: white; - } -} -</style><rect id="favicon" x="0" y="0" width="2250" height="2250" style="fill:none;"/><g id="favicon1" serif:id="favicon"><path d="M1991.66,1034.72c-38.493,0 -64.144,-22.57 -64.144,-68.897l-0,-266.084c-0,-169.867 -69.982,-263.709 -250.762,-263.709l-83.976,0l-0,179.368l25.661,0c71.144,0 104.967,39.201 104.967,109.285l0,235.201c0,102.156 30.324,143.733 96.806,165.114c-66.482,20.196 -96.806,62.958 -96.806,165.114l0,174.621c0,48.7 0,96.216 -12.829,144.917c-12.829,45.141 -33.823,87.903 -62.98,124.726c-16.329,21.386 -34.991,39.202 -55.981,55.835l-0,23.755l83.971,-0c180.781,-0 250.763,-93.843 250.763,-263.709l-0,-266.084c-0,-47.516 24.485,-68.897 64.144,-68.897l47.822,-0l-0,-179.37l-46.656,-0l0,-1.186Z" style="fill-rule:nonzero;"/><path d="M1420.16,706.904l-258.923,0c-5.833,0 -10.495,-4.752 -10.495,-10.691l-0,-20.192c-0,-5.941 4.662,-10.692 10.495,-10.692l260.089,0c5.83,0 10.495,4.751 10.495,10.692l0,20.192c0,5.939 -5.833,10.691 -11.661,10.691Z" style="fill-rule:nonzero;"/><path d="M1464.48,963.474l-188.942,0c-5.833,0 -10.501,-4.754 -10.501,-10.693l0,-20.192c0,-5.938 4.668,-10.691 10.501,-10.691l188.942,-0c5.833,-0 10.495,4.753 10.495,10.691l-0,20.192c-0,4.754 -4.662,10.693 -10.495,10.693Z" style="fill-rule:nonzero;"/><path d="M1539.12,835.188l-377.885,0c-5.833,0 -10.495,-4.75 -10.495,-10.689l-0,-20.196c-0,-5.939 4.662,-10.69 10.495,-10.69l376.719,0c5.833,0 10.499,4.751 10.499,10.69l-0,20.196c-0,4.75 -3.5,10.689 -9.333,10.689Z" style="fill-rule:nonzero;"/><path d="M861.493,765.074c25.658,0 51.319,2.376 75.811,8.316l0,-48.705c0,-68.897 34.989,-109.285 104.971,-109.285l25.658,0l-0,-179.368l-83.977,0c-180.781,0 -250.758,93.842 -250.758,263.709l0,87.901c40.819,-14.252 83.977,-22.568 128.295,-22.568Z" style="fill-rule:nonzero;"/><path d="M1618.44,1411.25c-18.662,-150.861 -132.962,-276.776 -279.919,-305.285c-40.818,-8.314 -81.642,-9.504 -121.295,-2.376c-1.166,-0 -1.166,-1.189 -2.332,-1.189c-64.148,-136.605 -201.772,-226.884 -351.063,-226.884c-149.289,-0 -285.747,87.905 -351.062,224.51c-1.166,-0 -1.166,1.188 -2.332,1.188c-41.987,-4.753 -83.975,-2.379 -125.963,8.314c-144.623,35.634 -254.257,159.175 -274.085,308.847c-2.332,15.441 -3.499,30.883 -3.499,45.141c0,45.136 30.325,86.713 74.645,92.652c54.817,8.317 102.636,-34.448 101.469,-89.089c0,-8.317 0,-17.821 1.167,-26.134c9.331,-76.025 66.48,-140.168 141.123,-157.99c23.328,-5.939 46.654,-7.124 68.814,-3.559c71.146,9.502 141.124,-27.324 171.449,-91.467c22.162,-47.516 57.151,-89.094 103.804,-111.664c51.314,-24.946 109.633,-28.506 163.286,-9.499c55.979,20.192 97.966,62.954 123.627,116.409c26.824,52.27 39.653,89.093 96.805,96.221c23.325,3.559 88.639,2.374 113.132,1.185c47.82,0 95.64,16.631 129.463,51.079c22.156,23.757 38.485,53.455 45.486,86.715c10.495,53.455 -2.334,106.908 -33.825,147.296c-22.162,28.509 -52.485,49.89 -86.308,59.394c-16.329,4.754 -32.657,5.939 -48.986,5.939l-257.757,0c-51.314,0 -92.138,-41.573 -92.138,-93.842l0,-348.049c0,-14.251 -11.661,-26.13 -25.658,-26.13l-36.156,0c-71.148,1.185 -128.295,81.964 -128.295,167.488l-0,312.415c-0,92.652 73.476,167.488 164.451,167.488c0,0 404.714,-1.19 410.544,-1.19c93.304,-9.503 179.614,-58.204 237.927,-133.04c58.319,-72.46 85.142,-167.492 73.481,-264.894Z" style="fill-rule:nonzero;"/></g></svg> \ No newline at end of file diff --git a/src/browser/media/favicon.ico b/src/browser/media/favicon.ico deleted file mode 100644 index e721447bd9d175c1e64eb6bf9a14846f8ed5f7e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4868 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 diff --git a/src/browser/media/favicon.svg b/src/browser/media/favicon.svg deleted file mode 100644 index 45388729b6b4..000000000000 --- a/src/browser/media/favicon.svg +++ /dev/null @@ -1 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 2250 2250" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><rect id="favicon" x="0" y="0" width="2250" height="2250" style="fill:none;"/><g id="favicon1" serif:id="favicon"><path d="M1991.66,1034.72c-38.493,0 -64.144,-22.57 -64.144,-68.897l-0,-266.084c-0,-169.867 -69.982,-263.709 -250.762,-263.709l-83.976,0l-0,179.368l25.661,0c71.144,0 104.967,39.201 104.967,109.285l0,235.201c0,102.156 30.324,143.733 96.806,165.114c-66.482,20.196 -96.806,62.958 -96.806,165.114l0,174.621c0,48.7 0,96.216 -12.829,144.917c-12.829,45.141 -33.823,87.903 -62.98,124.726c-16.329,21.386 -34.991,39.202 -55.981,55.835l-0,23.755l83.971,-0c180.781,-0 250.763,-93.843 250.763,-263.709l-0,-266.084c-0,-47.516 24.485,-68.897 64.144,-68.897l47.822,-0l-0,-179.37l-46.656,-0l0,-1.186Z" style="fill-rule:nonzero;"/><path d="M1420.16,706.904l-258.923,0c-5.833,0 -10.495,-4.752 -10.495,-10.691l-0,-20.192c-0,-5.941 4.662,-10.692 10.495,-10.692l260.089,0c5.83,0 10.495,4.751 10.495,10.692l0,20.192c0,5.939 -5.833,10.691 -11.661,10.691Z" style="fill-rule:nonzero;"/><path d="M1464.48,963.474l-188.942,0c-5.833,0 -10.501,-4.754 -10.501,-10.693l0,-20.192c0,-5.938 4.668,-10.691 10.501,-10.691l188.942,-0c5.833,-0 10.495,4.753 10.495,10.691l-0,20.192c-0,4.754 -4.662,10.693 -10.495,10.693Z" style="fill-rule:nonzero;"/><path d="M1539.12,835.188l-377.885,0c-5.833,0 -10.495,-4.75 -10.495,-10.689l-0,-20.196c-0,-5.939 4.662,-10.69 10.495,-10.69l376.719,0c5.833,0 10.499,4.751 10.499,10.69l-0,20.196c-0,4.75 -3.5,10.689 -9.333,10.689Z" style="fill-rule:nonzero;"/><path d="M861.493,765.074c25.658,0 51.319,2.376 75.811,8.316l0,-48.705c0,-68.897 34.989,-109.285 104.971,-109.285l25.658,0l-0,-179.368l-83.977,0c-180.781,0 -250.758,93.842 -250.758,263.709l0,87.901c40.819,-14.252 83.977,-22.568 128.295,-22.568Z" style="fill-rule:nonzero;"/><path d="M1618.44,1411.25c-18.662,-150.861 -132.962,-276.776 -279.919,-305.285c-40.818,-8.314 -81.642,-9.504 -121.295,-2.376c-1.166,-0 -1.166,-1.189 -2.332,-1.189c-64.148,-136.605 -201.772,-226.884 -351.063,-226.884c-149.289,-0 -285.747,87.905 -351.062,224.51c-1.166,-0 -1.166,1.188 -2.332,1.188c-41.987,-4.753 -83.975,-2.379 -125.963,8.314c-144.623,35.634 -254.257,159.175 -274.085,308.847c-2.332,15.441 -3.499,30.883 -3.499,45.141c0,45.136 30.325,86.713 74.645,92.652c54.817,8.317 102.636,-34.448 101.469,-89.089c0,-8.317 0,-17.821 1.167,-26.134c9.331,-76.025 66.48,-140.168 141.123,-157.99c23.328,-5.939 46.654,-7.124 68.814,-3.559c71.146,9.502 141.124,-27.324 171.449,-91.467c22.162,-47.516 57.151,-89.094 103.804,-111.664c51.314,-24.946 109.633,-28.506 163.286,-9.499c55.979,20.192 97.966,62.954 123.627,116.409c26.824,52.27 39.653,89.093 96.805,96.221c23.325,3.559 88.639,2.374 113.132,1.185c47.82,0 95.64,16.631 129.463,51.079c22.156,23.757 38.485,53.455 45.486,86.715c10.495,53.455 -2.334,106.908 -33.825,147.296c-22.162,28.509 -52.485,49.89 -86.308,59.394c-16.329,4.754 -32.657,5.939 -48.986,5.939l-257.757,0c-51.314,0 -92.138,-41.573 -92.138,-93.842l0,-348.049c0,-14.251 -11.661,-26.13 -25.658,-26.13l-36.156,0c-71.148,1.185 -128.295,81.964 -128.295,167.488l-0,312.415c-0,92.652 73.476,167.488 164.451,167.488c0,0 404.714,-1.19 410.544,-1.19c93.304,-9.503 179.614,-58.204 237.927,-133.04c58.319,-72.46 85.142,-167.492 73.481,-264.894Z" style="fill-rule:nonzero;"/></g></svg> \ No newline at end of file diff --git a/src/browser/media/manifest.json b/src/browser/media/manifest.json deleted file mode 100644 index a16709e1ee90..000000000000 --- a/src/browser/media/manifest.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "code-server", - "short_name": "code-server", - "start_url": "{{BASE}}", - "display": "fullscreen", - "background-color": "#fff", - "description": "Run editors on a remote server.", - "icons": [ - { - "src": "{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-192.png", - "type": "image/png", - "sizes": "192x192" - }, - { - "src": "{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-512.png", - "type": "image/png", - "sizes": "512x512" - } - ] -} diff --git a/src/browser/media/pwa-icon-192.png b/src/browser/media/pwa-icon-192.png deleted file mode 100644 index a6ee503115d8d4824730e125836e90cad72c6f19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5486 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 diff --git a/src/browser/media/pwa-icon-512.png b/src/browser/media/pwa-icon-512.png deleted file mode 100644 index ff42978ce9a52611d19eb011a43d830efef9647e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14689 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 diff --git a/src/browser/media/pwa-icon.png b/src/browser/media/pwa-icon.png deleted file mode 100644 index d4f5188ffc0c4c2db014367c6bed74da09f2db34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19318 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�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 F{|jCDHoE`- diff --git a/src/browser/pages/error.css b/src/browser/pages/error.css deleted file mode 100644 index 15b7d4aca532..000000000000 --- a/src/browser/pages/error.css +++ /dev/null @@ -1,32 +0,0 @@ -.error-display { - box-sizing: border-box; - padding: 20px; - text-align: center; -} - -.error-display > .header { - font-size: 6rem; - margin: 0; -} - -.error-display > .body { - color: #444; - font-size: 1.2rem; -} - -.error-display > .links { - margin-top: 16px; -} - -.error-display > .links > .link { - color: rgb(87, 114, 245); - text-decoration: none; -} - -.error-display > .links > .link:hover { - text-decoration: underline; -} - -.error-display .success { - color: green; -} diff --git a/src/browser/pages/error.html b/src/browser/pages/error.html deleted file mode 100644 index 73a9599bd6bc..000000000000 --- a/src/browser/pages/error.html +++ /dev/null @@ -1,34 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - <head> - <meta charset="utf-8" /> - <meta - name="viewport" - content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" - /> - <meta - http-equiv="Content-Security-Policy" - content="style-src 'self'; manifest-src 'self'; img-src 'self' data:; font-src 'self' data:;" - /> - <title>{{ERROR_TITLE}} - code-server - - - - - - - - - - - - - diff --git a/src/browser/pages/global.css b/src/browser/pages/global.css deleted file mode 100644 index fcc3ace34300..000000000000 --- a/src/browser/pages/global.css +++ /dev/null @@ -1,85 +0,0 @@ -html, -body, -#root { - height: 100%; - width: 100%; -} - -body { - background: rgb(244, 247, 252); - color: #111; - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", - "Segoe UI Emoji", "Segoe UI Symbol"; - overflow: hidden; -} - -input, -button { - font-family: inherit; - font-size: 1rem; - line-height: 1rem; -} - -.-button { - background-color: rgb(87, 114, 245); - border-radius: 5px; - border: none; - box-sizing: border-box; - color: white; - cursor: pointer; - padding: 18px 20px; - text-decoration: none; -} - -.center-container { - align-items: center; - box-sizing: border-box; - display: flex; - flex-direction: column; - justify-content: center; - min-height: 100%; - padding: 20px; - width: 100%; -} - -.card-box { - background-color: rgb(250, 253, 258); - border-radius: 5px; - box-shadow: rgba(60, 66, 87, 0.117647) 0px 7px 14px 0px, rgba(0, 0, 0, 0.117647) 0px 3px 6px 0px; - max-width: 650px; - width: 100%; -} - -.card-box > .header { - border-bottom: 1px solid #ddd; - color: #444; - padding: 30px; -} - -.card-box > .header > .main { - margin: 0; - font-size: 1.5rem; -} - -.card-box > .header > .sub { - color: #555; - margin-top: 10px; -} - -.card-box > .content { - padding: 40px; -} - -.card-box > .content > .none { - margin: 2px 0; -} - -.card-box + .card-box { - margin-top: 26px; -} - -canvas { - top: 0; - left: 0; -} diff --git a/src/browser/pages/login.css b/src/browser/pages/login.css deleted file mode 100644 index 026cac97f5d6..000000000000 --- a/src/browser/pages/login.css +++ /dev/null @@ -1,58 +0,0 @@ -body { - min-height: 568px; - min-width: 320px; - overflow: auto; -} - -.login-form { - display: flex; - flex-direction: column; - flex: 1; - justify-content: center; -} - -.login-form > .field { - display: flex; - flex-direction: row; - width: 100%; -} - -@media (max-width: 600px) { - .login-form > .field { - flex-direction: column; - } -} - -.login-form > .error { - color: red; - margin-top: 16px; -} - -.login-form > .field > .password { - background-color: rgb(244, 247, 252); - border-radius: 5px; - border: 1px solid #ddd; - box-sizing: border-box; - color: black; - flex: 1; - padding: 16px; -} - -.login-form > .user { - display: none; -} - -.login-form > .field > .submit { - margin-left: 20px; -} - -@media (max-width: 600px) { - .login-form > .field > .submit { - margin-left: 0px; - margin-top: 16px; - } -} - -input { - -webkit-appearance: none; -} diff --git a/src/browser/pages/login.html b/src/browser/pages/login.html deleted file mode 100644 index ef3f16a40700..000000000000 --- a/src/browser/pages/login.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - code-server login - - - - - - - - - -
    -
    -
    -

    Welcome to code-server

    -
    Please log in below. {{PASSWORD_MSG}}
    -
    -
    - -
    -
    -
    - - - - diff --git a/src/browser/pages/login.ts b/src/browser/pages/login.ts deleted file mode 100644 index c7fc92d4a0e7..000000000000 --- a/src/browser/pages/login.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { getOptions } from "../../common/util" - -const options = getOptions() -const el = document.getElementById("base") as HTMLInputElement -if (el) { - el.value = options.base -} diff --git a/src/browser/pages/vscode.html b/src/browser/pages/vscode.html deleted file mode 100644 index 48a3469940a3..000000000000 --- a/src/browser/pages/vscode.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/browser/pages/vscode.ts b/src/browser/pages/vscode.ts deleted file mode 100644 index d95e91741033..000000000000 --- a/src/browser/pages/vscode.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { getOptions } from "../../common/util" - -const options = getOptions() - -// TODO: Add proper types. -/* eslint-disable @typescript-eslint/no-explicit-any */ - -let nlsConfig: any -try { - nlsConfig = JSON.parse(document.getElementById("vscode-remote-nls-configuration")!.getAttribute("data-settings")!) - if (nlsConfig._resolvedLanguagePackCoreLocation) { - const bundles = Object.create(null) - nlsConfig.loadBundle = (bundle: any, _language: any, cb: any): void => { - const result = bundles[bundle] - if (result) { - return cb(undefined, result) - } - // FIXME: Only works if path separators are /. - const path = nlsConfig._resolvedLanguagePackCoreLocation + "/" + bundle.replace(/\//g, "!") + ".nls.json" - fetch(`${options.base}/vscode/resource/?path=${encodeURIComponent(path)}`) - .then((response) => response.json()) - .then((json) => { - bundles[bundle] = json - cb(undefined, json) - }) - .catch(cb) - } - } -} catch (error) { - /* Probably fine. */ -} - -;(self.require as any) = { - // Without the full URL VS Code will try to load file://. - baseUrl: `${window.location.origin}${options.csStaticBase}/lib/vscode/out`, - recordStats: true, - paths: { - "vscode-textmate": `../node_modules/vscode-textmate/release/main`, - "vscode-oniguruma": `../node_modules/vscode-oniguruma/release/main`, - xterm: `../node_modules/xterm/lib/xterm.js`, - "xterm-addon-search": `../node_modules/xterm-addon-search/lib/xterm-addon-search.js`, - "xterm-addon-unicode11": `../node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`, - "xterm-addon-webgl": `../node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js`, - "tas-client-umd": `../node_modules/tas-client-umd/lib/tas-client-umd.js`, - "iconv-lite-umd": `../node_modules/iconv-lite-umd/lib/iconv-lite-umd.js`, - jschardet: `../node_modules/jschardet/dist/jschardet.min.js`, - }, - "vs/nls": nlsConfig, -} - -try { - document.body.style.background = JSON.parse(localStorage.getItem("colorThemeData")!).colorMap["editor.background"] -} catch (error) { - // Oh well. -} diff --git a/src/browser/register.ts b/src/browser/register.ts deleted file mode 100644 index b4f4dc6c8876..000000000000 --- a/src/browser/register.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { logger } from "@coder/logger" -import { getOptions, normalize, logError } from "../common/util" - -import "./pages/error.css" -import "./pages/global.css" -import "./pages/login.css" - -export async function registerServiceWorker(): Promise { - const options = getOptions() - logger.level = options.logLevel - - const path = normalize(`${options.csStaticBase}/dist/serviceWorker.js`) - try { - await navigator.serviceWorker.register(path, { - scope: options.base + "/", - }) - logger.info(`[Service Worker] registered`) - } catch (error) { - logError(logger, `[Service Worker] registration`, error) - } -} - -if (typeof navigator !== "undefined" && "serviceWorker" in navigator) { - registerServiceWorker() -} else { - logger.error(`[Service Worker] navigator is undefined`) -} diff --git a/src/browser/robots.txt b/src/browser/robots.txt deleted file mode 100644 index 1f53798bb4fe..000000000000 --- a/src/browser/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: / diff --git a/src/browser/serviceWorker.ts b/src/browser/serviceWorker.ts deleted file mode 100644 index 25765a1a4a68..000000000000 --- a/src/browser/serviceWorker.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -self.addEventListener("install", () => { - console.log("[Service Worker] installed") -}) - -self.addEventListener("activate", (event: any) => { - event.waitUntil((self as any).clients.claim()) - console.log("[Service Worker] activated") -}) - -self.addEventListener("fetch", () => { - // Without this event handler we won't be recognized as a PWA. -}) diff --git a/lib/vscode/src/buildfile.js b/src/buildfile.js similarity index 100% rename from lib/vscode/src/buildfile.js rename to src/buildfile.js diff --git a/lib/vscode/src/cli.js b/src/cli.js similarity index 100% rename from lib/vscode/src/cli.js rename to src/cli.js diff --git a/src/common/emitter.ts b/src/common/emitter.ts deleted file mode 100644 index 353ce851e825..000000000000 --- a/src/common/emitter.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { logger } from "@coder/logger" - -/** - * Event emitter callback. Called with the emitted value and a promise that - * resolves when all emitters have finished. - */ -export type Callback> = (t: T, p: Promise) => R - -export interface Disposable { - dispose(): void -} - -export interface Event { - (listener: Callback): Disposable -} - -/** - * Emitter typecasts for a single event type. - */ -export class Emitter { - private listeners: Array> = [] - - public get event(): Event { - return (cb: Callback): Disposable => { - this.listeners.push(cb) - - return { - dispose: (): void => { - const i = this.listeners.indexOf(cb) - if (i !== -1) { - this.listeners.splice(i, 1) - } - }, - } - } - } - - /** - * Emit an event with a value. - */ - public async emit(value: T): Promise { - let resolve: () => void - const promise = new Promise((r) => (resolve = r)) - - await Promise.all( - this.listeners.map(async (cb) => { - try { - await cb(value, promise) - } catch (error) { - logger.error(error.message) - } - }), - ) - - resolve!() - } - - public dispose(): void { - this.listeners = [] - } -} diff --git a/src/common/http.ts b/src/common/http.ts deleted file mode 100644 index c08c8673b477..000000000000 --- a/src/common/http.ts +++ /dev/null @@ -1,20 +0,0 @@ -export enum HttpCode { - Ok = 200, - Redirect = 302, - NotFound = 404, - BadRequest = 400, - Unauthorized = 401, - LargePayload = 413, - ServerError = 500, -} - -/** - * Represents an error with a message and an HTTP status code. This code will be - * used in the HTTP response. - */ -export class HttpError extends Error { - public constructor(message: string, public readonly status: HttpCode, public readonly details?: object) { - super(message) - this.name = this.constructor.name - } -} diff --git a/src/common/util.ts b/src/common/util.ts deleted file mode 100644 index 4e4f23cfd818..000000000000 --- a/src/common/util.ts +++ /dev/null @@ -1,130 +0,0 @@ -/* - * This file exists in two locations: - * - src/common/util.ts - * - lib/vscode/src/vs/server/common/util.ts - * The second is a symlink to the first. - */ - -/** - * Base options included on every page. - */ -export interface Options { - base: string - csStaticBase: string - logLevel: number -} - -/** - * Split a string up to the delimiter. If the delimiter doesn't exist the first - * item will have all the text and the second item will be an empty string. - */ -export const split = (str: string, delimiter: string): [string, string] => { - const index = str.indexOf(delimiter) - return index !== -1 ? [str.substring(0, index).trim(), str.substring(index + 1)] : [str, ""] -} - -/** - * Appends an 's' to the provided string if count is greater than one; - * otherwise the string is returned - */ -export const plural = (count: number, str: string): string => (count === 1 ? str : `${str}s`) - -export const generateUuid = (length = 24): string => { - const possible = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - return Array(length) - .fill(1) - .map(() => possible[Math.floor(Math.random() * possible.length)]) - .join("") -} - -/** - * Remove extra slashes in a URL. - */ -export const normalize = (url: string, keepTrailing = false): string => { - return url.replace(/\/\/+/g, "/").replace(/\/+$/, keepTrailing ? "/" : "") -} - -/** - * Remove leading and trailing slashes. - */ -export const trimSlashes = (url: string): string => { - return url.replace(/^\/+|\/+$/g, "") -} - -/** - * Resolve a relative base against the window location. This is used for - * anything that doesn't work with a relative path. - */ -export const resolveBase = (base?: string): string => { - // After resolving the base will either start with / or be an empty string. - if (!base || base.startsWith("/")) { - return base ?? "" - } - const parts = location.pathname.split("/") - parts[parts.length - 1] = base - const url = new URL(location.origin + "/" + parts.join("/")) - return normalize(url.pathname) -} - -/** - * Get options embedded in the HTML or query params. - */ -export const getOptions = (): T => { - let options: T - try { - options = JSON.parse(document.getElementById("coder-options")!.getAttribute("data-settings")!) - } catch (error) { - options = {} as T - } - - // You can also pass options in stringified form to the options query - // variable. Options provided here will override the ones in the options - // element. - const params = new URLSearchParams(location.search) - const queryOpts = params.get("options") - if (queryOpts) { - options = { - ...options, - ...JSON.parse(queryOpts), - } - } - - options.base = resolveBase(options.base) - options.csStaticBase = resolveBase(options.csStaticBase) - - return options -} - -/** - * Wrap the value in an array if it's not already an array. If the value is - * undefined return an empty array. - */ -export const arrayify = (value?: T | T[]): T[] => { - if (Array.isArray(value)) { - return value - } - if (typeof value === "undefined") { - return [] - } - return [value] -} - -/** - * Get the first string. If there's no string return undefined. - */ -export const getFirstString = (value: string | string[] | object | undefined): string | undefined => { - if (Array.isArray(value)) { - return value[0] - } - - return typeof value === "string" ? value : undefined -} - -// TODO: Might make sense to add Error handling to the logger itself. -export function logError(logger: { error: (msg: string) => void }, prefix: string, err: Error | string): void { - if (err instanceof Error) { - logger.error(`${prefix}: ${err.message} ${err.stack}`) - } else { - logger.error(`${prefix}: ${err}`) - } -} diff --git a/lib/vscode/src/main.js b/src/main.js similarity index 100% rename from lib/vscode/src/main.js rename to src/main.js diff --git a/src/node/app.ts b/src/node/app.ts deleted file mode 100644 index 97ad62c3fe4c..000000000000 --- a/src/node/app.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { logger } from "@coder/logger" -import compression from "compression" -import express, { Express } from "express" -import { promises as fs } from "fs" -import http from "http" -import * as httpolyglot from "httpolyglot" -import * as util from "../common/util" -import { DefaultedArgs } from "./cli" -import { handleUpgrade } from "./wsRouter" - -/** - * Create an Express app and an HTTP/S server to serve it. - */ -export const createApp = async (args: DefaultedArgs): Promise<[Express, Express, http.Server]> => { - const app = express() - - app.use(compression()) - - const server = args.cert - ? httpolyglot.createServer( - { - cert: args.cert && (await fs.readFile(args.cert.value)), - key: args["cert-key"] && (await fs.readFile(args["cert-key"])), - }, - app, - ) - : http.createServer(app) - - let resolved = false - await new Promise(async (resolve2, reject) => { - const resolve = () => { - resolved = true - resolve2() - } - server.on("error", (err) => { - if (!resolved) { - reject(err) - } else { - // Promise resolved earlier so this is an unrelated error. - util.logError(logger, "http server error", err) - } - }) - - if (args.socket) { - try { - await fs.unlink(args.socket) - } catch (error) { - if (error.code !== "ENOENT") { - logger.error(error.message) - } - } - server.listen(args.socket, resolve) - } else { - // [] is the correct format when using :: but Node errors with them. - server.listen(args.port, args.host.replace(/^\[|\]$/g, ""), resolve) - } - }) - - const wsApp = express() - handleUpgrade(wsApp, server) - - return [app, wsApp, server] -} - -/** - * Get the address of a server as a string (protocol *is* included) while - * ensuring there is one (will throw if there isn't). - */ -export const ensureAddress = (server: http.Server): string => { - const addr = server.address() - if (!addr) { - throw new Error("server has no address") - } - if (typeof addr !== "string") { - return `http://${addr.address}:${addr.port}` - } - return addr -} diff --git a/src/node/cli.ts b/src/node/cli.ts deleted file mode 100644 index 461a2e186faf..000000000000 --- a/src/node/cli.ts +++ /dev/null @@ -1,652 +0,0 @@ -import { field, Level, logger } from "@coder/logger" -import { promises as fs } from "fs" -import yaml from "js-yaml" -import * as os from "os" -import * as path from "path" -import { Args as VsArgs } from "../../typings/ipc" -import { canConnect, generateCertificate, generatePassword, humanPath, paths } from "./util" - -export enum AuthType { - Password = "password", - None = "none", -} - -export class Optional { - public constructor(public readonly value?: T) {} -} - -export enum LogLevel { - Trace = "trace", - Debug = "debug", - Info = "info", - Warn = "warn", - Error = "error", -} - -export class OptionalString extends Optional {} - -export interface Args extends VsArgs { - config?: string - auth?: AuthType - password?: string - "hashed-password"?: string - cert?: OptionalString - "cert-host"?: string - "cert-key"?: string - "disable-telemetry"?: boolean - "disable-update-check"?: boolean - help?: boolean - host?: string - json?: boolean - log?: LogLevel - open?: boolean - port?: number - "bind-addr"?: string - socket?: string - version?: boolean - force?: boolean - "list-extensions"?: boolean - "install-extension"?: string[] - "show-versions"?: boolean - "uninstall-extension"?: string[] - "proxy-domain"?: string[] - locale?: string - _: string[] - "reuse-window"?: boolean - "new-window"?: boolean - - link?: OptionalString -} - -interface Option { - type: T - /** - * Short flag for the option. - */ - short?: string - /** - * Whether the option is a path and should be resolved. - */ - path?: boolean - /** - * Description of the option. Leave blank to hide the option. - */ - description?: string - - /** - * If marked as beta, the option is marked as beta in help. - */ - beta?: boolean -} - -type OptionType = T extends boolean - ? "boolean" - : T extends OptionalString - ? typeof OptionalString - : T extends LogLevel - ? typeof LogLevel - : T extends AuthType - ? typeof AuthType - : T extends number - ? "number" - : T extends string - ? "string" - : T extends string[] - ? "string[]" - : "unknown" - -type Options = { - [P in keyof T]: Option> -} - -const options: Options> = { - auth: { type: AuthType, description: "The type of authentication to use." }, - password: { - type: "string", - description: "The password for password authentication (can only be passed in via $PASSWORD or the config file).", - }, - "hashed-password": { - type: "string", - description: - "The password hashed with SHA-256 for password authentication (can only be passed in via $HASHED_PASSWORD or the config file). \n" + - "Takes precedence over 'password'.", - }, - cert: { - type: OptionalString, - path: true, - description: "Path to certificate. A self signed certificate is generated if none is provided.", - }, - "cert-host": { - type: "string", - description: "Hostname to use when generating a self signed certificate.", - }, - "cert-key": { type: "string", path: true, description: "Path to certificate key when using non-generated cert." }, - "disable-telemetry": { type: "boolean", description: "Disable telemetry." }, - "disable-update-check": { - type: "boolean", - description: - "Disable update check. Without this flag, code-server checks every 6 hours against the latest github release and \n" + - "then notifies you once every week that a new release is available.", - }, - help: { type: "boolean", short: "h", description: "Show this output." }, - json: { type: "boolean" }, - open: { type: "boolean", description: "Open in browser on startup. Does not work remotely." }, - - "bind-addr": { - type: "string", - description: "Address to bind to in host:port. You can also use $PORT to override the port.", - }, - - config: { - type: "string", - description: "Path to yaml config file. Every flag maps directly to a key in the config file.", - }, - - // These two have been deprecated by bindAddr. - host: { type: "string", description: "" }, - port: { type: "number", description: "" }, - - socket: { type: "string", path: true, description: "Path to a socket (bind-addr will be ignored)." }, - version: { type: "boolean", short: "v", description: "Display version information." }, - _: { type: "string[]" }, - - "user-data-dir": { type: "string", path: true, description: "Path to the user data directory." }, - "extensions-dir": { type: "string", path: true, description: "Path to the extensions directory." }, - "builtin-extensions-dir": { type: "string", path: true }, - "extra-extensions-dir": { type: "string[]", path: true }, - "extra-builtin-extensions-dir": { type: "string[]", path: true }, - "list-extensions": { type: "boolean", description: "List installed VS Code extensions." }, - force: { type: "boolean", description: "Avoid prompts when installing VS Code extensions." }, - "install-extension": { - type: "string[]", - description: - "Install or update a VS Code extension by id or vsix. The identifier of an extension is `${publisher}.${name}`.\n" + - "To install a specific version provide `@${version}`. For example: 'vscode.csharp@1.2.3'.", - }, - "enable-proposed-api": { - type: "string[]", - description: - "Enable proposed API features for extensions. Can receive one or more extension IDs to enable individually.", - }, - "uninstall-extension": { type: "string[]", description: "Uninstall a VS Code extension by id." }, - "show-versions": { type: "boolean", description: "Show VS Code extension versions." }, - "proxy-domain": { type: "string[]", description: "Domain used for proxying ports." }, - "ignore-last-opened": { - type: "boolean", - short: "e", - description: "Ignore the last opened directory or workspace in favor of an empty window.", - }, - "new-window": { - type: "boolean", - short: "n", - description: "Force to open a new window.", - }, - "reuse-window": { - type: "boolean", - short: "r", - description: "Force to open a file or folder in an already opened window.", - }, - - locale: { type: "string" }, - log: { type: LogLevel }, - verbose: { type: "boolean", short: "vvv", description: "Enable verbose logging." }, - - link: { - type: OptionalString, - description: ` - Securely bind code-server via our cloud service with the passed name. You'll get a URL like - https://hostname-username.cdr.co at which you can easily access your code-server instance. - Authorization is done via GitHub. - `, - beta: true, - }, -} - -export const optionDescriptions = (): string[] => { - const entries = Object.entries(options).filter(([, v]) => !!v.description) - const widths = entries.reduce( - (prev, [k, v]) => ({ - long: k.length > prev.long ? k.length : prev.long, - short: v.short && v.short.length > prev.short ? v.short.length : prev.short, - }), - { short: 0, long: 0 }, - ) - return entries.map(([k, v]) => { - const help = `${" ".repeat(widths.short - (v.short ? v.short.length : 0))}${v.short ? `-${v.short}` : " "} --${k} ` - return ( - help + - v.description - ?.trim() - .split(/\n/) - .map((line, i) => { - line = line.trim() - if (i === 0) { - return " ".repeat(widths.long - k.length) + (v.beta ? "(beta) " : "") + line - } - return " ".repeat(widths.long + widths.short + 6) + line - }) - .join("\n") + - (typeof v.type === "object" ? ` [${Object.values(v.type).join(", ")}]` : "") - ) - }) -} - -export const parse = ( - argv: string[], - opts?: { - configFile?: string - }, -): Args => { - const error = (msg: string): Error => { - if (opts?.configFile) { - msg = `error reading ${opts.configFile}: ${msg}` - } - return new Error(msg) - } - - const args: Args = { _: [] } - let ended = false - - for (let i = 0; i < argv.length; ++i) { - const arg = argv[i] - - // -- signals the end of option parsing. - if (!ended && arg === "--") { - ended = true - continue - } - - // Options start with a dash and require a value if non-boolean. - if (!ended && arg.startsWith("-")) { - let key: keyof Args | undefined - let value: string | undefined - if (arg.startsWith("--")) { - const split = arg.replace(/^--/, "").split("=", 2) - key = split[0] as keyof Args - value = split[1] - } else { - const short = arg.replace(/^-/, "") - const pair = Object.entries(options).find(([, v]) => v.short === short) - if (pair) { - key = pair[0] as keyof Args - } - } - - if (!key || !options[key]) { - throw error(`Unknown option ${arg}`) - } - - if (key === "password" && !opts?.configFile) { - throw new Error("--password can only be set in the config file or passed in via $PASSWORD") - } - - if (key === "hashed-password" && !opts?.configFile) { - throw new Error("--hashed-password can only be set in the config file or passed in via $HASHED_PASSWORD") - } - - const option = options[key] - if (option.type === "boolean") { - ;(args[key] as boolean) = true - continue - } - - // Might already have a value if it was the --long=value format. - if (typeof value === "undefined") { - // A value is only valid if it doesn't look like an option. - value = argv[i + 1] && !argv[i + 1].startsWith("-") ? argv[++i] : undefined - } - - if (!value && option.type === OptionalString) { - ;(args[key] as OptionalString) = new OptionalString(value) - continue - } else if (!value) { - throw error(`--${key} requires a value`) - } - - if (option.type === OptionalString && value === "false") { - continue - } - - if (option.path) { - value = path.resolve(value) - } - - switch (option.type) { - case "string": - ;(args[key] as string) = value - break - case "string[]": - if (!args[key]) { - ;(args[key] as string[]) = [] - } - ;(args[key] as string[]).push(value) - break - case "number": - ;(args[key] as number) = parseInt(value, 10) - if (isNaN(args[key] as number)) { - throw error(`--${key} must be a number`) - } - break - case OptionalString: - ;(args[key] as OptionalString) = new OptionalString(value) - break - default: { - if (!Object.values(option.type).includes(value)) { - throw error(`--${key} valid values: [${Object.values(option.type).join(", ")}]`) - } - ;(args[key] as string) = value - break - } - } - - continue - } - - // Everything else goes into _. - args._.push(arg) - } - - // If a cert was provided a key must also be provided. - if (args.cert && args.cert.value && !args["cert-key"]) { - throw new Error("--cert-key is missing") - } - - logger.debug(() => ["parsed command line", field("args", { ...args, password: undefined })]) - - return args -} - -export interface DefaultedArgs extends ConfigArgs { - auth: AuthType - cert?: { - value: string - } - host: string - port: number - "proxy-domain": string[] - verbose: boolean - usingEnvPassword: boolean - usingEnvHashedPassword: boolean - "extensions-dir": string - "user-data-dir": string -} - -/** - * Take CLI and config arguments (optional) and return a single set of arguments - * with the defaults set. Arguments from the CLI are prioritized over config - * arguments. - */ -export async function setDefaults(cliArgs: Args, configArgs?: ConfigArgs): Promise { - const args = Object.assign({}, configArgs || {}, cliArgs) - - if (!args["user-data-dir"]) { - args["user-data-dir"] = paths.data - } - - if (!args["extensions-dir"]) { - args["extensions-dir"] = path.join(args["user-data-dir"], "extensions") - } - - // --verbose takes priority over --log and --log takes priority over the - // environment variable. - if (args.verbose) { - args.log = LogLevel.Trace - } else if ( - !args.log && - process.env.LOG_LEVEL && - Object.values(LogLevel).includes(process.env.LOG_LEVEL as LogLevel) - ) { - args.log = process.env.LOG_LEVEL as LogLevel - } - - // Sync --log, --verbose, the environment variable, and logger level. - if (args.log) { - process.env.LOG_LEVEL = args.log - } - switch (args.log) { - case LogLevel.Trace: - logger.level = Level.Trace - args.verbose = true - break - case LogLevel.Debug: - logger.level = Level.Debug - args.verbose = false - break - case LogLevel.Info: - logger.level = Level.Info - args.verbose = false - break - case LogLevel.Warn: - logger.level = Level.Warning - args.verbose = false - break - case LogLevel.Error: - logger.level = Level.Error - args.verbose = false - break - } - - // Default to using a password. - if (!args.auth) { - args.auth = AuthType.Password - } - - const addr = bindAddrFromAllSources(configArgs || { _: [] }, cliArgs) - args.host = addr.host - args.port = addr.port - - // If we're being exposed to the cloud, we listen on a random address and - // disable auth. - if (args.link) { - args.host = "localhost" - args.port = 0 - args.socket = undefined - args.cert = undefined - args.auth = AuthType.None - } - - if (args.cert && !args.cert.value) { - const { cert, certKey } = await generateCertificate(args["cert-host"] || "localhost") - args.cert = { - value: cert, - } - args["cert-key"] = certKey - } - - let usingEnvPassword = !!process.env.PASSWORD - if (process.env.PASSWORD) { - args.password = process.env.PASSWORD - } - - const usingEnvHashedPassword = !!process.env.HASHED_PASSWORD - if (process.env.HASHED_PASSWORD) { - args["hashed-password"] = process.env.HASHED_PASSWORD - usingEnvPassword = false - } - - // Ensure they're not readable by child processes. - delete process.env.PASSWORD - delete process.env.HASHED_PASSWORD - - // Filter duplicate proxy domains and remove any leading `*.`. - const proxyDomains = new Set((args["proxy-domain"] || []).map((d) => d.replace(/^\*\./, ""))) - args["proxy-domain"] = Array.from(proxyDomains) - - return { - ...args, - usingEnvPassword, - usingEnvHashedPassword, - } as DefaultedArgs // TODO: Technically no guarantee this is fulfilled. -} - -async function defaultConfigFile(): Promise { - return `bind-addr: 127.0.0.1:8080 -auth: password -password: ${await generatePassword()} -cert: false -` -} - -interface ConfigArgs extends Args { - config: string -} - -/** - * Reads the code-server yaml config file and returns it as Args. - * - * @param configPath Read the config from configPath instead of $CODE_SERVER_CONFIG or the default. - */ -export async function readConfigFile(configPath?: string): Promise { - if (!configPath) { - configPath = process.env.CODE_SERVER_CONFIG - if (!configPath) { - configPath = path.join(paths.config, "config.yaml") - } - } - - await fs.mkdir(path.dirname(configPath), { recursive: true }) - - try { - await fs.writeFile(configPath, await defaultConfigFile(), { - flag: "wx", // wx means to fail if the path exists. - }) - logger.info(`Wrote default config file to ${humanPath(configPath)}`) - } catch (error) { - // EEXIST is fine; we don't want to overwrite existing configurations. - if (error.code !== "EEXIST") { - throw error - } - } - - const configFile = await fs.readFile(configPath, "utf8") - return parseConfigFile(configFile, configPath) -} - -/** - * parseConfigFile parses configFile into ConfigArgs. - * configPath is used as the filename in error messages - */ -export function parseConfigFile(configFile: string, configPath: string): ConfigArgs { - if (!configFile) { - return { _: [], config: configPath } - } - - const config = yaml.load(configFile, { - filename: configPath, - }) - if (!config || typeof config === "string") { - throw new Error(`invalid config: ${config}`) - } - - // We convert the config file into a set of flags. - // This is a temporary measure until we add a proper CLI library. - const configFileArgv = Object.entries(config).map(([optName, opt]) => { - if (opt === true) { - return `--${optName}` - } - return `--${optName}=${opt}` - }) - const args = parse(configFileArgv, { - configFile: configPath, - }) - return { - ...args, - config: configPath, - } -} - -function parseBindAddr(bindAddr: string): Addr { - const u = new URL(`http://${bindAddr}`) - return { - host: u.hostname, - // With the http scheme 80 will be dropped so assume it's 80 if missing. - // This means --bind-addr without a port will default to 80 as well - // and not the code-server default. - port: u.port ? parseInt(u.port, 10) : 80, - } -} - -interface Addr { - host: string - port: number -} - -function bindAddrFromArgs(addr: Addr, args: Args): Addr { - addr = { ...addr } - if (args["bind-addr"]) { - addr = parseBindAddr(args["bind-addr"]) - } - if (args.host) { - addr.host = args.host - } - - if (process.env.PORT) { - addr.port = parseInt(process.env.PORT, 10) - } - if (args.port !== undefined) { - addr.port = args.port - } - return addr -} - -function bindAddrFromAllSources(...argsConfig: Args[]): Addr { - let addr: Addr = { - host: "localhost", - port: 8080, - } - - for (const args of argsConfig) { - addr = bindAddrFromArgs(addr, args) - } - - return addr -} - -export const shouldRunVsCodeCli = (args: Args): boolean => { - return !!args["list-extensions"] || !!args["install-extension"] || !!args["uninstall-extension"] -} - -/** - * Determine if it looks like the user is trying to open a file or folder in an - * existing instance. The arguments here should be the arguments the user - * explicitly passed on the command line, not defaults or the configuration. - */ -export const shouldOpenInExistingInstance = async (args: Args): Promise => { - // Always use the existing instance if we're running from VS Code's terminal. - if (process.env.VSCODE_IPC_HOOK_CLI) { - return process.env.VSCODE_IPC_HOOK_CLI - } - - const readSocketPath = async (): Promise => { - try { - return await fs.readFile(path.join(os.tmpdir(), "vscode-ipc"), "utf8") - } catch (error) { - if (error.code !== "ENOENT") { - throw error - } - } - return undefined - } - - // If these flags are set then assume the user is trying to open in an - // existing instance since these flags have no effect otherwise. - const openInFlagCount = ["reuse-window", "new-window"].reduce((prev, cur) => { - return args[cur as keyof Args] ? prev + 1 : prev - }, 0) - if (openInFlagCount > 0) { - return readSocketPath() - } - - // It's possible the user is trying to spawn another instance of code-server. - // Check if any unrelated flags are set (check against one because `_` always - // exists), that a file or directory was passed, and that the socket is - // active. - if (Object.keys(args).length === 1 && args._.length > 0) { - const socketPath = await readSocketPath() - if (socketPath && (await canConnect(socketPath))) { - return socketPath - } - } - - return undefined -} diff --git a/src/node/coder_cloud.ts b/src/node/coder_cloud.ts deleted file mode 100644 index 7bca6342a6de..000000000000 --- a/src/node/coder_cloud.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { logger } from "@coder/logger" -import { spawn } from "child_process" -import path from "path" -import split2 from "split2" - -// https://github.com/cdr/coder-cloud -const coderCloudAgent = path.resolve(__dirname, "../../lib/coder-cloud-agent") - -function runAgent(...args: string[]): Promise { - logger.debug(`running agent with ${args}`) - - const agent = spawn(coderCloudAgent, args, { - stdio: ["inherit", "inherit", "pipe"], - }) - - agent.stderr.pipe(split2()).on("data", (line) => { - line = line.replace(/^[0-9-]+ [0-9:]+ [^ ]+\t/, "") - logger.info(line) - }) - - return new Promise((res, rej) => { - agent.on("error", rej) - - agent.on("close", (code) => { - if (code !== 0) { - rej({ - message: `--link agent exited with ${code}`, - }) - return - } - res() - }) - }) -} - -export function coderCloudBind(csAddr: string, serverName = ""): Promise { - // addr needs to be in host:port format. - // So we trim the protocol. - csAddr = csAddr.replace(/^https?:\/\//, "") - return runAgent("bind", `--code-server-addr=${csAddr}`, serverName) -} diff --git a/src/node/constants.ts b/src/node/constants.ts deleted file mode 100644 index c198f8fb3929..000000000000 --- a/src/node/constants.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { logger } from "@coder/logger" -import { JSONSchemaForNPMPackageJsonFiles } from "@schemastore/package" -import * as os from "os" -import * as path from "path" - -export function getPackageJson(relativePath: string): JSONSchemaForNPMPackageJsonFiles { - let pkg = {} - try { - pkg = require(relativePath) - } catch (error) { - logger.warn(error.message) - } - - return pkg -} - -const pkg = getPackageJson("../../package.json") - -export const version = pkg.version || "development" -export const commit = pkg.commit || "development" -export const rootPath = path.resolve(__dirname, "../..") -export const tmpdir = path.join(os.tmpdir(), "code-server") diff --git a/src/node/entry.ts b/src/node/entry.ts deleted file mode 100644 index b7b61b8f4dde..000000000000 --- a/src/node/entry.ts +++ /dev/null @@ -1,220 +0,0 @@ -import { field, logger } from "@coder/logger" -import * as cp from "child_process" -import http from "http" -import * as path from "path" -import { CliMessage, OpenCommandPipeArgs } from "../../typings/ipc" -import { plural } from "../common/util" -import { createApp, ensureAddress } from "./app" -import { - AuthType, - DefaultedArgs, - optionDescriptions, - parse, - readConfigFile, - setDefaults, - shouldOpenInExistingInstance, - shouldRunVsCodeCli, -} from "./cli" -import { coderCloudBind } from "./coder_cloud" -import { commit, version } from "./constants" -import * as proxyAgent from "./proxy_agent" -import { register } from "./routes" -import { humanPath, isFile, open } from "./util" -import { isChild, wrapper } from "./wrapper" - -export const runVsCodeCli = (args: DefaultedArgs): void => { - logger.debug("forking vs code cli...") - const vscode = cp.fork(path.resolve(__dirname, "../../lib/vscode/out/vs/server/fork"), [], { - env: { - ...process.env, - CODE_SERVER_PARENT_PID: process.pid.toString(), - }, - }) - vscode.once("message", (message: any) => { - logger.debug("got message from VS Code", field("message", message)) - if (message.type !== "ready") { - logger.error("Unexpected response waiting for ready response", field("type", message.type)) - process.exit(1) - } - const send: CliMessage = { type: "cli", args } - vscode.send(send) - }) - vscode.once("error", (error) => { - logger.error("Got error from VS Code", field("error", error)) - process.exit(1) - }) - vscode.on("exit", (code) => process.exit(code || 0)) -} - -export const openInExistingInstance = async (args: DefaultedArgs, socketPath: string): Promise => { - const pipeArgs: OpenCommandPipeArgs & { fileURIs: string[] } = { - type: "open", - folderURIs: [], - fileURIs: [], - forceReuseWindow: args["reuse-window"], - forceNewWindow: args["new-window"], - } - - for (let i = 0; i < args._.length; i++) { - const fp = path.resolve(args._[i]) - if (await isFile(fp)) { - pipeArgs.fileURIs.push(fp) - } else { - pipeArgs.folderURIs.push(fp) - } - } - - if (pipeArgs.forceNewWindow && pipeArgs.fileURIs.length > 0) { - logger.error("--new-window can only be used with folder paths") - process.exit(1) - } - - if (pipeArgs.folderURIs.length === 0 && pipeArgs.fileURIs.length === 0) { - logger.error("Please specify at least one file or folder") - process.exit(1) - } - - const vscode = http.request( - { - path: "/", - method: "POST", - socketPath, - }, - (response) => { - response.on("data", (message) => { - logger.debug("got message from VS Code", field("message", message.toString())) - }) - }, - ) - vscode.on("error", (error: unknown) => { - logger.error("got error from VS Code", field("error", error)) - }) - vscode.write(JSON.stringify(pipeArgs)) - vscode.end() -} - -const main = async (args: DefaultedArgs): Promise => { - logger.info(`code-server ${version} ${commit}`) - - logger.info(`Using user-data-dir ${humanPath(args["user-data-dir"])}`) - logger.trace(`Using extensions-dir ${humanPath(args["extensions-dir"])}`) - - if (args.auth === AuthType.Password && !args.password && !args["hashed-password"]) { - throw new Error( - "Please pass in a password via the config file or environment variable ($PASSWORD or $HASHED_PASSWORD)", - ) - } - - const [app, wsApp, server] = await createApp(args) - const serverAddress = ensureAddress(server) - await register(app, wsApp, server, args) - - logger.info(`Using config file ${humanPath(args.config)}`) - logger.info(`HTTP server listening on ${serverAddress} ${args.link ? "(randomized by --link)" : ""}`) - - if (args.auth === AuthType.Password) { - logger.info(" - Authentication is enabled") - if (args.usingEnvPassword) { - logger.info(" - Using password from $PASSWORD") - } else if (args.usingEnvHashedPassword) { - logger.info(" - Using password from $HASHED_PASSWORD") - } else { - logger.info(` - Using password from ${humanPath(args.config)}`) - } - } else { - logger.info(` - Authentication is disabled ${args.link ? "(disabled by --link)" : ""}`) - } - - if (args.cert) { - logger.info(` - Using certificate for HTTPS: ${humanPath(args.cert.value)}`) - } else { - logger.info(` - Not serving HTTPS ${args.link ? "(disabled by --link)" : ""}`) - } - - if (args["proxy-domain"].length > 0) { - logger.info(` - ${plural(args["proxy-domain"].length, "Proxying the following domain")}:`) - args["proxy-domain"].forEach((domain) => logger.info(` - *.${domain}`)) - } - - if (args.link) { - try { - await coderCloudBind(serverAddress.replace(/^https?:\/\//, ""), args.link.value) - logger.info(" - Connected to cloud agent") - } catch (err) { - logger.error(err.message) - wrapper.exit(1) - } - } - - if (!args.socket && args.open) { - // The web socket doesn't seem to work if browsing with 0.0.0.0. - const openAddress = serverAddress.replace("://0.0.0.0", "://localhost") - try { - await open(openAddress) - logger.info(`Opened ${openAddress}`) - } catch (error) { - logger.error("Failed to open", field("address", openAddress), field("error", error)) - } - } -} - -async function entry(): Promise { - proxyAgent.monkeyPatch(false) - - // There's no need to check flags like --help or to spawn in an existing - // instance for the child process because these would have already happened in - // the parent and the child wouldn't have been spawned. We also get the - // arguments from the parent so we don't have to parse twice and to account - // for environment manipulation (like how PASSWORD gets removed to avoid - // leaking to child processes). - if (isChild(wrapper)) { - const args = await wrapper.handshake() - wrapper.preventExit() - return main(args) - } - - const cliArgs = parse(process.argv.slice(2)) - const configArgs = await readConfigFile(cliArgs.config) - const args = await setDefaults(cliArgs, configArgs) - - if (args.help) { - console.log("code-server", version, commit) - console.log("") - console.log(`Usage: code-server [options] [path]`) - console.log("") - console.log("Options") - optionDescriptions().forEach((description) => { - console.log("", description) - }) - return - } - - if (args.version) { - if (args.json) { - console.log({ - codeServer: version, - commit, - vscode: require("../../lib/vscode/package.json").version, - }) - } else { - console.log(version, commit) - } - return - } - - if (shouldRunVsCodeCli(args)) { - return runVsCodeCli(args) - } - - const socketPath = await shouldOpenInExistingInstance(cliArgs) - if (socketPath) { - return openInExistingInstance(args, socketPath) - } - - return wrapper.start(args) -} - -entry().catch((error) => { - logger.error(error.message) - wrapper.exit(error) -}) diff --git a/src/node/heart.ts b/src/node/heart.ts deleted file mode 100644 index 1eada79b3a70..000000000000 --- a/src/node/heart.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { logger } from "@coder/logger" -import { promises as fs } from "fs" - -/** - * Provides a heartbeat using a local file to indicate activity. - */ -export class Heart { - private heartbeatTimer?: NodeJS.Timeout - private heartbeatInterval = 60000 - public lastHeartbeat = 0 - - public constructor(private readonly heartbeatPath: string, private readonly isActive: () => Promise) {} - - public alive(): boolean { - const now = Date.now() - return now - this.lastHeartbeat < this.heartbeatInterval - } - /** - * Write to the heartbeat file if we haven't already done so within the - * timeout and start or reset a timer that keeps running as long as there is - * activity. Failures are logged as warnings. - */ - public beat(): void { - if (this.alive()) { - return - } - - logger.trace("heartbeat") - fs.writeFile(this.heartbeatPath, "").catch((error) => { - logger.warn(error.message) - }) - this.lastHeartbeat = Date.now() - if (typeof this.heartbeatTimer !== "undefined") { - clearTimeout(this.heartbeatTimer) - } - this.heartbeatTimer = setTimeout(() => { - this.isActive() - .then((active) => { - if (active) { - this.beat() - } - }) - .catch((error) => { - logger.warn(error.message) - }) - }, this.heartbeatInterval) - } - - /** - * Call to clear any heartbeatTimer for shutdown. - */ - public dispose(): void { - if (typeof this.heartbeatTimer !== "undefined") { - clearTimeout(this.heartbeatTimer) - } - } -} diff --git a/src/node/http.ts b/src/node/http.ts deleted file mode 100644 index eb8c91f94218..000000000000 --- a/src/node/http.ts +++ /dev/null @@ -1,160 +0,0 @@ -import { field, logger } from "@coder/logger" -import * as express from "express" -import * as expressCore from "express-serve-static-core" -import qs from "qs" -import safeCompare from "safe-compare" -import { HttpCode, HttpError } from "../common/http" -import { normalize, Options } from "../common/util" -import { AuthType, DefaultedArgs } from "./cli" -import { commit, rootPath } from "./constants" -import { Heart } from "./heart" -import { hash } from "./util" - -declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace Express { - export interface Request { - args: DefaultedArgs - heart: Heart - } - } -} - -/** - * Replace common variable strings in HTML templates. - */ -export const replaceTemplates = ( - req: express.Request, - content: string, - extraOpts?: Omit, -): string => { - const base = relativeRoot(req) - const options: Options = { - base, - csStaticBase: base + "/static/" + commit + rootPath, - logLevel: logger.level, - ...extraOpts, - } - return content - .replace(/{{TO}}/g, (typeof req.query.to === "string" && req.query.to) || "/") - .replace(/{{BASE}}/g, options.base) - .replace(/{{CS_STATIC_BASE}}/g, options.csStaticBase) - .replace(/"{{OPTIONS}}"/, `'${JSON.stringify(options)}'`) -} - -/** - * Throw an error if not authorized. Call `next` if provided. - */ -export const ensureAuthenticated = (req: express.Request, _?: express.Response, next?: express.NextFunction): void => { - if (!authenticated(req)) { - throw new HttpError("Unauthorized", HttpCode.Unauthorized) - } - if (next) { - next() - } -} - -/** - * Return true if authenticated via cookies. - */ -export const authenticated = (req: express.Request): boolean => { - switch (req.args.auth) { - case AuthType.None: - return true - case AuthType.Password: - // The password is stored in the cookie after being hashed. - return !!( - req.cookies.key && - (req.args["hashed-password"] - ? safeCompare(req.cookies.key, req.args["hashed-password"]) - : req.args.password && safeCompare(req.cookies.key, hash(req.args.password))) - ) - default: - throw new Error(`Unsupported auth type ${req.args.auth}`) - } -} - -/** - * Get the relative path that will get us to the root of the page. For each - * slash we need to go up a directory. For example: - * / => . - * /foo => . - * /foo/ => ./.. - * /foo/bar => ./.. - * /foo/bar/ => ./../.. - */ -export const relativeRoot = (req: express.Request): string => { - const depth = (req.originalUrl.split("?", 1)[0].match(/\//g) || []).length - return normalize("./" + (depth > 1 ? "../".repeat(depth - 1) : "")) -} - -/** - * Redirect relatively to `/${to}`. Query variables will be preserved. - * `override` will merge with the existing query (use `undefined` to unset). - */ -export const redirect = ( - req: express.Request, - res: express.Response, - to: string, - override: expressCore.Query = {}, -): void => { - const query = Object.assign({}, req.query, override) - Object.keys(override).forEach((key) => { - if (typeof override[key] === "undefined") { - delete query[key] - } - }) - - const relativePath = normalize(`${relativeRoot(req)}/${to}`, true) - const queryString = qs.stringify(query) - const redirectPath = `${relativePath}${queryString ? `?${queryString}` : ""}` - logger.debug(`redirecting from ${req.originalUrl} to ${redirectPath}`) - res.redirect(redirectPath) -} - -/** - * Get the value that should be used for setting a cookie domain. This will - * allow the user to authenticate once no matter what sub-domain they use to log - * in. This will use the highest level proxy domain (e.g. `coder.com` over - * `test.coder.com` if both are specified). - */ -export const getCookieDomain = (host: string, proxyDomains: string[]): string | undefined => { - const idx = host.lastIndexOf(":") - host = idx !== -1 ? host.substring(0, idx) : host - // If any of these are true we will still set cookies but without an explicit - // `Domain` attribute on the cookie. - if ( - // The host can be be blank or missing so there's nothing we can set. - !host || - // IP addresses can't have subdomains so there's no value in setting the - // domain for them. Assume that anything with a : is ipv6 (valid domain name - // characters are alphanumeric or dashes)... - host.includes(":") || - // ...and that anything entirely numbers and dots is ipv4 (currently tlds - // cannot be entirely numbers). - !/[^0-9.]/.test(host) || - // localhost subdomains don't seem to work at all (browser bug?). A cookie - // set at dev.localhost cannot be read by 8080.dev.localhost. - host.endsWith(".localhost") || - // Domains without at least one dot (technically two since domain.tld will - // become .domain.tld) are considered invalid according to the spec so don't - // set the domain for them. In my testing though localhost is the only - // problem (the browser just doesn't store the cookie at all). localhost has - // an additional problem which is that a reverse proxy might give - // code-server localhost even though the domain is really domain.tld (by - // default NGINX does this). - !host.includes(".") - ) { - logger.debug("no valid cookie doman", field("host", host)) - return undefined - } - - proxyDomains.forEach((domain) => { - if (host.endsWith(domain) && domain.length < host.length) { - host = domain - } - }) - - logger.debug("got cookie doman", field("host", host)) - return host || undefined -} diff --git a/src/node/plugin.ts b/src/node/plugin.ts deleted file mode 100644 index 036e118e88c9..000000000000 --- a/src/node/plugin.ts +++ /dev/null @@ -1,302 +0,0 @@ -import { field, Level, Logger } from "@coder/logger" -import * as express from "express" -import * as fs from "fs" -import * as path from "path" -import * as semver from "semver" -import * as pluginapi from "../../typings/pluginapi" -import { HttpCode, HttpError } from "../common/http" -import { version } from "./constants" -import { authenticated, ensureAuthenticated, replaceTemplates } from "./http" -import { proxy } from "./proxy" -import * as util from "./util" -import { Router as WsRouter, WebsocketRouter, wss } from "./wsRouter" -const fsp = fs.promises - -// Represents a required module which could be anything. -type Module = any - -/** - * Inject code-server when `require`d. This is required because the API provides - * more than just types so these need to be provided at run-time. - */ -const originalLoad = require("module")._load -require("module")._load = function (request: string, parent: object, isMain: boolean): Module { - return request === "code-server" ? codeServer : originalLoad.apply(this, [request, parent, isMain]) -} - -/** - * The module you get when importing "code-server". - */ -export const codeServer = { - HttpCode, - HttpError, - Level, - authenticated, - ensureAuthenticated, - express, - field, - proxy, - replaceTemplates, - WsRouter, - wss, -} - -interface Plugin extends pluginapi.Plugin { - /** - * These fields are populated from the plugin's package.json - * and now guaranteed to exist. - */ - name: string - version: string - - /** - * path to the node module on the disk. - */ - modulePath: string -} - -interface Application extends pluginapi.Application { - /* - * Clone of the above without functions. - */ - plugin: Omit -} - -/** - * PluginAPI implements the plugin API described in typings/pluginapi.d.ts - * Please see that file for details. - */ -export class PluginAPI { - private readonly plugins = new Map() - private readonly logger: Logger - - public constructor( - logger: Logger, - /** - * These correspond to $CS_PLUGIN_PATH and $CS_PLUGIN respectively. - */ - private readonly csPlugin = "", - private readonly csPluginPath = `${path.join(util.paths.data, "plugins")}:/usr/share/code-server/plugins`, - private readonly workingDirectory: string | undefined = undefined, - ) { - this.logger = logger.named("pluginapi") - } - - /** - * applications grabs the full list of applications from - * all loaded plugins. - */ - public async applications(): Promise { - const apps = new Array() - for (const [, p] of this.plugins) { - if (!p.applications) { - continue - } - const pluginApps = await p.applications() - - // Add plugin key to each app. - apps.push( - ...pluginApps.map((app) => { - app = { ...app, path: path.join(p.routerPath, app.path || "") } - app = { ...app, iconPath: path.join(app.path || "", app.iconPath) } - return { - ...app, - plugin: { - name: p.name, - version: p.version, - modulePath: p.modulePath, - - displayName: p.displayName, - description: p.description, - routerPath: p.routerPath, - homepageURL: p.homepageURL, - }, - } - }), - ) - } - return apps - } - - /** - * mount mounts all plugin routers onto r and websocket routers onto wr. - */ - public mount(r: express.Router, wr: express.Router): void { - for (const [, p] of this.plugins) { - if (p.router) { - r.use(`${p.routerPath}`, p.router()) - } - if (p.wsRouter) { - wr.use(`${p.routerPath}`, (p.wsRouter() as WebsocketRouter).router) - } - } - } - - /** - * loadPlugins loads all plugins based on this.csPlugin, - * this.csPluginPath and the built in plugins. - */ - public async loadPlugins(loadBuiltin = true): Promise { - for (const dir of this.csPlugin.split(":")) { - if (!dir) { - continue - } - await this.loadPlugin(dir) - } - - for (const dir of this.csPluginPath.split(":")) { - if (!dir) { - continue - } - await this._loadPlugins(dir) - } - - if (loadBuiltin) { - await this._loadPlugins(path.join(__dirname, "../../plugins")) - } - } - - /** - * _loadPlugins is the counterpart to loadPlugins. - * - * It differs in that it loads all plugins in a single - * directory whereas loadPlugins uses all available directories - * as documented. - */ - private async _loadPlugins(dir: string): Promise { - try { - const entries = await fsp.readdir(dir, { withFileTypes: true }) - for (const ent of entries) { - if (!ent.isDirectory()) { - continue - } - await this.loadPlugin(path.join(dir, ent.name)) - } - } catch (err) { - if (err.code !== "ENOENT") { - this.logger.warn(`failed to load plugins from ${q(dir)}: ${err.message}`) - } - } - } - - private async loadPlugin(dir: string): Promise { - try { - const str = await fsp.readFile(path.join(dir, "package.json"), { - encoding: "utf8", - }) - const packageJSON: PackageJSON = JSON.parse(str) - for (const [, p] of this.plugins) { - if (p.name === packageJSON.name) { - this.logger.warn( - `ignoring duplicate plugin ${q(p.name)} at ${q(dir)}, using previously loaded ${q(p.modulePath)}`, - ) - return - } - } - const p = this._loadPlugin(dir, packageJSON) - this.plugins.set(p.name, p) - } catch (err) { - if (err.code !== "ENOENT") { - this.logger.warn(`failed to load plugin: ${err.stack}`) - } - } - } - - /** - * _loadPlugin is the counterpart to loadPlugin and actually - * loads the plugin now that we know there is no duplicate - * and that the package.json has been read. - */ - private _loadPlugin(dir: string, packageJSON: PackageJSON): Plugin { - dir = path.resolve(dir) - - const logger = this.logger.named(packageJSON.name) - logger.debug("loading plugin", field("plugin_dir", dir), field("package_json", packageJSON)) - - if (!packageJSON.name) { - throw new Error("plugin package.json missing name") - } - if (!packageJSON.version) { - throw new Error("plugin package.json missing version") - } - if (!packageJSON.engines || !packageJSON.engines["code-server"]) { - throw new Error(`plugin package.json missing code-server range like: - "engines": { - "code-server": "^3.7.0" - } -`) - } - if (!semver.satisfies(version, packageJSON.engines["code-server"])) { - throw new Error( - `plugin range ${q(packageJSON.engines["code-server"])} incompatible` + ` with code-server version ${version}`, - ) - } - - const pluginModule = require(dir) - if (!pluginModule.plugin) { - throw new Error("plugin module does not export a plugin") - } - - const p = { - name: packageJSON.name, - version: packageJSON.version, - modulePath: dir, - ...pluginModule.plugin, - } as Plugin - - if (!p.displayName) { - throw new Error("plugin missing displayName") - } - if (!p.description) { - throw new Error("plugin missing description") - } - if (!p.routerPath) { - throw new Error("plugin missing router path") - } - if (!p.routerPath.startsWith("/")) { - throw new Error(`plugin router path ${q(p.routerPath)}: invalid`) - } - if (!p.homepageURL) { - throw new Error("plugin missing homepage") - } - - p.init({ - logger: logger, - workingDirectory: this.workingDirectory, - }) - - logger.debug("loaded") - - return p - } - - public async dispose(): Promise { - await Promise.all( - Array.from(this.plugins.values()).map(async (p) => { - if (!p.deinit) { - return - } - try { - await p.deinit() - } catch (error) { - this.logger.error("plugin failed to deinit", field("name", p.name), field("error", error.message)) - } - }), - ) - } -} - -interface PackageJSON { - name: string - version: string - engines: { - "code-server": string - } -} - -function q(s: string | undefined): string { - if (s === undefined) { - s = "undefined" - } - return JSON.stringify(s) -} diff --git a/src/node/proxy.ts b/src/node/proxy.ts deleted file mode 100644 index c03d3d5d4cbf..000000000000 --- a/src/node/proxy.ts +++ /dev/null @@ -1,17 +0,0 @@ -import proxyServer from "http-proxy" -import { HttpCode } from "../common/http" - -export const proxy = proxyServer.createProxyServer({}) - -proxy.on("error", (error, _, res) => { - res.writeHead(HttpCode.ServerError) - res.end(error.message) -}) - -// Intercept the response to rewrite absolute redirects against the base path. -// Is disabled when the request has no base path which means /absproxy is in use. -proxy.on("proxyRes", (res, req) => { - if (res.headers.location && res.headers.location.startsWith("/") && (req as any).base) { - res.headers.location = (req as any).base + res.headers.location - } -}) diff --git a/src/node/proxy_agent.ts b/src/node/proxy_agent.ts deleted file mode 100644 index 416a9786884b..000000000000 --- a/src/node/proxy_agent.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { logger } from "@coder/logger" -import * as http from "http" -import * as proxyAgent from "proxy-agent" -import * as proxyFromEnv from "proxy-from-env" - -/** - * This file has nothing to do with the code-server proxy. - * It is to support $HTTP_PROXY, $HTTPS_PROXY and $NO_PROXY. - * - * - https://github.com/cdr/code-server/issues/124 - * - https://www.npmjs.com/package/proxy-agent - * - https://www.npmjs.com/package/proxy-from-env - * - * This file exists in two locations: - * - src/node/proxy_agent.ts - * - lib/vscode/src/vs/base/node/proxy_agent.ts - * The second is a symlink to the first. - */ - -/** - * monkeyPatch patches the node http,https modules to route all requests through the - * agent we get from the proxy-agent package. - * - * This approach only works if there is no code specifying an explicit agent when making - * a request. - * - * None of our code ever passes in a explicit agent to the http,https modules. - * VS Code's does sometimes but only when a user sets the http.proxy configuration. - * See https://code.visualstudio.com/docs/setup/network#_legacy-proxy-server-support - * - * Even if they do, it's probably the same proxy so we should be fine! And those knobs - * are deprecated anyway. - */ -export function monkeyPatch(inVSCode: boolean): void { - if (shouldEnableProxy()) { - const http = require("http") - const https = require("https") - - // If we do not pass in a proxy URL, proxy-agent will get the URL from the environment. - // See https://www.npmjs.com/package/proxy-from-env. - // Also see shouldEnableProxy. - const pa = newProxyAgent(inVSCode) - http.globalAgent = pa - https.globalAgent = pa - } -} - -function newProxyAgent(inVSCode: boolean): http.Agent { - // The reasoning for this split is that VS Code's build process does not have - // esModuleInterop enabled but the code-server one does. As a result depending on where - // we execute, we either have a default attribute or we don't. - // - // I can't enable esModuleInterop in VS Code's build process as it breaks and spits out - // a huge number of errors. And we can't use require as otherwise the modules won't be - // included in the final product. - if (inVSCode) { - return new (proxyAgent as any)() - } else { - return new (proxyAgent as any).default() - } -} - -// If they have $NO_PROXY set to example.com then this check won't work! -// But that's drastically unlikely. -function shouldEnableProxy(): boolean { - let shouldEnable = false - - const httpProxy = proxyFromEnv.getProxyForUrl(`http://example.com`) - if (httpProxy) { - shouldEnable = true - logger.debug(`using $HTTP_PROXY ${httpProxy}`) - } - - const httpsProxy = proxyFromEnv.getProxyForUrl(`https://example.com`) - if (httpsProxy) { - shouldEnable = true - logger.debug(`using $HTTPS_PROXY ${httpsProxy}`) - } - - return shouldEnable -} diff --git a/src/node/routes/apps.ts b/src/node/routes/apps.ts deleted file mode 100644 index 5c8541fc9ad4..000000000000 --- a/src/node/routes/apps.ts +++ /dev/null @@ -1,17 +0,0 @@ -import * as express from "express" -import { PluginAPI } from "../plugin" - -/** - * Implements the /api/applications endpoint - * - * See typings/pluginapi.d.ts for details. - */ -export function router(papi: PluginAPI): express.Router { - const router = express.Router() - - router.get("/", async (req, res) => { - res.json(await papi.applications()) - }) - - return router -} diff --git a/src/node/routes/domainProxy.ts b/src/node/routes/domainProxy.ts deleted file mode 100644 index 6b527255ac39..000000000000 --- a/src/node/routes/domainProxy.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Request, Router } from "express" -import { HttpCode, HttpError } from "../../common/http" -import { normalize } from "../../common/util" -import { authenticated, ensureAuthenticated, redirect } from "../http" -import { proxy } from "../proxy" -import { Router as WsRouter } from "../wsRouter" - -export const router = Router() - -/** - * Return the port if the request should be proxied. Anything that ends in a - * proxy domain and has a *single* subdomain should be proxied. Anything else - * should return `undefined` and will be handled as normal. - * - * For example if `coder.com` is specified `8080.coder.com` will be proxied - * but `8080.test.coder.com` and `test.8080.coder.com` will not. - */ -const maybeProxy = (req: Request): string | undefined => { - // Split into parts. - const host = req.headers.host || "" - const idx = host.indexOf(":") - const domain = idx !== -1 ? host.substring(0, idx) : host - const parts = domain.split(".") - - // There must be an exact match. - const port = parts.shift() - const proxyDomain = parts.join(".") - if (!port || !req.args["proxy-domain"].includes(proxyDomain)) { - return undefined - } - - return port -} - -router.all("*", (req, res, next) => { - const port = maybeProxy(req) - if (!port) { - return next() - } - - // Must be authenticated to use the proxy. - if (!authenticated(req)) { - // Let the assets through since they're used on the login page. - if (req.path.startsWith("/static/") && req.method === "GET") { - return next() - } - - // Assume anything that explicitly accepts text/html is a user browsing a - // page (as opposed to an xhr request). Don't use `req.accepts()` since - // *every* request that I've seen (in Firefox and Chromium at least) - // includes `*/*` making it always truthy. Even for css/javascript. - if (req.headers.accept && req.headers.accept.includes("text/html")) { - // Let the login through. - if (/\/login\/?/.test(req.path)) { - return next() - } - // Redirect all other pages to the login. - const to = normalize(`${req.baseUrl}${req.path}`) - return redirect(req, res, "login", { - to: to !== "/" ? to : undefined, - }) - } - - // Everything else gets an unauthorized message. - throw new HttpError("Unauthorized", HttpCode.Unauthorized) - } - - proxy.web(req, res, { - ignorePath: true, - target: `http://0.0.0.0:${port}${req.originalUrl}`, - }) -}) - -export const wsRouter = WsRouter() - -wsRouter.ws("*", (req, _, next) => { - const port = maybeProxy(req) - if (!port) { - return next() - } - - // Must be authenticated to use the proxy. - ensureAuthenticated(req) - - proxy.ws(req, req.ws, req.head, { - ignorePath: true, - target: `http://0.0.0.0:${port}${req.originalUrl}`, - }) -}) diff --git a/src/node/routes/health.ts b/src/node/routes/health.ts deleted file mode 100644 index faf1f9c75141..000000000000 --- a/src/node/routes/health.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Router } from "express" -import { wss, Router as WsRouter } from "../wsRouter" - -export const router = Router() - -router.get("/", (req, res) => { - res.json({ - status: req.heart.alive() ? "alive" : "expired", - lastHeartbeat: req.heart.lastHeartbeat, - }) -}) - -export const wsRouter = WsRouter() - -wsRouter.ws("/", async (req) => { - wss.handleUpgrade(req, req.ws, req.head, (ws) => { - ws.addEventListener("message", () => { - ws.send( - JSON.stringify({ - event: "health", - status: req.heart.alive() ? "alive" : "expired", - lastHeartbeat: req.heart.lastHeartbeat, - }), - ) - }) - req.ws.resume() - }) -}) diff --git a/src/node/routes/index.ts b/src/node/routes/index.ts deleted file mode 100644 index c183b42b10cb..000000000000 --- a/src/node/routes/index.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { logger } from "@coder/logger" -import bodyParser from "body-parser" -import cookieParser from "cookie-parser" -import * as express from "express" -import { promises as fs } from "fs" -import http from "http" -import * as path from "path" -import * as tls from "tls" -import * as pluginapi from "../../../typings/pluginapi" -import { HttpCode, HttpError } from "../../common/http" -import { plural } from "../../common/util" -import { AuthType, DefaultedArgs } from "../cli" -import { rootPath } from "../constants" -import { Heart } from "../heart" -import { ensureAuthenticated, redirect, replaceTemplates } from "../http" -import { PluginAPI } from "../plugin" -import { getMediaMime, paths } from "../util" -import { wrapper } from "../wrapper" -import * as apps from "./apps" -import * as domainProxy from "./domainProxy" -import * as health from "./health" -import * as login from "./login" -import * as logout from "./logout" -import * as pathProxy from "./pathProxy" -// static is a reserved keyword. -import * as _static from "./static" -import * as update from "./update" -import * as vscode from "./vscode" - -/** - * Register all routes and middleware. - */ -export const register = async ( - app: express.Express, - wsApp: express.Express, - server: http.Server, - args: DefaultedArgs, -): Promise => { - const heart = new Heart(path.join(paths.data, "heartbeat"), async () => { - return new Promise((resolve, reject) => { - server.getConnections((error, count) => { - if (error) { - return reject(error) - } - logger.debug(plural(count, `${count} active connection`)) - resolve(count > 0) - }) - }) - }) - server.on("close", () => { - heart.dispose() - }) - - app.disable("x-powered-by") - wsApp.disable("x-powered-by") - - app.use(cookieParser()) - wsApp.use(cookieParser()) - - const common: express.RequestHandler = (req, _, next) => { - // /healthz|/healthz/ needs to be excluded otherwise health checks will make - // it look like code-server is always in use. - if (!/^\/healthz\/?$/.test(req.url)) { - heart.beat() - } - - // Add common variables routes can use. - req.args = args - req.heart = heart - - next() - } - - app.use(common) - wsApp.use(common) - - app.use(async (req, res, next) => { - // If we're handling TLS ensure all requests are redirected to HTTPS. - // TODO: This does *NOT* work if you have a base path since to specify the - // protocol we need to specify the whole path. - if (args.cert && !(req.connection as tls.TLSSocket).encrypted) { - return res.redirect(`https://${req.headers.host}${req.originalUrl}`) - } - - // Return robots.txt. - if (req.originalUrl === "/robots.txt") { - const resourcePath = path.resolve(rootPath, "src/browser/robots.txt") - res.set("Content-Type", getMediaMime(resourcePath)) - return res.send(await fs.readFile(resourcePath)) - } - - next() - }) - - app.use("/", domainProxy.router) - wsApp.use("/", domainProxy.wsRouter.router) - - app.all("/proxy/(:port)(/*)?", (req, res) => { - pathProxy.proxy(req, res) - }) - wsApp.get("/proxy/(:port)(/*)?", (req) => { - pathProxy.wsProxy(req as pluginapi.WebsocketRequest) - }) - // These two routes pass through the path directly. - // So the proxied app must be aware it is running - // under /absproxy// - app.all("/absproxy/(:port)(/*)?", (req, res) => { - pathProxy.proxy(req, res, { - passthroughPath: true, - }) - }) - wsApp.get("/absproxy/(:port)(/*)?", (req) => { - pathProxy.wsProxy(req as pluginapi.WebsocketRequest, { - passthroughPath: true, - }) - }) - - if (!process.env.CS_DISABLE_PLUGINS) { - const workingDir = args._ && args._.length > 0 ? path.resolve(args._[args._.length - 1]) : undefined - const pluginApi = new PluginAPI(logger, process.env.CS_PLUGIN, process.env.CS_PLUGIN_PATH, workingDir) - await pluginApi.loadPlugins() - pluginApi.mount(app, wsApp) - app.use("/api/applications", ensureAuthenticated, apps.router(pluginApi)) - wrapper.onDispose(() => pluginApi.dispose()) - } - - app.use(bodyParser.json()) - app.use(bodyParser.urlencoded({ extended: true })) - - app.use("/", vscode.router) - wsApp.use("/", vscode.wsRouter.router) - app.use("/vscode", vscode.router) - wsApp.use("/vscode", vscode.wsRouter.router) - - app.use("/healthz", health.router) - wsApp.use("/healthz", health.wsRouter.router) - - if (args.auth === AuthType.Password) { - app.use("/login", login.router) - app.use("/logout", logout.router) - } else { - app.all("/login", (req, res) => redirect(req, res, "/", {})) - app.all("/logout", (req, res) => redirect(req, res, "/", {})) - } - - app.use("/static", _static.router) - app.use("/update", update.router) - - app.use(() => { - throw new HttpError("Not Found", HttpCode.NotFound) - }) - - const errorHandler: express.ErrorRequestHandler = async (err, req, res, next) => { - if (err.code === "ENOENT" || err.code === "EISDIR") { - err.status = HttpCode.NotFound - } - - const status = err.status ?? err.statusCode ?? 500 - res.status(status) - - // Assume anything that explicitly accepts text/html is a user browsing a - // page (as opposed to an xhr request). Don't use `req.accepts()` since - // *every* request that I've seen (in Firefox and Chromium at least) - // includes `*/*` making it always truthy. Even for css/javascript. - if (req.headers.accept && req.headers.accept.includes("text/html")) { - const resourcePath = path.resolve(rootPath, "src/browser/pages/error.html") - res.set("Content-Type", getMediaMime(resourcePath)) - const content = await fs.readFile(resourcePath, "utf8") - res.send( - replaceTemplates(req, content) - .replace(/{{ERROR_TITLE}}/g, status) - .replace(/{{ERROR_HEADER}}/g, status) - .replace(/{{ERROR_BODY}}/g, err.message), - ) - } else { - res.json({ - error: err.message, - ...(err.details || {}), - }) - } - } - - app.use(errorHandler) - - const wsErrorHandler: express.ErrorRequestHandler = async (err, req, res, next) => { - logger.error(`${err.message} ${err.stack}`) - ;(req as pluginapi.WebsocketRequest).ws.end() - } - - wsApp.use(wsErrorHandler) -} diff --git a/src/node/routes/login.ts b/src/node/routes/login.ts deleted file mode 100644 index 017b88307f2f..000000000000 --- a/src/node/routes/login.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { Router, Request } from "express" -import { promises as fs } from "fs" -import { RateLimiter as Limiter } from "limiter" -import * as path from "path" -import safeCompare from "safe-compare" -import { rootPath } from "../constants" -import { authenticated, getCookieDomain, redirect, replaceTemplates } from "../http" -import { hash, humanPath } from "../util" - -export enum Cookie { - Key = "key", -} - -// RateLimiter wraps around the limiter library for logins. -// It allows 2 logins every minute plus 12 logins every hour. -export class RateLimiter { - private readonly minuteLimiter = new Limiter(2, "minute") - private readonly hourLimiter = new Limiter(12, "hour") - - public canTry(): boolean { - // Note: we must check using >= 1 because technically when there are no tokens left - // you get back a number like 0.00013333333333333334 - // which would cause fail if the logic were > 0 - return this.minuteLimiter.getTokensRemaining() >= 1 || this.hourLimiter.getTokensRemaining() >= 1 - } - - public removeToken(): boolean { - return this.minuteLimiter.tryRemoveTokens(1) || this.hourLimiter.tryRemoveTokens(1) - } -} - -const getRoot = async (req: Request, error?: Error): Promise => { - const content = await fs.readFile(path.join(rootPath, "src/browser/pages/login.html"), "utf8") - let passwordMsg = `Check the config file at ${humanPath(req.args.config)} for the password.` - if (req.args.usingEnvPassword) { - passwordMsg = "Password was set from $PASSWORD." - } else if (req.args.usingEnvHashedPassword) { - passwordMsg = "Password was set from $HASHED_PASSWORD." - } - return replaceTemplates( - req, - content - .replace(/{{PASSWORD_MSG}}/g, passwordMsg) - .replace(/{{ERROR}}/, error ? `
    ${error.message}
    ` : ""), - ) -} - -const limiter = new RateLimiter() - -export const router = Router() - -router.use((req, res, next) => { - const to = (typeof req.query.to === "string" && req.query.to) || "/" - if (authenticated(req)) { - return redirect(req, res, to, { to: undefined }) - } - next() -}) - -router.get("/", async (req, res) => { - res.send(await getRoot(req)) -}) - -router.post("/", async (req, res) => { - try { - // Check to see if they exceeded their login attempts - if (!limiter.canTry()) { - throw new Error("Login rate limited!") - } - - if (!req.body.password) { - throw new Error("Missing password") - } - - if ( - req.args["hashed-password"] - ? safeCompare(hash(req.body.password), req.args["hashed-password"]) - : req.args.password && safeCompare(req.body.password, req.args.password) - ) { - // The hash does not add any actual security but we do it for - // obfuscation purposes (and as a side effect it handles escaping). - res.cookie(Cookie.Key, hash(req.body.password), { - domain: getCookieDomain(req.headers.host || "", req.args["proxy-domain"]), - path: req.body.base || "/", - sameSite: "lax", - }) - - const to = (typeof req.query.to === "string" && req.query.to) || "/" - return redirect(req, res, to, { to: undefined }) - } - - // Note: successful logins should not count against the RateLimiter - // which is why this logic must come after the successful login logic - limiter.removeToken() - - console.error( - "Failed login attempt", - JSON.stringify({ - xForwardedFor: req.headers["x-forwarded-for"], - remoteAddress: req.connection.remoteAddress, - userAgent: req.headers["user-agent"], - timestamp: Math.floor(new Date().getTime() / 1000), - }), - ) - - throw new Error("Incorrect password") - } catch (error) { - res.send(await getRoot(req, error)) - } -}) diff --git a/src/node/routes/logout.ts b/src/node/routes/logout.ts deleted file mode 100644 index e42789b48e23..000000000000 --- a/src/node/routes/logout.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Router } from "express" -import { getCookieDomain, redirect } from "../http" -import { Cookie } from "./login" - -export const router = Router() - -router.get("/", async (req, res) => { - // Must use the *identical* properties used to set the cookie. - res.clearCookie(Cookie.Key, { - domain: getCookieDomain(req.headers.host || "", req.args["proxy-domain"]), - path: req.body.base || "/", - sameSite: "lax", - }) - - const to = (typeof req.query.to === "string" && req.query.to) || "/" - return redirect(req, res, to, { to: undefined, base: undefined }) -}) diff --git a/src/node/routes/pathProxy.ts b/src/node/routes/pathProxy.ts deleted file mode 100644 index 789fa5c18294..000000000000 --- a/src/node/routes/pathProxy.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Request, Response } from "express" -import * as path from "path" -import qs from "qs" -import * as pluginapi from "../../../typings/pluginapi" -import { HttpCode, HttpError } from "../../common/http" -import { normalize } from "../../common/util" -import { authenticated, ensureAuthenticated, redirect } from "../http" -import { proxy as _proxy } from "../proxy" - -const getProxyTarget = (req: Request, passthroughPath?: boolean): string => { - if (passthroughPath) { - return `http://0.0.0.0:${req.params.port}/${req.originalUrl}` - } - const query = qs.stringify(req.query) - return `http://0.0.0.0:${req.params.port}/${req.params[0] || ""}${query ? `?${query}` : ""}` -} - -export function proxy( - req: Request, - res: Response, - opts?: { - passthroughPath?: boolean - }, -): void { - if (!authenticated(req)) { - // If visiting the root (/:port only) redirect to the login page. - if (!req.params[0] || req.params[0] === "/") { - const to = normalize(`${req.baseUrl}${req.path}`) - return redirect(req, res, "login", { - to: to !== "/" ? to : undefined, - }) - } - throw new HttpError("Unauthorized", HttpCode.Unauthorized) - } - - if (!opts?.passthroughPath) { - // Absolute redirects need to be based on the subpath when rewriting. - // See proxy.ts. - ;(req as any).base = req.path.split(path.sep).slice(0, 3).join(path.sep) - } - - _proxy.web(req, res, { - ignorePath: true, - target: getProxyTarget(req, opts?.passthroughPath), - }) -} - -export function wsProxy( - req: pluginapi.WebsocketRequest, - opts?: { - passthroughPath?: boolean - }, -): void { - ensureAuthenticated(req) - _proxy.ws(req, req.ws, req.head, { - ignorePath: true, - target: getProxyTarget(req, opts?.passthroughPath), - }) -} diff --git a/src/node/routes/static.ts b/src/node/routes/static.ts deleted file mode 100644 index 30eed03167b6..000000000000 --- a/src/node/routes/static.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { field, logger } from "@coder/logger" -import { Router } from "express" -import { promises as fs } from "fs" -import * as path from "path" -import { Readable } from "stream" -import * as tarFs from "tar-fs" -import * as zlib from "zlib" -import { HttpCode, HttpError } from "../../common/http" -import { getFirstString } from "../../common/util" -import { rootPath } from "../constants" -import { authenticated, ensureAuthenticated, replaceTemplates } from "../http" -import { getMediaMime, pathToFsPath } from "../util" - -export const router = Router() - -// The commit is for caching. -router.get("/(:commit)(/*)?", async (req, res) => { - // Used by VS Code to load extensions into the web worker. - const tar = getFirstString(req.query.tar) - if (tar) { - ensureAuthenticated(req) - let stream: Readable = tarFs.pack(pathToFsPath(tar)) - if (req.headers["accept-encoding"] && req.headers["accept-encoding"].includes("gzip")) { - logger.debug("gzipping tar", field("path", tar)) - const compress = zlib.createGzip() - stream.pipe(compress) - stream.on("error", (error) => compress.destroy(error)) - stream.on("close", () => compress.end()) - stream = compress - res.header("content-encoding", "gzip") - } - res.set("Content-Type", "application/x-tar") - stream.on("close", () => res.end()) - return stream.pipe(res) - } - - // If not a tar use the remainder of the path to load the resource. - if (!req.params[0]) { - throw new HttpError("Not Found", HttpCode.NotFound) - } - - const resourcePath = path.resolve(req.params[0]) - - // Make sure it's in code-server if you aren't authenticated. This lets - // unauthenticated users load the login assets. - if (!resourcePath.startsWith(rootPath) && !authenticated(req)) { - throw new HttpError("Unauthorized", HttpCode.Unauthorized) - } - - // Don't cache during development. - can also be used if you want to make a - // static request without caching. - if (req.params.commit !== "development" && req.params.commit !== "-") { - res.header("Cache-Control", "public, max-age=31536000") - } - - // Without this the default is to use the directory the script loaded from. - if (req.headers["service-worker"]) { - res.header("service-worker-allowed", "/") - } - - res.set("Content-Type", getMediaMime(resourcePath)) - - if (resourcePath.endsWith("manifest.json")) { - const content = await fs.readFile(resourcePath, "utf8") - return res.send(replaceTemplates(req, content)) - } - - const content = await fs.readFile(resourcePath) - return res.send(content) -}) diff --git a/src/node/routes/update.ts b/src/node/routes/update.ts deleted file mode 100644 index 5c9aa181e9e2..000000000000 --- a/src/node/routes/update.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Router } from "express" -import { version } from "../constants" -import { ensureAuthenticated } from "../http" -import { UpdateProvider } from "../update" - -export const router = Router() - -const provider = new UpdateProvider() - -router.get("/check", ensureAuthenticated, async (req, res) => { - const update = await provider.getUpdate(req.query.force === "true") - res.json({ - checked: update.checked, - latest: update.version, - current: version, - isLatest: provider.isLatestVersion(update), - }) -}) diff --git a/src/node/routes/vscode.ts b/src/node/routes/vscode.ts deleted file mode 100644 index 0d9c63096b57..000000000000 --- a/src/node/routes/vscode.ts +++ /dev/null @@ -1,222 +0,0 @@ -import * as crypto from "crypto" -import { Request, Router } from "express" -import { promises as fs } from "fs" -import * as path from "path" -import qs from "qs" -import * as ipc from "../../../typings/ipc" -import { Emitter } from "../../common/emitter" -import { HttpCode, HttpError } from "../../common/http" -import { getFirstString } from "../../common/util" -import { commit, rootPath, version } from "../constants" -import { authenticated, ensureAuthenticated, redirect, replaceTemplates } from "../http" -import { getMediaMime, pathToFsPath } from "../util" -import { VscodeProvider } from "../vscode" -import { Router as WsRouter } from "../wsRouter" - -export const router = Router() - -const vscode = new VscodeProvider() - -router.get("/", async (req, res) => { - if (!authenticated(req)) { - return redirect(req, res, "login", { - // req.baseUrl can be blank if already at the root. - to: req.baseUrl && req.baseUrl !== "/" ? req.baseUrl : undefined, - }) - } - - const [content, options] = await Promise.all([ - await fs.readFile(path.join(rootPath, "src/browser/pages/vscode.html"), "utf8"), - (async () => { - try { - return await vscode.initialize({ args: req.args, remoteAuthority: req.headers.host || "" }, req.query) - } catch (error) { - const devMessage = commit === "development" ? "It might not have finished compiling." : "" - throw new Error(`VS Code failed to load. ${devMessage} ${error.message}`) - } - })(), - ]) - - options.productConfiguration.codeServerVersion = version - - res.send( - replaceTemplates( - req, - // Uncomment prod blocks if not in development. TODO: Would this be - // better as a build step? Or maintain two HTML files again? - commit !== "development" ? content.replace(//g, "") : content, - { - authed: req.args.auth !== "none", - disableTelemetry: !!req.args["disable-telemetry"], - disableUpdateCheck: !!req.args["disable-update-check"], - }, - ) - .replace(`"{{REMOTE_USER_DATA_URI}}"`, `'${JSON.stringify(options.remoteUserDataUri)}'`) - .replace(`"{{PRODUCT_CONFIGURATION}}"`, `'${JSON.stringify(options.productConfiguration)}'`) - .replace(`"{{WORKBENCH_WEB_CONFIGURATION}}"`, `'${JSON.stringify(options.workbenchWebConfiguration)}'`) - .replace(`"{{NLS_CONFIGURATION}}"`, `'${JSON.stringify(options.nlsConfiguration)}'`), - ) -}) - -/** - * TODO: Might currently be unused. - */ -router.get("/resource(/*)?", ensureAuthenticated, async (req, res) => { - if (typeof req.query.path === "string") { - res.set("Content-Type", getMediaMime(req.query.path)) - res.send(await fs.readFile(pathToFsPath(req.query.path))) - } -}) - -/** - * Used by VS Code to load files. - */ -router.get("/vscode-remote-resource(/*)?", ensureAuthenticated, async (req, res) => { - if (typeof req.query.path === "string") { - res.set("Content-Type", getMediaMime(req.query.path)) - res.send(await fs.readFile(pathToFsPath(req.query.path))) - } -}) - -/** - * VS Code webviews use these paths to load files and to load webview assets - * like HTML and JavaScript. - */ -router.get("/webview/*", ensureAuthenticated, async (req, res) => { - res.set("Content-Type", getMediaMime(req.path)) - if (/^vscode-resource/.test(req.params[0])) { - return res.send(await fs.readFile(req.params[0].replace(/^vscode-resource(\/file)?/, ""))) - } - return res.send( - await fs.readFile(path.join(vscode.vsRootPath, "out/vs/workbench/contrib/webview/browser/pre", req.params[0])), - ) -}) - -interface Callback { - uri: { - scheme: string - authority?: string - path?: string - query?: string - fragment?: string - } - timeout: NodeJS.Timeout -} - -const callbacks = new Map() -const callbackEmitter = new Emitter<{ id: string; callback: Callback }>() - -/** - * Get vscode-requestId from the query and throw if it's missing or invalid. - */ -const getRequestId = (req: Request): string => { - if (!req.query["vscode-requestId"]) { - throw new HttpError("vscode-requestId is missing", HttpCode.BadRequest) - } - - if (typeof req.query["vscode-requestId"] !== "string") { - throw new HttpError("vscode-requestId is not a string", HttpCode.BadRequest) - } - - return req.query["vscode-requestId"] -} - -// Matches VS Code's fetch timeout. -const fetchTimeout = 5 * 60 * 1000 - -// The callback endpoints are used during authentication. A URI is stored on -// /callback and then fetched later on /fetch-callback. -// See ../../../lib/vscode/resources/web/code-web.js -router.get("/callback", ensureAuthenticated, async (req, res) => { - const uriKeys = [ - "vscode-requestId", - "vscode-scheme", - "vscode-authority", - "vscode-path", - "vscode-query", - "vscode-fragment", - ] - - const id = getRequestId(req) - - // Move any query variables that aren't URI keys into the URI's query - // (importantly, this will include the code for oauth). - const query: qs.ParsedQs = {} - for (const key in req.query) { - if (!uriKeys.includes(key)) { - query[key] = req.query[key] - } - } - - const callback = { - uri: { - scheme: getFirstString(req.query["vscode-scheme"]) || "code-oss", - authority: getFirstString(req.query["vscode-authority"]), - path: getFirstString(req.query["vscode-path"]), - query: (getFirstString(req.query.query) || "") + "&" + qs.stringify(query), - fragment: getFirstString(req.query["vscode-fragment"]), - }, - // Make sure the map doesn't leak if nothing fetches this URI. - timeout: setTimeout(() => callbacks.delete(id), fetchTimeout), - } - - callbacks.set(id, callback) - callbackEmitter.emit({ id, callback }) - - res.sendFile(path.join(rootPath, "lib/vscode/resources/web/callback.html")) -}) - -router.get("/fetch-callback", ensureAuthenticated, async (req, res) => { - const id = getRequestId(req) - - const send = (callback: Callback) => { - clearTimeout(callback.timeout) - callbacks.delete(id) - res.json(callback.uri) - } - - const callback = callbacks.get(id) - if (callback) { - return send(callback) - } - - // VS Code will try again if the route returns no content but it seems more - // efficient to just wait on this request for as long as possible? - const handler = callbackEmitter.event(({ id: emitId, callback }) => { - if (id === emitId) { - handler.dispose() - send(callback) - } - }) - - // If the client closes the connection. - req.on("close", () => handler.dispose()) -}) - -export const wsRouter = WsRouter() - -wsRouter.ws("/", ensureAuthenticated, async (req) => { - const magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - const reply = crypto - .createHash("sha1") - .update(req.headers["sec-websocket-key"] + magic) - .digest("base64") - - const responseHeaders = [ - "HTTP/1.1 101 Switching Protocols", - "Upgrade: websocket", - "Connection: Upgrade", - `Sec-WebSocket-Accept: ${reply}`, - ] - - // TODO: Parse this header properly. - const extensions = req.headers["sec-websocket-extensions"] - const permessageDeflate = extensions ? extensions.includes("permessage-deflate") : false - if (permessageDeflate) { - responseHeaders.push("Sec-WebSocket-Extensions: permessage-deflate; server_max_window_bits=15") - } - - req.ws.write(responseHeaders.join("\r\n") + "\r\n\r\n") - - await vscode.sendWebsocket(req.ws, req.query, permessageDeflate) -}) diff --git a/src/node/settings.ts b/src/node/settings.ts deleted file mode 100644 index ee955aad9e99..000000000000 --- a/src/node/settings.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { logger } from "@coder/logger" -import { Query } from "express-serve-static-core" -import { promises as fs } from "fs" -import * as path from "path" -import { paths } from "./util" - -export type Settings = { [key: string]: Settings | string | boolean | number } - -/** - * Provides read and write access to settings. - */ -export class SettingsProvider { - public constructor(private readonly settingsPath: string) {} - - /** - * Read settings from the file. On a failure return last known settings and - * log a warning. - */ - public async read(): Promise { - try { - const raw = (await fs.readFile(this.settingsPath, "utf8")).trim() - return raw ? JSON.parse(raw) : {} - } catch (error) { - if (error.code !== "ENOENT") { - logger.warn(error.message) - } - } - return {} as T - } - - /** - * Write settings combined with current settings. On failure log a warning. - * Settings will be merged shallowly. - */ - public async write(settings: Partial): Promise { - try { - const oldSettings = await this.read() - const nextSettings = { ...oldSettings, ...settings } - await fs.writeFile(this.settingsPath, JSON.stringify(nextSettings, null, 2)) - } catch (error) { - logger.warn(error.message) - } - } -} - -export interface UpdateSettings { - update: { - checked: number - version: string - } -} - -/** - * Global code-server settings. - */ -export interface CoderSettings extends UpdateSettings { - lastVisited: { - url: string - workspace: boolean - } - query: Query -} - -/** - * Global code-server settings file. - */ -export const settings = new SettingsProvider(path.join(paths.data, "coder.json")) diff --git a/src/node/socket.ts b/src/node/socket.ts deleted file mode 100644 index 9c937bbb5013..000000000000 --- a/src/node/socket.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { promises as fs } from "fs" -import * as net from "net" -import * as path from "path" -import * as tls from "tls" -import { Emitter } from "../common/emitter" -import { generateUuid } from "../common/util" -import { tmpdir } from "./constants" -import { canConnect } from "./util" - -/** - * Provides a way to proxy a TLS socket. Can be used when you need to pass a - * socket to a child process since you can't pass the TLS socket. - */ -export class SocketProxyProvider { - private readonly onProxyConnect = new Emitter() - private proxyPipe = path.join(tmpdir, "tls-proxy") - private _proxyServer?: Promise - private readonly proxyTimeout = 5000 - - /** - * Stop the proxy server. - */ - public stop(): void { - if (this._proxyServer) { - this._proxyServer.then((server) => server.close()) - this._proxyServer = undefined - } - } - - /** - * Create a socket proxy for TLS sockets. If it's not a TLS socket the - * original socket is returned. This will spawn a proxy server on demand. - */ - public async createProxy(socket: net.Socket): Promise { - if (!(socket instanceof tls.TLSSocket)) { - return socket - } - - await this.startProxyServer() - - return new Promise((resolve, reject) => { - const id = generateUuid() - const proxy = net.connect(this.proxyPipe) - proxy.once("connect", () => proxy.write(id)) - - const timeout = setTimeout(() => { - listener.dispose() // eslint-disable-line @typescript-eslint/no-use-before-define - socket.destroy() - proxy.destroy() - reject(new Error("TLS socket proxy timed out")) - }, this.proxyTimeout) - - const listener = this.onProxyConnect.event((connection) => { - connection.once("data", (data) => { - if (!socket.destroyed && !proxy.destroyed && data.toString() === id) { - clearTimeout(timeout) - listener.dispose() - ;[ - [proxy, socket], - [socket, proxy], - ].forEach(([a, b]) => { - a.pipe(b) - a.on("error", () => b.destroy()) - a.on("close", () => b.destroy()) - a.on("end", () => b.end()) - }) - resolve(connection) - } - }) - }) - }) - } - - private async startProxyServer(): Promise { - if (!this._proxyServer) { - this._proxyServer = this.findFreeSocketPath(this.proxyPipe) - .then((pipe) => { - this.proxyPipe = pipe - return Promise.all([fs.mkdir(tmpdir, { recursive: true }), fs.rmdir(this.proxyPipe, { recursive: true })]) - }) - .then(() => { - return new Promise((resolve) => { - const proxyServer = net.createServer((p) => this.onProxyConnect.emit(p)) - proxyServer.once("listening", () => resolve(proxyServer)) - proxyServer.listen(this.proxyPipe) - }) - }) - } - return this._proxyServer - } - - public async findFreeSocketPath(basePath: string, maxTries = 100): Promise { - let i = 0 - let path = basePath - while ((await canConnect(path)) && i < maxTries) { - path = `${basePath}-${++i}` - } - return path - } -} diff --git a/src/node/update.ts b/src/node/update.ts deleted file mode 100644 index 6f9aa39e58c7..000000000000 --- a/src/node/update.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { field, logger } from "@coder/logger" -import * as http from "http" -import * as https from "https" -import * as semver from "semver" -import * as url from "url" -import { version } from "./constants" -import { settings as globalSettings, SettingsProvider, UpdateSettings } from "./settings" - -export interface Update { - checked: number - version: string -} - -export interface LatestResponse { - name: string -} - -/** - * Provide update information. - */ -export class UpdateProvider { - private update?: Promise - private updateInterval = 1000 * 60 * 60 * 24 // Milliseconds between update checks. - - public constructor( - /** - * The URL for getting the latest version of code-server. Should return JSON - * that fulfills `LatestResponse`. - */ - private readonly latestUrl = "https://api.github.com/repos/cdr/code-server/releases/latest", - /** - * Update information will be stored here. If not provided, the global - * settings will be used. - */ - private readonly settings: SettingsProvider = globalSettings, - ) {} - - /** - * Query for and return the latest update. - */ - public async getUpdate(force?: boolean): Promise { - // Don't run multiple requests at a time. - if (!this.update) { - this.update = this._getUpdate(force) - this.update.then(() => (this.update = undefined)) - } - - return this.update - } - - private async _getUpdate(force?: boolean): Promise { - const now = Date.now() - try { - let { update } = !force ? await this.settings.read() : { update: undefined } - if (!update || update.checked + this.updateInterval < now) { - const buffer = await this.request(this.latestUrl) - const data = JSON.parse(buffer.toString()) as LatestResponse - update = { checked: now, version: data.name.replace(/^v/, "") } - await this.settings.write({ update }) - } - logger.debug("got latest version", field("latest", update.version)) - return update - } catch (error) { - logger.error("Failed to get latest version", field("error", error.message)) - return { - checked: now, - version: "unknown", - } - } - } - - /** - * Return true if the currently installed version is the latest. - */ - public isLatestVersion(latest: Update): boolean { - logger.debug("comparing versions", field("current", version), field("latest", latest.version)) - try { - return semver.lte(latest.version, version) - } catch (error) { - return true - } - } - - private async request(uri: string): Promise { - const response = await this.requestResponse(uri) - return new Promise((resolve, reject) => { - const chunks: Buffer[] = [] - let bufferLength = 0 - response.on("data", (chunk) => { - bufferLength += chunk.length - chunks.push(chunk) - }) - response.on("error", reject) - response.on("end", () => { - resolve(Buffer.concat(chunks, bufferLength)) - }) - }) - } - - private async requestResponse(uri: string): Promise { - let redirects = 0 - const maxRedirects = 10 - return new Promise((resolve, reject) => { - const request = (uri: string): void => { - logger.debug("Making request", field("uri", uri)) - const httpx = uri.startsWith("https") ? https : http - const client = httpx.get(uri, { headers: { "User-Agent": "code-server" } }, (response) => { - if (!response.statusCode || response.statusCode < 200 || response.statusCode >= 400) { - response.destroy() - return reject(new Error(`${uri}: ${response.statusCode || "500"}`)) - } - - if (response.statusCode >= 300) { - response.destroy() - ++redirects - if (redirects > maxRedirects) { - return reject(new Error("reached max redirects")) - } - if (!response.headers.location) { - return reject(new Error("received redirect with no location header")) - } - return request(url.resolve(uri, response.headers.location)) - } - - resolve(response) - }) - client.on("error", reject) - } - request(uri) - }) - } -} diff --git a/src/node/util.ts b/src/node/util.ts deleted file mode 100644 index 380e32b9bdd4..000000000000 --- a/src/node/util.ts +++ /dev/null @@ -1,294 +0,0 @@ -import * as cp from "child_process" -import * as crypto from "crypto" -import envPaths from "env-paths" -import { promises as fs } from "fs" -import * as net from "net" -import * as os from "os" -import * as path from "path" -import * as util from "util" -import xdgBasedir from "xdg-basedir" - -interface Paths { - data: string - config: string -} - -export const paths = getEnvPaths() - -/** - * Gets the config and data paths for the current platform/configuration. - * On MacOS this function gets the standard XDG directories instead of using the native macOS - * ones. Most CLIs do this as in practice only GUI apps use the standard macOS directories. - */ -function getEnvPaths(): Paths { - let paths: Paths - if (process.platform === "win32") { - paths = envPaths("code-server", { - suffix: "", - }) - } else { - if (xdgBasedir.data === undefined || xdgBasedir.config === undefined) { - throw new Error("No home folder?") - } - paths = { - data: path.join(xdgBasedir.data, "code-server"), - config: path.join(xdgBasedir.config, "code-server"), - } - } - - return paths -} - -/** - * humanPath replaces the home directory in p with ~. - * Makes it more readable. - * - * @param p - */ -export function humanPath(p?: string): string { - if (!p) { - return "" - } - return p.replace(os.homedir(), "~") -} - -export const generateCertificate = async (hostname: string): Promise<{ cert: string; certKey: string }> => { - const certPath = path.join(paths.data, `${hostname.replace(/\./g, "_")}.crt`) - const certKeyPath = path.join(paths.data, `${hostname.replace(/\./g, "_")}.key`) - - // Try generating the certificates if we can't access them (which probably - // means they don't exist). - try { - await Promise.all([fs.access(certPath), fs.access(certKeyPath)]) - } catch (error) { - // Require on demand so openssl isn't required if you aren't going to - // generate certificates. - const pem = require("pem") as typeof import("pem") - const certs = await new Promise((resolve, reject): void => { - pem.createCertificate( - { - selfSigned: true, - commonName: hostname, - config: ` -[req] -req_extensions = v3_req - -[ v3_req ] -basicConstraints = CA:true -extendedKeyUsage = serverAuth -subjectAltName = @alt_names - -[alt_names] -DNS.1 = ${hostname} -`, - }, - (error, result) => { - return error ? reject(error) : resolve(result) - }, - ) - }) - await fs.mkdir(paths.data, { recursive: true }) - await Promise.all([fs.writeFile(certPath, certs.certificate), fs.writeFile(certKeyPath, certs.serviceKey)]) - } - - return { - cert: certPath, - certKey: certKeyPath, - } -} - -export const generatePassword = async (length = 24): Promise => { - const buffer = Buffer.alloc(Math.ceil(length / 2)) - await util.promisify(crypto.randomFill)(buffer) - return buffer.toString("hex").substring(0, length) -} - -export const hash = (str: string): string => { - return crypto.createHash("sha256").update(str).digest("hex") -} - -const mimeTypes: { [key: string]: string } = { - ".aac": "audio/x-aac", - ".avi": "video/x-msvideo", - ".bmp": "image/bmp", - ".css": "text/css", - ".flv": "video/x-flv", - ".gif": "image/gif", - ".html": "text/html", - ".ico": "image/x-icon", - ".jpe": "image/jpg", - ".jpeg": "image/jpg", - ".jpg": "image/jpg", - ".js": "application/javascript", - ".json": "application/json", - ".m1v": "video/mpeg", - ".m2a": "audio/mpeg", - ".m2v": "video/mpeg", - ".m3a": "audio/mpeg", - ".mid": "audio/midi", - ".midi": "audio/midi", - ".mk3d": "video/x-matroska", - ".mks": "video/x-matroska", - ".mkv": "video/x-matroska", - ".mov": "video/quicktime", - ".movie": "video/x-sgi-movie", - ".mp2": "audio/mpeg", - ".mp2a": "audio/mpeg", - ".mp3": "audio/mpeg", - ".mp4": "video/mp4", - ".mp4a": "audio/mp4", - ".mp4v": "video/mp4", - ".mpe": "video/mpeg", - ".mpeg": "video/mpeg", - ".mpg": "video/mpeg", - ".mpg4": "video/mp4", - ".mpga": "audio/mpeg", - ".oga": "audio/ogg", - ".ogg": "audio/ogg", - ".ogv": "video/ogg", - ".png": "image/png", - ".psd": "image/vnd.adobe.photoshop", - ".qt": "video/quicktime", - ".spx": "audio/ogg", - ".svg": "image/svg+xml", - ".tga": "image/x-tga", - ".tif": "image/tiff", - ".tiff": "image/tiff", - ".txt": "text/plain", - ".wav": "audio/x-wav", - ".wasm": "application/wasm", - ".webm": "video/webm", - ".webp": "image/webp", - ".wma": "audio/x-ms-wma", - ".wmv": "video/x-ms-wmv", - ".woff": "application/font-woff", -} - -export const getMediaMime = (filePath?: string): string => { - return (filePath && mimeTypes[path.extname(filePath)]) || "text/plain" -} - -export const isWsl = async (): Promise => { - return ( - (process.platform === "linux" && os.release().toLowerCase().indexOf("microsoft") !== -1) || - (await fs.readFile("/proc/version", "utf8")).toLowerCase().indexOf("microsoft") !== -1 - ) -} - -/** - * Try opening a URL using whatever the system has set for opening URLs. - */ -export const open = async (url: string): Promise => { - const args = [] as string[] - const options = {} as cp.SpawnOptions - const platform = (await isWsl()) ? "wsl" : process.platform - let command = platform === "darwin" ? "open" : "xdg-open" - if (platform === "win32" || platform === "wsl") { - command = platform === "wsl" ? "cmd.exe" : "cmd" - args.push("/c", "start", '""', "/b") - url = url.replace(/&/g, "^&") - } - const proc = cp.spawn(command, [...args, url], options) - await new Promise((resolve, reject) => { - proc.on("error", reject) - proc.on("close", (code) => { - return code !== 0 ? reject(new Error(`Failed to open with code ${code}`)) : resolve() - }) - }) -} - -/** - * For iterating over an enum's values. - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export const enumToArray = (t: any): string[] => { - const values = [] as string[] - for (const k in t) { - values.push(t[k]) - } - return values -} - -/** - * For displaying all allowed options in an enum. - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export const buildAllowedMessage = (t: any): string => { - const values = enumToArray(t) - return `Allowed value${values.length === 1 ? " is" : "s are"} ${values.map((t) => `'${t}'`).join(", ")}` -} - -export const isObject = (obj: T): obj is T => { - return !Array.isArray(obj) && typeof obj === "object" && obj !== null -} - -/** - * Taken from vs/base/common/charCode.ts. Copied for now instead of importing so - * we don't have to set up a `vs` alias to be able to import with types (since - * the alternative is to directly import from `out`). - */ -const enum CharCode { - Slash = 47, - A = 65, - Z = 90, - a = 97, - z = 122, - Colon = 58, -} - -/** - * Compute `fsPath` for the given uri. - * Taken from vs/base/common/uri.ts. It's not imported to avoid also importing - * everything that file imports. - */ -export function pathToFsPath(path: string, keepDriveLetterCasing = false): string { - const isWindows = process.platform === "win32" - const uri = { authority: undefined, path, scheme: "file" } - let value: string - if (uri.authority && uri.path.length > 1 && uri.scheme === "file") { - // unc path: file://shares/c$/far/boo - value = `//${uri.authority}${uri.path}` - } else if ( - uri.path.charCodeAt(0) === CharCode.Slash && - ((uri.path.charCodeAt(1) >= CharCode.A && uri.path.charCodeAt(1) <= CharCode.Z) || - (uri.path.charCodeAt(1) >= CharCode.a && uri.path.charCodeAt(1) <= CharCode.z)) && - uri.path.charCodeAt(2) === CharCode.Colon - ) { - if (!keepDriveLetterCasing) { - // windows drive letter: file:///c:/far/boo - value = uri.path[1].toLowerCase() + uri.path.substr(2) - } else { - value = uri.path.substr(1) - } - } else { - // other path - value = uri.path - } - if (isWindows) { - value = value.replace(/\//g, "\\") - } - return value -} - -/** - * Return a promise that resolves with whether the socket path is active. - */ -export function canConnect(path: string): Promise { - return new Promise((resolve) => { - const socket = net.connect(path) - socket.once("error", () => resolve(false)) - socket.once("connect", () => { - socket.destroy() - resolve(true) - }) - }) -} - -export const isFile = async (path: string): Promise => { - try { - const stat = await fs.stat(path) - return stat.isFile() - } catch (error) { - return false - } -} diff --git a/src/node/vscode.ts b/src/node/vscode.ts deleted file mode 100644 index a69253fb21f4..000000000000 --- a/src/node/vscode.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { logger } from "@coder/logger" -import * as cp from "child_process" -import * as net from "net" -import * as path from "path" -import * as ipc from "../../typings/ipc" -import { arrayify, generateUuid } from "../common/util" -import { rootPath } from "./constants" -import { settings } from "./settings" -import { SocketProxyProvider } from "./socket" -import { isFile } from "./util" -import { onMessage, wrapper } from "./wrapper" - -export class VscodeProvider { - public readonly serverRootPath: string - public readonly vsRootPath: string - private _vscode?: Promise - private readonly socketProvider = new SocketProxyProvider() - - public constructor() { - this.vsRootPath = path.resolve(rootPath, "lib/vscode") - this.serverRootPath = path.join(this.vsRootPath, "out/vs/server") - wrapper.onDispose(() => this.dispose()) - } - - public async dispose(): Promise { - this.socketProvider.stop() - if (this._vscode) { - const vscode = await this._vscode - vscode.removeAllListeners() - vscode.kill() - this._vscode = undefined - } - } - - public async initialize( - options: Omit, - query: ipc.Query, - ): Promise { - const { lastVisited } = await settings.read() - let startPath = await this.getFirstPath([ - { url: query.workspace, workspace: true }, - { url: query.folder, workspace: false }, - options.args._ && options.args._.length > 0 - ? { url: path.resolve(options.args._[options.args._.length - 1]) } - : undefined, - !options.args["ignore-last-opened"] ? lastVisited : undefined, - ]) - - if (query.ew) { - startPath = undefined - } - - settings.write({ - lastVisited: startPath, - query, - }) - - const id = generateUuid() - const vscode = await this.fork() - - logger.debug("setting up vs code...") - - this.send( - { - type: "init", - id, - options: { - ...options, - startPath, - }, - }, - vscode, - ) - - const message = await onMessage( - vscode, - (message): message is ipc.OptionsMessage => { - // There can be parallel initializations so wait for the right ID. - return message.type === "options" && message.id === id - }, - ) - - return message.options - } - - private fork(): Promise { - if (this._vscode) { - return this._vscode - } - - logger.debug("forking vs code...") - const vscode = cp.fork(path.join(this.serverRootPath, "fork")) - - const dispose = () => { - vscode.removeAllListeners() - vscode.kill() - this._vscode = undefined - } - - vscode.on("error", (error: Error) => { - logger.error(error.message) - if (error.stack) { - logger.debug(error.stack) - } - dispose() - }) - - vscode.on("exit", (code) => { - logger.error(`VS Code exited unexpectedly with code ${code}`) - dispose() - }) - - this._vscode = onMessage(vscode, (message): message is ipc.ReadyMessage => { - return message.type === "ready" - }).then(() => vscode) - - return this._vscode - } - - /** - * VS Code expects a raw socket. It will handle all the web socket frames. - */ - public async sendWebsocket(socket: net.Socket, query: ipc.Query, permessageDeflate: boolean): Promise { - const vscode = await this._vscode - // TLS sockets cannot be transferred to child processes so we need an - // in-between. Non-TLS sockets will be returned as-is. - const socketProxy = await this.socketProvider.createProxy(socket) - this.send({ type: "socket", query, permessageDeflate }, vscode, socketProxy) - } - - private send(message: ipc.CodeServerMessage, vscode?: cp.ChildProcess, socket?: net.Socket): void { - if (!vscode || vscode.killed) { - throw new Error("vscode is not running") - } - vscode.send(message, socket) - } - - /** - * Choose the first non-empty path from the provided array. - * - * Each array item consists of `url` and an optional `workspace` boolean that - * indicates whether that url is for a workspace. - * - * `url` can be a fully qualified URL or just the path portion. - * - * `url` can also be a query object to make it easier to pass in query - * variables directly but anything that isn't a string or string array is not - * valid and will be ignored. - */ - private async getFirstPath( - startPaths: Array<{ url?: string | string[] | ipc.Query | ipc.Query[]; workspace?: boolean } | undefined>, - ): Promise { - for (let i = 0; i < startPaths.length; ++i) { - const startPath = startPaths[i] - const url = arrayify(startPath && startPath.url).find((p) => !!p) - if (startPath && url && typeof url === "string") { - return { - url, - // The only time `workspace` is undefined is for the command-line - // argument, in which case it's a path (not a URL) so we can stat it - // without having to parse it. - workspace: typeof startPath.workspace !== "undefined" ? startPath.workspace : await isFile(url), - } - } - } - return undefined - } -} diff --git a/src/node/wrapper.ts b/src/node/wrapper.ts deleted file mode 100644 index 68eacbbcadc3..000000000000 --- a/src/node/wrapper.ts +++ /dev/null @@ -1,370 +0,0 @@ -import { field, Logger, logger } from "@coder/logger" -import * as cp from "child_process" -import * as path from "path" -import * as rfs from "rotating-file-stream" -import { Emitter } from "../common/emitter" -import { DefaultedArgs } from "./cli" -import { paths } from "./util" - -const timeoutInterval = 10000 // 10s, matches VS Code's timeouts. - -/** - * Listen to a single message from a process. Reject if the process errors, - * exits, or times out. - * - * `fn` is a function that determines whether the message is the one we're - * waiting for. - */ -export function onMessage( - proc: cp.ChildProcess | NodeJS.Process, - fn: (message: M) => message is T, - customLogger?: Logger, -): Promise { - return new Promise((resolve, reject) => { - const cleanup = () => { - proc.off("error", onError) - proc.off("exit", onExit) - proc.off("message", onMessage) - clearTimeout(timeout) - } - - const timeout = setTimeout(() => { - cleanup() - reject(new Error("timed out")) - }, timeoutInterval) - - const onError = (error: Error) => { - cleanup() - reject(error) - } - - const onExit = (code: number) => { - cleanup() - reject(new Error(`exited unexpectedly with code ${code}`)) - } - - const onMessage = (message: M) => { - ;(customLogger || logger).trace("got message", field("message", message)) - if (fn(message)) { - cleanup() - resolve(message) - } - } - - proc.on("message", onMessage) - // NodeJS.Process doesn't have `error` but binding anyway shouldn't break - // anything. It does have `exit` but the types aren't working. - ;(proc as cp.ChildProcess).on("error", onError) - ;(proc as cp.ChildProcess).on("exit", onExit) - }) -} - -interface ParentHandshakeMessage { - type: "handshake" - args: DefaultedArgs -} - -interface ChildHandshakeMessage { - type: "handshake" -} - -interface RelaunchMessage { - type: "relaunch" - version: string -} - -type ChildMessage = RelaunchMessage | ChildHandshakeMessage -type ParentMessage = ParentHandshakeMessage - -class ProcessError extends Error { - public constructor(message: string, public readonly code: number | undefined) { - super(message) - this.name = this.constructor.name - Error.captureStackTrace(this, this.constructor) - } -} - -/** - * Wrapper around a process that tries to gracefully exit when a process exits - * and provides a way to prevent `process.exit`. - */ -abstract class Process { - /** - * Emit this to trigger a graceful exit. - */ - protected readonly _onDispose = new Emitter() - - /** - * Emitted when the process is about to be disposed. - */ - public readonly onDispose = this._onDispose.event - - /** - * Uniquely named logger for the process. - */ - public abstract logger: Logger - - public constructor() { - process.on("SIGINT", () => this._onDispose.emit("SIGINT")) - process.on("SIGTERM", () => this._onDispose.emit("SIGTERM")) - process.on("exit", () => this._onDispose.emit(undefined)) - - this.onDispose((signal, wait) => { - // Remove listeners to avoid possibly triggering disposal again. - process.removeAllListeners() - - // Try waiting for other handlers to run first then exit. - this.logger.debug("disposing", field("code", signal)) - wait.then(() => this.exit(0)) - setTimeout(() => this.exit(0), 5000) - }) - } - - /** - * Ensure control over when the process exits. - */ - public preventExit(): void { - ;(process.exit as any) = (code?: number) => { - this.logger.warn(`process.exit() was prevented: ${code || "unknown code"}.`) - } - } - - private readonly processExit: (code?: number) => never = process.exit - - /** - * Will always exit even if normal exit is being prevented. - */ - public exit(error?: number | ProcessError): never { - if (error && typeof error !== "number") { - this.processExit(typeof error.code === "number" ? error.code : 1) - } else { - this.processExit(error) - } - } -} - -/** - * Child process that will clean up after itself if the parent goes away and can - * perform a handshake with the parent and ask it to relaunch. - */ -class ChildProcess extends Process { - public logger = logger.named(`child:${process.pid}`) - - public constructor(private readonly parentPid: number) { - super() - - // Kill the inner process if the parent dies. This is for the case where the - // parent process is forcefully terminated and cannot clean up. - setInterval(() => { - try { - // process.kill throws an exception if the process doesn't exist. - process.kill(this.parentPid, 0) - } catch (_) { - // Consider this an error since it should have been able to clean up - // the child process unless it was forcefully killed. - this.logger.error(`parent process ${parentPid} died`) - this._onDispose.emit(undefined) - } - }, 5000) - } - - /** - * Initiate the handshake and wait for a response from the parent. - */ - public async handshake(): Promise { - this.send({ type: "handshake" }) - const message = await onMessage( - process, - (message): message is ParentHandshakeMessage => { - return message.type === "handshake" - }, - this.logger, - ) - return message.args - } - - /** - * Notify the parent process that it should relaunch the child. - */ - public relaunch(version: string): void { - this.send({ type: "relaunch", version }) - } - - /** - * Send a message to the parent. - */ - private send(message: ChildMessage): void { - if (!process.send) { - throw new Error("not spawned with IPC") - } - process.send(message) - } -} - -/** - * Parent process wrapper that spawns the child process and performs a handshake - * with it. Will relaunch the child if it receives a SIGUSR1 or is asked to by - * the child. If the child otherwise exits the parent will also exit. - */ -export class ParentProcess extends Process { - public logger = logger.named(`parent:${process.pid}`) - - private child?: cp.ChildProcess - private started?: Promise - private readonly logStdoutStream: rfs.RotatingFileStream - private readonly logStderrStream: rfs.RotatingFileStream - - protected readonly _onChildMessage = new Emitter() - protected readonly onChildMessage = this._onChildMessage.event - - private args?: DefaultedArgs - - public constructor(private currentVersion: string) { - super() - - process.on("SIGUSR1", async () => { - this.logger.info("Received SIGUSR1; hotswapping") - this.relaunch() - }) - - const opts = { - size: "10M", - maxFiles: 10, - } - this.logStdoutStream = rfs.createStream(path.join(paths.data, "coder-logs", "code-server-stdout.log"), opts) - this.logStderrStream = rfs.createStream(path.join(paths.data, "coder-logs", "code-server-stderr.log"), opts) - - this.onDispose(() => this.disposeChild()) - - this.onChildMessage((message) => { - switch (message.type) { - case "relaunch": - this.logger.info(`Relaunching: ${this.currentVersion} -> ${message.version}`) - this.currentVersion = message.version - this.relaunch() - break - default: - this.logger.error(`Unrecognized message ${message}`) - break - } - }) - } - - private async disposeChild(): Promise { - this.started = undefined - if (this.child) { - const child = this.child - child.removeAllListeners() - child.kill() - // Wait for the child to exit otherwise its output will be lost which can - // be especially problematic if you're trying to debug why cleanup failed. - await new Promise((r) => child!.on("exit", r)) - } - } - - private async relaunch(): Promise { - this.disposeChild() - try { - this.started = this._start() - await this.started - } catch (error) { - this.logger.error(error.message) - this.exit(typeof error.code === "number" ? error.code : 1) - } - } - - public start(args: DefaultedArgs): Promise { - // Store for relaunches. - this.args = args - if (!this.started) { - this.started = this._start() - } - return this.started - } - - private async _start(): Promise { - const child = this.spawn() - this.child = child - - // Log both to stdout and to the log directory. - if (child.stdout) { - child.stdout.pipe(this.logStdoutStream) - child.stdout.pipe(process.stdout) - } - if (child.stderr) { - child.stderr.pipe(this.logStderrStream) - child.stderr.pipe(process.stderr) - } - - this.logger.debug(`spawned inner process ${child.pid}`) - - await this.handshake(child) - - child.once("exit", (code) => { - this.logger.debug(`inner process ${child.pid} exited unexpectedly`) - this.exit(code || 0) - }) - } - - private spawn(): cp.ChildProcess { - // Use spawn (instead of fork) to use the new binary in case it was updated. - return cp.spawn(process.argv[0], process.argv.slice(1), { - env: { - ...process.env, - CODE_SERVER_PARENT_PID: process.pid.toString(), - NODE_OPTIONS: `--max-old-space-size=2048 ${process.env.NODE_OPTIONS || ""}`, - }, - stdio: ["inherit", "inherit", "inherit", "ipc"], - }) - } - - /** - * Wait for a handshake from the child then reply. - */ - private async handshake(child: cp.ChildProcess): Promise { - if (!this.args) { - throw new Error("started without args") - } - await onMessage( - child, - (message): message is ChildHandshakeMessage => { - return message.type === "handshake" - }, - this.logger, - ) - this.send(child, { type: "handshake", args: this.args }) - } - - /** - * Send a message to the child. - */ - private send(child: cp.ChildProcess, message: ParentMessage): void { - child.send(message) - } -} - -/** - * Process wrapper. - */ -export const wrapper = - typeof process.env.CODE_SERVER_PARENT_PID !== "undefined" - ? new ChildProcess(parseInt(process.env.CODE_SERVER_PARENT_PID)) - : new ParentProcess(require("../../package.json").version) - -export function isChild(proc: ChildProcess | ParentProcess): proc is ChildProcess { - return proc instanceof ChildProcess -} - -// It's possible that the pipe has closed (for example if you run code-server -// --version | head -1). Assume that means we're done. -if (!process.stdout.isTTY) { - process.stdout.on("error", () => wrapper.exit()) -} - -// Don't let uncaught exceptions crash the process. -process.on("uncaughtException", (error) => { - wrapper.logger.error(`Uncaught exception: ${error.message}`) - if (typeof error.stack !== "undefined") { - wrapper.logger.error(error.stack) - } -}) diff --git a/src/node/wsRouter.ts b/src/node/wsRouter.ts deleted file mode 100644 index d829d08213d6..000000000000 --- a/src/node/wsRouter.ts +++ /dev/null @@ -1,53 +0,0 @@ -import * as express from "express" -import * as expressCore from "express-serve-static-core" -import * as http from "http" -import Websocket from "ws" -import * as pluginapi from "../../typings/pluginapi" - -export const handleUpgrade = (app: express.Express, server: http.Server): void => { - server.on("upgrade", (req, socket, head) => { - socket.pause() - - req.ws = socket - req.head = head - req._ws_handled = false - - // Send the request off to be handled by Express. - ;(app as any).handle(req, new http.ServerResponse(req), () => { - if (!req._ws_handled) { - socket.end("HTTP/1.1 404 Not Found\r\n\r\n") - } - }) - }) -} - -interface InternalWebsocketRequest extends pluginapi.WebsocketRequest { - _ws_handled: boolean -} - -export class WebsocketRouter { - public readonly router = express.Router() - - /** - * Handle a websocket at this route. Note that websockets are immediately - * paused when they come in. - */ - public ws(route: expressCore.PathParams, ...handlers: pluginapi.WebSocketHandler[]): void { - this.router.get( - route, - ...handlers.map((handler) => { - const wrapped: express.Handler = (req, res, next) => { - ;(req as InternalWebsocketRequest)._ws_handled = true - return handler(req as pluginapi.WebsocketRequest, res, next) - } - return wrapped - }), - ) - } -} - -export function Router(): WebsocketRouter { - return new WebsocketRouter() -} - -export const wss = new Websocket.Server({ noServer: true }) diff --git a/lib/vscode/src/tsconfig.base.json b/src/tsconfig.base.json similarity index 100% rename from lib/vscode/src/tsconfig.base.json rename to src/tsconfig.base.json diff --git a/lib/vscode/src/tsconfig.json b/src/tsconfig.json similarity index 100% rename from lib/vscode/src/tsconfig.json rename to src/tsconfig.json diff --git a/lib/vscode/src/tsconfig.monaco.json b/src/tsconfig.monaco.json similarity index 100% rename from lib/vscode/src/tsconfig.monaco.json rename to src/tsconfig.monaco.json diff --git a/lib/vscode/src/tsconfig.tsec.json b/src/tsconfig.tsec.json similarity index 100% rename from lib/vscode/src/tsconfig.tsec.json rename to src/tsconfig.tsec.json diff --git a/lib/vscode/src/tsec.exemptions.json b/src/tsec.exemptions.json similarity index 96% rename from lib/vscode/src/tsec.exemptions.json rename to src/tsec.exemptions.json index 2f123f56f0ed..bac5c3c40057 100644 --- a/lib/vscode/src/tsec.exemptions.json +++ b/src/tsec.exemptions.json @@ -20,6 +20,7 @@ "vs/editor/browser/view/domLineBreaksComputer.ts", "vs/editor/browser/view/viewLayer.ts", "vs/editor/browser/widget/diffEditorWidget.ts", + "vs/editor/contrib/inlineCompletions/ghostTextWidget.ts", "vs/editor/browser/widget/diffReview.ts", "vs/editor/standalone/browser/colorizer.ts", "vs/workbench/api/worker/extHostExtensionService.ts", diff --git a/lib/vscode/src/typings/require.d.ts b/src/typings/require.d.ts similarity index 100% rename from lib/vscode/src/typings/require.d.ts rename to src/typings/require.d.ts diff --git a/lib/vscode/src/typings/thenable.d.ts b/src/typings/thenable.d.ts similarity index 100% rename from lib/vscode/src/typings/thenable.d.ts rename to src/typings/thenable.d.ts diff --git a/lib/vscode/src/vs/base/browser/browser.ts b/src/vs/base/browser/browser.ts similarity index 97% rename from lib/vscode/src/vs/base/browser/browser.ts rename to src/vs/base/browser/browser.ts index 485df81cb29f..ed6b696e40cb 100644 --- a/lib/vscode/src/vs/base/browser/browser.ts +++ b/src/vs/base/browser/browser.ts @@ -115,7 +115,6 @@ export const isWebKit = (userAgent.indexOf('AppleWebKit') >= 0); export const isChrome = (userAgent.indexOf('Chrome') >= 0); export const isSafari = (!isChrome && (userAgent.indexOf('Safari') >= 0)); export const isWebkitWebView = (!isChrome && !isSafari && isWebKit); -export const isIPad = (userAgent.indexOf('iPad') >= 0 || (isSafari && navigator.maxTouchPoints > 0)); export const isEdgeLegacyWebView = (userAgent.indexOf('Edge/') >= 0) && (userAgent.indexOf('WebView/') >= 0); export const isElectron = (userAgent.indexOf('Electron/') >= 0); export const isAndroid = (userAgent.indexOf('Android') >= 0); diff --git a/lib/vscode/src/vs/base/browser/canIUse.ts b/src/vs/base/browser/canIUse.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/canIUse.ts rename to src/vs/base/browser/canIUse.ts diff --git a/lib/vscode/src/vs/base/browser/contextmenu.ts b/src/vs/base/browser/contextmenu.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/contextmenu.ts rename to src/vs/base/browser/contextmenu.ts diff --git a/lib/vscode/src/vs/base/browser/dnd.ts b/src/vs/base/browser/dnd.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/dnd.ts rename to src/vs/base/browser/dnd.ts diff --git a/lib/vscode/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts similarity index 94% rename from lib/vscode/src/vs/base/browser/dom.ts rename to src/vs/base/browser/dom.ts index 022fe7c0c193..a5d014dc8a80 100644 --- a/lib/vscode/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -17,6 +17,7 @@ import { FileAccess, RemoteAuthorities } from 'vs/base/common/network'; import { BrowserFeatures } from 'vs/base/browser/canIUse'; import { insane, InsaneOptions } from 'vs/base/common/insane/insane'; import { KeyCode } from 'vs/base/common/keyCodes'; +import { withNullAsUndefined } from 'vs/base/common/types'; export function clearNode(node: HTMLElement): void { while (node.firstChild) { @@ -347,16 +348,7 @@ export function getClientArea(element: HTMLElement): Dimension { // If visual view port exits and it's on mobile, it should be used instead of window innerWidth / innerHeight, or document.body.clientWidth / document.body.clientHeight if (platform.isIOS && window.visualViewport) { - const width = window.visualViewport.width; - const height = window.visualViewport.height - ( - browser.isStandalone - // in PWA mode, the visual viewport always includes the safe-area-inset-bottom (which is for the home indicator) - // even when you are using the onscreen monitor, the visual viewport will include the area between system statusbar and the onscreen keyboard - // plus the area between onscreen keyboard and the bottom bezel, which is 20px on iOS. - ? (20 + 4) // + 4px for body margin - : 0 - ); - return new Dimension(width, height); + return new Dimension(window.visualViewport.width, window.visualViewport.height); } // Try innerWidth / innerHeight @@ -1187,28 +1179,44 @@ export function computeScreenAwareSize(cssPx: number): number { } /** + * Open safely a new window. This is the best way to do so, but you cannot tell + * if the window was opened or if it was blocked by the brower's popup blocker. + * If you want to tell if the browser blocked the new window, use `windowOpenNoOpenerWithSuccess`. + * * See https://github.com/microsoft/monaco-editor/issues/601 * To protect against malicious code in the linked site, particularly phishing attempts, * the window.opener should be set to null to prevent the linked site from having access * to change the location of the current page. * See https://mathiasbynens.github.io/rel-noopener/ */ -export function windowOpenNoOpener(url: string): boolean { - if (browser.isElectron || browser.isEdgeLegacyWebView) { - // In VSCode, window.open() always returns null... - // The same is true for a WebView (see https://github.com/microsoft/monaco-editor/issues/628) - // Also call directly window.open in sandboxed Electron (see https://github.com/microsoft/monaco-editor/issues/2220) - window.open(url); +export function windowOpenNoOpener(url: string): void { + // By using 'noopener' in the `windowFeatures` argument, the newly created window will + // not be able to use `window.opener` to reach back to the current page. + // See https://stackoverflow.com/a/46958731 + // See https://developer.mozilla.org/en-US/docs/Web/API/Window/open#noopener + // However, this also doesn't allow us to realize if the browser blocked + // the creation of the window. + window.open(url, '_blank', 'noopener'); +} + +/** + * Open safely a new window. This technique is not appropiate in certain contexts, + * like for example when the JS context is executing inside a sandboxed iframe. + * If it is not necessary to know if the browser blocked the new window, use + * `windowOpenNoOpener`. + * + * See https://github.com/microsoft/monaco-editor/issues/601 + * See https://github.com/microsoft/monaco-editor/issues/2474 + * See https://mathiasbynens.github.io/rel-noopener/ + */ +export function windowOpenNoOpenerWithSuccess(url: string): boolean { + const newTab = window.open(); + if (newTab) { + (newTab as any).opener = null; + newTab.location.href = url; return true; - } else { - let newTab = window.open(); - if (newTab) { - (newTab as any).opener = null; - newTab.location.href = url; - return true; - } - return false; } + return false; } export function animate(fn: () => void): IDisposable { @@ -1266,6 +1274,29 @@ export function triggerDownload(dataOrUri: Uint8Array | URI, name: string): void setTimeout(() => document.body.removeChild(anchor)); } +export function triggerUpload(): Promise { + return new Promise(resolve => { + + // In order to upload to the browser, create a + // input element of type `file` and click it + // to gather the selected files + const input = document.createElement('input'); + document.body.appendChild(input); + input.type = 'file'; + input.multiple = true; + + // Resolve once the input event has fired once + Event.once(Event.fromDOMEventEmitter(input, 'input'))(() => { + resolve(withNullAsUndefined(input.files)); + }); + + input.click(); + + // Ensure to remove the element from DOM eventually + setTimeout(() => document.body.removeChild(input)); + }); +} + export enum DetectedFullscreenMode { /** @@ -1450,6 +1481,9 @@ export class ModifierKeyEmitter extends Emitter { }; this._subscriptions.add(domEvent(window, 'keydown', true)(e => { + if (e.defaultPrevented) { + return; + } const event = new StandardKeyboardEvent(e); // If Alt-key keydown event is repeated, ignore it #112347 @@ -1484,6 +1518,10 @@ export class ModifierKeyEmitter extends Emitter { })); this._subscriptions.add(domEvent(window, 'keyup', true)(e => { + if (e.defaultPrevented) { + return; + } + if (!e.altKey && this._keyStatus.altKey) { this._keyStatus.lastKeyReleased = 'alt'; } else if (!e.ctrlKey && this._keyStatus.ctrlKey) { @@ -1574,3 +1612,13 @@ export function getCookieValue(name: string): string | undefined { return match ? match.pop() : undefined; } + +export function addMatchMediaChangeListener(query: string, callback: () => void): void { + const mediaQueryList = window.matchMedia(query); + if (typeof mediaQueryList.addEventListener === 'function') { + mediaQueryList.addEventListener('change', callback); + } else { + // Safari 13.x + mediaQueryList.addListener(callback); + } +} diff --git a/lib/vscode/src/vs/base/browser/event.ts b/src/vs/base/browser/event.ts similarity index 59% rename from lib/vscode/src/vs/base/browser/event.ts rename to src/vs/base/browser/event.ts index 9ae46f15147a..a1214db777db 100644 --- a/lib/vscode/src/vs/base/browser/event.ts +++ b/src/vs/base/browser/event.ts @@ -3,7 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { GestureEvent } from 'vs/base/browser/touch'; import { Event as BaseEvent, Emitter } from 'vs/base/common/event'; +import { IDisposable } from 'vs/base/common/lifecycle'; export type EventHandler = HTMLElement | HTMLDocument | Window; @@ -12,6 +14,9 @@ export interface IDomEvent { (element: EventHandler, type: string, useCapture?: boolean): BaseEvent; } +/** + * @deprecated Use `DomEmitter` instead + */ export const domEvent: IDomEvent = (element: EventHandler, type: string, useCapture?: boolean) => { const fn = (e: Event) => emitter.fire(e); const emitter = new Emitter({ @@ -26,6 +31,35 @@ export const domEvent: IDomEvent = (element: EventHandler, type: string, useCapt return emitter.event; }; +export interface DOMEventMap extends HTMLElementEventMap { + '-monaco-gesturetap': GestureEvent; + '-monaco-gesturechange': GestureEvent; + '-monaco-gesturestart': GestureEvent; + '-monaco-gesturesend': GestureEvent; + '-monaco-gesturecontextmenu': GestureEvent; +} + +export class DomEmitter implements IDisposable { + + private emitter: Emitter; + + get event(): BaseEvent { + return this.emitter.event; + } + + constructor(element: EventHandler, type: K, useCapture?: boolean) { + const fn = (e: Event) => this.emitter.fire(e as DOMEventMap[K]); + this.emitter = new Emitter({ + onFirstListenerAdd: () => element.addEventListener(type, fn, useCapture), + onLastListenerRemove: () => element.removeEventListener(type, fn, useCapture) + }); + } + + dispose(): void { + this.emitter.dispose(); + } +} + export interface CancellableEvent { preventDefault(): void; stopPropagation(): void; diff --git a/lib/vscode/src/vs/base/browser/fastDomNode.ts b/src/vs/base/browser/fastDomNode.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/fastDomNode.ts rename to src/vs/base/browser/fastDomNode.ts diff --git a/lib/vscode/src/vs/base/browser/formattedTextRenderer.ts b/src/vs/base/browser/formattedTextRenderer.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/formattedTextRenderer.ts rename to src/vs/base/browser/formattedTextRenderer.ts diff --git a/lib/vscode/src/vs/base/browser/globalMouseMoveMonitor.ts b/src/vs/base/browser/globalMouseMoveMonitor.ts similarity index 96% rename from lib/vscode/src/vs/base/browser/globalMouseMoveMonitor.ts rename to src/vs/base/browser/globalMouseMoveMonitor.ts index 4911b59e0801..6745aafbb135 100644 --- a/lib/vscode/src/vs/base/browser/globalMouseMoveMonitor.ts +++ b/src/vs/base/browser/globalMouseMoveMonitor.ts @@ -7,6 +7,7 @@ import * as dom from 'vs/base/browser/dom'; import { IframeUtils } from 'vs/base/browser/iframe'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { isIOS } from 'vs/base/common/platform'; export interface IStandardMouseMoveEventData { leftButton: boolean; @@ -88,7 +89,7 @@ export class GlobalMouseMoveMonitor implements I this._onStopCallback = onStopCallback; const windowChain = IframeUtils.getSameOriginWindowChain(); - const mouseMove = 'mousemove'; + const mouseMove = isIOS ? 'pointermove' : 'mousemove'; // Safari sends wrong event, workaround for #122653 const mouseUp = 'mouseup'; const listenTo: (Document | ShadowRoot)[] = windowChain.map(element => element.window.document); diff --git a/lib/vscode/src/vs/base/browser/hash.ts b/src/vs/base/browser/hash.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/hash.ts rename to src/vs/base/browser/hash.ts diff --git a/lib/vscode/src/vs/base/browser/history.ts b/src/vs/base/browser/history.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/history.ts rename to src/vs/base/browser/history.ts diff --git a/lib/vscode/src/vs/base/browser/iframe.ts b/src/vs/base/browser/iframe.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/iframe.ts rename to src/vs/base/browser/iframe.ts diff --git a/lib/vscode/src/vs/base/browser/keyboardEvent.ts b/src/vs/base/browser/keyboardEvent.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/keyboardEvent.ts rename to src/vs/base/browser/keyboardEvent.ts diff --git a/lib/vscode/src/vs/base/browser/markdownRenderer.ts b/src/vs/base/browser/markdownRenderer.ts similarity index 97% rename from lib/vscode/src/vs/base/browser/markdownRenderer.ts rename to src/vs/base/browser/markdownRenderer.ts index 5378627e57ae..78451aa3776a 100644 --- a/lib/vscode/src/vs/base/browser/markdownRenderer.ts +++ b/src/vs/base/browser/markdownRenderer.ts @@ -312,6 +312,14 @@ function getInsaneOptions(options: { readonly isTrusted?: boolean }): InsaneOpti }; } +/** + * Strips all markdown from `string`, if it's an IMarkdownString. For example + * `# Header` would be output as `Header`. If it's not, the string is returned. + */ +export function renderStringAsPlaintext(string: IMarkdownString | string) { + return typeof string === 'string' ? string : renderMarkdownAsPlaintext(string); +} + /** * Strips all markdown from `markdown`. For example `# Header` would be output as `Header`. */ @@ -386,6 +394,7 @@ export function renderMarkdownAsPlaintext(markdown: IMarkdownString) { const unescapeInfo = new Map([ ['"', '"'], + [' ', ' '], ['&', '&'], [''', '\''], ['<', '<'], diff --git a/lib/vscode/src/vs/base/browser/mouseEvent.ts b/src/vs/base/browser/mouseEvent.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/mouseEvent.ts rename to src/vs/base/browser/mouseEvent.ts diff --git a/lib/vscode/src/vs/base/browser/touch.ts b/src/vs/base/browser/touch.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/touch.ts rename to src/vs/base/browser/touch.ts diff --git a/lib/vscode/src/vs/base/browser/ui/actionbar/actionViewItems.ts b/src/vs/base/browser/ui/actionbar/actionViewItems.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/actionbar/actionViewItems.ts rename to src/vs/base/browser/ui/actionbar/actionViewItems.ts diff --git a/lib/vscode/src/vs/base/browser/ui/actionbar/actionbar.css b/src/vs/base/browser/ui/actionbar/actionbar.css similarity index 92% rename from lib/vscode/src/vs/base/browser/ui/actionbar/actionbar.css rename to src/vs/base/browser/ui/actionbar/actionbar.css index 7020bdc67008..71ecf512f7c0 100644 --- a/lib/vscode/src/vs/base/browser/ui/actionbar/actionbar.css +++ b/src/vs/base/browser/ui/actionbar/actionbar.css @@ -75,6 +75,16 @@ margin-right: .8em; } +.monaco-action-bar .action-item .action-label.separator { + width: 1px; + height: 16px; + margin: 5px 4px !important; + cursor: default; + min-width: 1px; + padding: 0; + background-color: #bbb; +} + .secondary-actions .monaco-action-bar .action-label { margin-left: 6px; } diff --git a/lib/vscode/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/actionbar/actionbar.ts rename to src/vs/base/browser/ui/actionbar/actionbar.ts diff --git a/lib/vscode/src/vs/base/browser/ui/aria/aria.css b/src/vs/base/browser/ui/aria/aria.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/aria/aria.css rename to src/vs/base/browser/ui/aria/aria.css diff --git a/lib/vscode/src/vs/base/browser/ui/aria/aria.ts b/src/vs/base/browser/ui/aria/aria.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/aria/aria.ts rename to src/vs/base/browser/ui/aria/aria.ts diff --git a/lib/vscode/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css rename to src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css diff --git a/lib/vscode/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts rename to src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts diff --git a/lib/vscode/src/vs/base/browser/ui/button/button.css b/src/vs/base/browser/ui/button/button.css similarity index 98% rename from lib/vscode/src/vs/base/browser/ui/button/button.css rename to src/vs/base/browser/ui/button/button.css index fb4ebbf081df..46a5b0e04819 100644 --- a/lib/vscode/src/vs/base/browser/ui/button/button.css +++ b/src/vs/base/browser/ui/button/button.css @@ -35,6 +35,7 @@ .monaco-button-dropdown { display: flex; + cursor: pointer; } .monaco-button-dropdown > .monaco-dropdown-button { diff --git a/lib/vscode/src/vs/base/browser/ui/button/button.ts b/src/vs/base/browser/ui/button/button.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/button/button.ts rename to src/vs/base/browser/ui/button/button.ts diff --git a/lib/vscode/src/vs/base/browser/ui/centered/centeredViewLayout.ts b/src/vs/base/browser/ui/centered/centeredViewLayout.ts similarity index 99% rename from lib/vscode/src/vs/base/browser/ui/centered/centeredViewLayout.ts rename to src/vs/base/browser/ui/centered/centeredViewLayout.ts index 52cc64b8a369..c774bfaf5eaa 100644 --- a/lib/vscode/src/vs/base/browser/ui/centered/centeredViewLayout.ts +++ b/src/vs/base/browser/ui/centered/centeredViewLayout.ts @@ -165,6 +165,7 @@ export class CenteredViewLayout implements IDisposable { this.splitView = undefined; this.emptyViews = undefined; this.container.appendChild(this.view.element); + this.view.layout(this.width, this.height, 0, 0); } } diff --git a/lib/vscode/src/vs/base/browser/ui/checkbox/checkbox.css b/src/vs/base/browser/ui/checkbox/checkbox.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/checkbox/checkbox.css rename to src/vs/base/browser/ui/checkbox/checkbox.css diff --git a/lib/vscode/src/vs/base/browser/ui/checkbox/checkbox.ts b/src/vs/base/browser/ui/checkbox/checkbox.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/checkbox/checkbox.ts rename to src/vs/base/browser/ui/checkbox/checkbox.ts diff --git a/lib/vscode/src/vs/base/browser/ui/codicons/codicon/codicon-modifiers.css b/src/vs/base/browser/ui/codicons/codicon/codicon-modifiers.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/codicons/codicon/codicon-modifiers.css rename to src/vs/base/browser/ui/codicons/codicon/codicon-modifiers.css diff --git a/lib/vscode/src/vs/base/browser/ui/codicons/codicon/codicon.css b/src/vs/base/browser/ui/codicons/codicon/codicon.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/codicons/codicon/codicon.css rename to src/vs/base/browser/ui/codicons/codicon/codicon.css diff --git a/lib/vscode/src/vs/base/browser/ui/codicons/codicon/codicon.ttf b/src/vs/base/browser/ui/codicons/codicon/codicon.ttf similarity index 91% rename from lib/vscode/src/vs/base/browser/ui/codicons/codicon/codicon.ttf rename to src/vs/base/browser/ui/codicons/codicon/codicon.ttf index 016e9a1e000af380e5512c4bdb85aec40db82477..eec2d491b9c142d8e745468c1acb4ac9fb38a4ae 100644 GIT binary patch delta 3954 zcmXZf2~HHOJ@ zjwj7xHZ|5P7&XQav$@q;O_kUrwVK*AnJ=+6TT`20@8>P&{NA1SX5PFx-(Akf{ypB? zU-aG{<$4_8RsdCX?X_Klj$HZ@@ZAm!uV2x2SL4HT=AQ*3P6L;lni^{B!#94IA)mc0 z((DD_z5#RP^$`)>)V_M{=AfH5<@>Gz1NOFc*42(HU(^qTe+xJ+w%4xha%|-dd4HsQ zer!i=dqd>zu)K{RQse{vU7f2|UmAEU9(3daL+3nnBr2y>-jo}F-q4t9ONV5Che2MS z%N2a`Mv?s`x8lv4H*a`-<@JS}`oUqZ%AefBR`(db!gD=m=|8~T=W{Z-^w!tGs~BFl zUd2lE2fRz+?KMVj8hq;ud_2GOZ1o)XoHQloocjac#D;zN55C8P_?%O4k;CyGMj7499T- zzsG6(5ohryoX4N>7hJ+$B}t#+Z@7xT<1_pN24CVUT*E(c9sk1D_!i&c-}nJH@L&9h zpU{t+1if7xKp*&_ybDW$R@7fR63c%T;?%<7_$+GEPMzTm!bqarHXvq zSNw0dulo;l1=zw09%hfWx&Y5IC1nIpt-?Nu%axQ3JatM62%dT+r36odg4DC8QAv5h zvqIsb#3m&r2T!v+*wZXeeotbH;wX1VKwR5{zCc$>suE5=IPsyIoaT@pd*Lyrs~i<2cjq$o4O)2$dU(XFI=;CWc#5sClD zD0%%T;A0O=>{&E;)&S`)m_bVV3`P=aNyotiD(O9#!AiOiW{8r0gb7m8nJ~dhdK5<1 z*^+LB8LFgjVI*UgbTEvh&}9$O%rGOAv^7kqk_Ly7$!JNd!;DhW^e|yc+8<`LvQyWD zD;WtevbdHE2N+pIOU49Dgu+p{V8+Uckl6tfsbq@4j8igCU}WVinJh5TN@fhqcqP*Y zCPvBJftjFW0>MZ&ESW_xw=0=SFp^<2NlHit6wDn;Mioq~lA#47>9%Bi!Ne&UWH6F$ z3zsD(C>d@rQo5FmIhZ6R0}m!y$>@VgQ8EN!Y%Llg^AILY$z+5{S281EGL%e97->gK z<|a(0k_ifvrDT@EWGk7fFjJMxR~V;~Neh#sTrzZFa+Qowe7$#rINQRlFWH`f2 zS2CtyW+)lhFa=6RH%y_zO^GuV<#(GRMQ@44Hvh%a3%TI&>Tfz~V9LTpg9#n-543vPv? zt&Ju{TN}-aHgzqEk~)`Zl@mdmyEa9eyLLsJyADN3mFZNp>FQFn>H3+XP1j0Ao32%g zHZ7|aZ7P0#iwm^5SfglDai^kP{nPK~C&)Zd9~OwMoft0Omd=`vREzmFy5;exYQq0JB-)HFwLX3MRXI<@mNc zBrKj4?)A-frv9)%0;&7Jf@f<@wlR0niGn75>G1TOFX5R z?cNa{#Sh)R;i03J%C)mf_Gd8X6n6Gp4KJkYKx{~CW9_|9}(3iM5acAPGBu7$5Qg_m|Q~pSsIA%o*pbckXju z%kg*RWaiZ5e3~1RdpK`w-j=){@?-O#%J0kXpH?$%!?bPFmruVm!)L~}8J`wZ7n~}L zF5FPKzwr9Z%9*`IF-6OYwiLZu^ii>+IKOy%@!{gHXC=(qG3(Oo=-CJ6#LRhi&h?Tt zC5K9G%x#?eYH3nwRq5KYEoCRlu9gRtuPlGG{B*^LiqjRY?<+GZH&pJb{A8Z@y!Xy}Y*X^qhs_$xuX=rM=yJ2g?6AdpnhBekS?rglaB5lQ<6_=V)nvOKDYd+KB z(^A~Br{(+BnXMhIeXTc!wPm(-v|VoxY4>zAb_R8JcYfBD(sLwY)cgvmD!{AHs}%vV ziytQc;iX5021f-)21gE$oG^gF>Au0CQ8`Y>wVa%vLO7-WxYO&g{w2Fx&#d>F>~!}3 zig)%0B<+clrJ79wHTF}96CHIb+BWM!|4^r3F%`T zgT3M$PNsAGu8$*}Q}TQ=S{~TCs=z;`aoW)Gd!`PVzwO1H>m%kBQ&pRBB cwu7H}^Rlm>Z*#}0u7(^b delta 3867 zcmXxn33Sxe6$bF{W*4#`TOb4y2tte@`(_d*E7=K22-%S=WM3W%E1j8r5?4` z6%kOYP*6lf1ypJ=+88NPi`FXURhm+vEfv%6aV?zR|K`mMb8_BY&SmpXk3Bm)HitPM z1>_z8RV}?u1D6g2909y}o>JA`b5mRG(Q#2g$N}JVct>l~%HZmg$NAaQl+?i&yoWtY z`7__g+>YMWYi|!98{_wV1$b`n>2GODHkXEgV4mHEdz;n{xZN!m`TjJ1KD4i?w{`aO zL0Pu}WA+2%2Kra6KEJv7UWkkWlX4z75SGye;b-ZR@2QC^0@BZ8y!#oxf>Yay-TxoQ z#>OtXf9L)!&pvRouksK7jdZzY$;&dhdr-!Cx<229mJ(Sk z<+4;NWtmh@$x^cR4UX2lA@NQ=UGSEz5G^BbPp6zc{f?FyeVb|}^oMmiPVVeC@2B}Tdx zQW<-ctYGX_as^|bk}Dbe6)O@W1AuF|r zi#^BJ)+tskMx2WEi;?vT?=!MLEh%tq^ow?8^K_?TZDZsv1^YX0RFc5BNl7r{-Ab-u zaSFz_{{1m$n#$T}yVFDC85{7qcu{U9O=N7vZh81G5UtuOGb}kI_Yq5u6rT|X+ zU^~N1RcvgSK*bh^Vd5<|JIr*&wucE)8~`vg6h{FJFVwO#*YM&jjt7`oih}|sL~&#| zVM2KzP7j#bigN^pmt}FHz%Y{*XA8_+#VG@GmEydCnWs2;V3+`lGYBSJaT>ues}|=H zOoYXv;)sG_>Maf{7^c|b*n(N0IKW_-VvC~;CR%Z*!Ne$zHy9SP#X$!Xr#SLp;uVJ< z49m~r7=&>q@a}{Qx;)I29 zD9&1#4CUn5g~?PLz%W^gqZlSzaVW#&D2`{CT*W~Rvq*7d!{jLrZLhwC0>k+m3T9jD)C_~Q{u~5uEcgsg%W?prAh)AE0vv{W|@*n z%)hBpGKH~P$yCM~C4r2!N^A$zDG6e%S2BySK}iVXawVaR*D0~Zy+VmC;zn}vA-0N} zl-Me6R$?o+MTxD}l}c<;wkolO*rvo5U%L`pCml*yBc@Y{O=Fi5rqOA-c_6WQ>``L# z*sH|mu}_K3UB42h%?v29sr#7{o4V_j*wn33VpFtQiA~E5mpLIeFKd+8yxge7reduU zn~Iy1*i_uC#9sf;mDuaQMTx!ITb0@&U6=aSefaj?1upa3g`)u8_(2yyBJu zvqN!Tfw8|V;VoC>jIf3Kd3s54hk>!zK-^|v>@^Vg8kkoUHyjvyC4?c@Ju{-6$vnNP z#5UV&O6=v^Zzr*x{kq~t1am;)KE^i`?+WIi;=Tm)rsC!Vb4bB{=UYl_kGu`E*@xK1 zct?qCn8Qla8ILGg$aqwVgYjJ@8I12K$z*(ANfzTVC26iFg2Uzy^K@Ksw!wU;xVym& zD!aw){ysQgoM$4_BR54JTrhRPi75Z5^-*V|;yOs`DI;T}OR&K03Q2EueIm^ye&8upt+FspNy|rdu&B~fnwLZ0Z zwa4mw>MH6Ut~*^HQGZMQw)zVV`=@%E|ho7xX{OzwEBv!V0F&ab;7x;AwUcZYYEcJJ*z*%LImr?h9V z=UnfxzP!HC{_FdX4oqfdJ_wm!z5Ci5hZZ2v-DbJP$0a8vJ7oSm z{`H>a=I`b`C(6ws$@9Y!;{&IJNkduRHFLWkt*$R$l8_WUGuV+;J+YuOI3kvsCRc2%cr%mg+ck4~LlH79JhE?-Y9U-6XUi<8~ Y4bru**-eJr_N92rY43fZe$wajKT5GA8~^|S diff --git a/lib/vscode/src/vs/base/browser/ui/codicons/codiconStyles.ts b/src/vs/base/browser/ui/codicons/codiconStyles.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/codicons/codiconStyles.ts rename to src/vs/base/browser/ui/codicons/codiconStyles.ts diff --git a/lib/vscode/src/vs/base/browser/ui/contextview/contextview.css b/src/vs/base/browser/ui/contextview/contextview.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/contextview/contextview.css rename to src/vs/base/browser/ui/contextview/contextview.css diff --git a/lib/vscode/src/vs/base/browser/ui/contextview/contextview.ts b/src/vs/base/browser/ui/contextview/contextview.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/contextview/contextview.ts rename to src/vs/base/browser/ui/contextview/contextview.ts diff --git a/lib/vscode/src/vs/base/browser/ui/countBadge/countBadge.css b/src/vs/base/browser/ui/countBadge/countBadge.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/countBadge/countBadge.css rename to src/vs/base/browser/ui/countBadge/countBadge.css diff --git a/lib/vscode/src/vs/base/browser/ui/countBadge/countBadge.ts b/src/vs/base/browser/ui/countBadge/countBadge.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/countBadge/countBadge.ts rename to src/vs/base/browser/ui/countBadge/countBadge.ts diff --git a/lib/vscode/src/vs/base/browser/ui/dialog/dialog.css b/src/vs/base/browser/ui/dialog/dialog.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/dialog/dialog.css rename to src/vs/base/browser/ui/dialog/dialog.css diff --git a/lib/vscode/src/vs/base/browser/ui/dialog/dialog.ts b/src/vs/base/browser/ui/dialog/dialog.ts similarity index 93% rename from lib/vscode/src/vs/base/browser/ui/dialog/dialog.ts rename to src/vs/base/browser/ui/dialog/dialog.ts index 2c5d315a82b2..6df00351bfc7 100644 --- a/lib/vscode/src/vs/base/browser/ui/dialog/dialog.ts +++ b/src/vs/base/browser/ui/dialog/dialog.ts @@ -101,16 +101,17 @@ export class Dialog extends Disposable { this.buttonsContainer = buttonsRowElement.appendChild($('.dialog-buttons')); const messageRowElement = this.element.appendChild($('.dialog-message-row')); - this.iconElement = messageRowElement.appendChild($('.dialog-icon')); + this.iconElement = messageRowElement.appendChild($('#monaco-dialog-icon.dialog-icon')); + this.iconElement.setAttribute('aria-label', this.getIconAriaLabel()); this.messageContainer = messageRowElement.appendChild($('.dialog-message-container')); if (this.options.detail || this.options.renderBody) { const messageElement = this.messageContainer.appendChild($('.dialog-message')); - const messageTextElement = messageElement.appendChild($('.dialog-message-text')); + const messageTextElement = messageElement.appendChild($('#monaco-dialog-message-text.dialog-message-text')); messageTextElement.innerText = this.message; } - this.messageDetailElement = this.messageContainer.appendChild($('.dialog-message-detail')); + this.messageDetailElement = this.messageContainer.appendChild($('#monaco-dialog-message-detail.dialog-message-detail')); if (this.options.detail || !this.options.renderBody) { this.messageDetailElement.innerText = this.options.detail ? this.options.detail : message; } else { @@ -118,8 +119,12 @@ export class Dialog extends Disposable { } if (this.options.renderBody) { - const customBody = this.messageContainer.appendChild($('.dialog-message-body')); + const customBody = this.messageContainer.appendChild($('#monaco-dialog-message-body.dialog-message-body')); this.options.renderBody(customBody); + + for (const el of this.messageContainer.querySelectorAll('a')) { + el.tabIndex = 0; + } } if (this.options.inputs) { @@ -157,7 +162,7 @@ export class Dialog extends Disposable { this.toolbarContainer = toolbarRowElement.appendChild($('.dialog-toolbar')); } - private getAriaLabel(): string { + private getIconAriaLabel(): string { let typeLabel = nls.localize('dialogInfoMessage', 'Info'); switch (this.options.type) { case 'error': @@ -176,7 +181,7 @@ export class Dialog extends Disposable { break; } - return `${typeLabel}: ${this.message} ${this.options.detail || ''}`; + return typeLabel; } updateMessage(message: string): void { @@ -218,6 +223,10 @@ export class Dialog extends Disposable { this._register(domEvent(window, 'keydown', true)((e: KeyboardEvent) => { const evt = new StandardKeyboardEvent(e); + if (evt.equals(KeyMod.Alt)) { + evt.preventDefault(); + } + if (evt.equals(KeyCode.Enter)) { // Enter in input field should OK the dialog @@ -246,6 +255,17 @@ export class Dialog extends Disposable { // Build a list of focusable elements in their visual order const focusableElements: { focus: () => void }[] = []; let focusedIndex = -1; + + if (this.messageContainer) { + const links = this.messageContainer.querySelectorAll('a'); + for (const link of links) { + focusableElements.push(link); + if (link === document.activeElement) { + focusedIndex = focusableElements.length - 1; + } + } + } + for (const input of this.inputs) { focusableElements.push(input); if (input.hasFocus()) { @@ -371,7 +391,7 @@ export class Dialog extends Disposable { this.applyStyles(); - this.element.setAttribute('aria-label', this.getAriaLabel()); + this.element.setAttribute('aria-labelledby', 'monaco-dialog-icon monaco-dialog-message-text monaco-dialog-message-detail monaco-dialog-message-body'); show(this.element); // Focus first element (input or button) diff --git a/lib/vscode/src/vs/base/browser/ui/dropdown/dropdown.css b/src/vs/base/browser/ui/dropdown/dropdown.css similarity index 82% rename from lib/vscode/src/vs/base/browser/ui/dropdown/dropdown.css rename to src/vs/base/browser/ui/dropdown/dropdown.css index b363b5578963..aeb837a6da79 100644 --- a/lib/vscode/src/vs/base/browser/ui/dropdown/dropdown.css +++ b/src/vs/base/browser/ui/dropdown/dropdown.css @@ -37,3 +37,10 @@ line-height: 16px; margin-left: -4px; } + +.monaco-dropdown-with-primary > .dropdown-action-container > .monaco-dropdown > .dropdown-label > .action-label { + display: block; + background-size: 16px; + background-position: center center; + background-repeat: no-repeat; +} diff --git a/lib/vscode/src/vs/base/browser/ui/dropdown/dropdown.ts b/src/vs/base/browser/ui/dropdown/dropdown.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/dropdown/dropdown.ts rename to src/vs/base/browser/ui/dropdown/dropdown.ts diff --git a/lib/vscode/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts b/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts rename to src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts diff --git a/lib/vscode/src/vs/base/browser/ui/findinput/findInput.css b/src/vs/base/browser/ui/findinput/findInput.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/findinput/findInput.css rename to src/vs/base/browser/ui/findinput/findInput.css diff --git a/lib/vscode/src/vs/base/browser/ui/findinput/findInput.ts b/src/vs/base/browser/ui/findinput/findInput.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/findinput/findInput.ts rename to src/vs/base/browser/ui/findinput/findInput.ts diff --git a/lib/vscode/src/vs/base/browser/ui/findinput/findInputCheckboxes.ts b/src/vs/base/browser/ui/findinput/findInputCheckboxes.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/findinput/findInputCheckboxes.ts rename to src/vs/base/browser/ui/findinput/findInputCheckboxes.ts diff --git a/lib/vscode/src/vs/base/browser/ui/findinput/replaceInput.ts b/src/vs/base/browser/ui/findinput/replaceInput.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/findinput/replaceInput.ts rename to src/vs/base/browser/ui/findinput/replaceInput.ts diff --git a/lib/vscode/src/vs/base/browser/ui/grid/grid.ts b/src/vs/base/browser/ui/grid/grid.ts similarity index 98% rename from lib/vscode/src/vs/base/browser/ui/grid/grid.ts rename to src/vs/base/browser/ui/grid/grid.ts index 38bc8c53d9e9..512d2d8a7ec0 100644 --- a/lib/vscode/src/vs/base/browser/ui/grid/grid.ts +++ b/src/vs/base/browser/ui/grid/grid.ts @@ -210,7 +210,9 @@ export class Grid extends Disposable { get minimumHeight(): number { return this.gridview.minimumHeight; } get maximumWidth(): number { return this.gridview.maximumWidth; } get maximumHeight(): number { return this.gridview.maximumHeight; } - get onDidChange(): Event<{ width: number; height: number; } | undefined> { return this.gridview.onDidChange; } + + readonly onDidChange: Event<{ width: number; height: number; } | undefined>; + readonly onDidScroll: Event; get boundarySashes(): IBoundarySashes { return this.gridview.boundarySashes; } set boundarySashes(boundarySashes: IBoundarySashes) { this.gridview.boundarySashes = boundarySashes; } @@ -232,8 +234,8 @@ export class Grid extends Disposable { } else { this.gridview = new GridView(options); } - this._register(this.gridview); + this._register(this.gridview); this._register(this.gridview.onDidSashReset(this.onDidSashReset, this)); const size: number | GridViewSizing = typeof options.firstViewVisibleCachedSize === 'number' @@ -243,6 +245,9 @@ export class Grid extends Disposable { if (!(view instanceof GridView)) { this._addView(view, size, [0]); } + + this.onDidChange = this.gridview.onDidChange; + this.onDidScroll = this.gridview.onDidScroll; } style(styles: IGridStyles): void { diff --git a/lib/vscode/src/vs/base/browser/ui/grid/gridview.css b/src/vs/base/browser/ui/grid/gridview.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/grid/gridview.css rename to src/vs/base/browser/ui/grid/gridview.css diff --git a/lib/vscode/src/vs/base/browser/ui/grid/gridview.ts b/src/vs/base/browser/ui/grid/gridview.ts similarity index 94% rename from lib/vscode/src/vs/base/browser/ui/grid/gridview.ts rename to src/vs/base/browser/ui/grid/gridview.ts index 323f71fd6336..996b968ddc06 100644 --- a/lib/vscode/src/vs/base/browser/ui/grid/gridview.ts +++ b/src/vs/base/browser/ui/grid/gridview.ts @@ -9,9 +9,10 @@ import { Orientation, Sash } from 'vs/base/browser/ui/sash/sash'; import { SplitView, IView as ISplitView, Sizing, LayoutPriority, ISplitViewStyles } from 'vs/base/browser/ui/splitview/splitview'; import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { $ } from 'vs/base/browser/dom'; -import { tail2 as tail } from 'vs/base/common/arrays'; +import { equals as arrayEquals, tail2 as tail } from 'vs/base/common/arrays'; import { Color } from 'vs/base/common/color'; import { clamp } from 'vs/base/common/numbers'; +import { isUndefined } from 'vs/base/common/types'; export { Sizing, LayoutPriority } from 'vs/base/browser/ui/splitview/splitview'; export { Orientation } from 'vs/base/browser/ui/sash/sash'; @@ -242,6 +243,10 @@ class BranchNode implements ISplitView, IDisposable { private readonly _onDidChange = new Emitter(); readonly onDidChange: Event = this._onDidChange.event; + private _onDidScroll = new Emitter(); + private onDidScrollDisposable: IDisposable = Disposable.None; + readonly onDidScroll: Event = this._onDidScroll.event; + private childrenChangeDisposable: IDisposable = Disposable.None; private readonly _onDidSashReset = new Emitter(); @@ -343,11 +348,7 @@ class BranchNode implements ISplitView, IDisposable { const onDidSashReset = Event.map(this.splitview.onDidSashReset, i => [i]); this.splitviewSashResetDisposable = onDidSashReset(this._onDidSashReset.fire, this._onDidSashReset); - const onDidChildrenChange = Event.map(Event.any(...this.children.map(c => c.onDidChange)), () => undefined); - this.childrenChangeDisposable = onDidChildrenChange(this._onDidChange.fire, this._onDidChange); - - const onDidChildrenSashReset = Event.any(...this.children.map((c, i) => Event.map(c.onDidSashReset, location => [i, ...location]))); - this.childrenSashResetDisposable = onDidChildrenSashReset(this._onDidSashReset.fire, this._onDidSashReset); + this.updateChildrenEvents(); } style(styles: IGridViewStyles): void { @@ -566,6 +567,11 @@ class BranchNode implements ISplitView, IDisposable { } private onDidChildrenChange(): void { + this.updateChildrenEvents(); + this._onDidChange.fire(undefined); + } + + private updateChildrenEvents(): void { const onDidChildrenChange = Event.map(Event.any(...this.children.map(c => c.onDidChange)), () => undefined); this.childrenChangeDisposable.dispose(); this.childrenChangeDisposable = onDidChildrenChange(this._onDidChange.fire, this._onDidChange); @@ -574,7 +580,9 @@ class BranchNode implements ISplitView, IDisposable { this.childrenSashResetDisposable.dispose(); this.childrenSashResetDisposable = onDidChildrenSashReset(this._onDidSashReset.fire, this._onDidSashReset); - this._onDidChange.fire(undefined); + const onDidScroll = Event.any(Event.signal(this.splitview.onDidScroll), ...this.children.map(c => c.onDidScroll)); + this.onDidScrollDisposable.dispose(); + this.onDidScrollDisposable = onDidScroll(this._onDidScroll.fire, this._onDidScroll); } trySet2x2(other: BranchNode): IDisposable { @@ -646,6 +654,25 @@ class BranchNode implements ISplitView, IDisposable { } } +/** + * Creates a latched event that avoids being fired when the view + * constraints do not change at all. + */ +function createLatchedOnDidChangeViewEvent(view: IView): Event { + const [onDidChangeViewConstraints, onDidSetViewSize] = Event.split(view.onDidChange, isUndefined); + + return Event.any( + onDidSetViewSize, + Event.map( + Event.latch( + Event.map(onDidChangeViewConstraints, _ => ([view.minimumWidth, view.maximumWidth, view.minimumHeight, view.maximumHeight])), + arrayEquals + ), + _ => undefined + ) + ); +} + class LeafNode implements ISplitView, IDisposable { private _size: number = 0; @@ -657,6 +684,7 @@ class LeafNode implements ISplitView, IDisposable { private absoluteOffset: number = 0; private absoluteOrthogonalOffset: number = 0; + readonly onDidScroll: Event = Event.None; readonly onDidSashReset: Event = Event.None; private _onDidLinkedWidthNodeChange = new Relay(); @@ -691,7 +719,8 @@ class LeafNode implements ISplitView, IDisposable { this._orthogonalSize = orthogonalSize; this._size = size; - this._onDidViewChange = Event.map(this.view.onDidChange, e => e && (this.orientation === Orientation.VERTICAL ? e.width : e.height)); + const onDidChange = createLatchedOnDidChangeViewEvent(view); + this._onDidViewChange = Event.map(onDidChange, e => e && (this.orientation === Orientation.VERTICAL ? e.width : e.height)); this.onDidChange = Event.any(this._onDidViewChange, this._onDidSetLinkedNode.event, this._onDidLinkedWidthNodeChange.event, this._onDidLinkedHeightNodeChange.event); } @@ -778,7 +807,25 @@ class LeafNode implements ISplitView, IDisposable { this._orthogonalSize = ctx.orthogonalSize; this.absoluteOffset = ctx.absoluteOffset + offset; this.absoluteOrthogonalOffset = ctx.absoluteOrthogonalOffset; - this.view.layout(this.width, this.height, this.top, this.left); + + this._layout(this.width, this.height, this.top, this.left); + } + + private cachedWidth: number = 0; + private cachedHeight: number = 0; + private cachedTop: number = 0; + private cachedLeft: number = 0; + + private _layout(width: number, height: number, top: number, left: number): void { + if (this.cachedWidth === width && this.cachedHeight === height && this.cachedTop === top && this.cachedLeft === left) { + return; + } + + this.cachedWidth = width; + this.cachedHeight = height; + this.cachedTop = top; + this.cachedLeft = left; + this.view.layout(width, height, top, left); } setVisible(visible: boolean): void { @@ -852,6 +899,7 @@ export class GridView implements IDisposable { this.element.appendChild(root.element); this.onDidSashResetRelay.input = root.onDidSashReset; this._onDidChange.input = Event.map(root.onDidChange, () => undefined); // TODO + this._onDidScroll.input = root.onDidScroll; } get orientation(): Orientation { @@ -877,6 +925,9 @@ export class GridView implements IDisposable { get maximumWidth(): number { return this.root.maximumHeight; } get maximumHeight(): number { return this.root.maximumHeight; } + private _onDidScroll = new Relay(); + readonly onDidScroll = this._onDidScroll.event; + private _onDidChange = new Relay(); readonly onDidChange = this._onDidChange.event; diff --git a/lib/vscode/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts b/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts rename to src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts diff --git a/lib/vscode/src/vs/base/browser/ui/hover/hover.css b/src/vs/base/browser/ui/hover/hover.css similarity index 96% rename from lib/vscode/src/vs/base/browser/ui/hover/hover.css rename to src/vs/base/browser/ui/hover/hover.css index f22533eebad4..8296d64a6971 100644 --- a/lib/vscode/src/vs/base/browser/ui/hover/hover.css +++ b/src/vs/base/browser/ui/hover/hover.css @@ -138,3 +138,8 @@ margin-bottom: 4px; display: inline-block; } + +.monaco-hover-content .action-container a { + -webkit-user-select: none; + user-select: none; +} diff --git a/lib/vscode/src/vs/base/browser/ui/hover/hoverWidget.ts b/src/vs/base/browser/ui/hover/hoverWidget.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/hover/hoverWidget.ts rename to src/vs/base/browser/ui/hover/hoverWidget.ts diff --git a/lib/vscode/src/vs/base/browser/ui/iconLabel/iconHoverDelegate.ts b/src/vs/base/browser/ui/iconLabel/iconHoverDelegate.ts similarity index 94% rename from lib/vscode/src/vs/base/browser/ui/iconLabel/iconHoverDelegate.ts rename to src/vs/base/browser/ui/iconLabel/iconHoverDelegate.ts index 33e7c72fd65d..83c61d9bd159 100644 --- a/lib/vscode/src/vs/base/browser/ui/iconLabel/iconHoverDelegate.ts +++ b/src/vs/base/browser/ui/iconLabel/iconHoverDelegate.ts @@ -16,9 +16,11 @@ export interface IHoverDelegateOptions { text: IMarkdownString | string; target: IHoverDelegateTarget | HTMLElement; hoverPosition?: HoverPosition; + showPointer?: boolean; } export interface IHoverDelegate { showHover(options: IHoverDelegateOptions): IDisposable | undefined; delay: number; + placement?: 'mouse' | 'element'; } diff --git a/lib/vscode/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts similarity index 63% rename from lib/vscode/src/vs/base/browser/ui/iconLabel/iconLabel.ts rename to src/vs/base/browser/ui/iconLabel/iconLabel.ts index ba6727884bf5..d4103d7c8b20 100644 --- a/lib/vscode/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -10,13 +10,10 @@ import { IMatch } from 'vs/base/common/filters'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { Range } from 'vs/base/common/range'; import { equals } from 'vs/base/common/objects'; -import { IHoverDelegate, IHoverDelegateOptions, IHoverDelegateTarget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; +import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; import { IMarkdownString } from 'vs/base/common/htmlContent'; -import { isFunction, isString } from 'vs/base/common/types'; -import { domEvent } from 'vs/base/browser/event'; -import { localize } from 'vs/nls'; -import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; -import { HoverPosition } from 'vs/base/browser/ui/hover/hoverWidget'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { setupCustomHover, setupNativeHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover'; export interface IIconLabelCreationOptions { supportHighlights?: boolean; @@ -91,17 +88,17 @@ class FastLabelNode { export class IconLabel extends Disposable { - private domNode: FastLabelNode; + private readonly domNode: FastLabelNode; - private nameNode: Label | LabelWithHighlights; + private readonly nameNode: Label | LabelWithHighlights; - private descriptionContainer: FastLabelNode; + private readonly descriptionContainer: FastLabelNode; private descriptionNode: FastLabelNode | HighlightedLabel | undefined; - private descriptionNodeFactory: () => FastLabelNode | HighlightedLabel; + private readonly descriptionNodeFactory: () => FastLabelNode | HighlightedLabel; - private labelContainer: HTMLElement; + private readonly labelContainer: HTMLElement; - private hoverDelegate: IHoverDelegate | undefined = undefined; + private readonly hoverDelegate: IHoverDelegate | undefined; private readonly customHovers: Map = new Map(); constructor(container: HTMLElement, options?: IIconLabelCreationOptions) { @@ -114,7 +111,7 @@ export class IconLabel extends Disposable { const nameContainer = dom.append(this.labelContainer, dom.$('span.monaco-icon-name-container')); this.descriptionContainer = this._register(new FastLabelNode(dom.append(this.labelContainer, dom.$('span.monaco-icon-description-container')))); - if (options?.supportHighlights) { + if (options?.supportHighlights || options?.supportIcons) { this.nameNode = new LabelWithHighlights(nameContainer, !!options.supportIcons); } else { this.nameNode = new Label(nameContainer); @@ -126,9 +123,7 @@ export class IconLabel extends Disposable { this.descriptionNodeFactory = () => this._register(new FastLabelNode(dom.append(this.descriptionContainer.element, dom.$('span.label-description')))); } - if (options?.hoverDelegate) { - this.hoverDelegate = options.hoverDelegate; - } + this.hoverDelegate = options?.hoverDelegate; } get element(): HTMLElement { @@ -185,116 +180,21 @@ export class IconLabel extends Disposable { } if (!this.hoverDelegate) { - return this.setupNativeHover(htmlElement, tooltip); - } else { - return this.setupCustomHover(this.hoverDelegate, htmlElement, tooltip); - } - } - - private static adjustXAndShowCustomHover(hoverOptions: IHoverDelegateOptions | undefined, mouseX: number | undefined, hoverDelegate: IHoverDelegate, isHovering: boolean): IDisposable | undefined { - if (hoverOptions && isHovering) { - if (mouseX !== undefined) { - (hoverOptions.target).x = mouseX + 10; - } - return hoverDelegate.showHover(hoverOptions); - } - return undefined; - } - - private getTooltipForCustom(markdownTooltip: string | IIconLabelMarkdownString): (token: CancellationToken) => Promise { - if (isString(markdownTooltip)) { - return async () => markdownTooltip; - } else if (isFunction(markdownTooltip.markdown)) { - return markdownTooltip.markdown; + setupNativeHover(htmlElement, tooltip); } else { - const markdown = markdownTooltip.markdown; - return async () => markdown; - } - } - - private setupCustomHover(hoverDelegate: IHoverDelegate, htmlElement: HTMLElement, markdownTooltip: string | IIconLabelMarkdownString): void { - htmlElement.setAttribute('title', ''); - htmlElement.removeAttribute('title'); - let tooltip = this.getTooltipForCustom(markdownTooltip); - - let hoverOptions: IHoverDelegateOptions | undefined; - let mouseX: number | undefined; - let isHovering = false; - let tokenSource: CancellationTokenSource; - let hoverDisposable: IDisposable | undefined; - function mouseOver(this: HTMLElement, e: MouseEvent): void { - if (isHovering) { - return; - } - tokenSource = new CancellationTokenSource(); - function mouseLeaveOrDown(this: HTMLElement, e: MouseEvent): void { - const isMouseDown = e.type === dom.EventType.MOUSE_DOWN; - if (isMouseDown) { - hoverDisposable?.dispose(); - hoverDisposable = undefined; - } - if (isMouseDown || (e).fromElement === htmlElement) { - isHovering = false; - hoverOptions = undefined; - tokenSource.dispose(true); - mouseLeaveDisposable.dispose(); - mouseDownDisposable.dispose(); - } - } - const mouseLeaveDisposable = domEvent(htmlElement, dom.EventType.MOUSE_LEAVE, true)(mouseLeaveOrDown.bind(htmlElement)); - const mouseDownDisposable = domEvent(htmlElement, dom.EventType.MOUSE_DOWN, true)(mouseLeaveOrDown.bind(htmlElement)); - isHovering = true; - - function mouseMove(this: HTMLElement, e: MouseEvent): void { - mouseX = e.x; + const hoverDisposable = setupCustomHover(this.hoverDelegate, htmlElement, tooltip); + if (hoverDisposable) { + this.customHovers.set(htmlElement, hoverDisposable); } - const mouseMoveDisposable = domEvent(htmlElement, dom.EventType.MOUSE_MOVE, true)(mouseMove.bind(htmlElement)); - setTimeout(async () => { - if (isHovering && tooltip) { - // Re-use the already computed hover options if they exist. - if (!hoverOptions) { - const target: IHoverDelegateTarget = { - targetElements: [this], - dispose: () => { } - }; - hoverOptions = { - text: localize('iconLabel.loading', "Loading..."), - target, - hoverPosition: HoverPosition.BELOW - }; - hoverDisposable = IconLabel.adjustXAndShowCustomHover(hoverOptions, mouseX, hoverDelegate, isHovering); - - const resolvedTooltip = (await tooltip(tokenSource.token)) ?? (!isString(markdownTooltip) ? markdownTooltip.markdownNotSupportedFallback : undefined); - if (resolvedTooltip) { - hoverOptions = { - text: resolvedTooltip, - target, - hoverPosition: HoverPosition.BELOW - }; - // awaiting the tooltip could take a while. Make sure we're still hovering. - hoverDisposable = IconLabel.adjustXAndShowCustomHover(hoverOptions, mouseX, hoverDelegate, isHovering); - } else if (hoverDisposable) { - hoverDisposable.dispose(); - hoverDisposable = undefined; - } - } - - } - mouseMoveDisposable.dispose(); - }, hoverDelegate.delay); } - const mouseOverDisposable = this._register(domEvent(htmlElement, dom.EventType.MOUSE_OVER, true)(mouseOver.bind(htmlElement))); - this.customHovers.set(htmlElement, mouseOverDisposable); } - private setupNativeHover(htmlElement: HTMLElement, tooltip: string | IIconLabelMarkdownString | undefined): void { - let stringTooltip: string = ''; - if (isString(tooltip)) { - stringTooltip = tooltip; - } else if (tooltip?.markdownNotSupportedFallback) { - stringTooltip = tooltip.markdownNotSupportedFallback; + public override dispose() { + super.dispose(); + for (const disposable of this.customHovers.values()) { + disposable.dispose(); } - htmlElement.title = stringTooltip; + this.customHovers.clear(); } } diff --git a/src/vs/base/browser/ui/iconLabel/iconLabelHover.ts b/src/vs/base/browser/ui/iconLabel/iconLabelHover.ts new file mode 100644 index 000000000000..a80a53e02bb5 --- /dev/null +++ b/src/vs/base/browser/ui/iconLabel/iconLabelHover.ts @@ -0,0 +1,130 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { isFunction, isString } from 'vs/base/common/types'; +import * as dom from 'vs/base/browser/dom'; +import { IIconLabelMarkdownString } from 'vs/base/browser/ui/iconLabel/iconLabel'; +import { IHoverDelegate, IHoverDelegateOptions, IHoverDelegateTarget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; +import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; +import { IDisposable } from 'vs/base/common/lifecycle'; +import { DomEmitter } from 'vs/base/browser/event'; +import { HoverPosition } from 'vs/base/browser/ui/hover/hoverWidget'; +import { localize } from 'vs/nls'; +import { IMarkdownString } from 'vs/base/common/htmlContent'; + + +export function setupNativeHover(htmlElement: HTMLElement, tooltip: string | IIconLabelMarkdownString | undefined): void { + if (isString(tooltip)) { + htmlElement.title = tooltip; + } else if (tooltip?.markdownNotSupportedFallback) { + htmlElement.title = tooltip.markdownNotSupportedFallback; + } else { + htmlElement.removeAttribute('title'); + } +} + +export function setupCustomHover(hoverDelegate: IHoverDelegate, htmlElement: HTMLElement, markdownTooltip: string | IIconLabelMarkdownString | undefined): IDisposable | undefined { + if (!markdownTooltip) { + return undefined; + } + + const tooltip = getTooltipForCustom(markdownTooltip); + + let hoverOptions: IHoverDelegateOptions | undefined; + let mouseX: number | undefined; + let isHovering = false; + let tokenSource: CancellationTokenSource; + let hoverDisposable: IDisposable | undefined; + + const mouseOverDomEmitter = new DomEmitter(htmlElement, dom.EventType.MOUSE_OVER, true); + mouseOverDomEmitter.event((e: MouseEvent) => { + if (isHovering) { + return; + } + tokenSource = new CancellationTokenSource(); + function mouseLeaveOrDown(e: MouseEvent): void { + const isMouseDown = e.type === dom.EventType.MOUSE_DOWN; + if (isMouseDown) { + hoverDisposable?.dispose(); + hoverDisposable = undefined; + } + if (isMouseDown || (e).fromElement === htmlElement) { + isHovering = false; + hoverOptions = undefined; + tokenSource.dispose(true); + mouseLeaveDomEmitter.dispose(); + mouseDownDomEmitter.dispose(); + } + } + const mouseLeaveDomEmitter = new DomEmitter(htmlElement, dom.EventType.MOUSE_LEAVE, true); + mouseLeaveDomEmitter.event(mouseLeaveOrDown); + const mouseDownDomEmitter = new DomEmitter(htmlElement, dom.EventType.MOUSE_DOWN, true); + mouseDownDomEmitter.event(mouseLeaveOrDown); + isHovering = true; + + function mouseMove(e: MouseEvent): void { + mouseX = e.x; + } + const mouseMoveDomEmitter = new DomEmitter(htmlElement, dom.EventType.MOUSE_MOVE, true); + mouseMoveDomEmitter.event(mouseMove); + setTimeout(async () => { + if (isHovering && tooltip) { + // Re-use the already computed hover options if they exist. + if (!hoverOptions) { + const target: IHoverDelegateTarget = { + targetElements: [htmlElement], + dispose: () => { } + }; + hoverOptions = { + text: localize('iconLabel.loading', "Loading..."), + target, + hoverPosition: HoverPosition.BELOW + }; + hoverDisposable = adjustXAndShowCustomHover(hoverOptions, mouseX, hoverDelegate, isHovering); + + const resolvedTooltip = (await tooltip(tokenSource.token)) ?? (!isString(markdownTooltip) ? markdownTooltip.markdownNotSupportedFallback : undefined); + if (resolvedTooltip) { + hoverOptions = { + text: resolvedTooltip, + target, + showPointer: hoverDelegate.placement === 'element', + hoverPosition: HoverPosition.BELOW + }; + // awaiting the tooltip could take a while. Make sure we're still hovering. + hoverDisposable = adjustXAndShowCustomHover(hoverOptions, mouseX, hoverDelegate, isHovering); + } else if (hoverDisposable) { + hoverDisposable.dispose(); + hoverDisposable = undefined; + } + } + + } + mouseMoveDomEmitter.dispose(); + }, hoverDelegate.delay); + }); + return mouseOverDomEmitter; +} + + +function getTooltipForCustom(markdownTooltip: string | IIconLabelMarkdownString): (token: CancellationToken) => Promise { + if (isString(markdownTooltip)) { + return async () => markdownTooltip; + } else if (isFunction(markdownTooltip.markdown)) { + return markdownTooltip.markdown; + } else { + const markdown = markdownTooltip.markdown; + return async () => markdown; + } +} + +function adjustXAndShowCustomHover(hoverOptions: IHoverDelegateOptions | undefined, mouseX: number | undefined, hoverDelegate: IHoverDelegate, isHovering: boolean): IDisposable | undefined { + if (hoverOptions && isHovering) { + if (mouseX !== undefined && (hoverDelegate.placement === undefined || hoverDelegate.placement === 'mouse')) { + (hoverOptions.target).x = mouseX + 10; + } + return hoverDelegate.showHover(hoverOptions); + } + return undefined; +} diff --git a/lib/vscode/src/vs/base/browser/ui/iconLabel/iconLabels.ts b/src/vs/base/browser/ui/iconLabel/iconLabels.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/iconLabel/iconLabels.ts rename to src/vs/base/browser/ui/iconLabel/iconLabels.ts diff --git a/lib/vscode/src/vs/base/browser/ui/iconLabel/iconlabel.css b/src/vs/base/browser/ui/iconLabel/iconlabel.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/iconLabel/iconlabel.css rename to src/vs/base/browser/ui/iconLabel/iconlabel.css diff --git a/lib/vscode/src/vs/base/browser/ui/iconLabel/simpleIconLabel.ts b/src/vs/base/browser/ui/iconLabel/simpleIconLabel.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/iconLabel/simpleIconLabel.ts rename to src/vs/base/browser/ui/iconLabel/simpleIconLabel.ts diff --git a/lib/vscode/src/vs/base/browser/ui/inputbox/inputBox.css b/src/vs/base/browser/ui/inputbox/inputBox.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/inputbox/inputBox.css rename to src/vs/base/browser/ui/inputbox/inputBox.css diff --git a/lib/vscode/src/vs/base/browser/ui/inputbox/inputBox.ts b/src/vs/base/browser/ui/inputbox/inputBox.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/inputbox/inputBox.ts rename to src/vs/base/browser/ui/inputbox/inputBox.ts diff --git a/lib/vscode/src/vs/base/browser/ui/keybindingLabel/keybindingLabel.css b/src/vs/base/browser/ui/keybindingLabel/keybindingLabel.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/keybindingLabel/keybindingLabel.css rename to src/vs/base/browser/ui/keybindingLabel/keybindingLabel.css diff --git a/lib/vscode/src/vs/base/browser/ui/keybindingLabel/keybindingLabel.ts b/src/vs/base/browser/ui/keybindingLabel/keybindingLabel.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/keybindingLabel/keybindingLabel.ts rename to src/vs/base/browser/ui/keybindingLabel/keybindingLabel.ts diff --git a/lib/vscode/src/vs/base/browser/ui/list/list.css b/src/vs/base/browser/ui/list/list.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/list/list.css rename to src/vs/base/browser/ui/list/list.css diff --git a/lib/vscode/src/vs/base/browser/ui/list/list.ts b/src/vs/base/browser/ui/list/list.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/list/list.ts rename to src/vs/base/browser/ui/list/list.ts diff --git a/lib/vscode/src/vs/base/browser/ui/list/listPaging.ts b/src/vs/base/browser/ui/list/listPaging.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/list/listPaging.ts rename to src/vs/base/browser/ui/list/listPaging.ts diff --git a/lib/vscode/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts similarity index 99% rename from lib/vscode/src/vs/base/browser/ui/list/listView.ts rename to src/vs/base/browser/ui/list/listView.ts index 6a2e9867dde2..580812f11975 100644 --- a/lib/vscode/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -898,7 +898,7 @@ export class ListView implements ISpliceable, IDisposable { @memoize get onMouseOver(): Event> { return Event.map(domEvent(this.domNode, 'mouseover'), e => this.toMouseEvent(e)); } @memoize get onMouseMove(): Event> { return Event.map(domEvent(this.domNode, 'mousemove'), e => this.toMouseEvent(e)); } @memoize get onMouseOut(): Event> { return Event.map(domEvent(this.domNode, 'mouseout'), e => this.toMouseEvent(e)); } - @memoize get onContextMenu(): Event> { return Event.map(domEvent(this.domNode, 'contextmenu'), e => this.toMouseEvent(e)); } + @memoize get onContextMenu(): Event | IListGestureEvent> { return Event.any(Event.map(domEvent(this.domNode, 'contextmenu'), e => this.toMouseEvent(e)), Event.map(domEvent(this.domNode, TouchEventType.Contextmenu) as Event, e => this.toGestureEvent(e))); } @memoize get onTouchStart(): Event> { return Event.map(domEvent(this.domNode, 'touchstart'), e => this.toTouchEvent(e)); } @memoize get onTap(): Event> { return Event.map(domEvent(this.rowsContainer, TouchEventType.Tap), e => this.toGestureEvent(e as GestureEvent)); } diff --git a/lib/vscode/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts similarity index 99% rename from lib/vscode/src/vs/base/browser/ui/list/listWidget.ts rename to src/vs/base/browser/ui/list/listWidget.ts index e66c6bbcc974..93906052348d 100644 --- a/lib/vscode/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -660,9 +660,15 @@ export class MouseController implements IDisposable { private changeSelection(e: IListMouseEvent | IListTouchEvent): void { const focus = e.index!; - const anchor = this.list.getAnchor(); + let anchor = this.list.getAnchor(); + + if (this.isSelectionRangeChangeEvent(e)) { + if (typeof anchor === 'undefined') { + const currentFocus = this.list.getFocus()[0]; + anchor = currentFocus ?? focus; + this.list.setAnchor(anchor); + } - if (this.isSelectionRangeChangeEvent(e) && typeof anchor === 'number') { const min = Math.min(anchor, focus); const max = Math.max(anchor, focus); const rangeSelection = range(min, max + 1); @@ -1201,7 +1207,7 @@ export class List implements ISpliceable, IThemable, IDisposable { const fromMouse = Event.chain(this.view.onContextMenu) .filter(_ => !didJustPressContextMenuKey) - .map(({ element, index, browserEvent }) => ({ element, index, anchor: { x: browserEvent.clientX + 1, y: browserEvent.clientY }, browserEvent })) + .map(({ element, index, browserEvent }) => ({ element, index, anchor: { x: browserEvent.pageX + 1, y: browserEvent.pageY }, browserEvent })) .event; return Event.any>(fromKeyDown, fromKeyUp, fromMouse); diff --git a/lib/vscode/src/vs/base/browser/ui/list/rangeMap.ts b/src/vs/base/browser/ui/list/rangeMap.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/list/rangeMap.ts rename to src/vs/base/browser/ui/list/rangeMap.ts diff --git a/lib/vscode/src/vs/base/browser/ui/list/rowCache.ts b/src/vs/base/browser/ui/list/rowCache.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/list/rowCache.ts rename to src/vs/base/browser/ui/list/rowCache.ts diff --git a/lib/vscode/src/vs/base/browser/ui/list/splice.ts b/src/vs/base/browser/ui/list/splice.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/list/splice.ts rename to src/vs/base/browser/ui/list/splice.ts diff --git a/lib/vscode/src/vs/base/browser/ui/menu/menu.ts b/src/vs/base/browser/ui/menu/menu.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/menu/menu.ts rename to src/vs/base/browser/ui/menu/menu.ts diff --git a/lib/vscode/src/vs/base/browser/ui/menu/menubar.css b/src/vs/base/browser/ui/menu/menubar.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/menu/menubar.css rename to src/vs/base/browser/ui/menu/menubar.css diff --git a/lib/vscode/src/vs/base/browser/ui/menu/menubar.ts b/src/vs/base/browser/ui/menu/menubar.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/menu/menubar.ts rename to src/vs/base/browser/ui/menu/menubar.ts diff --git a/lib/vscode/src/vs/base/browser/ui/mouseCursor/mouseCursor.css b/src/vs/base/browser/ui/mouseCursor/mouseCursor.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/mouseCursor/mouseCursor.css rename to src/vs/base/browser/ui/mouseCursor/mouseCursor.css diff --git a/lib/vscode/src/vs/base/browser/ui/mouseCursor/mouseCursor.ts b/src/vs/base/browser/ui/mouseCursor/mouseCursor.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/mouseCursor/mouseCursor.ts rename to src/vs/base/browser/ui/mouseCursor/mouseCursor.ts diff --git a/lib/vscode/src/vs/base/browser/ui/progressbar/progressbar.css b/src/vs/base/browser/ui/progressbar/progressbar.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/progressbar/progressbar.css rename to src/vs/base/browser/ui/progressbar/progressbar.css diff --git a/lib/vscode/src/vs/base/browser/ui/progressbar/progressbar.ts b/src/vs/base/browser/ui/progressbar/progressbar.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/progressbar/progressbar.ts rename to src/vs/base/browser/ui/progressbar/progressbar.ts diff --git a/lib/vscode/src/vs/base/browser/ui/sash/sash.css b/src/vs/base/browser/ui/sash/sash.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/sash/sash.css rename to src/vs/base/browser/ui/sash/sash.css diff --git a/lib/vscode/src/vs/base/browser/ui/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts similarity index 72% rename from lib/vscode/src/vs/base/browser/ui/sash/sash.ts rename to src/vs/base/browser/ui/sash/sash.ts index c08459895d6e..85f2ed8c4d09 100644 --- a/lib/vscode/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -4,15 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./sash'; -import { IDisposable, dispose, Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { isMacintosh } from 'vs/base/common/platform'; -import * as types from 'vs/base/common/types'; -import { EventType, GestureEvent, Gesture } from 'vs/base/browser/touch'; -import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; +import { EventType, Gesture, GestureEvent } from 'vs/base/browser/touch'; import { Event, Emitter } from 'vs/base/common/event'; -import { getElementsByTagName, EventHelper, createStyleSheet, addDisposableListener, append, $ } from 'vs/base/browser/dom'; -import { domEvent } from 'vs/base/browser/event'; +import { getElementsByTagName, EventHelper, createStyleSheet, append, $, EventLike } from 'vs/base/browser/dom'; +import { DomEmitter } from 'vs/base/browser/event'; import { Delayer } from 'vs/base/common/async'; +import { memoize } from 'vs/base/common/decorators'; let DEBUG = false; // DEBUG = Boolean("true"); // done "weirdly" so that a lint warning prevents you from pushing this @@ -88,6 +87,78 @@ export function setGlobalHoverDelay(size: number): void { onDidChangeHoverDelay.fire(size); } +interface PointerEvent extends EventLike { + readonly pageX: number; + readonly pageY: number; + readonly altKey: boolean; + readonly target: EventTarget | null; +} + +interface IPointerEventFactory { + readonly onPointerMove: Event; + readonly onPointerUp: Event; + dispose(): void; +} + +class MouseEventFactory implements IPointerEventFactory { + + private disposables = new DisposableStore(); + + @memoize + get onPointerMove(): Event { + return this.disposables.add(new DomEmitter(window, 'mousemove')).event; + } + + @memoize + get onPointerUp(): Event { + return this.disposables.add(new DomEmitter(window, 'mouseup')).event; + } + + dispose(): void { + this.disposables.dispose(); + } +} + +class GestureEventFactory implements IPointerEventFactory { + + private disposables = new DisposableStore(); + + @memoize + get onPointerMove(): Event { + return this.disposables.add(new DomEmitter(this.el, EventType.Change)).event; + } + + @memoize + get onPointerUp(): Event { + return this.disposables.add(new DomEmitter(this.el, EventType.End)).event; + } + + constructor(private el: HTMLElement) { } + + dispose(): void { + this.disposables.dispose(); + } +} + +class OrthogonalPointerEventFactory implements IPointerEventFactory { + + @memoize + get onPointerMove(): Event { + return this.factory.onPointerMove; + } + + @memoize + get onPointerUp(): Event { + return this.factory.onPointerUp; + } + + constructor(private factory: IPointerEventFactory) { } + + dispose(): void { + // noop + } +} + export class Sash extends Disposable { private el: HTMLElement; @@ -146,9 +217,9 @@ export class Sash extends Disposable { if (state !== SashState.Disabled) { this._orthogonalStartDragHandle = append(this.el, $('.orthogonal-drag-handle.start')); this.orthogonalStartDragHandleDisposables.add(toDisposable(() => this._orthogonalStartDragHandle!.remove())); - domEvent(this._orthogonalStartDragHandle, 'mouseenter') + this.orthogonalEndDragHandleDisposables.add(new DomEmitter(this._orthogonalStartDragHandle, 'mouseenter')).event (() => Sash.onMouseEnter(sash), undefined, this.orthogonalStartDragHandleDisposables); - domEvent(this._orthogonalStartDragHandle, 'mouseleave') + this.orthogonalEndDragHandleDisposables.add(new DomEmitter(this._orthogonalStartDragHandle, 'mouseleave')).event (() => Sash.onMouseLeave(sash), undefined, this.orthogonalStartDragHandleDisposables); } }; @@ -176,9 +247,9 @@ export class Sash extends Disposable { if (state !== SashState.Disabled) { this._orthogonalEndDragHandle = append(this.el, $('.orthogonal-drag-handle.end')); this.orthogonalEndDragHandleDisposables.add(toDisposable(() => this._orthogonalEndDragHandle!.remove())); - domEvent(this._orthogonalEndDragHandle, 'mouseenter') + this.orthogonalEndDragHandleDisposables.add(new DomEmitter(this._orthogonalEndDragHandle, 'mouseenter')).event (() => Sash.onMouseEnter(sash), undefined, this.orthogonalEndDragHandleDisposables); - domEvent(this._orthogonalEndDragHandle, 'mouseleave') + this.orthogonalEndDragHandleDisposables.add(new DomEmitter(this._orthogonalEndDragHandle, 'mouseleave')).event (() => Sash.onMouseLeave(sash), undefined, this.orthogonalEndDragHandleDisposables); } }; @@ -205,13 +276,28 @@ export class Sash extends Disposable { this.el.classList.add('mac'); } - this._register(domEvent(this.el, 'mousedown')(this.onMouseDown, this)); - this._register(domEvent(this.el, 'dblclick')(this.onMouseDoubleClick, this)); - this._register(domEvent(this.el, 'mouseenter')(() => Sash.onMouseEnter(this))); - this._register(domEvent(this.el, 'mouseleave')(() => Sash.onMouseLeave(this))); + const onMouseDown = this._register(new DomEmitter(this.el, 'mousedown')).event; + this._register(onMouseDown(e => this.onPointerStart(e, new MouseEventFactory()), this)); + const onMouseDoubleClick = this._register(new DomEmitter(this.el, 'dblclick')).event; + this._register(onMouseDoubleClick(this.onPointerDoublePress, this)); + const onMouseEnter = this._register(new DomEmitter(this.el, 'mouseenter')).event; + this._register(onMouseEnter(() => Sash.onMouseEnter(this))); + const onMouseLeave = this._register(new DomEmitter(this.el, 'mouseleave')).event; + this._register(onMouseLeave(() => Sash.onMouseLeave(this))); this._register(Gesture.addTarget(this.el)); - this._register(domEvent(this.el, EventType.Start)(e => this.onTouchStart(e as GestureEvent), this)); + + const onTouchStart = Event.map(this._register(new DomEmitter(this.el, EventType.Start)).event, e => ({ ...e, target: e.initialTarget ?? null })); + this._register(onTouchStart(e => this.onPointerStart(e, new GestureEventFactory(this.el)), this)); + const onTap = this._register(new DomEmitter(this.el, EventType.Tap)).event; + const onDoubleTap = Event.map( + Event.filter( + Event.debounce(onTap, (res, event) => ({ event, count: (res?.count ?? 0) + 1 }), 250), + ({ count }) => count === 2 + ), + ({ event }) => ({ ...event, target: event.initialTarget ?? null }) + ); + this._register(onDoubleTap(this.onPointerDoublePress, this)); if (typeof options.size === 'number') { this.size = options.size; @@ -252,24 +338,24 @@ export class Sash extends Disposable { this.layout(); } - private onMouseDown(e: MouseEvent): void { - EventHelper.stop(e, false); + private onPointerStart(event: PointerEvent, pointerEventFactory: IPointerEventFactory): void { + EventHelper.stop(event); let isMultisashResize = false; - if (!(e as any).__orthogonalSashEvent) { - const orthogonalSash = this.getOrthogonalSash(e); + if (!(event as any).__orthogonalSashEvent) { + const orthogonalSash = this.getOrthogonalSash(event); if (orthogonalSash) { isMultisashResize = true; - (e as any).__orthogonalSashEvent = true; - orthogonalSash.onMouseDown(e); + (event as any).__orthogonalSashEvent = true; + orthogonalSash.onPointerStart(event, new OrthogonalPointerEventFactory(pointerEventFactory)); } } - if (this.linkedSash && !(e as any).__linkedSashEvent) { - (e as any).__linkedSashEvent = true; - this.linkedSash.onMouseDown(e); + if (this.linkedSash && !(event as any).__linkedSashEvent) { + (event as any).__linkedSashEvent = true; + this.linkedSash.onPointerStart(event, new OrthogonalPointerEventFactory(pointerEventFactory)); } if (!this.state) { @@ -287,10 +373,9 @@ export class Sash extends Disposable { iframe.style.pointerEvents = 'none'; // disable mouse events on iframes as long as we drag the sash } - const mouseDownEvent = new StandardMouseEvent(e); - const startX = mouseDownEvent.posx; - const startY = mouseDownEvent.posy; - const altKey = mouseDownEvent.altKey; + const startX = event.pageX; + const startY = event.pageY; + const altKey = event.altKey; const startEvent: ISashEvent = { startX, currentX: startX, startY, currentY: startY, altKey }; this.el.classList.add('active'); @@ -332,15 +417,14 @@ export class Sash extends Disposable { this.onDidEnablementChange(updateStyle, null, disposables); } - const onMouseMove = (e: MouseEvent) => { + const onPointerMove = (e: PointerEvent) => { EventHelper.stop(e, false); - const mouseMoveEvent = new StandardMouseEvent(e); - const event: ISashEvent = { startX, currentX: mouseMoveEvent.posx, startY, currentY: mouseMoveEvent.posy, altKey }; + const event: ISashEvent = { startX, currentX: e.pageX, startY, currentY: e.pageY, altKey }; this._onDidChange.fire(event); }; - const onMouseUp = (e: MouseEvent) => { + const onPointerUp = (e: PointerEvent) => { EventHelper.stop(e, false); this.el.removeChild(style); @@ -355,11 +439,12 @@ export class Sash extends Disposable { } }; - domEvent(window, 'mousemove')(onMouseMove, null, disposables); - domEvent(window, 'mouseup')(onMouseUp, null, disposables); + pointerEventFactory.onPointerMove(onPointerMove, null, disposables); + pointerEventFactory.onPointerUp(onPointerUp, null, disposables); + disposables.add(pointerEventFactory); } - private onMouseDoubleClick(e: MouseEvent): void { + private onPointerDoublePress(e: MouseEvent): void { const orthogonalSash = this.getOrthogonalSash(e); if (orthogonalSash) { @@ -373,41 +458,6 @@ export class Sash extends Disposable { this._onDidReset.fire(); } - private onTouchStart(event: GestureEvent): void { - EventHelper.stop(event); - - const listeners: IDisposable[] = []; - - const startX = event.pageX; - const startY = event.pageY; - const altKey = event.altKey; - - this._onDidStart.fire({ - startX: startX, - currentX: startX, - startY: startY, - currentY: startY, - altKey - }); - - listeners.push(addDisposableListener(this.el, EventType.Change, (event: GestureEvent) => { - if (types.isNumber(event.pageX) && types.isNumber(event.pageY)) { - this._onDidChange.fire({ - startX: startX, - currentX: event.pageX, - startY: startY, - currentY: event.pageY, - altKey - }); - } - })); - - listeners.push(addDisposableListener(this.el, EventType.End, () => { - this._onDidEnd.fire(); - dispose(listeners); - })); - } - private static onMouseEnter(sash: Sash, fromLinkedSash: boolean = false): void { if (sash.el.classList.contains('active')) { sash.hoverDelayer.cancel(); @@ -476,7 +526,7 @@ export class Sash extends Disposable { return this.hidden; } - private getOrthogonalSash(e: MouseEvent): Sash | undefined { + private getOrthogonalSash(e: PointerEvent): Sash | undefined { if (!e.target || !(e.target instanceof HTMLElement)) { return undefined; } diff --git a/lib/vscode/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts b/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts rename to src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts diff --git a/lib/vscode/src/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts b/src/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts rename to src/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts diff --git a/lib/vscode/src/vs/base/browser/ui/scrollbar/media/scrollbars.css b/src/vs/base/browser/ui/scrollbar/media/scrollbars.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/scrollbar/media/scrollbars.css rename to src/vs/base/browser/ui/scrollbar/media/scrollbars.css diff --git a/lib/vscode/src/vs/base/browser/ui/scrollbar/scrollableElement.ts b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/scrollbar/scrollableElement.ts rename to src/vs/base/browser/ui/scrollbar/scrollableElement.ts diff --git a/lib/vscode/src/vs/base/browser/ui/scrollbar/scrollableElementOptions.ts b/src/vs/base/browser/ui/scrollbar/scrollableElementOptions.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/scrollbar/scrollableElementOptions.ts rename to src/vs/base/browser/ui/scrollbar/scrollableElementOptions.ts diff --git a/lib/vscode/src/vs/base/browser/ui/scrollbar/scrollbarArrow.ts b/src/vs/base/browser/ui/scrollbar/scrollbarArrow.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/scrollbar/scrollbarArrow.ts rename to src/vs/base/browser/ui/scrollbar/scrollbarArrow.ts diff --git a/lib/vscode/src/vs/base/browser/ui/scrollbar/scrollbarState.ts b/src/vs/base/browser/ui/scrollbar/scrollbarState.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/scrollbar/scrollbarState.ts rename to src/vs/base/browser/ui/scrollbar/scrollbarState.ts diff --git a/lib/vscode/src/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts b/src/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts rename to src/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts diff --git a/lib/vscode/src/vs/base/browser/ui/scrollbar/verticalScrollbar.ts b/src/vs/base/browser/ui/scrollbar/verticalScrollbar.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/scrollbar/verticalScrollbar.ts rename to src/vs/base/browser/ui/scrollbar/verticalScrollbar.ts diff --git a/lib/vscode/src/vs/base/browser/ui/selectBox/selectBox.css b/src/vs/base/browser/ui/selectBox/selectBox.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/selectBox/selectBox.css rename to src/vs/base/browser/ui/selectBox/selectBox.css diff --git a/lib/vscode/src/vs/base/browser/ui/selectBox/selectBox.ts b/src/vs/base/browser/ui/selectBox/selectBox.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/selectBox/selectBox.ts rename to src/vs/base/browser/ui/selectBox/selectBox.ts diff --git a/lib/vscode/src/vs/base/browser/ui/selectBox/selectBoxCustom.css b/src/vs/base/browser/ui/selectBox/selectBoxCustom.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/selectBox/selectBoxCustom.css rename to src/vs/base/browser/ui/selectBox/selectBoxCustom.css diff --git a/lib/vscode/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts similarity index 99% rename from lib/vscode/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts rename to src/vs/base/browser/ui/selectBox/selectBoxCustom.ts index 9f60bfb43ef3..a2447f6db793 100644 --- a/lib/vscode/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts +++ b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts @@ -329,7 +329,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi } if (this.styles.listFocusForeground) { - content.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row.focused:not(:hover) { color: ${this.styles.listFocusForeground} !important; }`); + content.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row.focused { color: ${this.styles.listFocusForeground} !important; }`); } if (this.styles.decoratorRightForeground) { diff --git a/lib/vscode/src/vs/base/browser/ui/selectBox/selectBoxNative.ts b/src/vs/base/browser/ui/selectBox/selectBoxNative.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/selectBox/selectBoxNative.ts rename to src/vs/base/browser/ui/selectBox/selectBoxNative.ts diff --git a/lib/vscode/src/vs/base/browser/ui/splitview/paneview.css b/src/vs/base/browser/ui/splitview/paneview.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/splitview/paneview.css rename to src/vs/base/browser/ui/splitview/paneview.css diff --git a/lib/vscode/src/vs/base/browser/ui/splitview/paneview.ts b/src/vs/base/browser/ui/splitview/paneview.ts similarity index 99% rename from lib/vscode/src/vs/base/browser/ui/splitview/paneview.ts rename to src/vs/base/browser/ui/splitview/paneview.ts index 06e8b064d49a..a84c6f5837e4 100644 --- a/lib/vscode/src/vs/base/browser/ui/splitview/paneview.ts +++ b/src/vs/base/browser/ui/splitview/paneview.ts @@ -16,6 +16,7 @@ import { isFirefox } from 'vs/base/browser/browser'; import { DataTransfers } from 'vs/base/browser/dnd'; import { Orientation } from 'vs/base/browser/ui/sash/sash'; import { localize } from 'vs/nls'; +import { ScrollEvent } from 'vs/base/common/scrollable'; export interface IPaneOptions { minimumBodySize?: number; @@ -444,6 +445,7 @@ export class PaneView extends Disposable { orientation: Orientation; readonly onDidSashChange: Event; + readonly onDidScroll: Event; constructor(container: HTMLElement, options: IPaneViewOptions = {}) { super(); @@ -453,6 +455,7 @@ export class PaneView extends Disposable { this.element = append(container, $('.monaco-pane-view')); this.splitview = this._register(new SplitView(this.element, { orientation: this.orientation })); this.onDidSashChange = this.splitview.onDidSashChange; + this.onDidScroll = this.splitview.onDidScroll; } addPane(pane: Pane, size: number, index = this.splitview.length): void { diff --git a/lib/vscode/src/vs/base/browser/ui/splitview/splitview.css b/src/vs/base/browser/ui/splitview/splitview.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/splitview/splitview.css rename to src/vs/base/browser/ui/splitview/splitview.css diff --git a/lib/vscode/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts similarity index 99% rename from lib/vscode/src/vs/base/browser/ui/splitview/splitview.ts rename to src/vs/base/browser/ui/splitview/splitview.ts index 8434bc1c528c..5996365a70f0 100644 --- a/lib/vscode/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -14,7 +14,7 @@ import { Color } from 'vs/base/common/color'; import { domEvent } from 'vs/base/browser/event'; import { $, append, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; import { SmoothScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; -import { Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable'; +import { Scrollable, ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable'; export { Orientation } from 'vs/base/browser/ui/sash/sash'; export interface ISplitViewStyles { @@ -237,6 +237,8 @@ export class SplitView extends Disposable { private _onDidSashReset = this._register(new Emitter()); readonly onDidSashReset = this._onDidSashReset.event; + readonly onDidScroll: Event; + get length(): number { return this.viewItems.length; } @@ -317,7 +319,8 @@ export class SplitView extends Disposable { horizontal: this.orientation === Orientation.HORIZONTAL ? (options.scrollbarVisibility ?? ScrollbarVisibility.Auto) : ScrollbarVisibility.Hidden }, this.scrollable)); - this._register(this.scrollableElement.onScroll(e => { + this.onDidScroll = this.scrollableElement.onScroll; + this._register(this.onDidScroll(e => { this.viewContainer.scrollTop = e.scrollTop; this.viewContainer.scrollLeft = e.scrollLeft; })); diff --git a/lib/vscode/src/vs/base/browser/ui/table/table.css b/src/vs/base/browser/ui/table/table.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/table/table.css rename to src/vs/base/browser/ui/table/table.css diff --git a/lib/vscode/src/vs/base/browser/ui/table/table.ts b/src/vs/base/browser/ui/table/table.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/table/table.ts rename to src/vs/base/browser/ui/table/table.ts diff --git a/lib/vscode/src/vs/base/browser/ui/table/tableWidget.ts b/src/vs/base/browser/ui/table/tableWidget.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/table/tableWidget.ts rename to src/vs/base/browser/ui/table/tableWidget.ts diff --git a/lib/vscode/src/vs/base/browser/ui/toolbar/toolbar.css b/src/vs/base/browser/ui/toolbar/toolbar.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/toolbar/toolbar.css rename to src/vs/base/browser/ui/toolbar/toolbar.css diff --git a/lib/vscode/src/vs/base/browser/ui/toolbar/toolbar.ts b/src/vs/base/browser/ui/toolbar/toolbar.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/toolbar/toolbar.ts rename to src/vs/base/browser/ui/toolbar/toolbar.ts diff --git a/lib/vscode/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/tree/abstractTree.ts rename to src/vs/base/browser/ui/tree/abstractTree.ts diff --git a/lib/vscode/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/tree/asyncDataTree.ts rename to src/vs/base/browser/ui/tree/asyncDataTree.ts diff --git a/lib/vscode/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts b/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts rename to src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts diff --git a/lib/vscode/src/vs/base/browser/ui/tree/dataTree.ts b/src/vs/base/browser/ui/tree/dataTree.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/tree/dataTree.ts rename to src/vs/base/browser/ui/tree/dataTree.ts diff --git a/lib/vscode/src/vs/base/browser/ui/tree/indexTree.ts b/src/vs/base/browser/ui/tree/indexTree.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/tree/indexTree.ts rename to src/vs/base/browser/ui/tree/indexTree.ts diff --git a/lib/vscode/src/vs/base/browser/ui/tree/indexTreeModel.ts b/src/vs/base/browser/ui/tree/indexTreeModel.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/tree/indexTreeModel.ts rename to src/vs/base/browser/ui/tree/indexTreeModel.ts diff --git a/lib/vscode/src/vs/base/browser/ui/tree/media/paneviewlet.css b/src/vs/base/browser/ui/tree/media/paneviewlet.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/tree/media/paneviewlet.css rename to src/vs/base/browser/ui/tree/media/paneviewlet.css diff --git a/lib/vscode/src/vs/base/browser/ui/tree/media/tree.css b/src/vs/base/browser/ui/tree/media/tree.css similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/tree/media/tree.css rename to src/vs/base/browser/ui/tree/media/tree.css diff --git a/lib/vscode/src/vs/base/browser/ui/tree/objectTree.ts b/src/vs/base/browser/ui/tree/objectTree.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/tree/objectTree.ts rename to src/vs/base/browser/ui/tree/objectTree.ts diff --git a/lib/vscode/src/vs/base/browser/ui/tree/objectTreeModel.ts b/src/vs/base/browser/ui/tree/objectTreeModel.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/tree/objectTreeModel.ts rename to src/vs/base/browser/ui/tree/objectTreeModel.ts diff --git a/lib/vscode/src/vs/base/browser/ui/tree/tree.ts b/src/vs/base/browser/ui/tree/tree.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/tree/tree.ts rename to src/vs/base/browser/ui/tree/tree.ts diff --git a/lib/vscode/src/vs/base/browser/ui/tree/treeDefaults.ts b/src/vs/base/browser/ui/tree/treeDefaults.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/tree/treeDefaults.ts rename to src/vs/base/browser/ui/tree/treeDefaults.ts diff --git a/lib/vscode/src/vs/base/browser/ui/tree/treeIcons.ts b/src/vs/base/browser/ui/tree/treeIcons.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/tree/treeIcons.ts rename to src/vs/base/browser/ui/tree/treeIcons.ts diff --git a/lib/vscode/src/vs/base/browser/ui/widget.ts b/src/vs/base/browser/ui/widget.ts similarity index 100% rename from lib/vscode/src/vs/base/browser/ui/widget.ts rename to src/vs/base/browser/ui/widget.ts diff --git a/lib/vscode/src/vs/base/common/actions.ts b/src/vs/base/common/actions.ts similarity index 96% rename from lib/vscode/src/vs/base/common/actions.ts rename to src/vs/base/common/actions.ts index 171853e2fd6f..9125a2c58371 100644 --- a/lib/vscode/src/vs/base/common/actions.ts +++ b/src/vs/base/common/actions.ts @@ -30,14 +30,14 @@ export interface IAction extends IDisposable { class: string | undefined; enabled: boolean; checked: boolean; - run(event?: unknown): Promise; + run(event?: unknown): unknown; } export interface IActionRunner extends IDisposable { readonly onDidRun: Event; readonly onBeforeRun: Event; - run(action: IAction, context?: unknown): Promise; + run(action: IAction, context?: unknown): unknown; } export interface IActionChangeEvent { @@ -59,9 +59,9 @@ export class Action extends Disposable implements IAction { protected _cssClass: string | undefined; protected _enabled: boolean = true; protected _checked: boolean = false; - protected readonly _actionCallback?: (event?: unknown) => Promise; + protected readonly _actionCallback?: (event?: unknown) => unknown; - constructor(id: string, label: string = '', cssClass: string = '', enabled: boolean = true, actionCallback?: (event?: unknown) => Promise) { + constructor(id: string, label: string = '', cssClass: string = '', enabled: boolean = true, actionCallback?: (event?: unknown) => unknown) { super(); this._id = id; this._label = label; diff --git a/lib/vscode/src/vs/base/common/amd.ts b/src/vs/base/common/amd.ts similarity index 100% rename from lib/vscode/src/vs/base/common/amd.ts rename to src/vs/base/common/amd.ts diff --git a/lib/vscode/src/vs/base/common/arrays.ts b/src/vs/base/common/arrays.ts similarity index 95% rename from lib/vscode/src/vs/base/common/arrays.ts rename to src/vs/base/common/arrays.ts index fceca7212f64..8d72d50d9ffe 100644 --- a/lib/vscode/src/vs/base/common/arrays.ts +++ b/src/vs/base/common/arrays.ts @@ -554,3 +554,37 @@ export function mapFind(array: Iterable, mapFn: (value: T) => R | undef return undefined; } + +/** + * Like Math.min with a delegate, and returns the winning index + */ +export function minIndex(array: readonly T[], fn: (value: T) => number): number { + let minValue = Number.MAX_SAFE_INTEGER; + let minIdx = 0; + array.forEach((value, i) => { + const thisValue = fn(value); + if (thisValue < minValue) { + minValue = thisValue; + minIdx = i; + } + }); + + return minIdx; +} + +/** + * Like Math.max with a delegate, and returns the winning index + */ +export function maxIndex(array: readonly T[], fn: (value: T) => number): number { + let minValue = Number.MIN_SAFE_INTEGER; + let maxIdx = 0; + array.forEach((value, i) => { + const thisValue = fn(value); + if (thisValue > minValue) { + minValue = thisValue; + maxIdx = i; + } + }); + + return maxIdx; +} diff --git a/lib/vscode/src/vs/base/common/assert.ts b/src/vs/base/common/assert.ts similarity index 100% rename from lib/vscode/src/vs/base/common/assert.ts rename to src/vs/base/common/assert.ts diff --git a/lib/vscode/src/vs/base/common/async.ts b/src/vs/base/common/async.ts similarity index 99% rename from lib/vscode/src/vs/base/common/async.ts rename to src/vs/base/common/async.ts index 7090d5add78d..fba360da12cd 100644 --- a/lib/vscode/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -536,7 +536,6 @@ export class Limiter { get size(): number { return this._size; - // return this.runningPromises + this.outstandingPromises.length; } queue(factory: ITask>): Promise { diff --git a/lib/vscode/src/vs/base/common/buffer.ts b/src/vs/base/common/buffer.ts similarity index 100% rename from lib/vscode/src/vs/base/common/buffer.ts rename to src/vs/base/common/buffer.ts diff --git a/lib/vscode/src/vs/base/common/cache.ts b/src/vs/base/common/cache.ts similarity index 100% rename from lib/vscode/src/vs/base/common/cache.ts rename to src/vs/base/common/cache.ts diff --git a/lib/vscode/src/vs/base/common/cancellation.ts b/src/vs/base/common/cancellation.ts similarity index 100% rename from lib/vscode/src/vs/base/common/cancellation.ts rename to src/vs/base/common/cancellation.ts diff --git a/lib/vscode/src/vs/base/common/charCode.ts b/src/vs/base/common/charCode.ts similarity index 100% rename from lib/vscode/src/vs/base/common/charCode.ts rename to src/vs/base/common/charCode.ts diff --git a/lib/vscode/src/vs/base/common/codicons.ts b/src/vs/base/common/codicons.ts similarity index 99% rename from lib/vscode/src/vs/base/common/codicons.ts rename to src/vs/base/common/codicons.ts index fc38ba8ee14c..da86ec14cce7 100644 --- a/lib/vscode/src/vs/base/common/codicons.ts +++ b/src/vs/base/common/codicons.ts @@ -573,6 +573,7 @@ export namespace Codicon { export const filterFilled = new Codicon('filter-filled', { fontCharacter: '\\ebce' }); export const wand = new Codicon('wand', { fontCharacter: '\\ebcf' }); export const debugLineByLine = new Codicon('debug-line-by-line', { fontCharacter: '\\ebd0' }); + export const inspect = new Codicon('inspect', { fontCharacter: '\\ebd1' }); export const dropDownButton = new Codicon('drop-down-button', Codicon.chevronDown.definition); } diff --git a/lib/vscode/src/vs/base/common/collections.ts b/src/vs/base/common/collections.ts similarity index 85% rename from lib/vscode/src/vs/base/common/collections.ts rename to src/vs/base/common/collections.ts index cc037ecfd717..24ed68bae5f9 100644 --- a/lib/vscode/src/vs/base/common/collections.ts +++ b/src/vs/base/common/collections.ts @@ -53,8 +53,8 @@ export function forEach(from: IStringDictionary | INumberDictionary, ca * Groups the collection into a dictionary based on the provided * group function. */ -export function groupBy(data: T[], groupFn: (element: T) => string): IStringDictionary { - const result: IStringDictionary = Object.create(null); +export function groupBy(data: V[], groupFn: (element: V) => K): Record { + const result: Record = Object.create(null); for (const element of data) { const key = groupFn(element); let target = result[key]; @@ -66,24 +66,6 @@ export function groupBy(data: T[], groupFn: (element: T) => string): IStringD return result; } -/** - * Groups the collection into a dictionary based on the provided - * group function. - */ -export function groupByNumber(data: T[], groupFn: (element: T) => number): Map { - const result = new Map(); - for (const element of data) { - const key = groupFn(element); - let target = result.get(key); - if (!target) { - target = []; - result.set(key, target); - } - target.push(element); - } - return result; -} - export function fromMap(original: Map): IStringDictionary { const result: IStringDictionary = Object.create(null); if (original) { diff --git a/lib/vscode/src/vs/base/common/color.ts b/src/vs/base/common/color.ts similarity index 99% rename from lib/vscode/src/vs/base/common/color.ts rename to src/vs/base/common/color.ts index eb5fd3b079a9..abfbad67c9e1 100644 --- a/lib/vscode/src/vs/base/common/color.ts +++ b/src/vs/base/common/color.ts @@ -523,7 +523,7 @@ export namespace Color { /** * The default format will use HEX if opaque and RGBA otherwise. */ - export function format(color: Color): string | null { + export function format(color: Color): string { if (color.isOpaque()) { return Color.Format.CSS.formatHex(color); } diff --git a/lib/vscode/src/vs/base/common/comparers.ts b/src/vs/base/common/comparers.ts similarity index 58% rename from lib/vscode/src/vs/base/common/comparers.ts rename to src/vs/base/common/comparers.ts index 7b45ce5abb6d..fe3c534467d4 100644 --- a/lib/vscode/src/vs/base/common/comparers.ts +++ b/src/vs/base/common/comparers.ts @@ -6,11 +6,11 @@ import { sep } from 'vs/base/common/path'; import { IdleValue } from 'vs/base/common/async'; -// When comparing large numbers of strings, such as in sorting large arrays, is better for -// performance to create an Intl.Collator object and use the function provided by its compare -// property than it is to use String.prototype.localeCompare() +// When comparing large numbers of strings it's better for performance to create an +// Intl.Collator object and use the function provided by its compare property +// than it is to use String.prototype.localeCompare() -// A collator with numeric sorting enabled, and no sensitivity to case or to accents +// A collator with numeric sorting enabled, and no sensitivity to case, accents or diacritics. const intlFileNameCollatorBaseNumeric: IdleValue<{ collator: Intl.Collator, collatorIsNumeric: boolean }> = new IdleValue(() => { const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }); return { @@ -28,19 +28,20 @@ const intlFileNameCollatorNumeric: IdleValue<{ collator: Intl.Collator }> = new }); // A collator with numeric sorting enabled, and sensitivity to accents and diacritics but not case. -const intlFileNameCollatorNumericCaseInsenstive: IdleValue<{ collator: Intl.Collator }> = new IdleValue(() => { +const intlFileNameCollatorNumericCaseInsensitive: IdleValue<{ collator: Intl.Collator }> = new IdleValue(() => { const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'accent' }); return { collator: collator }; -});/** Compares filenames without distinguishing the name from the extension. Disambiguates by unicode comparison. */ +}); + +/** Compares filenames without distinguishing the name from the extension. Disambiguates by unicode comparison. */ export function compareFileNames(one: string | null, other: string | null, caseSensitive = false): number { const a = one || ''; const b = other || ''; const result = intlFileNameCollatorBaseNumeric.value.collator.compare(a, b); - // Using the numeric option in the collator will - // make compare(`foo1`, `foo01`) === 0. We must disambiguate. + // Using the numeric option will make compare(`foo1`, `foo01`) === 0. Disambiguate. if (intlFileNameCollatorBaseNumeric.value.collatorIsNumeric && result === 0 && a !== b) { return a < b ? -1 : 1; } @@ -48,16 +49,45 @@ export function compareFileNames(one: string | null, other: string | null, caseS return result; } -/** Compares filenames without distinguishing the name from the extension. Disambiguates by length, not unicode comparison. */ +/** Compares full filenames without grouping by case. */ export function compareFileNamesDefault(one: string | null, other: string | null): number { const collatorNumeric = intlFileNameCollatorNumeric.value.collator; one = one || ''; other = other || ''; - // Compare the entire filename - both name and extension - and disambiguate by length if needed return compareAndDisambiguateByLength(collatorNumeric, one, other); } +/** Compares full filenames grouping uppercase names before lowercase. */ +export function compareFileNamesUpper(one: string | null, other: string | null) { + const collatorNumeric = intlFileNameCollatorNumeric.value.collator; + one = one || ''; + other = other || ''; + + return compareCaseUpperFirst(one, other) || compareAndDisambiguateByLength(collatorNumeric, one, other); +} + +/** Compares full filenames grouping lowercase names before uppercase. */ +export function compareFileNamesLower(one: string | null, other: string | null) { + const collatorNumeric = intlFileNameCollatorNumeric.value.collator; + one = one || ''; + other = other || ''; + + return compareCaseLowerFirst(one, other) || compareAndDisambiguateByLength(collatorNumeric, one, other); +} + +/** Compares full filenames by unicode value. */ +export function compareFileNamesUnicode(one: string | null, other: string | null) { + one = one || ''; + other = other || ''; + + if (one === other) { + return 0; + } + + return one < other ? -1 : 1; +} + export function noIntlCompareFileNames(one: string | null, other: string | null, caseSensitive = false): number { if (!caseSensitive) { one = one && one.toLowerCase(); @@ -78,6 +108,7 @@ export function noIntlCompareFileNames(one: string | null, other: string | null, return oneExtension < otherExtension ? -1 : 1; } +/** Compares filenames by extension, then by name. Disambiguates by unicode comparison. */ export function compareFileExtensions(one: string | null, other: string | null): number { const [oneName, oneExtension] = extractNameAndExtension(one); const [otherName, otherExtension] = extractNameAndExtension(other); @@ -85,8 +116,7 @@ export function compareFileExtensions(one: string | null, other: string | null): let result = intlFileNameCollatorBaseNumeric.value.collator.compare(oneExtension, otherExtension); if (result === 0) { - // Using the numeric option in the collator will - // make compare(`foo1`, `foo01`) === 0. We must disambiguate. + // Using the numeric option will make compare(`foo1`, `foo01`) === 0. Disambiguate. if (intlFileNameCollatorBaseNumeric.value.collatorIsNumeric && oneExtension !== otherExtension) { return oneExtension < otherExtension ? -1 : 1; } @@ -102,24 +132,65 @@ export function compareFileExtensions(one: string | null, other: string | null): return result; } -/** Compares filenames by extenson, then by full filename */ +/** Compares filenames by extenson, then by full filename. Mixes uppercase and lowercase names together. */ export function compareFileExtensionsDefault(one: string | null, other: string | null): number { one = one || ''; other = other || ''; const oneExtension = extractExtension(one); const otherExtension = extractExtension(other); const collatorNumeric = intlFileNameCollatorNumeric.value.collator; - const collatorNumericCaseInsensitive = intlFileNameCollatorNumericCaseInsenstive.value.collator; - let result; + const collatorNumericCaseInsensitive = intlFileNameCollatorNumericCaseInsensitive.value.collator; - // Check for extension differences, ignoring differences in case and comparing numbers numerically. - result = compareAndDisambiguateByLength(collatorNumericCaseInsensitive, oneExtension, otherExtension); - if (result !== 0) { - return result; + return compareAndDisambiguateByLength(collatorNumericCaseInsensitive, oneExtension, otherExtension) || + compareAndDisambiguateByLength(collatorNumeric, one, other); +} + +/** Compares filenames by extension, then case, then full filename. Groups uppercase names before lowercase. */ +export function compareFileExtensionsUpper(one: string | null, other: string | null): number { + one = one || ''; + other = other || ''; + const oneExtension = extractExtension(one); + const otherExtension = extractExtension(other); + const collatorNumeric = intlFileNameCollatorNumeric.value.collator; + const collatorNumericCaseInsensitive = intlFileNameCollatorNumericCaseInsensitive.value.collator; + + return compareAndDisambiguateByLength(collatorNumericCaseInsensitive, oneExtension, otherExtension) || + compareCaseUpperFirst(one, other) || + compareAndDisambiguateByLength(collatorNumeric, one, other); +} + +/** Compares filenames by extension, then case, then full filename. Groups lowercase names before uppercase. */ +export function compareFileExtensionsLower(one: string | null, other: string | null): number { + one = one || ''; + other = other || ''; + const oneExtension = extractExtension(one); + const otherExtension = extractExtension(other); + const collatorNumeric = intlFileNameCollatorNumeric.value.collator; + const collatorNumericCaseInsensitive = intlFileNameCollatorNumericCaseInsensitive.value.collator; + + return compareAndDisambiguateByLength(collatorNumericCaseInsensitive, oneExtension, otherExtension) || + compareCaseLowerFirst(one, other) || + compareAndDisambiguateByLength(collatorNumeric, one, other); +} + +/** Compares filenames by case-insensitive extension unicode value, then by full filename unicode value. */ +export function compareFileExtensionsUnicode(one: string | null, other: string | null) { + one = one || ''; + other = other || ''; + const oneExtension = extractExtension(one).toLowerCase(); + const otherExtension = extractExtension(other).toLowerCase(); + + // Check for extension differences + if (oneExtension !== otherExtension) { + return oneExtension < otherExtension ? -1 : 1; } - // Compare full filenames - return compareAndDisambiguateByLength(collatorNumeric, one, other); + // Check for full filename differences. + if (one !== other) { + return one < other ? -1 : 1; + } + + return 0; } const FileNameMatch = /^(.*?)(\.([^.]*))?$/; @@ -130,7 +201,7 @@ function extractNameAndExtension(str?: string | null, dotfilesAsNames = false): let result: [string, string] = [(match && match[1]) || '', (match && match[3]) || '']; - // if the dotfilesAsNames option is selected, treat an empty filename with an extension, + // if the dotfilesAsNames option is selected, treat an empty filename with an extension // or a filename that starts with a dot, as a dotfile name if (dotfilesAsNames && (!result[0] && result[1] || result[0] && result[0].charAt(0) === '.')) { result = [result[0] + '.' + result[1], '']; @@ -162,6 +233,54 @@ function compareAndDisambiguateByLength(collator: Intl.Collator, one: string, ot return 0; } +/** @returns `true` if the string is starts with a lowercase letter. Otherwise, `false`. */ +function startsWithLower(string: string) { + const character = string.charAt(0); + + return (character.toLocaleUpperCase() !== character) ? true : false; +} + +/** @returns `true` if the string starts with an uppercase letter. Otherwise, `false`. */ +function startsWithUpper(string: string) { + const character = string.charAt(0); + + return (character.toLocaleLowerCase() !== character) ? true : false; +} + +/** + * Compares the case of the provided strings - lowercase before uppercase + * + * @returns + * ```text + * -1 if one is lowercase and other is uppercase + * 1 if one is uppercase and other is lowercase + * 0 otherwise + * ``` + */ +function compareCaseLowerFirst(one: string, other: string): number { + if (startsWithLower(one) && startsWithUpper(other)) { + return -1; + } + return (startsWithUpper(one) && startsWithLower(other)) ? 1 : 0; +} + +/** + * Compares the case of the provided strings - uppercase before lowercase + * + * @returns + * ```text + * -1 if one is uppercase and other is lowercase + * 1 if one is lowercase and other is uppercase + * 0 otherwise + * ``` + */ +function compareCaseUpperFirst(one: string, other: string): number { + if (startsWithUpper(one) && startsWithLower(other)) { + return -1; + } + return (startsWithLower(one) && startsWithUpper(other)) ? 1 : 0; +} + function comparePathComponents(one: string, other: string, caseSensitive = false): number { if (!caseSensitive) { one = one && one.toLowerCase(); diff --git a/lib/vscode/src/vs/base/common/console.ts b/src/vs/base/common/console.ts similarity index 100% rename from lib/vscode/src/vs/base/common/console.ts rename to src/vs/base/common/console.ts diff --git a/lib/vscode/src/vs/base/common/date.ts b/src/vs/base/common/date.ts similarity index 100% rename from lib/vscode/src/vs/base/common/date.ts rename to src/vs/base/common/date.ts diff --git a/lib/vscode/src/vs/base/common/decorators.ts b/src/vs/base/common/decorators.ts similarity index 68% rename from lib/vscode/src/vs/base/common/decorators.ts rename to src/vs/base/common/decorators.ts index f9e39b6b941d..5eb4fa7ad833 100644 --- a/lib/vscode/src/vs/base/common/decorators.ts +++ b/src/vs/base/common/decorators.ts @@ -24,64 +24,39 @@ export function createDecorator(mapFn: (fn: Function, key: string) => Function): }; } -let memoizeId = 0; -export function createMemoizer() { - const memoizeKeyPrefix = `$memoize${memoizeId++}`; - let self: any = undefined; +export function memoize(_target: any, key: string, descriptor: any) { + let fnKey: string | null = null; + let fn: Function | null = null; - const result = function memoize(target: any, key: string, descriptor: any) { - let fnKey: string | null = null; - let fn: Function | null = null; - - if (typeof descriptor.value === 'function') { - fnKey = 'value'; - fn = descriptor.value; + if (typeof descriptor.value === 'function') { + fnKey = 'value'; + fn = descriptor.value; - if (fn!.length !== 0) { - console.warn('Memoize should only be used in functions with zero parameters'); - } - } else if (typeof descriptor.get === 'function') { - fnKey = 'get'; - fn = descriptor.get; + if (fn!.length !== 0) { + console.warn('Memoize should only be used in functions with zero parameters'); } - - if (!fn) { - throw new Error('not supported'); + } else if (typeof descriptor.get === 'function') { + fnKey = 'get'; + fn = descriptor.get; + } + + if (!fn) { + throw new Error('not supported'); + } + + const memoizeKey = `$memoize$${key}`; + descriptor[fnKey!] = function (...args: any[]) { + if (!this.hasOwnProperty(memoizeKey)) { + Object.defineProperty(this, memoizeKey, { + configurable: false, + enumerable: false, + writable: false, + value: fn!.apply(this, args) + }); } - const memoizeKey = `${memoizeKeyPrefix}:${key}`; - descriptor[fnKey!] = function (...args: any[]) { - self = this; - - if (!this.hasOwnProperty(memoizeKey)) { - Object.defineProperty(this, memoizeKey, { - configurable: true, - enumerable: false, - writable: true, - value: fn!.apply(this, args) - }); - } - - return this[memoizeKey]; - }; + return this[memoizeKey]; }; - - result.clear = () => { - if (typeof self === 'undefined') { - return; - } - Object.getOwnPropertyNames(self).forEach(property => { - if (property.indexOf(memoizeKeyPrefix) === 0) { - delete self[property]; - } - }); - }; - - return result; -} - -export function memoize(target: any, key: string, descriptor: any) { - return createMemoizer()(target, key, descriptor); } export interface IDebounceReducer { diff --git a/lib/vscode/src/vs/base/common/diff/diff.ts b/src/vs/base/common/diff/diff.ts similarity index 100% rename from lib/vscode/src/vs/base/common/diff/diff.ts rename to src/vs/base/common/diff/diff.ts diff --git a/lib/vscode/src/vs/base/common/diff/diffChange.ts b/src/vs/base/common/diff/diffChange.ts similarity index 100% rename from lib/vscode/src/vs/base/common/diff/diffChange.ts rename to src/vs/base/common/diff/diffChange.ts diff --git a/lib/vscode/src/vs/base/common/errorMessage.ts b/src/vs/base/common/errorMessage.ts similarity index 100% rename from lib/vscode/src/vs/base/common/errorMessage.ts rename to src/vs/base/common/errorMessage.ts diff --git a/lib/vscode/src/vs/base/common/errors.ts b/src/vs/base/common/errors.ts similarity index 100% rename from lib/vscode/src/vs/base/common/errors.ts rename to src/vs/base/common/errors.ts diff --git a/lib/vscode/src/vs/base/common/event.ts b/src/vs/base/common/event.ts similarity index 96% rename from lib/vscode/src/vs/base/common/event.ts rename to src/vs/base/common/event.ts index 8b4efda9d448..d992d0abe8a7 100644 --- a/lib/vscode/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -68,6 +68,7 @@ export namespace Event { * Given an event and a `filter` function, returns another event which emits those * elements for which the `filter` function returns `true`. */ + export function filter(event: Event, filter: (e: T | U) => e is T): Event; export function filter(event: Event, filter: (e: T) => boolean): Event; export function filter(event: Event, filter: (e: T | R) => e is R): Event; export function filter(event: Event, filter: (e: T) => boolean): Event { @@ -188,18 +189,29 @@ export namespace Event { * Given an event, it returns another event which fires only when the event * element changes. */ - export function latch(event: Event): Event { + export function latch(event: Event, equals: (a: T, b: T) => boolean = (a, b) => a === b): Event { let firstCall = true; let cache: T; return filter(event, value => { - const shouldEmit = firstCall || value !== cache; + const shouldEmit = firstCall || !equals(value, cache); firstCall = false; cache = value; return shouldEmit; }); } + /** + * Given an event, it returns another event which fires only when the event + * element changes. + */ + export function split(event: Event, isT: (e: T | U) => e is T): [Event, Event] { + return [ + Event.filter(event, isT), + Event.filter(event, e => !isT(e)) as Event, + ]; + } + /** * Buffers the provided event until a first listener comes * along, at which point fire all the events at once and @@ -633,10 +645,13 @@ export class Emitter { } dispose() { - this._listeners?.clear(); - this._deliveryQueue?.clear(); - this._leakageMon?.dispose(); - this._disposed = true; + if (!this._disposed) { + this._disposed = true; + this._listeners?.clear(); + this._deliveryQueue?.clear(); + this._options?.onLastListenerRemove?.(); + this._leakageMon?.dispose(); + } } } diff --git a/lib/vscode/src/vs/base/common/extpath.ts b/src/vs/base/common/extpath.ts similarity index 93% rename from lib/vscode/src/vs/base/common/extpath.ts rename to src/vs/base/common/extpath.ts index c6d8b39aa5f2..3d7d387c763a 100644 --- a/lib/vscode/src/vs/base/common/extpath.ts +++ b/src/vs/base/common/extpath.ts @@ -22,6 +22,23 @@ export function toSlashes(osPath: string) { return osPath.replace(/[\\/]/g, posix.sep); } +/** + * Takes a Windows OS path (using backward or forward slashes) and turns it into a posix path: + * - turns backward slashes into forward slashes + * - makes it absolute if it starts with a drive letter + * This should only be done for OS paths from Windows (or user provided paths potentially from Windows). + * Using it on a Linux or MaxOS path might change it. + */ +export function toPosixPath(osPath: string) { + if (osPath.indexOf('/') === -1) { + osPath = toSlashes(osPath); + } + if (/^[a-zA-Z]:(\/|$)/.test(osPath)) { // starts with a drive letter + osPath = '/' + osPath; + } + return osPath; +} + /** * Computes the _root_ this path, like `getRoot('c:\files') === c:\`, * `getRoot('files:///files/path') === files:///`, diff --git a/lib/vscode/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts similarity index 100% rename from lib/vscode/src/vs/base/common/filters.ts rename to src/vs/base/common/filters.ts diff --git a/lib/vscode/src/vs/base/common/functional.ts b/src/vs/base/common/functional.ts similarity index 100% rename from lib/vscode/src/vs/base/common/functional.ts rename to src/vs/base/common/functional.ts diff --git a/lib/vscode/src/vs/base/common/fuzzyScorer.ts b/src/vs/base/common/fuzzyScorer.ts similarity index 100% rename from lib/vscode/src/vs/base/common/fuzzyScorer.ts rename to src/vs/base/common/fuzzyScorer.ts diff --git a/lib/vscode/src/vs/base/common/glob.ts b/src/vs/base/common/glob.ts similarity index 100% rename from lib/vscode/src/vs/base/common/glob.ts rename to src/vs/base/common/glob.ts diff --git a/lib/vscode/src/vs/base/common/hash.ts b/src/vs/base/common/hash.ts similarity index 100% rename from lib/vscode/src/vs/base/common/hash.ts rename to src/vs/base/common/hash.ts diff --git a/lib/vscode/src/vs/base/common/history.ts b/src/vs/base/common/history.ts similarity index 100% rename from lib/vscode/src/vs/base/common/history.ts rename to src/vs/base/common/history.ts diff --git a/lib/vscode/src/vs/base/common/htmlContent.ts b/src/vs/base/common/htmlContent.ts similarity index 88% rename from lib/vscode/src/vs/base/common/htmlContent.ts rename to src/vs/base/common/htmlContent.ts index 321fff44c961..50f9a858c90d 100644 --- a/lib/vscode/src/vs/base/common/htmlContent.ts +++ b/src/vs/base/common/htmlContent.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { equals } from 'vs/base/common/arrays'; import { UriComponents } from 'vs/base/common/uri'; import { escapeIcons } from 'vs/base/common/iconLabels'; import { illegalArgument } from 'vs/base/common/errors'; @@ -90,21 +89,7 @@ export function isMarkdownString(thing: any): thing is IMarkdownString { return false; } -export function markedStringsEquals(a: IMarkdownString | IMarkdownString[], b: IMarkdownString | IMarkdownString[]): boolean { - if (!a && !b) { - return true; - } else if (!a || !b) { - return false; - } else if (Array.isArray(a) && Array.isArray(b)) { - return equals(a, b, markdownStringEqual); - } else if (isMarkdownString(a) && isMarkdownString(b)) { - return markdownStringEqual(a, b); - } else { - return false; - } -} - -function markdownStringEqual(a: IMarkdownString, b: IMarkdownString): boolean { +export function markdownStringEqual(a: IMarkdownString, b: IMarkdownString): boolean { if (a === b) { return true; } else if (!a || !b) { diff --git a/lib/vscode/src/vs/base/common/iconLabels.ts b/src/vs/base/common/iconLabels.ts similarity index 100% rename from lib/vscode/src/vs/base/common/iconLabels.ts rename to src/vs/base/common/iconLabels.ts diff --git a/lib/vscode/src/vs/base/common/idGenerator.ts b/src/vs/base/common/idGenerator.ts similarity index 100% rename from lib/vscode/src/vs/base/common/idGenerator.ts rename to src/vs/base/common/idGenerator.ts diff --git a/lib/vscode/src/vs/base/common/insane/cgmanifest.json b/src/vs/base/common/insane/cgmanifest.json similarity index 100% rename from lib/vscode/src/vs/base/common/insane/cgmanifest.json rename to src/vs/base/common/insane/cgmanifest.json diff --git a/lib/vscode/src/vs/base/common/insane/insane.d.ts b/src/vs/base/common/insane/insane.d.ts similarity index 100% rename from lib/vscode/src/vs/base/common/insane/insane.d.ts rename to src/vs/base/common/insane/insane.d.ts diff --git a/lib/vscode/src/vs/base/common/insane/insane.js b/src/vs/base/common/insane/insane.js similarity index 100% rename from lib/vscode/src/vs/base/common/insane/insane.js rename to src/vs/base/common/insane/insane.js diff --git a/lib/vscode/src/vs/base/common/insane/insane.license.txt b/src/vs/base/common/insane/insane.license.txt similarity index 100% rename from lib/vscode/src/vs/base/common/insane/insane.license.txt rename to src/vs/base/common/insane/insane.license.txt diff --git a/lib/vscode/src/vs/base/common/iterator.ts b/src/vs/base/common/iterator.ts similarity index 96% rename from lib/vscode/src/vs/base/common/iterator.ts rename to src/vs/base/common/iterator.ts index 8b60c8757dc2..f7d81bf5bbc3 100644 --- a/lib/vscode/src/vs/base/common/iterator.ts +++ b/src/vs/base/common/iterator.ts @@ -61,9 +61,10 @@ export namespace Iterable { } } - export function* map(iterable: Iterable, fn: (t: T) => R): Iterable { + export function* map(iterable: Iterable, fn: (t: T, index: number) => R): Iterable { + let index = 0; for (const element of iterable) { - yield fn(element); + yield fn(element, index++); } } diff --git a/lib/vscode/src/vs/base/common/json.ts b/src/vs/base/common/json.ts similarity index 100% rename from lib/vscode/src/vs/base/common/json.ts rename to src/vs/base/common/json.ts diff --git a/lib/vscode/src/vs/base/common/jsonEdit.ts b/src/vs/base/common/jsonEdit.ts similarity index 100% rename from lib/vscode/src/vs/base/common/jsonEdit.ts rename to src/vs/base/common/jsonEdit.ts diff --git a/lib/vscode/src/vs/base/common/jsonErrorMessages.ts b/src/vs/base/common/jsonErrorMessages.ts similarity index 100% rename from lib/vscode/src/vs/base/common/jsonErrorMessages.ts rename to src/vs/base/common/jsonErrorMessages.ts diff --git a/lib/vscode/src/vs/base/common/jsonFormatter.ts b/src/vs/base/common/jsonFormatter.ts similarity index 100% rename from lib/vscode/src/vs/base/common/jsonFormatter.ts rename to src/vs/base/common/jsonFormatter.ts diff --git a/lib/vscode/src/vs/base/common/jsonSchema.ts b/src/vs/base/common/jsonSchema.ts similarity index 100% rename from lib/vscode/src/vs/base/common/jsonSchema.ts rename to src/vs/base/common/jsonSchema.ts diff --git a/lib/vscode/src/vs/base/common/keyCodes.ts b/src/vs/base/common/keyCodes.ts similarity index 100% rename from lib/vscode/src/vs/base/common/keyCodes.ts rename to src/vs/base/common/keyCodes.ts diff --git a/lib/vscode/src/vs/base/common/keybindingLabels.ts b/src/vs/base/common/keybindingLabels.ts similarity index 100% rename from lib/vscode/src/vs/base/common/keybindingLabels.ts rename to src/vs/base/common/keybindingLabels.ts diff --git a/lib/vscode/src/vs/base/common/keybindingParser.ts b/src/vs/base/common/keybindingParser.ts similarity index 100% rename from lib/vscode/src/vs/base/common/keybindingParser.ts rename to src/vs/base/common/keybindingParser.ts diff --git a/lib/vscode/src/vs/base/common/labels.ts b/src/vs/base/common/labels.ts similarity index 100% rename from lib/vscode/src/vs/base/common/labels.ts rename to src/vs/base/common/labels.ts diff --git a/lib/vscode/src/vs/base/common/lazy.ts b/src/vs/base/common/lazy.ts similarity index 100% rename from lib/vscode/src/vs/base/common/lazy.ts rename to src/vs/base/common/lazy.ts diff --git a/lib/vscode/src/vs/base/common/lifecycle.ts b/src/vs/base/common/lifecycle.ts similarity index 100% rename from lib/vscode/src/vs/base/common/lifecycle.ts rename to src/vs/base/common/lifecycle.ts diff --git a/lib/vscode/src/vs/base/common/linkedList.ts b/src/vs/base/common/linkedList.ts similarity index 94% rename from lib/vscode/src/vs/base/common/linkedList.ts rename to src/vs/base/common/linkedList.ts index ddeb494cccc7..6a3d9d7af6bd 100644 --- a/lib/vscode/src/vs/base/common/linkedList.ts +++ b/src/vs/base/common/linkedList.ts @@ -33,6 +33,14 @@ export class LinkedList { } clear(): void { + let node = this._first; + while (node !== Node.Undefined) { + const next = node.next; + node.prev = Node.Undefined; + node.next = Node.Undefined; + node = next; + } + this._first = Node.Undefined; this._last = Node.Undefined; this._size = 0; diff --git a/lib/vscode/src/vs/base/common/linkedText.ts b/src/vs/base/common/linkedText.ts similarity index 100% rename from lib/vscode/src/vs/base/common/linkedText.ts rename to src/vs/base/common/linkedText.ts diff --git a/lib/vscode/src/vs/base/common/map.ts b/src/vs/base/common/map.ts similarity index 98% rename from lib/vscode/src/vs/base/common/map.ts rename to src/vs/base/common/map.ts index 36d543ee934a..a552d658aac9 100644 --- a/lib/vscode/src/vs/base/common/map.ts +++ b/src/vs/base/common/map.ts @@ -497,10 +497,14 @@ export class TernarySearchTree { yield* this._entries(this._root); } - private *_entries(node: TernarySearchTreeNode | undefined): IterableIterator<[K, V]> { + private *_entries(node: TernarySearchTreeNode | undefined, i: number = 0): IterableIterator<[K, V]> { + if (i > 5000) { + console.log('potential CYCLE detected', new Error().stack); + return; + } if (node) { // left - yield* this._entries(node.left); + yield* this._entries(node.left, i++); // node if (node.value) { @@ -508,10 +512,10 @@ export class TernarySearchTree { yield [node.key, node.value]; } // mid - yield* this._entries(node.mid); + yield* this._entries(node.mid, i++); // right - yield* this._entries(node.right); + yield* this._entries(node.right, i++); } } } diff --git a/lib/vscode/src/vs/base/common/marked/cgmanifest.json b/src/vs/base/common/marked/cgmanifest.json similarity index 100% rename from lib/vscode/src/vs/base/common/marked/cgmanifest.json rename to src/vs/base/common/marked/cgmanifest.json diff --git a/lib/vscode/src/vs/base/common/marked/marked.d.ts b/src/vs/base/common/marked/marked.d.ts similarity index 100% rename from lib/vscode/src/vs/base/common/marked/marked.d.ts rename to src/vs/base/common/marked/marked.d.ts diff --git a/lib/vscode/src/vs/base/common/marked/marked.js b/src/vs/base/common/marked/marked.js similarity index 100% rename from lib/vscode/src/vs/base/common/marked/marked.js rename to src/vs/base/common/marked/marked.js diff --git a/lib/vscode/src/vs/base/common/marked/marked.license.txt b/src/vs/base/common/marked/marked.license.txt similarity index 100% rename from lib/vscode/src/vs/base/common/marked/marked.license.txt rename to src/vs/base/common/marked/marked.license.txt diff --git a/lib/vscode/src/vs/base/common/marshalling.ts b/src/vs/base/common/marshalling.ts similarity index 100% rename from lib/vscode/src/vs/base/common/marshalling.ts rename to src/vs/base/common/marshalling.ts diff --git a/lib/vscode/src/vs/base/common/mime.ts b/src/vs/base/common/mime.ts similarity index 94% rename from lib/vscode/src/vs/base/common/mime.ts rename to src/vs/base/common/mime.ts index dcaca6245b6f..368d77953e68 100644 --- a/lib/vscode/src/vs/base/common/mime.ts +++ b/src/vs/base/common/mime.ts @@ -316,3 +316,20 @@ export function getExtensionForMimeType(mimeType: string): string | undefined { return undefined; } + +const _simplePattern = /^(.+)\/(.+?)(;.+)?$/; + +export function normalizeMimeType(mimeType: string): string; +export function normalizeMimeType(mimeType: string, strict: true): string | undefined; +export function normalizeMimeType(mimeType: string, strict?: true): string | undefined { + + const match = _simplePattern.exec(mimeType); + if (!match) { + return strict + ? undefined + : mimeType; + } + // https://datatracker.ietf.org/doc/html/rfc2045#section-5.1 + // media and subtype must ALWAYS be lowercase, parameter not + return `${match[1].toLowerCase()}/${match[2].toLowerCase()}${match[3] ?? ''}`; +} diff --git a/lib/vscode/src/vs/base/common/navigator.ts b/src/vs/base/common/navigator.ts similarity index 100% rename from lib/vscode/src/vs/base/common/navigator.ts rename to src/vs/base/common/navigator.ts diff --git a/lib/vscode/src/vs/base/common/network.ts b/src/vs/base/common/network.ts similarity index 96% rename from lib/vscode/src/vs/base/common/network.ts rename to src/vs/base/common/network.ts index 5833339b33e5..d5bacc79d2d8 100644 --- a/lib/vscode/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts @@ -61,6 +61,7 @@ export namespace Schemas { export const vscodeNotebookCell = 'vscode-notebook-cell'; export const vscodeNotebookCellMetadata = 'vscode-notebook-cell-metadata'; + export const vscodeNotebookCellOutput = 'vscode-notebook-cell-output'; export const vscodeSettings = 'vscode-settings'; @@ -125,17 +126,16 @@ class RemoteAuthoritiesImpl { if (host && host.indexOf(':') !== -1) { host = `[${host}]`; } - // const port = this._ports[authority]; + const port = this._ports[authority]; const connectionToken = this._connectionTokens[authority]; let query = `path=${encodeURIComponent(uri.path)}`; if (typeof connectionToken === 'string') { query += `&tkn=${encodeURIComponent(connectionToken)}`; } - // NOTE@coder: Changed this to work against the current path. return URI.from({ scheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource, - authority: window.location.host, - path: `${window.location.pathname.replace(/\/+$/, '')}/vscode-remote-resource`, + authority: `${host}:${port}`, + path: `/vscode-remote-resource`, query }); } diff --git a/lib/vscode/src/vs/base/common/normalization.ts b/src/vs/base/common/normalization.ts similarity index 100% rename from lib/vscode/src/vs/base/common/normalization.ts rename to src/vs/base/common/normalization.ts diff --git a/lib/vscode/src/vs/base/common/numbers.ts b/src/vs/base/common/numbers.ts similarity index 100% rename from lib/vscode/src/vs/base/common/numbers.ts rename to src/vs/base/common/numbers.ts diff --git a/lib/vscode/src/vs/base/common/objects.ts b/src/vs/base/common/objects.ts similarity index 95% rename from lib/vscode/src/vs/base/common/objects.ts rename to src/vs/base/common/objects.ts index 2abc22e51e18..0b032d6a219c 100644 --- a/lib/vscode/src/vs/base/common/objects.ts +++ b/src/vs/base/common/objects.ts @@ -226,3 +226,13 @@ export function getCaseInsensitive(target: obj, key: string): any { const equivalentKey = Object.keys(target).find(k => k.toLowerCase() === lowercaseKey); return equivalentKey ? target[equivalentKey] : target[key]; } + +export function filter(obj: obj, predicate: (key: string, value: any) => boolean): obj { + const result = Object.create(null); + for (const key of Object.keys(obj)) { + if (predicate(key, obj[key])) { + result[key] = obj[key]; + } + } + return result; +} diff --git a/lib/vscode/src/vs/base/common/paging.ts b/src/vs/base/common/paging.ts similarity index 100% rename from lib/vscode/src/vs/base/common/paging.ts rename to src/vs/base/common/paging.ts diff --git a/lib/vscode/src/vs/base/common/parsers.ts b/src/vs/base/common/parsers.ts similarity index 100% rename from lib/vscode/src/vs/base/common/parsers.ts rename to src/vs/base/common/parsers.ts diff --git a/lib/vscode/src/vs/base/common/path.ts b/src/vs/base/common/path.ts similarity index 100% rename from lib/vscode/src/vs/base/common/path.ts rename to src/vs/base/common/path.ts diff --git a/lib/vscode/src/vs/base/common/performance.d.ts b/src/vs/base/common/performance.d.ts similarity index 100% rename from lib/vscode/src/vs/base/common/performance.d.ts rename to src/vs/base/common/performance.d.ts diff --git a/lib/vscode/src/vs/base/common/performance.js b/src/vs/base/common/performance.js similarity index 100% rename from lib/vscode/src/vs/base/common/performance.js rename to src/vs/base/common/performance.js diff --git a/lib/vscode/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts similarity index 93% rename from lib/vscode/src/vs/base/common/platform.ts rename to src/vs/base/common/platform.ts index 2bdfc7e6c7e7..512775eaddc6 100644 --- a/lib/vscode/src/vs/base/common/platform.ts +++ b/src/vs/base/common/platform.ts @@ -53,7 +53,7 @@ declare const self: unknown; export const globals: any = (typeof self === 'object' ? self : typeof global === 'object' ? global : {}); let nodeProcess: INodeProcess | undefined = undefined; -if (typeof globals.vscode !== 'undefined') { +if (typeof globals.vscode !== 'undefined' && typeof globals.vscode.process !== 'undefined') { // Native environment (sandboxed) nodeProcess = globals.vscode.process; } else if (typeof process !== 'undefined') { @@ -101,18 +101,6 @@ if (typeof navigator === 'object' && !isElectronRenderer) { _isWeb = true; _locale = navigator.language; _language = _locale; - - // NOTE@coder: Make languages work. - const el = typeof document !== 'undefined' && document.getElementById('vscode-remote-nls-configuration'); - const rawNlsConfig = el && el.getAttribute('data-settings'); - if (rawNlsConfig) { - try { - const nlsConfig: NLSConfig = JSON.parse(rawNlsConfig); - _locale = nlsConfig.locale; - _translationsConfigFile = nlsConfig._translationsConfigFile; - _language = nlsConfig.availableLanguages['*'] || LANGUAGE_DEFAULT; - } catch (error) { /* Oh well. */ } - } } // Native environment diff --git a/src/vs/base/common/ports.ts b/src/vs/base/common/ports.ts new file mode 100644 index 000000000000..5ec75530a871 --- /dev/null +++ b/src/vs/base/common/ports.ts @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/** + * @returns Returns a random port between 1025 and 65535. + */ +export function randomPort(): number { + const min = 1025; + const max = 65535; + return min + Math.floor((max - min) * Math.random()); +} diff --git a/lib/vscode/src/vs/base/common/process.ts b/src/vs/base/common/process.ts similarity index 94% rename from lib/vscode/src/vs/base/common/process.ts rename to src/vs/base/common/process.ts index 2df6dd5df2f1..ec90453aa83e 100644 --- a/lib/vscode/src/vs/base/common/process.ts +++ b/src/vs/base/common/process.ts @@ -9,7 +9,7 @@ let safeProcess: INodeProcess & { nextTick: (callback: (...args: any[]) => void) declare const process: INodeProcess; // Native sandbox environment -if (typeof globals.vscode !== 'undefined') { +if (typeof globals.vscode !== 'undefined' && typeof globals.vscode.process !== 'undefined') { const sandboxProcess: INodeProcess = globals.vscode.process; safeProcess = { get platform() { return sandboxProcess.platform; }, @@ -38,7 +38,7 @@ else { nextTick(callback: (...args: any[]) => void): void { return setImmediate(callback); }, // Unsupported - get env() { return Object.create(null); }, + get env() { return {}; }, cwd() { return '/'; } }; } diff --git a/lib/vscode/src/vs/base/common/processes.ts b/src/vs/base/common/processes.ts similarity index 99% rename from lib/vscode/src/vs/base/common/processes.ts rename to src/vs/base/common/processes.ts index 6b84dbedbf57..6c52c3f9ce2b 100644 --- a/lib/vscode/src/vs/base/common/processes.ts +++ b/src/vs/base/common/processes.ts @@ -111,7 +111,6 @@ export function sanitizeProcessEnvironment(env: IProcessEnvironment, ...preserve /^VSCODE_.+$/, /^SNAP(|_.*)$/, /^GDK_PIXBUF_.+$/, - /^CODE_SERVER_.+$/, ]; const envKeys = Object.keys(env); envKeys diff --git a/lib/vscode/src/vs/base/common/product.ts b/src/vs/base/common/product.ts similarity index 95% rename from lib/vscode/src/vs/base/common/product.ts rename to src/vs/base/common/product.ts index 9bfd5ae6a42f..a301b50683c1 100644 --- a/lib/vscode/src/vs/base/common/product.ts +++ b/src/vs/base/common/product.ts @@ -25,10 +25,12 @@ export type ExtensionUntrustedWorkspaceSupport = { readonly override?: boolean | 'limited' }; -export interface IProductConfiguration { - // NOTE@coder: add codeServerVersion - readonly codeServerVersion?: string; +export type ExtensionVirtualWorkspaceSupport = { + readonly default?: boolean, + readonly override?: boolean +}; +export interface IProductConfiguration { readonly version: string; readonly date?: string; readonly quality?: string; @@ -77,6 +79,7 @@ export interface IProductConfiguration { readonly remoteExtensionTips?: { [remoteName: string]: IRemoteExtensionTip; }; readonly extensionKeywords?: { [extension: string]: readonly string[]; }; readonly keymapExtensionTips?: readonly string[]; + readonly languageExtensionTips?: readonly string[]; readonly trustedExtensionUrlPublicKeys?: { [id: string]: string[]; }; readonly crashReporter?: { @@ -125,7 +128,7 @@ export interface IProductConfiguration { readonly extensionSyncedKeys?: { readonly [extensionId: string]: string[]; }; readonly extensionAllowedProposedApi?: readonly string[]; readonly extensionUntrustedWorkspaceSupport?: { readonly [extensionId: string]: ExtensionUntrustedWorkspaceSupport }; - readonly extensionVirtualWorkspacesSupport?: { readonly [extensionId: string]: { default?: boolean, override?: boolean } }; + readonly extensionVirtualWorkspacesSupport?: { readonly [extensionId: string]: ExtensionVirtualWorkspaceSupport }; readonly msftInternalDomains?: string[]; readonly linkProtectionTrustedDomains?: readonly string[]; @@ -133,6 +136,8 @@ export interface IProductConfiguration { readonly 'configurationSync.store'?: ConfigurationSyncStore; readonly darwinUniversalAssetId?: string; + + readonly webviewContentExternalBaseUrlTemplate?: string; } export type ImportantExtensionTip = { name: string; languages?: string[]; pattern?: string; isExtensionPack?: boolean }; diff --git a/lib/vscode/src/vs/base/common/range.ts b/src/vs/base/common/range.ts similarity index 100% rename from lib/vscode/src/vs/base/common/range.ts rename to src/vs/base/common/range.ts diff --git a/lib/vscode/src/vs/base/common/resourceTree.ts b/src/vs/base/common/resourceTree.ts similarity index 100% rename from lib/vscode/src/vs/base/common/resourceTree.ts rename to src/vs/base/common/resourceTree.ts diff --git a/lib/vscode/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts similarity index 98% rename from lib/vscode/src/vs/base/common/resources.ts rename to src/vs/base/common/resources.ts index f516eec5304d..5a40b0cc4247 100644 --- a/lib/vscode/src/vs/base/common/resources.ts +++ b/src/vs/base/common/resources.ts @@ -50,7 +50,7 @@ export interface IExtUri { /** * Creates a key from a resource URI to be used to resource comparison and for resource maps. - * @see ResourceMap + * @see {@link ResourceMap} * @param uri Uri * @param ignoreFragment Ignore the fragment (defaults to `false`) */ @@ -264,12 +264,7 @@ export class ExtUri implements IExtUri { path: newURI.path }); } - if (path.indexOf('/') === -1) { // no slashes? it's likely a Windows path - path = extpath.toSlashes(path); - if (/^[a-zA-Z]:(\/|$)/.test(path)) { // starts with a drive letter - path = '/' + path; - } - } + path = extpath.toPosixPath(path); // we allow path to be a windows path return base.with({ path: paths.posix.resolve(base.path, path) }); diff --git a/lib/vscode/src/vs/base/common/scanCode.ts b/src/vs/base/common/scanCode.ts similarity index 100% rename from lib/vscode/src/vs/base/common/scanCode.ts rename to src/vs/base/common/scanCode.ts diff --git a/lib/vscode/src/vs/base/common/scrollable.ts b/src/vs/base/common/scrollable.ts similarity index 100% rename from lib/vscode/src/vs/base/common/scrollable.ts rename to src/vs/base/common/scrollable.ts diff --git a/lib/vscode/src/vs/base/common/search.ts b/src/vs/base/common/search.ts similarity index 100% rename from lib/vscode/src/vs/base/common/search.ts rename to src/vs/base/common/search.ts diff --git a/lib/vscode/src/vs/base/common/semver/cgmanifest.json b/src/vs/base/common/semver/cgmanifest.json similarity index 100% rename from lib/vscode/src/vs/base/common/semver/cgmanifest.json rename to src/vs/base/common/semver/cgmanifest.json diff --git a/lib/vscode/src/vs/base/common/semver/semver.d.ts b/src/vs/base/common/semver/semver.d.ts similarity index 100% rename from lib/vscode/src/vs/base/common/semver/semver.d.ts rename to src/vs/base/common/semver/semver.d.ts diff --git a/lib/vscode/src/vs/base/common/semver/semver.js b/src/vs/base/common/semver/semver.js similarity index 100% rename from lib/vscode/src/vs/base/common/semver/semver.js rename to src/vs/base/common/semver/semver.js diff --git a/lib/vscode/src/vs/base/common/sequence.ts b/src/vs/base/common/sequence.ts similarity index 100% rename from lib/vscode/src/vs/base/common/sequence.ts rename to src/vs/base/common/sequence.ts diff --git a/lib/vscode/src/vs/base/common/severity.ts b/src/vs/base/common/severity.ts similarity index 100% rename from lib/vscode/src/vs/base/common/severity.ts rename to src/vs/base/common/severity.ts diff --git a/lib/vscode/src/vs/base/common/skipList.ts b/src/vs/base/common/skipList.ts similarity index 100% rename from lib/vscode/src/vs/base/common/skipList.ts rename to src/vs/base/common/skipList.ts diff --git a/lib/vscode/src/vs/base/common/stopwatch.ts b/src/vs/base/common/stopwatch.ts similarity index 100% rename from lib/vscode/src/vs/base/common/stopwatch.ts rename to src/vs/base/common/stopwatch.ts diff --git a/lib/vscode/src/vs/base/common/stream.ts b/src/vs/base/common/stream.ts similarity index 100% rename from lib/vscode/src/vs/base/common/stream.ts rename to src/vs/base/common/stream.ts diff --git a/lib/vscode/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts similarity index 96% rename from lib/vscode/src/vs/base/common/strings.ts rename to src/vs/base/common/strings.ts index e560d16925ba..67d4c7f16a32 100644 --- a/lib/vscode/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -1082,3 +1082,81 @@ function getGraphemeBreakRawData(): number[] { } //#endregion + +/** + * Computes the offset after performing a left delete on the given string, + * while considering unicode grapheme/emoji rules. +*/ +export function getLeftDeleteOffset(offset: number, str: string): number { + if (offset === 0) { + return 0; + } + + // Try to delete emoji part. + const emojiOffset = getOffsetBeforeLastEmojiComponent(offset, str); + if (emojiOffset !== undefined) { + return emojiOffset; + } + + // Otherwise, just skip a single code point. + const codePoint = getPrevCodePoint(str, offset); + offset -= getUTF16Length(codePoint); + return offset; +} + +function getOffsetBeforeLastEmojiComponent(offset: number, str: string): number | undefined { + // See https://www.unicode.org/reports/tr51/tr51-14.html#EBNF_and_Regex for the + // structure of emojis. + let codePoint = getPrevCodePoint(str, offset); + offset -= getUTF16Length(codePoint); + + // Skip modifiers + while ((isEmojiModifier(codePoint) || codePoint === CodePoint.emojiVariantSelector || codePoint === CodePoint.enclosingKeyCap)) { + if (offset === 0) { + // Cannot skip modifier, no preceding emoji base. + return undefined; + } + codePoint = getPrevCodePoint(str, offset); + offset -= getUTF16Length(codePoint); + } + + // Expect base emoji + if (!isEmojiImprecise(codePoint)) { + // Unexpected code point, not a valid emoji. + return undefined; + } + + if (offset >= 0) { + // Skip optional ZWJ code points that combine multiple emojis. + // In theory, we should check if that ZWJ actually combines multiple emojis + // to prevent deleting ZWJs in situations we didn't account for. + const optionalZwjCodePoint = getPrevCodePoint(str, offset); + if (optionalZwjCodePoint === CodePoint.zwj) { + offset -= getUTF16Length(optionalZwjCodePoint); + } + } + + return offset; +} + +function getUTF16Length(codePoint: number) { + return codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1; +} + +function isEmojiModifier(codePoint: number): boolean { + return 0x1F3FB <= codePoint && codePoint <= 0x1F3FF; +} + +const enum CodePoint { + zwj = 0x200D, + + /** + * Variation Selector-16 (VS16) + */ + emojiVariantSelector = 0xFE0F, + + /** + * Combining Enclosing Keycap + */ + enclosingKeyCap = 0x20E3, +} diff --git a/lib/vscode/src/vs/base/common/styler.ts b/src/vs/base/common/styler.ts similarity index 100% rename from lib/vscode/src/vs/base/common/styler.ts rename to src/vs/base/common/styler.ts diff --git a/lib/vscode/src/vs/base/common/types.ts b/src/vs/base/common/types.ts similarity index 100% rename from lib/vscode/src/vs/base/common/types.ts rename to src/vs/base/common/types.ts diff --git a/lib/vscode/src/vs/base/common/uint.ts b/src/vs/base/common/uint.ts similarity index 100% rename from lib/vscode/src/vs/base/common/uint.ts rename to src/vs/base/common/uint.ts diff --git a/lib/vscode/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts similarity index 99% rename from lib/vscode/src/vs/base/common/uri.ts rename to src/vs/base/common/uri.ts index c2b0b02eb867..da8c4de410d9 100644 --- a/lib/vscode/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -327,13 +327,15 @@ export class URI implements UriComponents { } static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string }): URI { - return new Uri( + const result = new Uri( components.scheme, components.authority, components.path, components.query, components.fragment, ); + _validateUri(result, true); + return result; } /** diff --git a/lib/vscode/src/vs/base/common/uriIpc.ts b/src/vs/base/common/uriIpc.ts similarity index 81% rename from lib/vscode/src/vs/base/common/uriIpc.ts rename to src/vs/base/common/uriIpc.ts index 29b2f9dfc2b7..ef2291d49b13 100644 --- a/lib/vscode/src/vs/base/common/uriIpc.ts +++ b/src/vs/base/common/uriIpc.ts @@ -5,7 +5,6 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { MarshalledObject } from 'vs/base/common/marshalling'; -import { Schemas } from './network'; export interface IURITransformer { transformIncoming(uri: UriComponents): UriComponents; @@ -32,35 +31,29 @@ function toJSON(uri: URI): UriComponents { export class URITransformer implements IURITransformer { - constructor(private readonly remoteAuthority: string) { + private readonly _uriTransformer: IRawURITransformer; + + constructor(uriTransformer: IRawURITransformer) { + this._uriTransformer = uriTransformer; } - // NOTE@coder: Coming in from the browser it'll be vscode-remote so it needs - // to be transformed into file. public transformIncoming(uri: UriComponents): UriComponents { - return uri.scheme === Schemas.vscodeRemote - ? toJSON(URI.file(uri.path)) - : uri; + const result = this._uriTransformer.transformIncoming(uri); + return (result === uri ? uri : toJSON(URI.from(result))); } - // NOTE@coder: Going out to the browser it'll be file so it needs to be - // transformed into vscode-remote. public transformOutgoing(uri: UriComponents): UriComponents { - return uri.scheme === Schemas.file - ? toJSON(URI.from({ authority: this.remoteAuthority, scheme: Schemas.vscodeRemote, path: uri.path })) - : uri; + const result = this._uriTransformer.transformOutgoing(uri); + return (result === uri ? uri : toJSON(URI.from(result))); } public transformOutgoingURI(uri: URI): URI { - return uri.scheme === Schemas.file - ? URI.from({ authority: this.remoteAuthority, scheme: Schemas.vscodeRemote, path:uri.path }) - : uri; + const result = this._uriTransformer.transformOutgoing(uri); + return (result === uri ? uri : URI.from(result)); } public transformOutgoingScheme(scheme: string): string { - return scheme === Schemas.file - ? Schemas.vscodeRemote - : scheme; + return this._uriTransformer.transformOutgoingScheme(scheme); } } @@ -159,4 +152,4 @@ export function transformAndReviveIncomingURIs(obj: T, transformer: IURITrans return obj; } return result; -} +} \ No newline at end of file diff --git a/lib/vscode/src/vs/base/common/uuid.ts b/src/vs/base/common/uuid.ts similarity index 100% rename from lib/vscode/src/vs/base/common/uuid.ts rename to src/vs/base/common/uuid.ts diff --git a/lib/vscode/src/vs/base/common/worker/simpleWorker.ts b/src/vs/base/common/worker/simpleWorker.ts similarity index 100% rename from lib/vscode/src/vs/base/common/worker/simpleWorker.ts rename to src/vs/base/common/worker/simpleWorker.ts diff --git a/lib/vscode/src/vs/base/node/cpuUsage.sh b/src/vs/base/node/cpuUsage.sh similarity index 100% rename from lib/vscode/src/vs/base/node/cpuUsage.sh rename to src/vs/base/node/cpuUsage.sh diff --git a/lib/vscode/src/vs/base/node/crypto.ts b/src/vs/base/node/crypto.ts similarity index 100% rename from lib/vscode/src/vs/base/node/crypto.ts rename to src/vs/base/node/crypto.ts diff --git a/lib/vscode/src/vs/base/node/decoder.ts b/src/vs/base/node/decoder.ts similarity index 100% rename from lib/vscode/src/vs/base/node/decoder.ts rename to src/vs/base/node/decoder.ts diff --git a/lib/vscode/src/vs/base/node/extpath.ts b/src/vs/base/node/extpath.ts similarity index 95% rename from lib/vscode/src/vs/base/node/extpath.ts rename to src/vs/base/node/extpath.ts index eaf62cd8e125..325c0d2d1dc3 100644 --- a/lib/vscode/src/vs/base/node/extpath.ts +++ b/src/vs/base/node/extpath.ts @@ -4,10 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import * as fs from 'fs'; -import { promisify } from 'util'; import { rtrim } from 'vs/base/common/strings'; import { sep, join, normalize, dirname, basename } from 'vs/base/common/path'; -import { readdirSync } from 'vs/base/node/pfs'; +import { Promises, readdirSync } from 'vs/base/node/pfs'; /** * Copied from: https://github.com/microsoft/vscode-node-debug/blob/master/src/node/pathUtilities.ts#L83 @@ -57,7 +56,7 @@ export async function realpath(path: string): Promise { // calls `fs.native.realpath` which will result in subst // drives to be resolved to their target on Windows // https://github.com/microsoft/vscode/issues/118562 - return await promisify(fs.realpath)(path); + return await Promises.realpath(path); } catch (error) { // We hit an error calling fs.realpath(). Since fs.realpath() is doing some path normalization @@ -67,7 +66,7 @@ export async function realpath(path: string): Promise { // to not resolve links but to simply see if the path is read accessible or not. const normalizedPath = normalizePath(path); - await fs.promises.access(normalizedPath, fs.constants.R_OK); + await Promises.access(normalizedPath, fs.constants.R_OK); return normalizedPath; } diff --git a/lib/vscode/src/vs/base/node/id.ts b/src/vs/base/node/id.ts similarity index 100% rename from lib/vscode/src/vs/base/node/id.ts rename to src/vs/base/node/id.ts diff --git a/lib/vscode/src/vs/base/node/languagePacks.d.ts b/src/vs/base/node/languagePacks.d.ts similarity index 100% rename from lib/vscode/src/vs/base/node/languagePacks.d.ts rename to src/vs/base/node/languagePacks.d.ts diff --git a/lib/vscode/src/vs/base/node/languagePacks.js b/src/vs/base/node/languagePacks.js similarity index 97% rename from lib/vscode/src/vs/base/node/languagePacks.js rename to src/vs/base/node/languagePacks.js index 0899cab4ed15..5c14fade8789 100644 --- a/lib/vscode/src/vs/base/node/languagePacks.js +++ b/src/vs/base/node/languagePacks.js @@ -73,10 +73,7 @@ function getLanguagePackConfigurations(userDataPath) { const configFile = path.join(userDataPath, 'languagepacks.json'); try { - // NOTE@coder: Swapped require with readFile since require is cached and - // we don't restart the server-side portion of code-server when the - // language changes. - return JSON.parse(fs.readFileSync(configFile, 'utf8')); + return nodeRequire(configFile); } catch (err) { // Do nothing. If we can't read the file we have no // language pack config. diff --git a/lib/vscode/src/vs/base/node/macAddress.ts b/src/vs/base/node/macAddress.ts similarity index 100% rename from lib/vscode/src/vs/base/node/macAddress.ts rename to src/vs/base/node/macAddress.ts diff --git a/lib/vscode/src/vs/base/node/pfs.ts b/src/vs/base/node/pfs.ts similarity index 88% rename from lib/vscode/src/vs/base/node/pfs.ts rename to src/vs/base/node/pfs.ts index 30d25a8cc338..40a81246b022 100644 --- a/lib/vscode/src/vs/base/node/pfs.ts +++ b/src/vs/base/node/pfs.ts @@ -5,6 +5,7 @@ import * as fs from 'fs'; import { tmpdir } from 'os'; +import { promisify } from 'util'; import { join } from 'vs/base/common/path'; import { ResourceQueue } from 'vs/base/common/async'; import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; @@ -56,7 +57,7 @@ async function rimrafMove(path: string): Promise { try { const pathInTemp = join(tmpdir(), generateUuid()); try { - await fs.promises.rename(path, pathInTemp); + await Promises.rename(path, pathInTemp); } catch (error) { return rimrafUnlink(path); // if rename fails, delete without tmp dir } @@ -71,7 +72,7 @@ async function rimrafMove(path: string): Promise { } async function rimrafUnlink(path: string): Promise { - return fs.promises.rmdir(path, { recursive: true, maxRetries: 3 }); + return Promises.rmdir(path, { recursive: true, maxRetries: 3 }); } export function rimrafSync(path: string): void { @@ -102,12 +103,12 @@ export interface IDirent { export async function readdir(path: string): Promise; export async function readdir(path: string, options: { withFileTypes: true }): Promise; export async function readdir(path: string, options?: { withFileTypes: true }): Promise<(string | IDirent)[]> { - return handleDirectoryChildren(await (options ? safeReaddirWithFileTypes(path) : fs.promises.readdir(path))); + return handleDirectoryChildren(await (options ? safeReaddirWithFileTypes(path) : Promises.readdir(path))); } async function safeReaddirWithFileTypes(path: string): Promise { try { - return await fs.promises.readdir(path, { withFileTypes: true }); + return await Promises.readdir(path, { withFileTypes: true }); } catch (error) { console.warn('[node.js fs] readdir with filetypes failed with error: ', error); } @@ -126,7 +127,7 @@ async function safeReaddirWithFileTypes(path: string): Promise { let isSymbolicLink = false; try { - const lstat = await fs.promises.lstat(join(path, child)); + const lstat = await Promises.lstat(join(path, child)); isFile = lstat.isFile(); isDirectory = lstat.isDirectory(); @@ -251,7 +252,7 @@ export namespace SymlinkSupport { // First stat the link let lstats: fs.Stats | undefined; try { - lstats = await fs.promises.lstat(path); + lstats = await Promises.lstat(path); // Return early if the stat is not a symbolic link at all if (!lstats.isSymbolicLink()) { @@ -264,7 +265,7 @@ export namespace SymlinkSupport { // If the stat is a symbolic link or failed to stat, use fs.stat() // which for symbolic links will stat the target they point to try { - const stats = await fs.promises.stat(path); + const stats = await Promises.stat(path); return { stat: stats, symbolicLink: lstats?.isSymbolicLink() ? { dangling: false } : undefined }; } catch (error) { @@ -279,7 +280,7 @@ export namespace SymlinkSupport { // are not supported (https://github.com/nodejs/node/issues/36790) if (isWindows && error.code === 'EACCES') { try { - const stats = await fs.promises.stat(await fs.promises.readlink(path)); + const stats = await Promises.stat(await Promises.readlink(path)); return { stat: stats, symbolicLink: { dangling: false } }; } catch (error) { @@ -488,24 +489,19 @@ export async function move(source: string, target: string): Promise { // as well because conceptually it is a change of a similar category. async function updateMtime(path: string): Promise { try { - const stat = await fs.promises.lstat(path); + const stat = await Promises.lstat(path); if (stat.isDirectory() || stat.isSymbolicLink()) { return; // only for files } - const fh = await fs.promises.open(path, 'a'); - try { - await fh.utimes(stat.atime, new Date()); - } finally { - await fh.close(); - } + await Promises.utimes(path, stat.atime, new Date()); } catch (error) { // Ignore any error } } try { - await fs.promises.rename(source, target); + await Promises.rename(source, target); await updateMtime(target); } catch (error) { @@ -594,7 +590,7 @@ async function doCopy(source: string, target: string, payload: ICopyPayload): Pr async function doCopyDirectory(source: string, target: string, mode: number, payload: ICopyPayload): Promise { // Create folder - await fs.promises.mkdir(target, { recursive: true, mode }); + await Promises.mkdir(target, { recursive: true, mode }); // Copy each file recursively const files = await readdir(source); @@ -606,16 +602,16 @@ async function doCopyDirectory(source: string, target: string, mode: number, pay async function doCopyFile(source: string, target: string, mode: number): Promise { // Copy file - await fs.promises.copyFile(source, target); + await Promises.copyFile(source, target); // restore mode (https://github.com/nodejs/node/issues/1104) - await fs.promises.chmod(target, mode); + await Promises.chmod(target, mode); } async function doCopySymlink(source: string, target: string, payload: ICopyPayload): Promise { // Figure out link target - let linkTarget = await fs.promises.readlink(source); + let linkTarget = await Promises.readlink(source); // Special case: the symlink points to a target that is // actually within the path that is being copied. In that @@ -626,7 +622,7 @@ async function doCopySymlink(source: string, target: string, payload: ICopyPaylo } // Create symlink - await fs.promises.symlink(linkTarget, target); + await Promises.symlink(linkTarget, target); } //#endregion @@ -635,7 +631,7 @@ async function doCopySymlink(source: string, target: string, payload: ICopyPaylo export async function exists(path: string): Promise { try { - await fs.promises.access(path); + await Promises.access(path); return true; } catch { @@ -644,3 +640,56 @@ export async function exists(path: string): Promise { } //#endregion + +//#region Promise based fs methods + +/** + * Note: prefer this namespace over the `fs.promises` API + * to enable `graceful-fs` to function properly. Given issue + * https://github.com/isaacs/node-graceful-fs/issues/160 it + * is evident that the module only takes care of the non-promise + * based fs methods. + * + * Another reason is `realpath` being entirely different in + * the promise based implementation compared to the other + * one (https://github.com/microsoft/vscode/issues/118562) + */ +export namespace Promises { + export const access = promisify(fs.access); + + export const stat = promisify(fs.stat); + export const lstat = promisify(fs.lstat); + export const utimes = promisify(fs.utimes); + + export const read = promisify(fs.read); + export const readFile = promisify(fs.readFile); + + export const write = promisify(fs.write); + export const writeFile = promisify(fs.writeFile); + + export const appendFile = promisify(fs.appendFile); + + export const fdatasync = promisify(fs.fdatasync); + export const truncate = promisify(fs.truncate); + + export const rename = promisify(fs.rename); + export const copyFile = promisify(fs.copyFile); + + export const open = promisify(fs.open); + export const close = promisify(fs.close); + + export const symlink = promisify(fs.symlink); + export const readlink = promisify(fs.readlink); + + export const chmod = promisify(fs.chmod); + + export const readdir = promisify(fs.readdir); + export const mkdir = promisify(fs.mkdir); + + export const unlink = promisify(fs.unlink); + export const rmdir = promisify(fs.rmdir); + + export const realpath = promisify(fs.realpath); +} + +//#endregion diff --git a/lib/vscode/src/vs/base/node/ports.ts b/src/vs/base/node/ports.ts similarity index 94% rename from lib/vscode/src/vs/base/node/ports.ts rename to src/vs/base/node/ports.ts index ba8297dc46ff..f6d27bb62154 100644 --- a/lib/vscode/src/vs/base/node/ports.ts +++ b/src/vs/base/node/ports.ts @@ -5,15 +5,6 @@ import * as net from 'net'; -/** - * @returns Returns a random port between 1025 and 65535. - */ -export function randomPort(): number { - const min = 1025; - const max = 65535; - return min + Math.floor((max - min) * Math.random()); -} - /** * Given a start point and a max number of retries, will find a port that * is openable. Will return 0 in case no free port can be found. diff --git a/lib/vscode/src/vs/base/node/powershell.ts b/src/vs/base/node/powershell.ts similarity index 100% rename from lib/vscode/src/vs/base/node/powershell.ts rename to src/vs/base/node/powershell.ts diff --git a/lib/vscode/src/vs/base/node/processes.ts b/src/vs/base/node/processes.ts similarity index 99% rename from lib/vscode/src/vs/base/node/processes.ts rename to src/vs/base/node/processes.ts index 363dc229f627..f1b1b3982122 100644 --- a/lib/vscode/src/vs/base/node/processes.ts +++ b/src/vs/base/node/processes.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import * as path from 'vs/base/common/path'; -import * as fs from 'fs'; import * as pfs from 'vs/base/node/pfs'; import * as cp from 'child_process'; import * as nls from 'vs/nls'; @@ -458,7 +457,7 @@ export namespace win32 { async function fileExists(path: string): Promise { if (await pfs.exists(path)) { - return !((await fs.promises.stat(path)).isDirectory()); + return !((await pfs.Promises.stat(path)).isDirectory()); } return false; } diff --git a/lib/vscode/src/vs/base/node/ps.sh b/src/vs/base/node/ps.sh similarity index 100% rename from lib/vscode/src/vs/base/node/ps.sh rename to src/vs/base/node/ps.sh diff --git a/lib/vscode/src/vs/base/node/ps.ts b/src/vs/base/node/ps.ts similarity index 100% rename from lib/vscode/src/vs/base/node/ps.ts rename to src/vs/base/node/ps.ts diff --git a/lib/vscode/src/vs/base/node/shell.ts b/src/vs/base/node/shell.ts similarity index 100% rename from lib/vscode/src/vs/base/node/shell.ts rename to src/vs/base/node/shell.ts diff --git a/lib/vscode/src/vs/base/node/terminalEncoding.ts b/src/vs/base/node/terminalEncoding.ts similarity index 100% rename from lib/vscode/src/vs/base/node/terminalEncoding.ts rename to src/vs/base/node/terminalEncoding.ts diff --git a/lib/vscode/src/vs/base/node/terminateProcess.sh b/src/vs/base/node/terminateProcess.sh similarity index 100% rename from lib/vscode/src/vs/base/node/terminateProcess.sh rename to src/vs/base/node/terminateProcess.sh diff --git a/lib/vscode/src/vs/base/node/watcher.ts b/src/vs/base/node/watcher.ts similarity index 100% rename from lib/vscode/src/vs/base/node/watcher.ts rename to src/vs/base/node/watcher.ts diff --git a/lib/vscode/src/vs/base/node/zip.ts b/src/vs/base/node/zip.ts similarity index 96% rename from lib/vscode/src/vs/base/node/zip.ts rename to src/vs/base/node/zip.ts index 0d74501d9977..3c289c297d12 100644 --- a/lib/vscode/src/vs/base/node/zip.ts +++ b/src/vs/base/node/zip.ts @@ -5,10 +5,10 @@ import * as nls from 'vs/nls'; import * as path from 'vs/base/common/path'; -import { promises, createWriteStream, WriteStream } from 'fs'; +import { createWriteStream, WriteStream } from 'fs'; import { Readable } from 'stream'; import { Sequencer, createCancelablePromise } from 'vs/base/common/async'; -import { rimraf } from 'vs/base/node/pfs'; +import { Promises, rimraf } from 'vs/base/node/pfs'; import { open as _openZip, Entry, ZipFile } from 'yauzl'; import * as yazl from 'yazl'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -86,7 +86,7 @@ function extractEntry(stream: Readable, fileName: string, mode: number, targetPa } }); - return Promise.resolve(promises.mkdir(targetDirName, { recursive: true })).then(() => new Promise((c, e) => { + return Promise.resolve(Promises.mkdir(targetDirName, { recursive: true })).then(() => new Promise((c, e) => { if (token.isCancellationRequested) { return; } @@ -149,7 +149,7 @@ function extractZip(zipfile: ZipFile, targetPath: string, options: IOptions, tok // directory file names end with '/' if (/\/$/.test(fileName)) { const targetFileName = path.join(targetPath, fileName); - last = createCancelablePromise(token => promises.mkdir(targetFileName, { recursive: true }).then(() => readNextEntry(token)).then(undefined, e)); + last = createCancelablePromise(token => Promises.mkdir(targetFileName, { recursive: true }).then(() => readNextEntry(token)).then(undefined, e)); return; } diff --git a/lib/vscode/src/vs/base/parts/contextmenu/common/contextmenu.ts b/src/vs/base/parts/contextmenu/common/contextmenu.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/contextmenu/common/contextmenu.ts rename to src/vs/base/parts/contextmenu/common/contextmenu.ts diff --git a/lib/vscode/src/vs/base/parts/contextmenu/electron-main/contextmenu.ts b/src/vs/base/parts/contextmenu/electron-main/contextmenu.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/contextmenu/electron-main/contextmenu.ts rename to src/vs/base/parts/contextmenu/electron-main/contextmenu.ts diff --git a/lib/vscode/src/vs/base/parts/contextmenu/electron-sandbox/contextmenu.ts b/src/vs/base/parts/contextmenu/electron-sandbox/contextmenu.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/contextmenu/electron-sandbox/contextmenu.ts rename to src/vs/base/parts/contextmenu/electron-sandbox/contextmenu.ts diff --git a/lib/vscode/src/vs/base/parts/ipc/browser/ipc.mp.ts b/src/vs/base/parts/ipc/browser/ipc.mp.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/ipc/browser/ipc.mp.ts rename to src/vs/base/parts/ipc/browser/ipc.mp.ts diff --git a/lib/vscode/src/vs/base/parts/ipc/common/ipc.electron.ts b/src/vs/base/parts/ipc/common/ipc.electron.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/ipc/common/ipc.electron.ts rename to src/vs/base/parts/ipc/common/ipc.electron.ts diff --git a/lib/vscode/src/vs/base/parts/ipc/common/ipc.mp.ts b/src/vs/base/parts/ipc/common/ipc.mp.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/ipc/common/ipc.mp.ts rename to src/vs/base/parts/ipc/common/ipc.mp.ts diff --git a/lib/vscode/src/vs/base/parts/ipc/common/ipc.net.ts b/src/vs/base/parts/ipc/common/ipc.net.ts similarity index 99% rename from lib/vscode/src/vs/base/parts/ipc/common/ipc.net.ts rename to src/vs/base/parts/ipc/common/ipc.net.ts index 0e88c4481c67..aad4fb4e92a2 100644 --- a/lib/vscode/src/vs/base/parts/ipc/common/ipc.net.ts +++ b/src/vs/base/parts/ipc/common/ipc.net.ts @@ -743,11 +743,6 @@ export class PersistentProtocol implements IMessagePassingProtocol { }, Math.max(ProtocolConstants.KeepAliveTimeoutTime - timeSinceLastIncomingMsg, 0) + 5); } - // NOTE@coder: Set the socket without initiating a reconnect. - public setSocket(socket: ISocket): void { - this._socket = socket; - } - public getSocket(): ISocket { return this._socket; } diff --git a/lib/vscode/src/vs/base/parts/ipc/common/ipc.ts b/src/vs/base/parts/ipc/common/ipc.ts similarity index 99% rename from lib/vscode/src/vs/base/parts/ipc/common/ipc.ts rename to src/vs/base/parts/ipc/common/ipc.ts index 0757b52ab813..c3a249d5c91f 100644 --- a/lib/vscode/src/vs/base/parts/ipc/common/ipc.ts +++ b/src/vs/base/parts/ipc/common/ipc.ts @@ -13,6 +13,7 @@ import { getRandomElement } from 'vs/base/common/arrays'; import { isFunction, isUndefinedOrNull } from 'vs/base/common/types'; import { revive } from 'vs/base/common/marshalling'; import * as strings from 'vs/base/common/strings'; +import { memoize } from 'vs/base/common/decorators'; /** * An `IChannel` is an abstraction over a collection of commands. @@ -723,11 +724,16 @@ export class ChannelClient implements IChannelClient, IDisposable { } } + @memoize + get onDidInitializePromise(): Promise { + return Event.toPromise(this.onDidInitialize); + } + private whenInitialized(): Promise { if (this.state === State.Idle) { return Promise.resolve(); } else { - return Event.toPromise(this.onDidInitialize); + return this.onDidInitializePromise; } } diff --git a/lib/vscode/src/vs/base/parts/ipc/electron-browser/ipc.mp.ts b/src/vs/base/parts/ipc/electron-browser/ipc.mp.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/ipc/electron-browser/ipc.mp.ts rename to src/vs/base/parts/ipc/electron-browser/ipc.mp.ts diff --git a/lib/vscode/src/vs/base/parts/ipc/electron-main/ipc.electron.ts b/src/vs/base/parts/ipc/electron-main/ipc.electron.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/ipc/electron-main/ipc.electron.ts rename to src/vs/base/parts/ipc/electron-main/ipc.electron.ts diff --git a/lib/vscode/src/vs/base/parts/ipc/electron-main/ipc.mp.ts b/src/vs/base/parts/ipc/electron-main/ipc.mp.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/ipc/electron-main/ipc.mp.ts rename to src/vs/base/parts/ipc/electron-main/ipc.mp.ts diff --git a/lib/vscode/src/vs/base/parts/ipc/electron-sandbox/ipc.electron.ts b/src/vs/base/parts/ipc/electron-sandbox/ipc.electron.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/ipc/electron-sandbox/ipc.electron.ts rename to src/vs/base/parts/ipc/electron-sandbox/ipc.electron.ts diff --git a/lib/vscode/src/vs/base/parts/ipc/node/ipc.cp.ts b/src/vs/base/parts/ipc/node/ipc.cp.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/ipc/node/ipc.cp.ts rename to src/vs/base/parts/ipc/node/ipc.cp.ts diff --git a/lib/vscode/src/vs/base/parts/ipc/node/ipc.net.ts b/src/vs/base/parts/ipc/node/ipc.net.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/ipc/node/ipc.net.ts rename to src/vs/base/parts/ipc/node/ipc.net.ts diff --git a/lib/vscode/src/vs/base/parts/ipc/test/browser/ipc.mp.test.ts b/src/vs/base/parts/ipc/test/browser/ipc.mp.test.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/ipc/test/browser/ipc.mp.test.ts rename to src/vs/base/parts/ipc/test/browser/ipc.mp.test.ts diff --git a/lib/vscode/src/vs/base/parts/ipc/test/common/ipc.test.ts b/src/vs/base/parts/ipc/test/common/ipc.test.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/ipc/test/common/ipc.test.ts rename to src/vs/base/parts/ipc/test/common/ipc.test.ts diff --git a/lib/vscode/src/vs/base/parts/ipc/test/electron-sandbox/ipc.mp.test.ts b/src/vs/base/parts/ipc/test/electron-sandbox/ipc.mp.test.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/ipc/test/electron-sandbox/ipc.mp.test.ts rename to src/vs/base/parts/ipc/test/electron-sandbox/ipc.mp.test.ts diff --git a/lib/vscode/src/vs/base/parts/ipc/test/node/ipc.cp.test.ts b/src/vs/base/parts/ipc/test/node/ipc.cp.test.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/ipc/test/node/ipc.cp.test.ts rename to src/vs/base/parts/ipc/test/node/ipc.cp.test.ts diff --git a/lib/vscode/src/vs/base/parts/ipc/test/node/ipc.net.test.ts b/src/vs/base/parts/ipc/test/node/ipc.net.test.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/ipc/test/node/ipc.net.test.ts rename to src/vs/base/parts/ipc/test/node/ipc.net.test.ts diff --git a/lib/vscode/src/vs/base/parts/ipc/test/node/testApp.ts b/src/vs/base/parts/ipc/test/node/testApp.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/ipc/test/node/testApp.ts rename to src/vs/base/parts/ipc/test/node/testApp.ts diff --git a/lib/vscode/src/vs/base/parts/ipc/test/node/testService.ts b/src/vs/base/parts/ipc/test/node/testService.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/ipc/test/node/testService.ts rename to src/vs/base/parts/ipc/test/node/testService.ts diff --git a/lib/vscode/src/vs/base/parts/quickinput/browser/media/quickInput.css b/src/vs/base/parts/quickinput/browser/media/quickInput.css similarity index 90% rename from lib/vscode/src/vs/base/parts/quickinput/browser/media/quickInput.css rename to src/vs/base/parts/quickinput/browser/media/quickInput.css index 297f763a76a0..651e43b00bff 100644 --- a/lib/vscode/src/vs/base/parts/quickinput/browser/media/quickInput.css +++ b/src/vs/base/parts/quickinput/browser/media/quickInput.css @@ -170,7 +170,7 @@ border-top-style: solid; } -.quick-input-list .monaco-list-row:first-child .quick-input-list-entry.quick-input-list-separator-border { +.quick-input-list .monaco-list-row[data-index="0"] .quick-input-list-entry.quick-input-list-separator-border { border-top-style: none; } @@ -276,3 +276,14 @@ .quick-input-list .monaco-list-row.focused .quick-input-list-entry-action-bar .action-label { display: flex; } + +/* focused items in quick pick */ +.quick-input-list .monaco-list-row.focused .monaco-keybinding-key, +.quick-input-list .monaco-list-row.focused .quick-input-list-entry .quick-input-list-separator, +.quick-input-list .monaco-list-row.focused .quick-input-list-rows .quick-input-list-row .codicon, +.quick-input-list .monaco-list-row.focused .quick-input-list-entry-action-bar .codicon { + color: inherit +} +.quick-input-list .monaco-list-row.focused .monaco-keybinding-key { + background: none; +} diff --git a/lib/vscode/src/vs/base/parts/quickinput/browser/quickInput.ts b/src/vs/base/parts/quickinput/browser/quickInput.ts similarity index 98% rename from lib/vscode/src/vs/base/parts/quickinput/browser/quickInput.ts rename to src/vs/base/parts/quickinput/browser/quickInput.ts index 7aed5e202bcf..2cb5092c9015 100644 --- a/lib/vscode/src/vs/base/parts/quickinput/browser/quickInput.ts +++ b/src/vs/base/parts/quickinput/browser/quickInput.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/quickInput'; -import { IQuickPickItem, IPickOptions, IInputOptions, IQuickNavigateConfiguration, IQuickPick, IQuickInput, IQuickInputButton, IInputBox, IQuickPickItemButtonEvent, QuickPickInput, IQuickPickSeparator, IKeyMods, IQuickPickAcceptEvent, NO_KEY_MODS, ItemActivation, QuickInputHideReason, IQuickInputHideEvent } from 'vs/base/parts/quickinput/common/quickInput'; +import { IQuickPickItem, IPickOptions, IInputOptions, IQuickNavigateConfiguration, IQuickPick, IQuickInput, IQuickInputButton, IInputBox, IQuickPickItemButtonEvent, QuickPickInput, IQuickPickSeparator, IKeyMods, IQuickPickDidAcceptEvent, NO_KEY_MODS, ItemActivation, QuickInputHideReason, IQuickInputHideEvent, IQuickPickWillAcceptEvent } from 'vs/base/parts/quickinput/common/quickInput'; import * as dom from 'vs/base/browser/dom'; import { CancellationToken } from 'vs/base/common/cancellation'; import { QuickInputList, QuickInputListFocus } from './quickInputList'; @@ -29,7 +29,6 @@ import { IInputBoxStyles } from 'vs/base/browser/ui/inputbox/inputBox'; import { Color } from 'vs/base/common/color'; import { registerCodicon, Codicon } from 'vs/base/common/codicons'; import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; -import { escape } from 'vs/base/common/strings'; import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { isString } from 'vs/base/common/types'; import { IKeybindingLabelStyles } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel'; @@ -359,7 +358,7 @@ class QuickInput extends Disposable implements IQuickInput { const validationMessage = this.validationMessage || this.noValidationMessage; if (this._lastValidationMessage !== validationMessage) { this._lastValidationMessage = validationMessage; - dom.reset(this.ui.message, ...renderLabelWithIcons(escape(validationMessage))); + dom.reset(this.ui.message, ...renderLabelWithIcons(validationMessage)); } if (this._lastSeverity !== this.severity) { this._lastSeverity = this.severity; @@ -428,7 +427,8 @@ class QuickPick extends QuickInput implements IQuickPi private _ariaLabel: string | undefined; private _placeholder: string | undefined; private readonly onDidChangeValueEmitter = this._register(new Emitter()); - private readonly onDidAcceptEmitter = this._register(new Emitter()); + private readonly onWillAcceptEmitter = this._register(new Emitter()); + private readonly onDidAcceptEmitter = this._register(new Emitter()); private readonly onDidCustomEmitter = this._register(new Emitter()); private _items: Array = []; private itemsUpdated = false; @@ -473,8 +473,11 @@ class QuickPick extends QuickInput implements IQuickPi } set value(value: string) { - this._value = value || ''; - this.update(); + if (this._value !== value) { + this._value = value || ''; + this.update(); + this.onDidChangeValueEmitter.fire(this._value); + } } filterValue = (value: string) => value; @@ -499,6 +502,7 @@ class QuickPick extends QuickInput implements IQuickPi onDidChangeValue = this.onDidChangeValueEmitter.event; + onWillAccept = this.onWillAcceptEmitter.event; onDidAccept = this.onDidAcceptEmitter.event; onDidCustom = this.onDidCustomEmitter.event; @@ -761,7 +765,7 @@ class QuickPick extends QuickInput implements IQuickPi if (this.activeItems[0]) { this._selectedItems = [this.activeItems[0]]; this.onDidChangeSelectionEmitter.fire(this.selectedItems); - this.onDidAcceptEmitter.fire({ inBackground: true }); + this.handleAccept(true); } break; @@ -784,7 +788,7 @@ class QuickPick extends QuickInput implements IQuickPi this._selectedItems = [this.activeItems[0]]; this.onDidChangeSelectionEmitter.fire(this.selectedItems); } - this.onDidAcceptEmitter.fire({ inBackground: false }); + this.handleAccept(false); })); this.visibleDisposables.add(this.ui.onDidCustom(() => { this.onDidCustomEmitter.fire(); @@ -812,7 +816,7 @@ class QuickPick extends QuickInput implements IQuickPi this._selectedItems = selectedItems as T[]; this.onDidChangeSelectionEmitter.fire(selectedItems as T[]); if (selectedItems.length) { - this.onDidAcceptEmitter.fire({ inBackground: event instanceof MouseEvent && event.button === 1 /* mouse middle click */ }); + this.handleAccept(event instanceof MouseEvent && event.button === 1 /* mouse middle click */); } })); this.visibleDisposables.add(this.ui.list.onChangedCheckedElements(checkedItems => { @@ -832,6 +836,18 @@ class QuickPick extends QuickInput implements IQuickPi super.show(); // TODO: Why have show() bubble up while update() trickles down? (Could move setComboboxAccessibility() here.) } + private handleAccept(inBackground: boolean): void { + + // Figure out veto via `onWillAccept` event + let veto = false; + this.onWillAcceptEmitter.fire({ veto: () => veto = true }); + + // Continue with `onDidAccpet` if no veto + if (!veto) { + this.onDidAcceptEmitter.fire({ inBackground }); + } + } + private registerQuickNavigation() { return dom.addDisposableListener(this.ui.container, dom.EventType.KEY_UP, e => { if (this.canSelectMany || !this._quickNavigate) { @@ -876,7 +892,7 @@ class QuickPick extends QuickInput implements IQuickPi if (this.activeItems[0]) { this._selectedItems = [this.activeItems[0]]; this.onDidChangeSelectionEmitter.fire(this.selectedItems); - this.onDidAcceptEmitter.fire({ inBackground: false }); + this.handleAccept(false); } // Unset quick navigate after press. It is only valid once // and should not result in any behaviour change afterwards diff --git a/lib/vscode/src/vs/base/parts/quickinput/browser/quickInputBox.ts b/src/vs/base/parts/quickinput/browser/quickInputBox.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/quickinput/browser/quickInputBox.ts rename to src/vs/base/parts/quickinput/browser/quickInputBox.ts diff --git a/lib/vscode/src/vs/base/parts/quickinput/browser/quickInputList.ts b/src/vs/base/parts/quickinput/browser/quickInputList.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/quickinput/browser/quickInputList.ts rename to src/vs/base/parts/quickinput/browser/quickInputList.ts diff --git a/lib/vscode/src/vs/base/parts/quickinput/browser/quickInputUtils.ts b/src/vs/base/parts/quickinput/browser/quickInputUtils.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/quickinput/browser/quickInputUtils.ts rename to src/vs/base/parts/quickinput/browser/quickInputUtils.ts diff --git a/lib/vscode/src/vs/base/parts/quickinput/common/quickInput.ts b/src/vs/base/parts/quickinput/common/quickInput.ts similarity index 95% rename from lib/vscode/src/vs/base/parts/quickinput/common/quickInput.ts rename to src/vs/base/parts/quickinput/common/quickInput.ts index 56aed1582031..7454b45a6d7c 100644 --- a/lib/vscode/src/vs/base/parts/quickinput/common/quickInput.ts +++ b/src/vs/base/parts/quickinput/common/quickInput.ts @@ -207,7 +207,17 @@ export interface IQuickInput extends IDisposable { hide(): void; } -export interface IQuickPickAcceptEvent { +export interface IQuickPickWillAcceptEvent { + + /** + * Allows to disable the default accept handling + * of the picker. If `veto` is called, the picker + * will not trigger the `onDidAccept` event. + */ + veto(): void; +} + +export interface IQuickPickDidAcceptEvent { /** * Signals if the picker item is to be accepted @@ -239,7 +249,8 @@ export interface IQuickPick extends IQuickInput { readonly onDidChangeValue: Event; - readonly onDidAccept: Event; + readonly onWillAccept: Event; + readonly onDidAccept: Event; /** * If enabled, will fire the `onDidAccept` event when diff --git a/lib/vscode/src/vs/base/parts/request/browser/request.ts b/src/vs/base/parts/request/browser/request.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/request/browser/request.ts rename to src/vs/base/parts/request/browser/request.ts diff --git a/lib/vscode/src/vs/base/parts/request/common/request.ts b/src/vs/base/parts/request/common/request.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/request/common/request.ts rename to src/vs/base/parts/request/common/request.ts diff --git a/lib/vscode/src/vs/base/parts/sandbox/common/electronTypes.ts b/src/vs/base/parts/sandbox/common/electronTypes.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/sandbox/common/electronTypes.ts rename to src/vs/base/parts/sandbox/common/electronTypes.ts index 5c36ba595531..01622e6bbab1 100644 --- a/lib/vscode/src/vs/base/parts/sandbox/common/electronTypes.ts +++ b/src/vs/base/parts/sandbox/common/electronTypes.ts @@ -13,6 +13,10 @@ export interface MessageBoxOptions { + /** + * Content of the message box. + */ + message: string; /** * Can be `"none"`, `"info"`, `"error"`, `"question"` or `"warning"`. On Windows, * `"question"` displays the same icon as `"info"`, unless you set an icon using @@ -34,10 +38,6 @@ export interface MessageBoxOptions { * Title of the message box, some platforms will not show it. */ title?: string; - /** - * Content of the message box. - */ - message: string; /** * Extra information of the message. */ diff --git a/lib/vscode/src/vs/base/parts/sandbox/common/sandboxTypes.ts b/src/vs/base/parts/sandbox/common/sandboxTypes.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/sandbox/common/sandboxTypes.ts rename to src/vs/base/parts/sandbox/common/sandboxTypes.ts diff --git a/lib/vscode/src/vs/base/parts/sandbox/electron-browser/preload.js b/src/vs/base/parts/sandbox/electron-browser/preload.js similarity index 96% rename from lib/vscode/src/vs/base/parts/sandbox/electron-browser/preload.js rename to src/vs/base/parts/sandbox/electron-browser/preload.js index bae46cc3d958..67857146ad4b 100644 --- a/lib/vscode/src/vs/base/parts/sandbox/electron-browser/preload.js +++ b/src/vs/base/parts/sandbox/electron-browser/preload.js @@ -112,12 +112,6 @@ ipcRenderer.invoke('vscode:fetchShellEnv') ]); - if (!process.env['VSCODE_SKIP_PROCESS_ENV_PATCHING'] /* TODO@bpasero for https://github.com/microsoft/vscode/issues/108804 */) { - // Assign all keys of the shell environment to our process environment - // But make sure that the user environment wins in the end over shell environment - Object.assign(process.env, shellEnv, userEnv); - } - return { ...process.env, ...shellEnv, ...userEnv }; })(); diff --git a/lib/vscode/src/vs/base/parts/sandbox/electron-sandbox/electronTypes.ts b/src/vs/base/parts/sandbox/electron-sandbox/electronTypes.ts similarity index 87% rename from lib/vscode/src/vs/base/parts/sandbox/electron-sandbox/electronTypes.ts rename to src/vs/base/parts/sandbox/electron-sandbox/electronTypes.ts index e03f9e136739..cd17ec0006eb 100644 --- a/lib/vscode/src/vs/base/parts/sandbox/electron-sandbox/electronTypes.ts +++ b/src/vs/base/parts/sandbox/electron-sandbox/electronTypes.ts @@ -36,6 +36,9 @@ export interface IpcRendererEvent extends Event { } export interface IpcRenderer { + + // Docs: https://electronjs.org/docs/api/ipc-renderer + /** * Listens to `channel`, when a new message arrives `listener` would be called with * `listener(event, args...)`. @@ -58,9 +61,13 @@ export interface IpcRenderer { * Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an * exception. * - * > **NOTE**: Sending non-standard JavaScript types such as DOM objects or special - * Electron objects is deprecated, and will begin throwing an exception starting - * with Electron 9. + * > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special + * Electron objects will throw an exception. + * + * Since the main process does not have support for DOM objects such as + * `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over + * Electron's IPC to the main process, as the main process would have no way to + * decode them. Attempting to send such objects over IPC will result in an error. * * The main process handles it by listening for `channel` with the `ipcMain` * module. @@ -81,9 +88,13 @@ export interface IpcRenderer { * included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw * an exception. * - * > **NOTE**: Sending non-standard JavaScript types such as DOM objects or special - * Electron objects is deprecated, and will begin throwing an exception starting - * with Electron 9. + * > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special + * Electron objects will throw an exception. + * + * Since the main process does not have support for DOM objects such as + * `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over + * Electron's IPC to the main process, as the main process would have no way to + * decode them. Attempting to send such objects over IPC will result in an error. * * The main process should listen for `channel` with `ipcMain.handle()`. * @@ -111,7 +122,7 @@ export interface IpcRenderer { // * For more information on using `MessagePort` and `MessageChannel`, see the MDN // * documentation. // */ - // postMessage(channel: string, message: any): void; + // postMessage(channel: string, message: any, transfer?: MessagePort[]): void; } export interface WebFrame { @@ -119,6 +130,11 @@ export interface WebFrame { * Changes the zoom level to the specified level. The original size is 0 and each * increment above or below represents zooming 20% larger or smaller to default * limits of 300% and 50% of original size, respectively. + * + * > **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that + * the zoom level for a specific domain propagates across all instances of windows + * with the same domain. Differentiating the window URLs will make zoom work + * per-window. */ setZoomLevel(level: number): void; } @@ -207,7 +223,7 @@ export interface CrashReporterStartOptions { rateLimit?: boolean; /** * If true, crash reports will be compressed and uploaded with `Content-Encoding: - * gzip`. Default is `false`. + * gzip`. Default is `true`. */ compress?: boolean; /** diff --git a/lib/vscode/src/vs/base/parts/sandbox/electron-sandbox/globals.ts b/src/vs/base/parts/sandbox/electron-sandbox/globals.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/sandbox/electron-sandbox/globals.ts rename to src/vs/base/parts/sandbox/electron-sandbox/globals.ts diff --git a/lib/vscode/src/vs/base/parts/sandbox/test/electron-sandbox/globals.test.ts b/src/vs/base/parts/sandbox/test/electron-sandbox/globals.test.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/sandbox/test/electron-sandbox/globals.test.ts rename to src/vs/base/parts/sandbox/test/electron-sandbox/globals.test.ts diff --git a/lib/vscode/src/vs/base/parts/storage/common/storage.ts b/src/vs/base/parts/storage/common/storage.ts similarity index 100% rename from lib/vscode/src/vs/base/parts/storage/common/storage.ts rename to src/vs/base/parts/storage/common/storage.ts diff --git a/lib/vscode/src/vs/base/parts/storage/node/storage.ts b/src/vs/base/parts/storage/node/storage.ts similarity index 98% rename from lib/vscode/src/vs/base/parts/storage/node/storage.ts rename to src/vs/base/parts/storage/node/storage.ts index e497862ddafe..e79d41f9e0da 100644 --- a/lib/vscode/src/vs/base/parts/storage/node/storage.ts +++ b/src/vs/base/parts/storage/node/storage.ts @@ -4,12 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import type { Database, Statement } from 'vscode-sqlite3'; -import { promises } from 'fs'; import { Event } from 'vs/base/common/event'; import { timeout } from 'vs/base/common/async'; import { mapToString, setToString } from 'vs/base/common/map'; import { basename } from 'vs/base/common/path'; -import { copy } from 'vs/base/node/pfs'; +import { copy, Promises } from 'vs/base/node/pfs'; import { IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest } from 'vs/base/parts/storage/common/storage'; interface IDatabaseConnection { @@ -187,7 +186,7 @@ export class SQLiteStorageDatabase implements IStorageDatabase { // Delete the existing DB. If the path does not exist or fails to // be deleted, we do not try to recover anymore because we assume // that the path is no longer writeable for us. - return promises.unlink(this.path).then(() => { + return Promises.unlink(this.path).then(() => { // Re-open the DB fresh return this.doConnect(this.path).then(recoveryConnection => { @@ -273,9 +272,9 @@ export class SQLiteStorageDatabase implements IStorageDatabase { // folder is really not writeable for us. // try { - await promises.unlink(path); + await Promises.unlink(path); try { - await promises.rename(this.toBackupPath(path), path); + await Promises.rename(this.toBackupPath(path), path); } catch (error) { // ignore } diff --git a/lib/vscode/src/vs/base/parts/storage/test/node/storage.test.ts b/src/vs/base/parts/storage/test/node/storage.test.ts similarity index 99% rename from lib/vscode/src/vs/base/parts/storage/test/node/storage.test.ts rename to src/vs/base/parts/storage/test/node/storage.test.ts index fd963590dc43..07846cf4a4f6 100644 --- a/lib/vscode/src/vs/base/parts/storage/test/node/storage.test.ts +++ b/src/vs/base/parts/storage/test/node/storage.test.ts @@ -7,9 +7,8 @@ import { SQLiteStorageDatabase, ISQLiteStorageDatabaseOptions } from 'vs/base/pa import { Storage, IStorageDatabase, IStorageItemsChangeEvent } from 'vs/base/parts/storage/common/storage'; import { join } from 'vs/base/common/path'; import { tmpdir } from 'os'; -import { promises } from 'fs'; import { strictEqual, ok } from 'assert'; -import { writeFile, exists, rimraf } from 'vs/base/node/pfs'; +import { writeFile, exists, rimraf, Promises } from 'vs/base/node/pfs'; import { timeout } from 'vs/base/common/async'; import { Event, Emitter } from 'vs/base/common/event'; import { isWindows } from 'vs/base/common/platform'; @@ -23,7 +22,7 @@ flakySuite('Storage Library', function () { setup(function () { testDir = getRandomTestPath(tmpdir(), 'vsctests', 'storagelibrary'); - return promises.mkdir(testDir, { recursive: true }); + return Promises.mkdir(testDir, { recursive: true }); }); teardown(function () { @@ -296,7 +295,7 @@ flakySuite('SQLite Storage Library', function () { setup(function () { testdir = getRandomTestPath(tmpdir(), 'vsctests', 'storagelibrary'); - return promises.mkdir(testdir, { recursive: true }); + return Promises.mkdir(testdir, { recursive: true }); }); teardown(function () { @@ -477,7 +476,7 @@ flakySuite('SQLite Storage Library', function () { // on shutdown. await storage.checkIntegrity(true).then(null, error => { } /* error is expected here but we do not want to fail */); - await promises.unlink(backupPath); // also test that the recovery DB is backed up properly + await Promises.unlink(backupPath); // also test that the recovery DB is backed up properly let recoveryCalled = false; await storage.close(() => { diff --git a/lib/vscode/src/vs/base/test/browser/actionbar.test.ts b/src/vs/base/test/browser/actionbar.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/actionbar.test.ts rename to src/vs/base/test/browser/actionbar.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/browser.test.ts b/src/vs/base/test/browser/browser.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/browser.test.ts rename to src/vs/base/test/browser/browser.test.ts diff --git a/src/vs/base/test/browser/comparers.test.ts b/src/vs/base/test/browser/comparers.test.ts new file mode 100644 index 000000000000..df66a081334f --- /dev/null +++ b/src/vs/base/test/browser/comparers.test.ts @@ -0,0 +1,709 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { + compareFileNames, + compareFileExtensions, + compareFileNamesDefault, + compareFileExtensionsDefault, + compareFileNamesUpper, + compareFileExtensionsUpper, + compareFileNamesLower, + compareFileExtensionsLower, + compareFileNamesUnicode, + compareFileExtensionsUnicode, +} from 'vs/base/common/comparers'; +import * as assert from 'assert'; + +const compareLocale = (a: string, b: string) => a.localeCompare(b); +const compareLocaleNumeric = (a: string, b: string) => a.localeCompare(b, undefined, { numeric: true }); + +suite('Comparers', () => { + + test('compareFileNames', () => { + + // + // Comparisons with the same results as compareFileNamesDefault + // + + // name-only comparisons + assert(compareFileNames(null, null) === 0, 'null should be equal'); + assert(compareFileNames(null, 'abc') < 0, 'null should be come before real values'); + assert(compareFileNames('', '') === 0, 'empty should be equal'); + assert(compareFileNames('abc', 'abc') === 0, 'equal names should be equal'); + assert(compareFileNames('z', 'A') > 0, 'z comes after A'); + assert(compareFileNames('Z', 'a') > 0, 'Z comes after a'); + + // name plus extension comparisons + assert(compareFileNames('bbb.aaa', 'aaa.bbb') > 0, 'compares the whole name all at once by locale'); + assert(compareFileNames('aggregate.go', 'aggregate_repo.go') > 0, 'compares the whole name all at once by locale'); + + // dotfile comparisons + assert(compareFileNames('.abc', '.abc') === 0, 'equal dotfile names should be equal'); + assert(compareFileNames('.env.', '.gitattributes') < 0, 'filenames starting with dots and with extensions should still sort properly'); + assert(compareFileNames('.env', '.aaa.env') > 0, 'dotfiles sort alphabetically when they contain multiple dots'); + assert(compareFileNames('.env', '.env.aaa') < 0, 'dotfiles with the same root sort shortest first'); + assert(compareFileNames('.aaa_env', '.aaa.env') < 0, 'an underscore in a dotfile name will sort before a dot'); + + // dotfile vs non-dotfile comparisons + assert(compareFileNames(null, '.abc') < 0, 'null should come before dotfiles'); + assert(compareFileNames('.env', 'aaa') < 0, 'dotfiles come before filenames without extensions'); + assert(compareFileNames('.env', 'aaa.env') < 0, 'dotfiles come before filenames with extensions'); + assert(compareFileNames('.md', 'A.MD') < 0, 'dotfiles sort before uppercase files'); + assert(compareFileNames('.MD', 'a.md') < 0, 'dotfiles sort before lowercase files'); + + // numeric comparisons + assert(compareFileNames('1', '1') === 0, 'numerically equal full names should be equal'); + assert(compareFileNames('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal'); + assert(compareFileNames('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order'); + assert(compareFileNames('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order even when they are multiple digits long'); + assert(compareFileNames('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically'); + assert(compareFileNames('abc1.10.txt', 'abc1.2.txt') > 0, 'numbers with dots between them are treated as two separate numbers, not one decimal number'); + assert(compareFileNames('a.ext1', 'b.Ext1') < 0, 'if names are different and extensions with numbers are equal except for case, filenames are sorted in name order'); + assert.deepStrictEqual(['a10.txt', 'A2.txt', 'A100.txt', 'a20.txt'].sort(compareFileNames), ['A2.txt', 'a10.txt', 'a20.txt', 'A100.txt'], 'filenames with number and case differences compare numerically'); + + // + // Comparisons with different results than compareFileNamesDefault + // + + // name-only comparisons + assert(compareFileNames('a', 'A') !== compareLocale('a', 'A'), 'the same letter sorts in unicode order, not by locale'); + assert(compareFileNames('â', 'Â') !== compareLocale('â', 'Â'), 'the same accented letter sorts in unicode order, not by locale'); + assert.notDeepStrictEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileNames), ['artichoke', 'Artichoke', 'art', 'Art'].sort(compareLocale), 'words with the same root and different cases do not sort in locale order'); + assert.notDeepStrictEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileNames), ['email', 'Email', 'émail', 'Émail'].sort(compareLocale), 'the same base characters with different case or accents do not sort in locale order'); + + // numeric comparisons + assert(compareFileNames('abc02.txt', 'abc002.txt') > 0, 'filenames with equivalent numbers and leading zeros sort in unicode order'); + assert(compareFileNames('abc.txt1', 'abc.txt01') > 0, 'same name plus extensions with equal numbers sort in unicode order'); + assert(compareFileNames('art01', 'Art01') !== 'art01'.localeCompare('Art01', undefined, { numeric: true }), + 'a numerically equivalent word of a different case does not compare numerically based on locale'); + assert(compareFileNames('a.ext1', 'a.Ext1') > 0, 'if names are equal and extensions with numbers are equal except for case, filenames are sorted in full filename unicode order'); + + }); + + test('compareFileExtensions', () => { + + // + // Comparisons with the same results as compareFileExtensionsDefault + // + + // name-only comparisons + assert(compareFileExtensions(null, null) === 0, 'null should be equal'); + assert(compareFileExtensions(null, 'abc') < 0, 'null should come before real files without extension'); + assert(compareFileExtensions('', '') === 0, 'empty should be equal'); + assert(compareFileExtensions('abc', 'abc') === 0, 'equal names should be equal'); + assert(compareFileExtensions('z', 'A') > 0, 'z comes after A'); + assert(compareFileExtensions('Z', 'a') > 0, 'Z comes after a'); + + // name plus extension comparisons + assert(compareFileExtensions('file.ext', 'file.ext') === 0, 'equal full names should be equal'); + assert(compareFileExtensions('a.ext', 'b.ext') < 0, 'if equal extensions, filenames should be compared'); + assert(compareFileExtensions('file.aaa', 'file.bbb') < 0, 'files with equal names should be compared by extensions'); + assert(compareFileExtensions('bbb.aaa', 'aaa.bbb') < 0, 'files should be compared by extensions even if filenames compare differently'); + + // dotfile comparisons + assert(compareFileExtensions('.abc', '.abc') === 0, 'equal dotfiles should be equal'); + assert(compareFileExtensions('.md', '.Gitattributes') > 0, 'dotfiles sort alphabetically regardless of case'); + + // dotfile vs non-dotfile comparisons + assert(compareFileExtensions(null, '.abc') < 0, 'null should come before dotfiles'); + assert(compareFileExtensions('.env', 'aaa.env') < 0, 'if equal extensions, filenames should be compared, empty filename should come before others'); + assert(compareFileExtensions('.MD', 'a.md') < 0, 'if extensions differ in case, files sort by extension in unicode order'); + + // numeric comparisons + assert(compareFileExtensions('1', '1') === 0, 'numerically equal full names should be equal'); + assert(compareFileExtensions('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal'); + assert(compareFileExtensions('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order'); + assert(compareFileExtensions('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order even when they are multiple digits long'); + assert(compareFileExtensions('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically'); + assert(compareFileExtensions('abc1.10.txt', 'abc1.2.txt') > 0, 'numbers with dots between them are treated as two separate numbers, not one decimal number'); + assert(compareFileExtensions('abc2.txt2', 'abc1.txt10') < 0, 'extensions with numbers should be in numerical order, not alphabetical order'); + assert(compareFileExtensions('txt.abc1', 'txt.abc1') === 0, 'equal extensions with numbers should be equal'); + assert(compareFileExtensions('txt.abc1', 'txt.abc2') < 0, 'extensions with numbers should be in numerical order, not alphabetical order'); + assert(compareFileExtensions('txt.abc2', 'txt.abc10') < 0, 'extensions with numbers should be in numerical order even when they are multiple digits long'); + assert(compareFileExtensions('a.ext1', 'b.ext1') < 0, 'if equal extensions with numbers, names should be compared'); + assert.deepStrictEqual(['a10.txt', 'A2.txt', 'A100.txt', 'a20.txt'].sort(compareFileExtensions), ['A2.txt', 'a10.txt', 'a20.txt', 'A100.txt'], 'filenames with number and case differences compare numerically'); + + // + // Comparisons with different results from compareFileExtensionsDefault + // + + // name-only comparisions + assert(compareFileExtensions('a', 'A') !== compareLocale('a', 'A'), 'the same letter of different case does not sort by locale'); + assert(compareFileExtensions('â', 'Â') !== compareLocale('â', 'Â'), 'the same accented letter of different case does not sort by locale'); + assert.notDeepStrictEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileExtensions), ['artichoke', 'Artichoke', 'art', 'Art'].sort(compareLocale), 'words with the same root and different cases do not sort in locale order'); + assert.notDeepStrictEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileExtensions), ['email', 'Email', 'émail', 'Émail'].sort((a, b) => a.localeCompare(b)), 'the same base characters with different case or accents do not sort in locale order'); + + // name plus extension comparisons + assert(compareFileExtensions('a.MD', 'a.md') < 0, 'case differences in extensions sort in unicode order'); + assert(compareFileExtensions('a.md', 'A.md') > 0, 'case differences in names sort in unicode order'); + assert(compareFileExtensions('a.md', 'b.MD') > 0, 'when extensions are the same except for case, the files sort by extension'); + assert(compareFileExtensions('aggregate.go', 'aggregate_repo.go') < 0, 'when extensions are equal, names sort in dictionary order'); + + // dotfile comparisons + assert(compareFileExtensions('.env', '.aaa.env') < 0, 'a dotfile with an extension is treated as a name plus an extension - equal extensions'); + assert(compareFileExtensions('.env', '.env.aaa') > 0, 'a dotfile with an extension is treated as a name plus an extension - unequal extensions'); + + // dotfile vs non-dotfile comparisons + assert(compareFileExtensions('.env', 'aaa') > 0, 'filenames without extensions come before dotfiles'); + assert(compareFileExtensions('.md', 'A.MD') > 0, 'a file with an uppercase extension sorts before a dotfile of the same lowercase extension'); + + // numeric comparisons + assert(compareFileExtensions('abc.txt01', 'abc.txt1') < 0, 'extensions with equal numbers sort in unicode order'); + assert(compareFileExtensions('art01', 'Art01') !== compareLocaleNumeric('art01', 'Art01'), 'a numerically equivalent word of a different case does not compare by locale'); + assert(compareFileExtensions('abc02.txt', 'abc002.txt') > 0, 'filenames with equivalent numbers and leading zeros sort in unicode order'); + assert(compareFileExtensions('txt.abc01', 'txt.abc1') < 0, 'extensions with equivalent numbers sort in unicode order'); + assert(compareFileExtensions('a.ext1', 'b.Ext1') > 0, 'if names are different and extensions with numbers are equal except for case, filenames are sorted in extension unicode order'); + assert(compareFileExtensions('a.ext1', 'a.Ext1') > 0, 'if names are equal and extensions with numbers are equal except for case, filenames are sorted in extension unicode order'); + + }); + + test('compareFileNamesDefault', () => { + + // + // Comparisons with the same results as compareFileNames + // + + // name-only comparisons + assert(compareFileNamesDefault(null, null) === 0, 'null should be equal'); + assert(compareFileNamesDefault(null, 'abc') < 0, 'null should be come before real values'); + assert(compareFileNamesDefault('', '') === 0, 'empty should be equal'); + assert(compareFileNamesDefault('abc', 'abc') === 0, 'equal names should be equal'); + assert(compareFileNamesDefault('z', 'A') > 0, 'z comes after A'); + assert(compareFileNamesDefault('Z', 'a') > 0, 'Z comes after a'); + + // name plus extension comparisons + assert(compareFileNamesDefault('file.ext', 'file.ext') === 0, 'equal full names should be equal'); + assert(compareFileNamesDefault('a.ext', 'b.ext') < 0, 'if equal extensions, filenames should be compared'); + assert(compareFileNamesDefault('file.aaa', 'file.bbb') < 0, 'files with equal names should be compared by extensions'); + assert(compareFileNamesDefault('bbb.aaa', 'aaa.bbb') > 0, 'files should be compared by names even if extensions compare differently'); + assert(compareFileNamesDefault('aggregate.go', 'aggregate_repo.go') > 0, 'compares the whole filename in locale order'); + + // dotfile comparisons + assert(compareFileNamesDefault('.abc', '.abc') === 0, 'equal dotfile names should be equal'); + assert(compareFileNamesDefault('.env.', '.gitattributes') < 0, 'filenames starting with dots and with extensions should still sort properly'); + assert(compareFileNamesDefault('.env', '.aaa.env') > 0, 'dotfiles sort alphabetically when they contain multiple dots'); + assert(compareFileNamesDefault('.env', '.env.aaa') < 0, 'dotfiles with the same root sort shortest first'); + assert(compareFileNamesDefault('.aaa_env', '.aaa.env') < 0, 'an underscore in a dotfile name will sort before a dot'); + + // dotfile vs non-dotfile comparisons + assert(compareFileNamesDefault(null, '.abc') < 0, 'null should come before dotfiles'); + assert(compareFileNamesDefault('.env', 'aaa') < 0, 'dotfiles come before filenames without extensions'); + assert(compareFileNamesDefault('.env', 'aaa.env') < 0, 'dotfiles come before filenames with extensions'); + assert(compareFileNamesDefault('.md', 'A.MD') < 0, 'dotfiles sort before uppercase files'); + assert(compareFileNamesDefault('.MD', 'a.md') < 0, 'dotfiles sort before lowercase files'); + + // numeric comparisons + assert(compareFileNamesDefault('1', '1') === 0, 'numerically equal full names should be equal'); + assert(compareFileNamesDefault('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal'); + assert(compareFileNamesDefault('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order'); + assert(compareFileNamesDefault('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order even when they are multiple digits long'); + assert(compareFileNamesDefault('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically'); + assert(compareFileNamesDefault('abc1.10.txt', 'abc1.2.txt') > 0, 'numbers with dots between them are treated as two separate numbers, not one decimal number'); + assert(compareFileNamesDefault('a.ext1', 'b.Ext1') < 0, 'if names are different and extensions with numbers are equal except for case, filenames are compared by full filename'); + assert.deepStrictEqual(['a10.txt', 'A2.txt', 'A100.txt', 'a20.txt'].sort(compareFileNamesDefault), ['A2.txt', 'a10.txt', 'a20.txt', 'A100.txt'], 'filenames with number and case differences compare numerically'); + + // + // Comparisons with different results than compareFileNames + // + + // name-only comparisons + assert(compareFileNamesDefault('a', 'A') === compareLocale('a', 'A'), 'the same letter sorts by locale'); + assert(compareFileNamesDefault('â', 'Â') === compareLocale('â', 'Â'), 'the same accented letter sorts by locale'); + assert.deepStrictEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileNamesDefault), ['email', 'Email', 'émail', 'Émail'].sort(compareLocale), 'the same base characters with different case or accents sort in locale order'); + + // numeric comparisons + assert(compareFileNamesDefault('abc02.txt', 'abc002.txt') < 0, 'filenames with equivalent numbers and leading zeros sort shortest number first'); + assert(compareFileNamesDefault('abc.txt1', 'abc.txt01') < 0, 'same name plus extensions with equal numbers sort shortest number first'); + assert(compareFileNamesDefault('art01', 'Art01') === compareLocaleNumeric('art01', 'Art01'), 'a numerically equivalent word of a different case compares numerically based on locale'); + assert(compareFileNamesDefault('a.ext1', 'a.Ext1') === compareLocale('ext1', 'Ext1'), 'if names are equal and extensions with numbers are equal except for case, filenames are sorted in extension locale order'); + }); + + test('compareFileExtensionsDefault', () => { + + // + // Comparisons with the same result as compareFileExtensions + // + + // name-only comparisons + assert(compareFileExtensionsDefault(null, null) === 0, 'null should be equal'); + assert(compareFileExtensionsDefault(null, 'abc') < 0, 'null should come before real files without extensions'); + assert(compareFileExtensionsDefault('', '') === 0, 'empty should be equal'); + assert(compareFileExtensionsDefault('abc', 'abc') === 0, 'equal names should be equal'); + assert(compareFileExtensionsDefault('z', 'A') > 0, 'z comes after A'); + assert(compareFileExtensionsDefault('Z', 'a') > 0, 'Z comes after a'); + + // name plus extension comparisons + assert(compareFileExtensionsDefault('file.ext', 'file.ext') === 0, 'equal full filenames should be equal'); + assert(compareFileExtensionsDefault('a.ext', 'b.ext') < 0, 'if equal extensions, filenames should be compared'); + assert(compareFileExtensionsDefault('file.aaa', 'file.bbb') < 0, 'files with equal names should be compared by extensions'); + assert(compareFileExtensionsDefault('bbb.aaa', 'aaa.bbb') < 0, 'files should be compared by extension first'); + + // dotfile comparisons + assert(compareFileExtensionsDefault('.abc', '.abc') === 0, 'equal dotfiles should be equal'); + assert(compareFileExtensionsDefault('.md', '.Gitattributes') > 0, 'dotfiles sort alphabetically regardless of case'); + + // dotfile vs non-dotfile comparisons + assert(compareFileExtensionsDefault(null, '.abc') < 0, 'null should come before dotfiles'); + assert(compareFileExtensionsDefault('.env', 'aaa.env') < 0, 'dotfiles come before filenames with extensions'); + assert(compareFileExtensionsDefault('.MD', 'a.md') < 0, 'dotfiles sort before lowercase files'); + + // numeric comparisons + assert(compareFileExtensionsDefault('1', '1') === 0, 'numerically equal full names should be equal'); + assert(compareFileExtensionsDefault('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal'); + assert(compareFileExtensionsDefault('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order'); + assert(compareFileExtensionsDefault('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order'); + assert(compareFileExtensionsDefault('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically'); + assert(compareFileExtensionsDefault('abc1.10.txt', 'abc1.2.txt') > 0, 'numbers with dots between them are treated as two separate numbers, not one decimal number'); + assert(compareFileExtensionsDefault('abc2.txt2', 'abc1.txt10') < 0, 'extensions with numbers should be in numerical order, not alphabetical order'); + assert(compareFileExtensionsDefault('txt.abc1', 'txt.abc1') === 0, 'equal extensions with numbers should be equal'); + assert(compareFileExtensionsDefault('txt.abc1', 'txt.abc2') < 0, 'extensions with numbers should be in numerical order, not alphabetical order'); + assert(compareFileExtensionsDefault('txt.abc2', 'txt.abc10') < 0, 'extensions with numbers should be in numerical order even when they are multiple digits long'); + assert(compareFileExtensionsDefault('a.ext1', 'b.ext1') < 0, 'if equal extensions with numbers, full filenames should be compared'); + assert.deepStrictEqual(['a10.txt', 'A2.txt', 'A100.txt', 'a20.txt'].sort(compareFileExtensionsDefault), ['A2.txt', 'a10.txt', 'a20.txt', 'A100.txt'], 'filenames with number and case differences compare numerically'); + + // + // Comparisons with different results than compareFileExtensions + // + + // name-only comparisons + assert(compareFileExtensionsDefault('a', 'A') === compareLocale('a', 'A'), 'the same letter of different case sorts by locale'); + assert(compareFileExtensionsDefault('â', 'Â') === compareLocale('â', 'Â'), 'the same accented letter of different case sorts by locale'); + assert.deepStrictEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileExtensionsDefault), ['email', 'Email', 'émail', 'Émail'].sort((a, b) => a.localeCompare(b)), 'the same base characters with different case or accents sort in locale order'); + + // name plus extension comparisons + assert(compareFileExtensionsDefault('a.MD', 'a.md') === compareLocale('MD', 'md'), 'case differences in extensions sort by locale'); + assert(compareFileExtensionsDefault('a.md', 'A.md') === compareLocale('a', 'A'), 'case differences in names sort by locale'); + assert(compareFileExtensionsDefault('a.md', 'b.MD') < 0, 'when extensions are the same except for case, the files sort by name'); + assert(compareFileExtensionsDefault('aggregate.go', 'aggregate_repo.go') > 0, 'names with the same extension sort in full filename locale order'); + + // dotfile comparisons + assert(compareFileExtensionsDefault('.env', '.aaa.env') > 0, 'dotfiles sort alphabetically when they contain multiple dots'); + assert(compareFileExtensionsDefault('.env', '.env.aaa') < 0, 'dotfiles with the same root sort shortest first'); + + // dotfile vs non-dotfile comparisons + assert(compareFileExtensionsDefault('.env', 'aaa') < 0, 'dotfiles come before filenames without extensions'); + assert(compareFileExtensionsDefault('.md', 'A.MD') < 0, 'dotfiles sort before uppercase files'); + + // numeric comparisons + assert(compareFileExtensionsDefault('abc.txt01', 'abc.txt1') > 0, 'extensions with equal numbers should be in shortest-first order'); + assert(compareFileExtensionsDefault('art01', 'Art01') === compareLocaleNumeric('art01', 'Art01'), 'a numerically equivalent word of a different case compares numerically based on locale'); + assert(compareFileExtensionsDefault('abc02.txt', 'abc002.txt') < 0, 'filenames with equivalent numbers and leading zeros sort shortest string first'); + assert(compareFileExtensionsDefault('txt.abc01', 'txt.abc1') > 0, 'extensions with equivalent numbers sort shortest extension first'); + assert(compareFileExtensionsDefault('a.ext1', 'b.Ext1') < 0, 'if extensions with numbers are equal except for case, full filenames should be compared'); + assert(compareFileExtensionsDefault('a.ext1', 'a.Ext1') === compareLocale('a.ext1', 'a.Ext1'), 'if extensions with numbers are equal except for case, full filenames are compared in locale order'); + + }); + + test('compareFileNamesUpper', () => { + + // + // Comparisons with the same results as compareFileNamesDefault + // + + // name-only comparisons + assert(compareFileNamesUpper(null, null) === 0, 'null should be equal'); + assert(compareFileNamesUpper(null, 'abc') < 0, 'null should be come before real values'); + assert(compareFileNamesUpper('', '') === 0, 'empty should be equal'); + assert(compareFileNamesUpper('abc', 'abc') === 0, 'equal names should be equal'); + assert(compareFileNamesUpper('z', 'A') > 0, 'z comes after A'); + + // name plus extension comparisons + assert(compareFileNamesUpper('file.ext', 'file.ext') === 0, 'equal full names should be equal'); + assert(compareFileNamesUpper('a.ext', 'b.ext') < 0, 'if equal extensions, filenames should be compared'); + assert(compareFileNamesUpper('file.aaa', 'file.bbb') < 0, 'files with equal names should be compared by extensions'); + assert(compareFileNamesUpper('bbb.aaa', 'aaa.bbb') > 0, 'files should be compared by names even if extensions compare differently'); + assert(compareFileNamesUpper('aggregate.go', 'aggregate_repo.go') > 0, 'compares the full filename in locale order'); + + // dotfile comparisons + assert(compareFileNamesUpper('.abc', '.abc') === 0, 'equal dotfile names should be equal'); + assert(compareFileNamesUpper('.env.', '.gitattributes') < 0, 'filenames starting with dots and with extensions should still sort properly'); + assert(compareFileNamesUpper('.env', '.aaa.env') > 0, 'dotfiles sort alphabetically when they contain multiple dots'); + assert(compareFileNamesUpper('.env', '.env.aaa') < 0, 'dotfiles with the same root sort shortest first'); + assert(compareFileNamesUpper('.aaa_env', '.aaa.env') < 0, 'an underscore in a dotfile name will sort before a dot'); + + // dotfile vs non-dotfile comparisons + assert(compareFileNamesUpper(null, '.abc') < 0, 'null should come before dotfiles'); + assert(compareFileNamesUpper('.env', 'aaa') < 0, 'dotfiles come before filenames without extensions'); + assert(compareFileNamesUpper('.env', 'aaa.env') < 0, 'dotfiles come before filenames with extensions'); + assert(compareFileNamesUpper('.md', 'A.MD') < 0, 'dotfiles sort before uppercase files'); + assert(compareFileNamesUpper('.MD', 'a.md') < 0, 'dotfiles sort before lowercase files'); + + // numeric comparisons + assert(compareFileNamesUpper('1', '1') === 0, 'numerically equal full names should be equal'); + assert(compareFileNamesUpper('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal'); + assert(compareFileNamesUpper('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order'); + assert(compareFileNamesUpper('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order even when they are multiple digits long'); + assert(compareFileNamesUpper('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically'); + assert(compareFileNamesUpper('abc1.10.txt', 'abc1.2.txt') > 0, 'numbers with dots between them are treated as two separate numbers, not one decimal number'); + assert(compareFileNamesUpper('abc02.txt', 'abc002.txt') < 0, 'filenames with equivalent numbers and leading zeros sort shortest number first'); + assert(compareFileNamesUpper('abc.txt1', 'abc.txt01') < 0, 'same name plus extensions with equal numbers sort shortest number first'); + assert(compareFileNamesUpper('a.ext1', 'b.Ext1') < 0, 'different names with the equal extensions except for case are sorted by full filename'); + assert(compareFileNamesUpper('a.ext1', 'a.Ext1') === compareLocale('a.ext1', 'a.Ext1'), 'same names with equal and extensions except for case are sorted in full filename locale order'); + + // + // Comparisons with different results than compareFileNamesDefault + // + + // name-only comparisons + assert(compareFileNamesUpper('Z', 'a') < 0, 'Z comes before a'); + assert(compareFileNamesUpper('a', 'A') > 0, 'the same letter sorts uppercase first'); + assert(compareFileNamesUpper('â', 'Â') > 0, 'the same accented letter sorts uppercase first'); + assert.deepStrictEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileNamesUpper), ['Art', 'Artichoke', 'art', 'artichoke'], 'names with the same root and different cases sort uppercase first'); + assert.deepStrictEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileNamesUpper), ['Email', 'Émail', 'email', 'émail'], 'the same base characters with different case or accents sort uppercase first'); + + // numeric comparisons + assert(compareFileNamesUpper('art01', 'Art01') > 0, 'a numerically equivalent name of a different case compares uppercase first'); + assert.deepStrictEqual(['a10.txt', 'A2.txt', 'A100.txt', 'a20.txt'].sort(compareFileNamesUpper), ['A2.txt', 'A100.txt', 'a10.txt', 'a20.txt'], 'filenames with number and case differences group by case then compare by number'); + + }); + + test('compareFileExtensionsUpper', () => { + + // + // Comparisons with the same result as compareFileExtensionsDefault + // + + // name-only comparisons + assert(compareFileExtensionsUpper(null, null) === 0, 'null should be equal'); + assert(compareFileExtensionsUpper(null, 'abc') < 0, 'null should come before real files without extensions'); + assert(compareFileExtensionsUpper('', '') === 0, 'empty should be equal'); + assert(compareFileExtensionsUpper('abc', 'abc') === 0, 'equal names should be equal'); + assert(compareFileExtensionsUpper('z', 'A') > 0, 'z comes after A'); + + // name plus extension comparisons + assert(compareFileExtensionsUpper('file.ext', 'file.ext') === 0, 'equal full filenames should be equal'); + assert(compareFileExtensionsUpper('a.ext', 'b.ext') < 0, 'if equal extensions, filenames should be compared'); + assert(compareFileExtensionsUpper('file.aaa', 'file.bbb') < 0, 'files with equal names should be compared by extensions'); + assert(compareFileExtensionsUpper('bbb.aaa', 'aaa.bbb') < 0, 'files should be compared by extension first'); + assert(compareFileExtensionsUpper('a.md', 'b.MD') < 0, 'when extensions are the same except for case, the files sort by name'); + assert(compareFileExtensionsUpper('a.MD', 'a.md') === compareLocale('MD', 'md'), 'case differences in extensions sort by locale'); + assert(compareFileExtensionsUpper('aggregate.go', 'aggregate_repo.go') > 0, 'when extensions are equal, compares the full filename'); + + // dotfile comparisons + assert(compareFileExtensionsUpper('.abc', '.abc') === 0, 'equal dotfiles should be equal'); + assert(compareFileExtensionsUpper('.md', '.Gitattributes') > 0, 'dotfiles sort alphabetically regardless of case'); + assert(compareFileExtensionsUpper('.env', '.aaa.env') > 0, 'dotfiles sort alphabetically when they contain multiple dots'); + assert(compareFileExtensionsUpper('.env', '.env.aaa') < 0, 'dotfiles with the same root sort shortest first'); + + // dotfile vs non-dotfile comparisons + assert(compareFileExtensionsUpper(null, '.abc') < 0, 'null should come before dotfiles'); + assert(compareFileExtensionsUpper('.env', 'aaa.env') < 0, 'dotfiles come before filenames with extensions'); + assert(compareFileExtensionsUpper('.MD', 'a.md') < 0, 'dotfiles sort before lowercase files'); + assert(compareFileExtensionsUpper('.env', 'aaa') < 0, 'dotfiles come before filenames without extensions'); + assert(compareFileExtensionsUpper('.md', 'A.MD') < 0, 'dotfiles sort before uppercase files'); + + // numeric comparisons + assert(compareFileExtensionsUpper('1', '1') === 0, 'numerically equal full names should be equal'); + assert(compareFileExtensionsUpper('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal'); + assert(compareFileExtensionsUpper('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order'); + assert(compareFileExtensionsUpper('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order'); + assert(compareFileExtensionsUpper('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically'); + assert(compareFileExtensionsUpper('abc1.10.txt', 'abc1.2.txt') > 0, 'numbers with dots between them are treated as two separate numbers, not one decimal number'); + assert(compareFileExtensionsUpper('abc2.txt2', 'abc1.txt10') < 0, 'extensions with numbers should be in numerical order, not alphabetical order'); + assert(compareFileExtensionsUpper('txt.abc1', 'txt.abc1') === 0, 'equal extensions with numbers should be equal'); + assert(compareFileExtensionsUpper('txt.abc1', 'txt.abc2') < 0, 'extensions with numbers should be in numerical order, not alphabetical order'); + assert(compareFileExtensionsUpper('txt.abc2', 'txt.abc10') < 0, 'extensions with numbers should be in numerical order even when they are multiple digits long'); + assert(compareFileExtensionsUpper('a.ext1', 'b.ext1') < 0, 'if equal extensions with numbers, full filenames should be compared'); + assert(compareFileExtensionsUpper('abc.txt01', 'abc.txt1') > 0, 'extensions with equal numbers should be in shortest-first order'); + assert(compareFileExtensionsUpper('abc02.txt', 'abc002.txt') < 0, 'filenames with equivalent numbers and leading zeros sort shortest string first'); + assert(compareFileExtensionsUpper('txt.abc01', 'txt.abc1') > 0, 'extensions with equivalent numbers sort shortest extension first'); + assert(compareFileExtensionsUpper('a.ext1', 'b.Ext1') < 0, 'different names and extensions that are equal except for case are sorted in full filename order'); + assert(compareFileExtensionsUpper('a.ext1', 'a.Ext1') === compareLocale('a.ext1', 'b.Ext1'), 'same names and extensions that are equal except for case are sorted in full filename locale order'); + + // + // Comparisons with different results than compareFileExtensionsDefault + // + + // name-only comparisons + assert(compareFileExtensionsUpper('Z', 'a') < 0, 'Z comes before a'); + assert(compareFileExtensionsUpper('a', 'A') > 0, 'the same letter sorts uppercase first'); + assert(compareFileExtensionsUpper('â', 'Â') > 0, 'the same accented letter sorts uppercase first'); + assert.deepStrictEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileExtensionsUpper), ['Art', 'Artichoke', 'art', 'artichoke'], 'names with the same root and different cases sort uppercase names first'); + assert.deepStrictEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileExtensionsUpper), ['Email', 'Émail', 'email', 'émail'], 'the same base characters with different case or accents sort uppercase names first'); + + // name plus extension comparisons + assert(compareFileExtensionsUpper('a.md', 'A.md') > 0, 'case differences in names sort uppercase first'); + assert(compareFileExtensionsUpper('art01', 'Art01') > 0, 'a numerically equivalent word of a different case sorts uppercase first'); + assert.deepStrictEqual(['a10.txt', 'A2.txt', 'A100.txt', 'a20.txt'].sort(compareFileExtensionsUpper), ['A2.txt', 'A100.txt', 'a10.txt', 'a20.txt',], 'filenames with number and case differences group by case then sort by number'); + + }); + + test('compareFileNamesLower', () => { + + // + // Comparisons with the same results as compareFileNamesDefault + // + + // name-only comparisons + assert(compareFileNamesLower(null, null) === 0, 'null should be equal'); + assert(compareFileNamesLower(null, 'abc') < 0, 'null should be come before real values'); + assert(compareFileNamesLower('', '') === 0, 'empty should be equal'); + assert(compareFileNamesLower('abc', 'abc') === 0, 'equal names should be equal'); + assert(compareFileNamesLower('Z', 'a') > 0, 'Z comes after a'); + + // name plus extension comparisons + assert(compareFileNamesLower('file.ext', 'file.ext') === 0, 'equal full names should be equal'); + assert(compareFileNamesLower('a.ext', 'b.ext') < 0, 'if equal extensions, filenames should be compared'); + assert(compareFileNamesLower('file.aaa', 'file.bbb') < 0, 'files with equal names should be compared by extensions'); + assert(compareFileNamesLower('bbb.aaa', 'aaa.bbb') > 0, 'files should be compared by names even if extensions compare differently'); + assert(compareFileNamesLower('aggregate.go', 'aggregate_repo.go') > 0, 'compares full filenames'); + + // dotfile comparisons + assert(compareFileNamesLower('.abc', '.abc') === 0, 'equal dotfile names should be equal'); + assert(compareFileNamesLower('.env.', '.gitattributes') < 0, 'filenames starting with dots and with extensions should still sort properly'); + assert(compareFileNamesLower('.env', '.aaa.env') > 0, 'dotfiles sort alphabetically when they contain multiple dots'); + assert(compareFileNamesLower('.env', '.env.aaa') < 0, 'dotfiles with the same root sort shortest first'); + assert(compareFileNamesLower('.aaa_env', '.aaa.env') < 0, 'an underscore in a dotfile name will sort before a dot'); + + // dotfile vs non-dotfile comparisons + assert(compareFileNamesLower(null, '.abc') < 0, 'null should come before dotfiles'); + assert(compareFileNamesLower('.env', 'aaa') < 0, 'dotfiles come before filenames without extensions'); + assert(compareFileNamesLower('.env', 'aaa.env') < 0, 'dotfiles come before filenames with extensions'); + assert(compareFileNamesLower('.md', 'A.MD') < 0, 'dotfiles sort before uppercase files'); + assert(compareFileNamesLower('.MD', 'a.md') < 0, 'dotfiles sort before lowercase files'); + + // numeric comparisons + assert(compareFileNamesLower('1', '1') === 0, 'numerically equal full names should be equal'); + assert(compareFileNamesLower('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal'); + assert(compareFileNamesLower('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order'); + assert(compareFileNamesLower('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order even when they are multiple digits long'); + assert(compareFileNamesLower('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically'); + assert(compareFileNamesLower('abc1.10.txt', 'abc1.2.txt') > 0, 'numbers with dots between them are treated as two separate numbers, not one decimal number'); + assert(compareFileNamesLower('abc02.txt', 'abc002.txt') < 0, 'filenames with equivalent numbers and leading zeros sort shortest number first'); + assert(compareFileNamesLower('abc.txt1', 'abc.txt01') < 0, 'same name plus extensions with equal numbers sort shortest number first'); + assert(compareFileNamesLower('a.ext1', 'b.Ext1') < 0, 'different names and extensions that are equal except for case are sorted in full filename order'); + assert(compareFileNamesLower('a.ext1', 'a.Ext1') === compareLocale('a.ext1', 'b.Ext1'), 'same names and extensions that are equal except for case are sorted in full filename locale order'); + + // + // Comparisons with different results than compareFileNamesDefault + // + + // name-only comparisons + assert(compareFileNamesLower('z', 'A') < 0, 'z comes before A'); + assert(compareFileNamesLower('a', 'A') < 0, 'the same letter sorts lowercase first'); + assert(compareFileNamesLower('â', 'Â') < 0, 'the same accented letter sorts lowercase first'); + assert.deepStrictEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileNamesLower), ['art', 'artichoke', 'Art', 'Artichoke'], 'names with the same root and different cases sort lowercase first'); + assert.deepStrictEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileNamesLower), ['email', 'émail', 'Email', 'Émail'], 'the same base characters with different case or accents sort lowercase first'); + + // numeric comparisons + assert(compareFileNamesLower('art01', 'Art01') < 0, 'a numerically equivalent name of a different case compares lowercase first'); + assert.deepStrictEqual(['a10.txt', 'A2.txt', 'A100.txt', 'a20.txt'].sort(compareFileNamesLower), ['a10.txt', 'a20.txt', 'A2.txt', 'A100.txt'], 'filenames with number and case differences group by case then compare by number'); + + }); + + test('compareFileExtensionsLower', () => { + + // + // Comparisons with the same result as compareFileExtensionsDefault + // + + // name-only comparisons + assert(compareFileExtensionsLower(null, null) === 0, 'null should be equal'); + assert(compareFileExtensionsLower(null, 'abc') < 0, 'null should come before real files without extensions'); + assert(compareFileExtensionsLower('', '') === 0, 'empty should be equal'); + assert(compareFileExtensionsLower('abc', 'abc') === 0, 'equal names should be equal'); + assert(compareFileExtensionsLower('Z', 'a') > 0, 'Z comes after a'); + + // name plus extension comparisons + assert(compareFileExtensionsLower('file.ext', 'file.ext') === 0, 'equal full filenames should be equal'); + assert(compareFileExtensionsLower('a.ext', 'b.ext') < 0, 'if equal extensions, filenames should be compared'); + assert(compareFileExtensionsLower('file.aaa', 'file.bbb') < 0, 'files with equal names should be compared by extensions'); + assert(compareFileExtensionsLower('bbb.aaa', 'aaa.bbb') < 0, 'files should be compared by extension first'); + assert(compareFileExtensionsLower('a.md', 'b.MD') < 0, 'when extensions are the same except for case, the files sort by name'); + assert(compareFileExtensionsLower('a.MD', 'a.md') === compareLocale('MD', 'md'), 'case differences in extensions sort by locale'); + + // dotfile comparisons + assert(compareFileExtensionsLower('.abc', '.abc') === 0, 'equal dotfiles should be equal'); + assert(compareFileExtensionsLower('.md', '.Gitattributes') > 0, 'dotfiles sort alphabetically regardless of case'); + assert(compareFileExtensionsLower('.env', '.aaa.env') > 0, 'dotfiles sort alphabetically when they contain multiple dots'); + assert(compareFileExtensionsLower('.env', '.env.aaa') < 0, 'dotfiles with the same root sort shortest first'); + + // dotfile vs non-dotfile comparisons + assert(compareFileExtensionsLower(null, '.abc') < 0, 'null should come before dotfiles'); + assert(compareFileExtensionsLower('.env', 'aaa.env') < 0, 'dotfiles come before filenames with extensions'); + assert(compareFileExtensionsLower('.MD', 'a.md') < 0, 'dotfiles sort before lowercase files'); + assert(compareFileExtensionsLower('.env', 'aaa') < 0, 'dotfiles come before filenames without extensions'); + assert(compareFileExtensionsLower('.md', 'A.MD') < 0, 'dotfiles sort before uppercase files'); + + // numeric comparisons + assert(compareFileExtensionsLower('1', '1') === 0, 'numerically equal full names should be equal'); + assert(compareFileExtensionsLower('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal'); + assert(compareFileExtensionsLower('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order'); + assert(compareFileExtensionsLower('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order'); + assert(compareFileExtensionsLower('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically'); + assert(compareFileExtensionsLower('abc1.10.txt', 'abc1.2.txt') > 0, 'numbers with dots between them are treated as two separate numbers, not one decimal number'); + assert(compareFileExtensionsLower('abc2.txt2', 'abc1.txt10') < 0, 'extensions with numbers should be in numerical order, not alphabetical order'); + assert(compareFileExtensionsLower('txt.abc1', 'txt.abc1') === 0, 'equal extensions with numbers should be equal'); + assert(compareFileExtensionsLower('txt.abc1', 'txt.abc2') < 0, 'extensions with numbers should be in numerical order, not alphabetical order'); + assert(compareFileExtensionsLower('txt.abc2', 'txt.abc10') < 0, 'extensions with numbers should be in numerical order even when they are multiple digits long'); + assert(compareFileExtensionsLower('a.ext1', 'b.ext1') < 0, 'if equal extensions with numbers, full filenames should be compared'); + assert(compareFileExtensionsLower('abc.txt01', 'abc.txt1') > 0, 'extensions with equal numbers should be in shortest-first order'); + assert(compareFileExtensionsLower('abc02.txt', 'abc002.txt') < 0, 'filenames with equivalent numbers and leading zeros sort shortest string first'); + assert(compareFileExtensionsLower('txt.abc01', 'txt.abc1') > 0, 'extensions with equivalent numbers sort shortest extension first'); + assert(compareFileExtensionsLower('a.ext1', 'b.Ext1') < 0, 'if extensions with numbers are equal except for case, full filenames should be compared'); + assert(compareFileExtensionsLower('a.ext1', 'a.Ext1') === compareLocale('a.ext1', 'a.Ext1'), 'if extensions with numbers are equal except for case, filenames are sorted in locale order'); + + // + // Comparisons with different results than compareFileExtensionsDefault + // + + // name-only comparisons + assert(compareFileExtensionsLower('z', 'A') < 0, 'z comes before A'); + assert(compareFileExtensionsLower('a', 'A') < 0, 'the same letter sorts lowercase first'); + assert(compareFileExtensionsLower('â', 'Â') < 0, 'the same accented letter sorts lowercase first'); + assert.deepStrictEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileExtensionsLower), ['art', 'artichoke', 'Art', 'Artichoke'], 'names with the same root and different cases sort lowercase names first'); + assert.deepStrictEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileExtensionsLower), ['email', 'émail', 'Email', 'Émail'], 'the same base characters with different case or accents sort lowercase names first'); + + // name plus extension comparisons + assert(compareFileExtensionsLower('a.md', 'A.md') < 0, 'case differences in names sort lowercase first'); + assert(compareFileExtensionsLower('art01', 'Art01') < 0, 'a numerically equivalent word of a different case sorts lowercase first'); + assert.deepStrictEqual(['a10.txt', 'A2.txt', 'A100.txt', 'a20.txt'].sort(compareFileExtensionsLower), ['a10.txt', 'a20.txt', 'A2.txt', 'A100.txt'], 'filenames with number and case differences group by case then sort by number'); + assert(compareFileExtensionsLower('aggregate.go', 'aggregate_repo.go') > 0, 'when extensions are equal, compares full filenames'); + + }); + + test('compareFileNamesUnicode', () => { + + // + // Comparisons with the same results as compareFileNamesDefault + // + + // name-only comparisons + assert(compareFileNamesUnicode(null, null) === 0, 'null should be equal'); + assert(compareFileNamesUnicode(null, 'abc') < 0, 'null should be come before real values'); + assert(compareFileNamesUnicode('', '') === 0, 'empty should be equal'); + assert(compareFileNamesUnicode('abc', 'abc') === 0, 'equal names should be equal'); + assert(compareFileNamesUnicode('z', 'A') > 0, 'z comes after A'); + + // name plus extension comparisons + assert(compareFileNamesUnicode('file.ext', 'file.ext') === 0, 'equal full names should be equal'); + assert(compareFileNamesUnicode('a.ext', 'b.ext') < 0, 'if equal extensions, filenames should be compared'); + assert(compareFileNamesUnicode('file.aaa', 'file.bbb') < 0, 'files with equal names should be compared by extensions'); + assert(compareFileNamesUnicode('bbb.aaa', 'aaa.bbb') > 0, 'files should be compared by names even if extensions compare differently'); + + // dotfile comparisons + assert(compareFileNamesUnicode('.abc', '.abc') === 0, 'equal dotfile names should be equal'); + assert(compareFileNamesUnicode('.env.', '.gitattributes') < 0, 'filenames starting with dots and with extensions should still sort properly'); + assert(compareFileNamesUnicode('.env', '.aaa.env') > 0, 'dotfiles sort alphabetically when they contain multiple dots'); + assert(compareFileNamesUnicode('.env', '.env.aaa') < 0, 'dotfiles with the same root sort shortest first'); + + // dotfile vs non-dotfile comparisons + assert(compareFileNamesUnicode(null, '.abc') < 0, 'null should come before dotfiles'); + assert(compareFileNamesUnicode('.env', 'aaa') < 0, 'dotfiles come before filenames without extensions'); + assert(compareFileNamesUnicode('.env', 'aaa.env') < 0, 'dotfiles come before filenames with extensions'); + assert(compareFileNamesUnicode('.md', 'A.MD') < 0, 'dotfiles sort before uppercase files'); + assert(compareFileNamesUnicode('.MD', 'a.md') < 0, 'dotfiles sort before lowercase files'); + + // numeric comparisons + assert(compareFileNamesUnicode('1', '1') === 0, 'numerically equal full names should be equal'); + assert(compareFileNamesUnicode('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal'); + assert(compareFileNamesUnicode('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order'); + assert(compareFileNamesUnicode('a.ext1', 'b.Ext1') < 0, 'if names are different and extensions with numbers are equal except for case, filenames are sorted by unicode full filename'); + assert(compareFileNamesUnicode('a.ext1', 'a.Ext1') > 0, 'if names are equal and extensions with numbers are equal except for case, filenames are sorted by unicode full filename'); + + // + // Comparisons with different results than compareFileNamesDefault + // + + // name-only comparisons + assert(compareFileNamesUnicode('Z', 'a') < 0, 'Z comes before a'); + assert(compareFileNamesUnicode('a', 'A') > 0, 'the same letter sorts uppercase first'); + assert(compareFileNamesUnicode('â', 'Â') > 0, 'the same accented letter sorts uppercase first'); + assert.deepStrictEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileNamesUnicode), ['Art', 'Artichoke', 'art', 'artichoke'], 'names with the same root and different cases sort uppercase first'); + assert.deepStrictEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileNamesUnicode), ['Email', 'email', 'Émail', 'émail'], 'the same base characters with different case or accents sort in unicode order'); + + // name plus extension comparisons + assert(compareFileNamesUnicode('aggregate.go', 'aggregate_repo.go') < 0, 'compares the whole name in unicode order, but dot comes before underscore'); + + // dotfile comparisons + assert(compareFileNamesUnicode('.aaa_env', '.aaa.env') > 0, 'an underscore in a dotfile name will sort after a dot'); + + // numeric comparisons + assert(compareFileNamesUnicode('abc2.txt', 'abc10.txt') > 0, 'filenames with numbers should be in unicode order even when they are multiple digits long'); + assert(compareFileNamesUnicode('abc02.txt', 'abc010.txt') > 0, 'filenames with numbers that have leading zeros sort in unicode order'); + assert(compareFileNamesUnicode('abc1.10.txt', 'abc1.2.txt') < 0, 'numbers with dots between them are sorted in unicode order'); + assert(compareFileNamesUnicode('abc02.txt', 'abc002.txt') > 0, 'filenames with equivalent numbers and leading zeros sort in unicode order'); + assert(compareFileNamesUnicode('abc.txt1', 'abc.txt01') > 0, 'same name plus extensions with equal numbers sort in unicode order'); + assert(compareFileNamesUnicode('art01', 'Art01') > 0, 'a numerically equivalent name of a different case compares uppercase first'); + assert.deepStrictEqual(['a10.txt', 'A2.txt', 'A100.txt', 'a20.txt'].sort(compareFileNamesUnicode), ['A100.txt', 'A2.txt', 'a10.txt', 'a20.txt'], 'filenames with number and case differences sort in unicode order'); + + }); + + test('compareFileExtensionsUnicode', () => { + + // + // Comparisons with the same result as compareFileExtensionsDefault + // + + // name-only comparisons + assert(compareFileExtensionsUnicode(null, null) === 0, 'null should be equal'); + assert(compareFileExtensionsUnicode(null, 'abc') < 0, 'null should come before real files without extensions'); + assert(compareFileExtensionsUnicode('', '') === 0, 'empty should be equal'); + assert(compareFileExtensionsUnicode('abc', 'abc') === 0, 'equal names should be equal'); + assert(compareFileExtensionsUnicode('z', 'A') > 0, 'z comes after A'); + + // name plus extension comparisons + assert(compareFileExtensionsUnicode('file.ext', 'file.ext') === 0, 'equal full filenames should be equal'); + assert(compareFileExtensionsUnicode('a.ext', 'b.ext') < 0, 'if equal extensions, filenames should be compared'); + assert(compareFileExtensionsUnicode('file.aaa', 'file.bbb') < 0, 'files with equal names should be compared by extensions'); + assert(compareFileExtensionsUnicode('bbb.aaa', 'aaa.bbb') < 0, 'files should be compared by extension first'); + assert(compareFileExtensionsUnicode('a.md', 'b.MD') < 0, 'when extensions are the same except for case, the files sort by name'); + assert(compareFileExtensionsUnicode('a.MD', 'a.md') < 0, 'case differences in extensions sort in unicode order'); + + // dotfile comparisons + assert(compareFileExtensionsUnicode('.abc', '.abc') === 0, 'equal dotfiles should be equal'); + assert(compareFileExtensionsUnicode('.md', '.Gitattributes') > 0, 'dotfiles sort alphabetically regardless of case'); + assert(compareFileExtensionsUnicode('.env', '.aaa.env') > 0, 'dotfiles sort alphabetically when they contain multiple dots'); + assert(compareFileExtensionsUnicode('.env', '.env.aaa') < 0, 'dotfiles with the same root sort shortest first'); + + // dotfile vs non-dotfile comparisons + assert(compareFileExtensionsUnicode(null, '.abc') < 0, 'null should come before dotfiles'); + assert(compareFileExtensionsUnicode('.env', 'aaa.env') < 0, 'dotfiles come before filenames with extensions'); + assert(compareFileExtensionsUnicode('.MD', 'a.md') < 0, 'dotfiles sort before lowercase files'); + assert(compareFileExtensionsUnicode('.env', 'aaa') < 0, 'dotfiles come before filenames without extensions'); + assert(compareFileExtensionsUnicode('.md', 'A.MD') < 0, 'dotfiles sort before uppercase files'); + + // numeric comparisons + assert(compareFileExtensionsUnicode('1', '1') === 0, 'numerically equal full names should be equal'); + assert(compareFileExtensionsUnicode('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal'); + assert(compareFileExtensionsUnicode('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order'); + assert(compareFileExtensionsUnicode('txt.abc1', 'txt.abc1') === 0, 'equal extensions with numbers should be equal'); + assert(compareFileExtensionsUnicode('txt.abc1', 'txt.abc2') < 0, 'extensions with numbers should be in numerical order, not alphabetical order'); + assert(compareFileExtensionsUnicode('a.ext1', 'b.ext1') < 0, 'if equal extensions with numbers, full filenames should be compared'); + + // + // Comparisons with different results than compareFileExtensionsDefault + // + + // name-only comparisons + assert(compareFileExtensionsUnicode('Z', 'a') < 0, 'Z comes before a'); + assert(compareFileExtensionsUnicode('a', 'A') > 0, 'the same letter sorts uppercase first'); + assert(compareFileExtensionsUnicode('â', 'Â') > 0, 'the same accented letter sorts uppercase first'); + assert.deepStrictEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileExtensionsUnicode), ['Art', 'Artichoke', 'art', 'artichoke'], 'names with the same root and different cases sort uppercase names first'); + assert.deepStrictEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileExtensionsUnicode), ['Email', 'email', 'Émail', 'émail'], 'the same base characters with different case or accents sort in unicode order'); + + // name plus extension comparisons + assert(compareFileExtensionsUnicode('a.MD', 'a.md') < 0, 'case differences in extensions sort by uppercase extension first'); + assert(compareFileExtensionsUnicode('a.md', 'A.md') > 0, 'case differences in names sort uppercase first'); + assert(compareFileExtensionsUnicode('art01', 'Art01') > 0, 'a numerically equivalent name of a different case sorts uppercase first'); + assert.deepStrictEqual(['a10.txt', 'A2.txt', 'A100.txt', 'a20.txt'].sort(compareFileExtensionsUnicode), ['A100.txt', 'A2.txt', 'a10.txt', 'a20.txt'], 'filenames with number and case differences sort in unicode order'); + assert(compareFileExtensionsUnicode('aggregate.go', 'aggregate_repo.go') < 0, 'when extensions are equal, compares full filenames in unicode order'); + + // numeric comparisons + assert(compareFileExtensionsUnicode('abc2.txt', 'abc10.txt') > 0, 'filenames with numbers should be in unicode order'); + assert(compareFileExtensionsUnicode('abc02.txt', 'abc010.txt') > 0, 'filenames with numbers that have leading zeros sort in unicode order'); + assert(compareFileExtensionsUnicode('abc1.10.txt', 'abc1.2.txt') < 0, 'numbers with dots between them sort in unicode order'); + assert(compareFileExtensionsUnicode('abc2.txt2', 'abc1.txt10') > 0, 'extensions with numbers should be in unicode order'); + assert(compareFileExtensionsUnicode('txt.abc2', 'txt.abc10') > 0, 'extensions with numbers should be in unicode order even when they are multiple digits long'); + assert(compareFileExtensionsUnicode('abc.txt01', 'abc.txt1') < 0, 'extensions with equal numbers should be in unicode order'); + assert(compareFileExtensionsUnicode('abc02.txt', 'abc002.txt') > 0, 'filenames with equivalent numbers and leading zeros sort in unicode order'); + assert(compareFileExtensionsUnicode('txt.abc01', 'txt.abc1') < 0, 'extensions with equivalent numbers sort in unicode order'); + assert(compareFileExtensionsUnicode('a.ext1', 'b.Ext1') < 0, 'if extensions with numbers are equal except for case, unicode full filenames should be compared'); + assert(compareFileExtensionsUnicode('a.ext1', 'a.Ext1') > 0, 'if extensions with numbers are equal except for case, unicode full filenames should be compared'); + + }); + +}); diff --git a/lib/vscode/src/vs/base/test/browser/dom.test.ts b/src/vs/base/test/browser/dom.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/dom.test.ts rename to src/vs/base/test/browser/dom.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/formattedTextRenderer.test.ts b/src/vs/base/test/browser/formattedTextRenderer.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/formattedTextRenderer.test.ts rename to src/vs/base/test/browser/formattedTextRenderer.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/hash.test.ts b/src/vs/base/test/browser/hash.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/hash.test.ts rename to src/vs/base/test/browser/hash.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/highlightedLabel.test.ts b/src/vs/base/test/browser/highlightedLabel.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/highlightedLabel.test.ts rename to src/vs/base/test/browser/highlightedLabel.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/iconLabels.test.ts b/src/vs/base/test/browser/iconLabels.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/iconLabels.test.ts rename to src/vs/base/test/browser/iconLabels.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/markdownRenderer.test.ts b/src/vs/base/test/browser/markdownRenderer.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/markdownRenderer.test.ts rename to src/vs/base/test/browser/markdownRenderer.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/progressBar.test.ts b/src/vs/base/test/browser/progressBar.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/progressBar.test.ts rename to src/vs/base/test/browser/progressBar.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/ui/contextview/contextview.test.ts b/src/vs/base/test/browser/ui/contextview/contextview.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/ui/contextview/contextview.test.ts rename to src/vs/base/test/browser/ui/contextview/contextview.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/ui/grid/grid.test.ts b/src/vs/base/test/browser/ui/grid/grid.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/ui/grid/grid.test.ts rename to src/vs/base/test/browser/ui/grid/grid.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/ui/grid/gridview.test.ts b/src/vs/base/test/browser/ui/grid/gridview.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/ui/grid/gridview.test.ts rename to src/vs/base/test/browser/ui/grid/gridview.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/ui/grid/util.ts b/src/vs/base/test/browser/ui/grid/util.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/ui/grid/util.ts rename to src/vs/base/test/browser/ui/grid/util.ts diff --git a/lib/vscode/src/vs/base/test/browser/ui/list/listView.test.ts b/src/vs/base/test/browser/ui/list/listView.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/ui/list/listView.test.ts rename to src/vs/base/test/browser/ui/list/listView.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/ui/list/rangeMap.test.ts b/src/vs/base/test/browser/ui/list/rangeMap.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/ui/list/rangeMap.test.ts rename to src/vs/base/test/browser/ui/list/rangeMap.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/ui/menu/menubar.test.ts b/src/vs/base/test/browser/ui/menu/menubar.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/ui/menu/menubar.test.ts rename to src/vs/base/test/browser/ui/menu/menubar.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/ui/scrollbar/scrollableElement.test.ts b/src/vs/base/test/browser/ui/scrollbar/scrollableElement.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/ui/scrollbar/scrollableElement.test.ts rename to src/vs/base/test/browser/ui/scrollbar/scrollableElement.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/ui/scrollbar/scrollbarState.test.ts b/src/vs/base/test/browser/ui/scrollbar/scrollbarState.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/ui/scrollbar/scrollbarState.test.ts rename to src/vs/base/test/browser/ui/scrollbar/scrollbarState.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/ui/splitview/splitview.test.ts b/src/vs/base/test/browser/ui/splitview/splitview.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/ui/splitview/splitview.test.ts rename to src/vs/base/test/browser/ui/splitview/splitview.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts b/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts rename to src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/ui/tree/compressedObjectTreeModel.test.ts b/src/vs/base/test/browser/ui/tree/compressedObjectTreeModel.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/ui/tree/compressedObjectTreeModel.test.ts rename to src/vs/base/test/browser/ui/tree/compressedObjectTreeModel.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/ui/tree/dataTree.test.ts b/src/vs/base/test/browser/ui/tree/dataTree.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/ui/tree/dataTree.test.ts rename to src/vs/base/test/browser/ui/tree/dataTree.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts b/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts rename to src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/ui/tree/objectTree.test.ts b/src/vs/base/test/browser/ui/tree/objectTree.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/ui/tree/objectTree.test.ts rename to src/vs/base/test/browser/ui/tree/objectTree.test.ts diff --git a/lib/vscode/src/vs/base/test/browser/ui/tree/objectTreeModel.test.ts b/src/vs/base/test/browser/ui/tree/objectTreeModel.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/browser/ui/tree/objectTreeModel.test.ts rename to src/vs/base/test/browser/ui/tree/objectTreeModel.test.ts diff --git a/lib/vscode/src/vs/base/test/common/arrays.test.ts b/src/vs/base/test/common/arrays.test.ts similarity index 92% rename from lib/vscode/src/vs/base/test/common/arrays.test.ts rename to src/vs/base/test/common/arrays.test.ts index e30a841551c8..08afd92a2b46 100644 --- a/lib/vscode/src/vs/base/test/common/arrays.test.ts +++ b/src/vs/base/test/common/arrays.test.ts @@ -295,4 +295,20 @@ suite('Arrays', () => { remove(); assert.strictEqual(array.length, 0); }); + + test('minIndex', () => { + const array = ['a', 'b', 'c']; + assert.strictEqual(arrays.minIndex(array, value => array.indexOf(value)), 0); + assert.strictEqual(arrays.minIndex(array, value => -array.indexOf(value)), 2); + assert.strictEqual(arrays.minIndex(array, _value => 0), 0); + assert.strictEqual(arrays.minIndex(array, value => value === 'b' ? 0 : 5), 1); + }); + + test('maxIndex', () => { + const array = ['a', 'b', 'c']; + assert.strictEqual(arrays.maxIndex(array, value => array.indexOf(value)), 2); + assert.strictEqual(arrays.maxIndex(array, value => -array.indexOf(value)), 0); + assert.strictEqual(arrays.maxIndex(array, _value => 0), 0); + assert.strictEqual(arrays.maxIndex(array, value => value === 'b' ? 5 : 0), 1); + }); }); diff --git a/lib/vscode/src/vs/base/test/common/assert.test.ts b/src/vs/base/test/common/assert.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/assert.test.ts rename to src/vs/base/test/common/assert.test.ts diff --git a/lib/vscode/src/vs/base/test/common/async.test.ts b/src/vs/base/test/common/async.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/async.test.ts rename to src/vs/base/test/common/async.test.ts diff --git a/lib/vscode/src/vs/base/test/common/buffer.test.ts b/src/vs/base/test/common/buffer.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/buffer.test.ts rename to src/vs/base/test/common/buffer.test.ts diff --git a/lib/vscode/src/vs/base/test/common/cache.test.ts b/src/vs/base/test/common/cache.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/cache.test.ts rename to src/vs/base/test/common/cache.test.ts diff --git a/lib/vscode/src/vs/base/test/common/cancellation.test.ts b/src/vs/base/test/common/cancellation.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/cancellation.test.ts rename to src/vs/base/test/common/cancellation.test.ts diff --git a/lib/vscode/src/vs/base/test/common/charCode.test.ts b/src/vs/base/test/common/charCode.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/charCode.test.ts rename to src/vs/base/test/common/charCode.test.ts diff --git a/lib/vscode/src/vs/base/test/common/codicons.test.ts b/src/vs/base/test/common/codicons.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/codicons.test.ts rename to src/vs/base/test/common/codicons.test.ts diff --git a/lib/vscode/src/vs/base/test/common/collections.test.ts b/src/vs/base/test/common/collections.test.ts similarity index 73% rename from lib/vscode/src/vs/base/test/common/collections.test.ts rename to src/vs/base/test/common/collections.test.ts index 881525a006bb..a86eeab2de04 100644 --- a/lib/vscode/src/vs/base/test/common/collections.test.ts +++ b/src/vs/base/test/common/collections.test.ts @@ -53,26 +53,4 @@ suite('Collections', () => { assert.strictEqual(grouped[group2].length, 1); assert.strictEqual(grouped[group2][0].value, value3); }); - - test('groupByNumber', () => { - - const group1 = 1, group2 = 2; - const value1 = 'a', value2 = 'b', value3 = 'c'; - let source = [ - { key: group1, value: value1 }, - { key: group1, value: value2 }, - { key: group2, value: value3 }, - ]; - - let grouped = collections.groupByNumber(source, x => x.key); - - // Group 1 - assert.strictEqual(grouped.get(group1)!.length, 2); - assert.strictEqual(grouped.get(group1)![0].value, value1); - assert.strictEqual(grouped.get(group1)![1].value, value2); - - // Group 2 - assert.strictEqual(grouped.get(group2)!.length, 1); - assert.strictEqual(grouped.get(group2)![0].value, value3); - }); }); diff --git a/lib/vscode/src/vs/base/test/common/color.test.ts b/src/vs/base/test/common/color.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/color.test.ts rename to src/vs/base/test/common/color.test.ts diff --git a/lib/vscode/src/vs/base/test/common/console.test.ts b/src/vs/base/test/common/console.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/console.test.ts rename to src/vs/base/test/common/console.test.ts diff --git a/lib/vscode/src/vs/base/test/common/decorators.test.ts b/src/vs/base/test/common/decorators.test.ts similarity index 88% rename from lib/vscode/src/vs/base/test/common/decorators.test.ts rename to src/vs/base/test/common/decorators.test.ts index 0e88e4f2ec09..873003106507 100644 --- a/lib/vscode/src/vs/base/test/common/decorators.test.ts +++ b/src/vs/base/test/common/decorators.test.ts @@ -5,7 +5,7 @@ import * as sinon from 'sinon'; import * as assert from 'assert'; -import { memoize, createMemoizer, throttle } from 'vs/base/common/decorators'; +import { memoize, throttle } from 'vs/base/common/decorators'; suite('Decorators', () => { test('memoize should memoize methods', () => { @@ -131,28 +131,6 @@ suite('Decorators', () => { } }); - test('memoize clear', () => { - const memoizer = createMemoizer(); - let counter = 0; - class Foo { - @memoizer - get answer() { - return ++counter; - } - } - - const foo = new Foo(); - assert.strictEqual(foo.answer, 1); - assert.strictEqual(foo.answer, 1); - memoizer.clear(); - assert.strictEqual(foo.answer, 2); - assert.strictEqual(foo.answer, 2); - memoizer.clear(); - assert.strictEqual(foo.answer, 3); - assert.strictEqual(foo.answer, 3); - assert.strictEqual(foo.answer, 3); - }); - test('throttle', () => { const spy = sinon.spy(); const clock = sinon.useFakeTimers(); diff --git a/lib/vscode/src/vs/base/test/common/diff/diff.test.ts b/src/vs/base/test/common/diff/diff.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/diff/diff.test.ts rename to src/vs/base/test/common/diff/diff.test.ts diff --git a/lib/vscode/src/vs/base/test/common/errors.test.ts b/src/vs/base/test/common/errors.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/errors.test.ts rename to src/vs/base/test/common/errors.test.ts diff --git a/lib/vscode/src/vs/base/test/common/event.test.ts b/src/vs/base/test/common/event.test.ts similarity index 92% rename from lib/vscode/src/vs/base/test/common/event.test.ts rename to src/vs/base/test/common/event.test.ts index a0f55cd405c1..680c4aa2804d 100644 --- a/lib/vscode/src/vs/base/test/common/event.test.ts +++ b/src/vs/base/test/common/event.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { Event, Emitter, EventBufferer, EventMultiplexer, PauseableEmitter } from 'vs/base/common/event'; +import { Event, Emitter, EventBufferer, EventMultiplexer, PauseableEmitter, Relay } from 'vs/base/common/event'; import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { errorHandler, setUnexpectedErrorHandler } from 'vs/base/common/errors'; import { AsyncEmitter, IWaitUntil, timeout } from 'vs/base/common/async'; @@ -894,4 +894,70 @@ suite('Event utils', () => { listener.dispose(); }); + test('dispose is reentrant', () => { + const emitter = new Emitter({ + onLastListenerRemove: () => { + emitter.dispose(); + } + }); + + const listener = emitter.event(() => undefined); + listener.dispose(); // should not crash + }); + + suite('Relay', () => { + test('should input work', () => { + const e1 = new Emitter(); + const e2 = new Emitter(); + const relay = new Relay(); + + const result: number[] = []; + const listener = (num: number) => result.push(num); + const subscription = relay.event(listener); + + e1.fire(1); + assert.deepStrictEqual(result, []); + + relay.input = e1.event; + e1.fire(2); + assert.deepStrictEqual(result, [2]); + + relay.input = e2.event; + e1.fire(3); + e2.fire(4); + assert.deepStrictEqual(result, [2, 4]); + + subscription.dispose(); + e1.fire(5); + e2.fire(6); + assert.deepStrictEqual(result, [2, 4]); + }); + + test('should Relay dispose work', () => { + const e1 = new Emitter(); + const e2 = new Emitter(); + const relay = new Relay(); + + const result: number[] = []; + const listener = (num: number) => result.push(num); + relay.event(listener); + + e1.fire(1); + assert.deepStrictEqual(result, []); + + relay.input = e1.event; + e1.fire(2); + assert.deepStrictEqual(result, [2]); + + relay.input = e2.event; + e1.fire(3); + e2.fire(4); + assert.deepStrictEqual(result, [2, 4]); + + relay.dispose(); + e1.fire(5); + e2.fire(6); + assert.deepStrictEqual(result, [2, 4]); + }); + }); }); diff --git a/lib/vscode/src/vs/base/test/common/extpath.test.ts b/src/vs/base/test/common/extpath.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/extpath.test.ts rename to src/vs/base/test/common/extpath.test.ts diff --git a/lib/vscode/src/vs/base/test/common/filters.perf.data.d.ts b/src/vs/base/test/common/filters.perf.data.d.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/filters.perf.data.d.ts rename to src/vs/base/test/common/filters.perf.data.d.ts diff --git a/lib/vscode/src/vs/base/test/common/filters.perf.data.js b/src/vs/base/test/common/filters.perf.data.js similarity index 100% rename from lib/vscode/src/vs/base/test/common/filters.perf.data.js rename to src/vs/base/test/common/filters.perf.data.js diff --git a/lib/vscode/src/vs/base/test/common/filters.perf.test.ts b/src/vs/base/test/common/filters.perf.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/filters.perf.test.ts rename to src/vs/base/test/common/filters.perf.test.ts diff --git a/lib/vscode/src/vs/base/test/common/filters.test.ts b/src/vs/base/test/common/filters.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/filters.test.ts rename to src/vs/base/test/common/filters.test.ts diff --git a/lib/vscode/src/vs/base/test/common/fuzzyScorer.test.ts b/src/vs/base/test/common/fuzzyScorer.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/fuzzyScorer.test.ts rename to src/vs/base/test/common/fuzzyScorer.test.ts diff --git a/lib/vscode/src/vs/base/test/common/glob.test.ts b/src/vs/base/test/common/glob.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/glob.test.ts rename to src/vs/base/test/common/glob.test.ts diff --git a/lib/vscode/src/vs/base/test/common/history.test.ts b/src/vs/base/test/common/history.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/history.test.ts rename to src/vs/base/test/common/history.test.ts diff --git a/lib/vscode/src/vs/base/test/common/iconLabels.test.ts b/src/vs/base/test/common/iconLabels.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/iconLabels.test.ts rename to src/vs/base/test/common/iconLabels.test.ts diff --git a/lib/vscode/src/vs/base/test/common/iterator.test.ts b/src/vs/base/test/common/iterator.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/iterator.test.ts rename to src/vs/base/test/common/iterator.test.ts diff --git a/lib/vscode/src/vs/base/test/common/json.test.ts b/src/vs/base/test/common/json.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/json.test.ts rename to src/vs/base/test/common/json.test.ts diff --git a/lib/vscode/src/vs/base/test/common/jsonEdit.test.ts b/src/vs/base/test/common/jsonEdit.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/jsonEdit.test.ts rename to src/vs/base/test/common/jsonEdit.test.ts diff --git a/lib/vscode/src/vs/base/test/common/jsonFormatter.test.ts b/src/vs/base/test/common/jsonFormatter.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/jsonFormatter.test.ts rename to src/vs/base/test/common/jsonFormatter.test.ts diff --git a/lib/vscode/src/vs/base/test/common/keyCodes.test.ts b/src/vs/base/test/common/keyCodes.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/keyCodes.test.ts rename to src/vs/base/test/common/keyCodes.test.ts diff --git a/lib/vscode/src/vs/base/test/common/labels.test.ts b/src/vs/base/test/common/labels.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/labels.test.ts rename to src/vs/base/test/common/labels.test.ts diff --git a/lib/vscode/src/vs/base/test/common/lazy.test.ts b/src/vs/base/test/common/lazy.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/lazy.test.ts rename to src/vs/base/test/common/lazy.test.ts diff --git a/lib/vscode/src/vs/base/test/common/lifecycle.test.ts b/src/vs/base/test/common/lifecycle.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/lifecycle.test.ts rename to src/vs/base/test/common/lifecycle.test.ts diff --git a/lib/vscode/src/vs/base/test/common/linkedList.test.ts b/src/vs/base/test/common/linkedList.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/linkedList.test.ts rename to src/vs/base/test/common/linkedList.test.ts diff --git a/lib/vscode/src/vs/base/test/common/linkedText.test.ts b/src/vs/base/test/common/linkedText.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/linkedText.test.ts rename to src/vs/base/test/common/linkedText.test.ts diff --git a/lib/vscode/src/vs/base/test/common/map.test.ts b/src/vs/base/test/common/map.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/map.test.ts rename to src/vs/base/test/common/map.test.ts diff --git a/lib/vscode/src/vs/base/test/common/markdownString.test.ts b/src/vs/base/test/common/markdownString.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/markdownString.test.ts rename to src/vs/base/test/common/markdownString.test.ts diff --git a/lib/vscode/src/vs/base/test/common/marshalling.test.ts b/src/vs/base/test/common/marshalling.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/marshalling.test.ts rename to src/vs/base/test/common/marshalling.test.ts diff --git a/lib/vscode/src/vs/base/test/common/mime.test.ts b/src/vs/base/test/common/mime.test.ts similarity index 91% rename from lib/vscode/src/vs/base/test/common/mime.test.ts rename to src/vs/base/test/common/mime.test.ts index f2583fed404c..05515ed1e59b 100644 --- a/lib/vscode/src/vs/base/test/common/mime.test.ts +++ b/src/vs/base/test/common/mime.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { guessMimeTypes, registerTextMime } from 'vs/base/common/mime'; +import { guessMimeTypes, normalizeMimeType, registerTextMime } from 'vs/base/common/mime'; import { URI } from 'vs/base/common/uri'; suite('Mime', () => { @@ -126,4 +126,13 @@ suite('Mime', () => { assert.deepStrictEqual(guessMimeTypes(URI.parse(`data:;label:something.data;description:data,`)), ['text/data', 'text/plain']); }); + + test('normalize', () => { + assert.strictEqual(normalizeMimeType('invalid'), 'invalid'); + assert.strictEqual(normalizeMimeType('invalid', true), undefined); + assert.strictEqual(normalizeMimeType('Text/plain'), 'text/plain'); + assert.strictEqual(normalizeMimeType('Text/pläin'), 'text/pläin'); + assert.strictEqual(normalizeMimeType('Text/plain;UPPER'), 'text/plain;UPPER'); + assert.strictEqual(normalizeMimeType('Text/plain;lower'), 'text/plain;lower'); + }); }); diff --git a/lib/vscode/src/vs/base/test/common/mock.ts b/src/vs/base/test/common/mock.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/mock.ts rename to src/vs/base/test/common/mock.ts diff --git a/lib/vscode/src/vs/base/test/common/network.test.ts b/src/vs/base/test/common/network.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/network.test.ts rename to src/vs/base/test/common/network.test.ts diff --git a/lib/vscode/src/vs/base/test/common/normalization.test.ts b/src/vs/base/test/common/normalization.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/normalization.test.ts rename to src/vs/base/test/common/normalization.test.ts diff --git a/lib/vscode/src/vs/base/test/common/objects.test.ts b/src/vs/base/test/common/objects.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/objects.test.ts rename to src/vs/base/test/common/objects.test.ts diff --git a/lib/vscode/src/vs/base/test/common/paging.test.ts b/src/vs/base/test/common/paging.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/paging.test.ts rename to src/vs/base/test/common/paging.test.ts diff --git a/lib/vscode/src/vs/base/test/common/path.test.ts b/src/vs/base/test/common/path.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/path.test.ts rename to src/vs/base/test/common/path.test.ts diff --git a/lib/vscode/src/vs/base/test/common/processes.test.ts b/src/vs/base/test/common/processes.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/processes.test.ts rename to src/vs/base/test/common/processes.test.ts diff --git a/lib/vscode/src/vs/base/test/common/resourceTree.test.ts b/src/vs/base/test/common/resourceTree.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/resourceTree.test.ts rename to src/vs/base/test/common/resourceTree.test.ts diff --git a/lib/vscode/src/vs/base/test/common/resources.test.ts b/src/vs/base/test/common/resources.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/resources.test.ts rename to src/vs/base/test/common/resources.test.ts diff --git a/lib/vscode/src/vs/base/test/common/scrollable.test.ts b/src/vs/base/test/common/scrollable.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/scrollable.test.ts rename to src/vs/base/test/common/scrollable.test.ts diff --git a/lib/vscode/src/vs/base/test/common/skipList.test.ts b/src/vs/base/test/common/skipList.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/skipList.test.ts rename to src/vs/base/test/common/skipList.test.ts diff --git a/lib/vscode/src/vs/base/test/common/stream.test.ts b/src/vs/base/test/common/stream.test.ts similarity index 99% rename from lib/vscode/src/vs/base/test/common/stream.test.ts rename to src/vs/base/test/common/stream.test.ts index 4cb309a84ea6..913cf6e08172 100644 --- a/lib/vscode/src/vs/base/test/common/stream.test.ts +++ b/src/vs/base/test/common/stream.test.ts @@ -91,7 +91,7 @@ suite('Stream', () => { }); test('WriteableStream - end with error works', async () => { - const reducer = (errors: Error[]) => errors.length > 0 ? errors[0] : null as unknown as Error; + const reducer = (errors: Error[]) => errors[0]; const stream = newWriteableStream(reducer); stream.end(new Error('error')); diff --git a/lib/vscode/src/vs/base/test/common/strings.test.ts b/src/vs/base/test/common/strings.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/strings.test.ts rename to src/vs/base/test/common/strings.test.ts diff --git a/lib/vscode/src/vs/base/test/common/troubleshooting.ts b/src/vs/base/test/common/troubleshooting.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/troubleshooting.ts rename to src/vs/base/test/common/troubleshooting.ts diff --git a/lib/vscode/src/vs/base/test/common/types.test.ts b/src/vs/base/test/common/types.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/types.test.ts rename to src/vs/base/test/common/types.test.ts diff --git a/lib/vscode/src/vs/base/test/common/uri.test.ts b/src/vs/base/test/common/uri.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/uri.test.ts rename to src/vs/base/test/common/uri.test.ts diff --git a/lib/vscode/src/vs/base/test/common/utils.ts b/src/vs/base/test/common/utils.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/utils.ts rename to src/vs/base/test/common/utils.ts diff --git a/lib/vscode/src/vs/base/test/common/uuid.test.ts b/src/vs/base/test/common/uuid.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/common/uuid.test.ts rename to src/vs/base/test/common/uuid.test.ts diff --git a/lib/vscode/src/vs/base/test/node/crypto.test.ts b/src/vs/base/test/node/crypto.test.ts similarity index 87% rename from lib/vscode/src/vs/base/test/node/crypto.test.ts rename to src/vs/base/test/node/crypto.test.ts index 67c188de8f05..f1b7ef70b948 100644 --- a/lib/vscode/src/vs/base/test/node/crypto.test.ts +++ b/src/vs/base/test/node/crypto.test.ts @@ -6,8 +6,7 @@ import { checksum } from 'vs/base/node/crypto'; import { join } from 'vs/base/common/path'; import { tmpdir } from 'os'; -import { promises } from 'fs'; -import { rimraf, writeFile } from 'vs/base/node/pfs'; +import { Promises, rimraf, writeFile } from 'vs/base/node/pfs'; import { flakySuite, getRandomTestPath } from 'vs/base/test/node/testUtils'; flakySuite('Crypto', () => { @@ -17,7 +16,7 @@ flakySuite('Crypto', () => { setup(function () { testDir = getRandomTestPath(tmpdir(), 'vsctests', 'crypto'); - return promises.mkdir(testDir, { recursive: true }); + return Promises.mkdir(testDir, { recursive: true }); }); teardown(function () { diff --git a/lib/vscode/src/vs/base/test/node/decoder.test.ts b/src/vs/base/test/node/decoder.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/node/decoder.test.ts rename to src/vs/base/test/node/decoder.test.ts diff --git a/lib/vscode/src/vs/base/test/node/extpath.test.ts b/src/vs/base/test/node/extpath.test.ts similarity index 92% rename from lib/vscode/src/vs/base/test/node/extpath.test.ts rename to src/vs/base/test/node/extpath.test.ts index a1c8a7f94d23..0487ffcaebf2 100644 --- a/lib/vscode/src/vs/base/test/node/extpath.test.ts +++ b/src/vs/base/test/node/extpath.test.ts @@ -5,8 +5,7 @@ import * as assert from 'assert'; import { tmpdir } from 'os'; -import { promises } from 'fs'; -import { rimraf } from 'vs/base/node/pfs'; +import { Promises, rimraf } from 'vs/base/node/pfs'; import { realcaseSync, realpath, realpathSync } from 'vs/base/node/extpath'; import { flakySuite, getRandomTestPath } from 'vs/base/test/node/testUtils'; @@ -16,7 +15,7 @@ flakySuite('Extpath', () => { setup(() => { testDir = getRandomTestPath(tmpdir(), 'vsctests', 'extpath'); - return promises.mkdir(testDir, { recursive: true }); + return Promises.mkdir(testDir, { recursive: true }); }); teardown(() => { diff --git a/lib/vscode/src/vs/base/test/node/id.test.ts b/src/vs/base/test/node/id.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/node/id.test.ts rename to src/vs/base/test/node/id.test.ts diff --git a/lib/vscode/src/vs/base/test/node/keytar.test.ts b/src/vs/base/test/node/keytar.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/node/keytar.test.ts rename to src/vs/base/test/node/keytar.test.ts diff --git a/lib/vscode/src/vs/base/test/node/pfs/fixtures/examples/company.jxs b/src/vs/base/test/node/pfs/fixtures/examples/company.jxs similarity index 100% rename from lib/vscode/src/vs/base/test/node/pfs/fixtures/examples/company.jxs rename to src/vs/base/test/node/pfs/fixtures/examples/company.jxs diff --git a/lib/vscode/src/vs/base/test/node/pfs/fixtures/examples/conway.jxs b/src/vs/base/test/node/pfs/fixtures/examples/conway.jxs similarity index 100% rename from lib/vscode/src/vs/base/test/node/pfs/fixtures/examples/conway.jxs rename to src/vs/base/test/node/pfs/fixtures/examples/conway.jxs diff --git a/lib/vscode/src/vs/base/test/node/pfs/fixtures/examples/employee.jxs b/src/vs/base/test/node/pfs/fixtures/examples/employee.jxs similarity index 100% rename from lib/vscode/src/vs/base/test/node/pfs/fixtures/examples/employee.jxs rename to src/vs/base/test/node/pfs/fixtures/examples/employee.jxs diff --git a/lib/vscode/src/vs/base/test/node/pfs/fixtures/examples/small.jxs b/src/vs/base/test/node/pfs/fixtures/examples/small.jxs similarity index 100% rename from lib/vscode/src/vs/base/test/node/pfs/fixtures/examples/small.jxs rename to src/vs/base/test/node/pfs/fixtures/examples/small.jxs diff --git a/lib/vscode/src/vs/base/test/node/pfs/fixtures/index.html b/src/vs/base/test/node/pfs/fixtures/index.html similarity index 100% rename from lib/vscode/src/vs/base/test/node/pfs/fixtures/index.html rename to src/vs/base/test/node/pfs/fixtures/index.html diff --git a/lib/vscode/src/vs/base/test/node/pfs/fixtures/site.css b/src/vs/base/test/node/pfs/fixtures/site.css similarity index 100% rename from lib/vscode/src/vs/base/test/node/pfs/fixtures/site.css rename to src/vs/base/test/node/pfs/fixtures/site.css diff --git a/lib/vscode/src/vs/base/test/node/pfs/pfs.test.ts b/src/vs/base/test/node/pfs/pfs.test.ts similarity index 94% rename from lib/vscode/src/vs/base/test/node/pfs/pfs.test.ts rename to src/vs/base/test/node/pfs/pfs.test.ts index 0eceb128b9af..2139f6cbe44e 100644 --- a/lib/vscode/src/vs/base/test/node/pfs/pfs.test.ts +++ b/src/vs/base/test/node/pfs/pfs.test.ts @@ -8,7 +8,7 @@ import * as fs from 'fs'; import { tmpdir } from 'os'; import { join, sep } from 'vs/base/common/path'; import { generateUuid } from 'vs/base/common/uuid'; -import { copy, exists, move, readdir, readDirsInDir, rimraf, RimRafMode, rimrafSync, SymlinkSupport, writeFile, writeFileSync } from 'vs/base/node/pfs'; +import { copy, exists, move, Promises, readdir, readDirsInDir, rimraf, RimRafMode, rimrafSync, SymlinkSupport, writeFile, writeFileSync } from 'vs/base/node/pfs'; import { timeout } from 'vs/base/common/async'; import { canNormalize } from 'vs/base/common/normalization'; import { VSBuffer } from 'vs/base/common/buffer'; @@ -22,7 +22,7 @@ flakySuite('PFS', function () { setup(() => { testDir = getRandomTestPath(tmpdir(), 'vsctests', 'pfs'); - return fs.promises.mkdir(testDir, { recursive: true }); + return Promises.mkdir(testDir, { recursive: true }); }); teardown(() => { @@ -36,7 +36,7 @@ flakySuite('PFS', function () { await writeFile(testFile, 'Hello World', (null!)); - assert.strictEqual((await fs.promises.readFile(testFile)).toString(), 'Hello World'); + assert.strictEqual((await Promises.readFile(testFile)).toString(), 'Hello World'); }); test('writeFile - parallel write on different files works', async () => { @@ -200,7 +200,7 @@ flakySuite('PFS', function () { const id3 = generateUuid(); const copyTarget = join(testDir, id3); - await fs.promises.mkdir(symbolicLinkTarget, { recursive: true }); + await Promises.mkdir(symbolicLinkTarget, { recursive: true }); fs.symlinkSync(symbolicLinkTarget, symLink, 'junction'); @@ -217,7 +217,7 @@ flakySuite('PFS', function () { assert.ok(symbolicLink); assert.ok(!symbolicLink.dangling); - const target = await fs.promises.readlink(copyTarget); + const target = await Promises.readlink(copyTarget); assert.strictEqual(target, symbolicLinkTarget); // Copy does not preserve symlinks if configured as such @@ -253,7 +253,7 @@ flakySuite('PFS', function () { const sourceLinkTestFolder = join(sourceFolder, 'link-test'); // copy-test/link-test const sourceLinkMD5JSFolder = join(sourceLinkTestFolder, 'md5'); // copy-test/link-test/md5 const sourceLinkMD5JSFile = join(sourceLinkMD5JSFolder, 'md5.js'); // copy-test/link-test/md5/md5.js - await fs.promises.mkdir(sourceLinkMD5JSFolder, { recursive: true }); + await Promises.mkdir(sourceLinkMD5JSFolder, { recursive: true }); await writeFile(sourceLinkMD5JSFile, 'Hello from MD5'); const sourceLinkMD5JSFolderLinked = join(sourceLinkTestFolder, 'md5-linked'); // copy-test/link-test/md5-linked @@ -278,10 +278,10 @@ flakySuite('PFS', function () { assert.ok(fs.existsSync(targetLinkMD5JSFolderLinked)); assert.ok(fs.lstatSync(targetLinkMD5JSFolderLinked).isSymbolicLink()); - const linkTarget = await fs.promises.readlink(targetLinkMD5JSFolderLinked); + const linkTarget = await Promises.readlink(targetLinkMD5JSFolderLinked); assert.strictEqual(linkTarget, targetLinkMD5JSFolder); - await fs.promises.rmdir(targetLinkTestFolder, { recursive: true }); + await Promises.rmdir(targetLinkTestFolder, { recursive: true }); } // Copy with `preserveSymlinks: false` and verify result @@ -315,7 +315,7 @@ flakySuite('PFS', function () { const id2 = generateUuid(); const symbolicLink = join(testDir, id2); - await fs.promises.mkdir(directory, { recursive: true }); + await Promises.mkdir(directory, { recursive: true }); fs.symlinkSync(directory, symbolicLink, 'junction'); @@ -334,7 +334,7 @@ flakySuite('PFS', function () { const id2 = generateUuid(); const symbolicLink = join(testDir, id2); - await fs.promises.mkdir(directory, { recursive: true }); + await Promises.mkdir(directory, { recursive: true }); fs.symlinkSync(directory, symbolicLink, 'junction'); @@ -350,7 +350,7 @@ flakySuite('PFS', function () { const id = generateUuid(); const newDir = join(testDir, 'pfs', id, 'öäü'); - await fs.promises.mkdir(newDir, { recursive: true }); + await Promises.mkdir(newDir, { recursive: true }); assert.ok(fs.existsSync(newDir)); @@ -362,7 +362,7 @@ flakySuite('PFS', function () { test('readdir (with file types)', async () => { if (canNormalize && typeof process.versions['electron'] !== 'undefined' /* needs electron */) { const newDir = join(testDir, 'öäü'); - await fs.promises.mkdir(newDir, { recursive: true }); + await Promises.mkdir(newDir, { recursive: true }); await writeFile(join(testDir, 'somefile.txt'), 'contents'); diff --git a/lib/vscode/src/vs/base/test/node/port.test.ts b/src/vs/base/test/node/port.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/node/port.test.ts rename to src/vs/base/test/node/port.test.ts diff --git a/lib/vscode/src/vs/base/test/node/powershell.test.ts b/src/vs/base/test/node/powershell.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/node/powershell.test.ts rename to src/vs/base/test/node/powershell.test.ts diff --git a/lib/vscode/src/vs/base/test/node/processes/fixtures/fork.ts b/src/vs/base/test/node/processes/fixtures/fork.ts similarity index 100% rename from lib/vscode/src/vs/base/test/node/processes/fixtures/fork.ts rename to src/vs/base/test/node/processes/fixtures/fork.ts diff --git a/lib/vscode/src/vs/base/test/node/processes/fixtures/fork_large.ts b/src/vs/base/test/node/processes/fixtures/fork_large.ts similarity index 100% rename from lib/vscode/src/vs/base/test/node/processes/fixtures/fork_large.ts rename to src/vs/base/test/node/processes/fixtures/fork_large.ts diff --git a/lib/vscode/src/vs/base/test/node/processes/processes.test.ts b/src/vs/base/test/node/processes/processes.test.ts similarity index 100% rename from lib/vscode/src/vs/base/test/node/processes/processes.test.ts rename to src/vs/base/test/node/processes/processes.test.ts diff --git a/lib/vscode/src/vs/base/test/node/testUtils.ts b/src/vs/base/test/node/testUtils.ts similarity index 100% rename from lib/vscode/src/vs/base/test/node/testUtils.ts rename to src/vs/base/test/node/testUtils.ts diff --git a/lib/vscode/src/vs/base/test/node/uri.test.data.txt b/src/vs/base/test/node/uri.test.data.txt similarity index 100% rename from lib/vscode/src/vs/base/test/node/uri.test.data.txt rename to src/vs/base/test/node/uri.test.data.txt diff --git a/lib/vscode/src/vs/base/test/node/uri.test.perf.ts b/src/vs/base/test/node/uri.test.perf.ts similarity index 100% rename from lib/vscode/src/vs/base/test/node/uri.test.perf.ts rename to src/vs/base/test/node/uri.test.perf.ts diff --git a/lib/vscode/src/vs/base/test/node/zip/fixtures/extract.zip b/src/vs/base/test/node/zip/fixtures/extract.zip similarity index 100% rename from lib/vscode/src/vs/base/test/node/zip/fixtures/extract.zip rename to src/vs/base/test/node/zip/fixtures/extract.zip diff --git a/lib/vscode/src/vs/base/test/node/zip/zip.test.ts b/src/vs/base/test/node/zip/zip.test.ts similarity index 89% rename from lib/vscode/src/vs/base/test/node/zip/zip.test.ts rename to src/vs/base/test/node/zip/zip.test.ts index 4f151af16e95..5e5470ce155b 100644 --- a/lib/vscode/src/vs/base/test/node/zip/zip.test.ts +++ b/src/vs/base/test/node/zip/zip.test.ts @@ -6,9 +6,8 @@ import * as assert from 'assert'; import * as path from 'vs/base/common/path'; import { tmpdir } from 'os'; -import { promises } from 'fs'; import { extract } from 'vs/base/node/zip'; -import { rimraf, exists } from 'vs/base/node/pfs'; +import { rimraf, exists, Promises } from 'vs/base/node/pfs'; import { createCancelablePromise } from 'vs/base/common/async'; import { getRandomTestPath, getPathFromAmdModule } from 'vs/base/test/node/testUtils'; @@ -19,7 +18,7 @@ suite('Zip', () => { setup(() => { testDir = getRandomTestPath(tmpdir(), 'vsctests', 'zip'); - return promises.mkdir(testDir, { recursive: true }); + return Promises.mkdir(testDir, { recursive: true }); }); teardown(() => { diff --git a/src/vs/base/test/parts/quickinput/browser/quickinput.test.ts b/src/vs/base/test/parts/quickinput/browser/quickinput.test.ts new file mode 100644 index 000000000000..f74c90e013a3 --- /dev/null +++ b/src/vs/base/test/parts/quickinput/browser/quickinput.test.ts @@ -0,0 +1,75 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; +import { List } from 'vs/base/browser/ui/list/listWidget'; +import { QuickInputController } from 'vs/base/parts/quickinput/browser/quickInput'; +import { IWorkbenchListOptions } from 'vs/platform/list/browser/listService'; + +// Simple promisify of setTimeout +function wait(delayMS: number) { + return new Promise(function (resolve) { + setTimeout(resolve, delayMS); + }); +} + +suite('QuickInput', () => { + let fixture: HTMLElement, controller: QuickInputController; + + setup(() => { + fixture = document.createElement('div'); + document.body.appendChild(fixture); + + controller = new QuickInputController({ + container: fixture, + idPrefix: 'testQuickInput', + ignoreFocusOut() { return false; }, + isScreenReaderOptimized() { return false; }, + returnFocus() { }, + backKeybindingLabel() { return undefined; }, + setContextKey() { return undefined; }, + createList: ( + user: string, + container: HTMLElement, + delegate: IListVirtualDelegate, + renderers: IListRenderer[], + options: IWorkbenchListOptions, + ) => new List(user, container, delegate, renderers, options), + styles: { + button: {}, + countBadge: {}, + inputBox: {}, + keybindingLabel: {}, + list: {}, + progressBar: {}, + widget: {} + } + }); + }); + + teardown(() => { + controller.dispose(); + document.body.removeChild(fixture); + }); + + test('onDidChangeValue gets triggered when .value is set', async () => { + const quickpick = controller.createQuickPick(); + + let value: string | undefined = undefined; + quickpick.onDidChangeValue((e) => value = e); + + // Trigger a change + quickpick.value = 'changed'; + + try { + // wait a bit to let the event play out. + await wait(200); + assert.strictEqual(value, quickpick.value); + } finally { + quickpick.dispose(); + } + }); +}); diff --git a/lib/vscode/src/vs/base/worker/defaultWorkerFactory.ts b/src/vs/base/worker/defaultWorkerFactory.ts similarity index 100% rename from lib/vscode/src/vs/base/worker/defaultWorkerFactory.ts rename to src/vs/base/worker/defaultWorkerFactory.ts diff --git a/lib/vscode/src/vs/base/worker/workerMain.ts b/src/vs/base/worker/workerMain.ts similarity index 100% rename from lib/vscode/src/vs/base/worker/workerMain.ts rename to src/vs/base/worker/workerMain.ts diff --git a/lib/vscode/src/vs/code/browser/workbench/callback.html b/src/vs/code/browser/workbench/callback.html similarity index 100% rename from lib/vscode/src/vs/code/browser/workbench/callback.html rename to src/vs/code/browser/workbench/callback.html diff --git a/lib/vscode/src/vs/code/browser/workbench/workbench-dev.html b/src/vs/code/browser/workbench/workbench-dev.html similarity index 100% rename from lib/vscode/src/vs/code/browser/workbench/workbench-dev.html rename to src/vs/code/browser/workbench/workbench-dev.html diff --git a/lib/vscode/src/vs/code/browser/workbench/workbench.html b/src/vs/code/browser/workbench/workbench.html similarity index 100% rename from lib/vscode/src/vs/code/browser/workbench/workbench.html rename to src/vs/code/browser/workbench/workbench.html diff --git a/lib/vscode/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts similarity index 89% rename from lib/vscode/src/vs/code/browser/workbench/workbench.ts rename to src/vs/code/browser/workbench/workbench.ts index e525a92725e9..9c222a0048ec 100644 --- a/lib/vscode/src/vs/code/browser/workbench/workbench.ts +++ b/src/vs/code/browser/workbench/workbench.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IWorkbenchConstructionOptions, create, ICredentialsProvider, IURLCallbackProvider, IWorkspaceProvider, IWorkspace, IWindowIndicator, IProductQualityChangeHandler, ISettingsSyncOptions } from 'vs/workbench/workbench.web.api'; +import { IWorkbenchConstructionOptions, create, ICredentialsProvider, IURLCallbackProvider, IWorkspaceProvider, IWorkspace, IWindowIndicator, IHomeIndicator, IProductQualityChangeHandler, ISettingsSyncOptions } from 'vs/workbench/workbench.web.api'; import { URI, UriComponents } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { generateUuid } from 'vs/base/common/uuid'; @@ -17,7 +17,7 @@ import { isStandalone } from 'vs/base/browser/browser'; import { localize } from 'vs/nls'; import { Schemas } from 'vs/base/common/network'; import product from 'vs/platform/product/common/product'; -import { encodePath } from 'vs/server/node/util'; +import { parseLogLevel } from 'vs/platform/log/common/log'; function doCreateUri(path: string, queryValues: Map): URI { let query: string | undefined = undefined; @@ -278,8 +278,8 @@ class WorkspaceProvider implements IWorkspaceProvider { readonly trusted = true; constructor( - public readonly workspace: IWorkspace, - public readonly payload: object + readonly workspace: IWorkspace, + readonly payload: object ) { } async open(workspace: IWorkspace, options?: { reuse?: boolean, payload?: object }): Promise { @@ -316,18 +316,12 @@ class WorkspaceProvider implements IWorkspaceProvider { // Folder else if (isFolderToOpen(workspace)) { - const target = workspace.folderUri.scheme === Schemas.vscodeRemote - ? encodePath(workspace.folderUri.path) - : encodeURIComponent(workspace.folderUri.toString()); - targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_FOLDER}=${target}`; + targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_FOLDER}=${encodeURIComponent(workspace.folderUri.toString())}`; } // Workspace else if (isWorkspaceToOpen(workspace)) { - const target = workspace.workspaceUri.scheme === Schemas.vscodeRemote - ? encodePath(workspace.workspaceUri.path) - : encodeURIComponent(workspace.workspaceUri.toString()); - targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_WORKSPACE}=${target}`; + targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_WORKSPACE}=${encodeURIComponent(workspace.workspaceUri.toString())}`; } // Append payload if any @@ -417,27 +411,51 @@ class WindowIndicator implements IWindowIndicator { throw new Error('Missing web configuration element'); } - const config: IWorkbenchConstructionOptions & { folderUri?: UriComponents, workspaceUri?: UriComponents } = { - webviewEndpoint: `${window.location.origin}${window.location.pathname.replace(/\/+$/, '')}/webview`, - ...JSON.parse(configElementAttribute), - }; - - // Strip the protocol from the authority if it exists. - const normalizeAuthority = (authority: string): string => authority.replace(/^https?:\/\//, ''); - if (config.remoteAuthority) { - (config as any).remoteAuthority = normalizeAuthority(config.remoteAuthority); - } - if (config.workspaceUri && config.workspaceUri.authority) { - config.workspaceUri.authority = normalizeAuthority(config.workspaceUri.authority); - } - if (config.folderUri && config.folderUri.authority) { - config.folderUri.authority = normalizeAuthority(config.folderUri.authority); - } + const config: IWorkbenchConstructionOptions & { folderUri?: UriComponents, workspaceUri?: UriComponents } = JSON.parse(configElementAttribute); // Find workspace to open and payload let foundWorkspace = false; let workspace: IWorkspace; - let payload = config.workspaceProvider?.payload || Object.create(null); + let payload = Object.create(null); + let logLevel: string | undefined = undefined; + + const query = new URL(document.location.href).searchParams; + query.forEach((value, key) => { + switch (key) { + + // Folder + case WorkspaceProvider.QUERY_PARAM_FOLDER: + workspace = { folderUri: URI.parse(value) }; + foundWorkspace = true; + break; + + // Workspace + case WorkspaceProvider.QUERY_PARAM_WORKSPACE: + workspace = { workspaceUri: URI.parse(value) }; + foundWorkspace = true; + break; + + // Empty + case WorkspaceProvider.QUERY_PARAM_EMPTY_WINDOW: + workspace = undefined; + foundWorkspace = true; + break; + + // Payload + case WorkspaceProvider.QUERY_PARAM_PAYLOAD: + try { + payload = JSON.parse(value); + } catch (error) { + console.error(error); // possible invalid JSON + } + break; + + // Log level + case 'logLevel': + logLevel = value; + break; + } + }); // If no workspace is provided through the URL, check for config attribute from server if (!foundWorkspace) { @@ -453,6 +471,13 @@ class WindowIndicator implements IWindowIndicator { // Workspace Provider const workspaceProvider = new WorkspaceProvider(workspace, payload); + // Home Indicator + const homeIndicator: IHomeIndicator = { + href: 'https://github.com/microsoft/vscode', + icon: 'code', + title: localize('home', "Home") + }; + // Window indicator (unless connected to a remote) let windowIndicator: WindowIndicator | undefined = undefined; if (!workspaceProvider.hasRemote()) { @@ -495,7 +520,12 @@ class WindowIndicator implements IWindowIndicator { // Finally create workbench create(document.body, { ...config, + developmentOptions: { + logLevel: logLevel ? parseLogLevel(logLevel) : undefined, + ...config.developmentOptions + }, settingsSyncOptions, + homeIndicator, windowIndicator, productQualityChangeHandler, workspaceProvider, diff --git a/lib/vscode/src/vs/code/buildfile.js b/src/vs/code/buildfile.js similarity index 100% rename from lib/vscode/src/vs/code/buildfile.js rename to src/vs/code/buildfile.js diff --git a/lib/vscode/src/vs/code/electron-browser/sharedProcess/contrib/deprecatedExtensionsCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/deprecatedExtensionsCleaner.ts similarity index 100% rename from lib/vscode/src/vs/code/electron-browser/sharedProcess/contrib/deprecatedExtensionsCleaner.ts rename to src/vs/code/electron-browser/sharedProcess/contrib/deprecatedExtensionsCleaner.ts diff --git a/lib/vscode/src/vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner.ts similarity index 93% rename from lib/vscode/src/vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner.ts rename to src/vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner.ts index 00df213a37cf..b76d76688020 100644 --- a/lib/vscode/src/vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner.ts +++ b/src/vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as fs from 'fs'; import * as path from 'vs/base/common/path'; import * as pfs from 'vs/base/node/pfs'; import { IStringDictionary } from 'vs/base/common/collections'; @@ -55,7 +54,7 @@ export class LanguagePackCachedDataCleaner extends Disposable { this._logService.info('Starting to clean up unused language packs.'); try { const installed: IStringDictionary = Object.create(null); - const metaData: LanguagePackFile = JSON.parse(await fs.promises.readFile(path.join(this._environmentService.userDataPath, 'languagepacks.json'), 'utf8')); + const metaData: LanguagePackFile = JSON.parse(await pfs.Promises.readFile(path.join(this._environmentService.userDataPath, 'languagepacks.json'), 'utf8')); for (let locale of Object.keys(metaData)) { const entry = metaData[locale]; installed[`${entry.hash}.${locale}`] = true; @@ -83,7 +82,7 @@ export class LanguagePackCachedDataCleaner extends Disposable { continue; } const candidate = path.join(folder, entry); - const stat = await fs.promises.stat(candidate); + const stat = await pfs.Promises.stat(candidate); if (stat.isDirectory()) { const diff = now - stat.mtime.getTime(); if (diff > this._DataMaxAge) { diff --git a/lib/vscode/src/vs/code/electron-browser/sharedProcess/contrib/localizationsUpdater.ts b/src/vs/code/electron-browser/sharedProcess/contrib/localizationsUpdater.ts similarity index 100% rename from lib/vscode/src/vs/code/electron-browser/sharedProcess/contrib/localizationsUpdater.ts rename to src/vs/code/electron-browser/sharedProcess/contrib/localizationsUpdater.ts diff --git a/lib/vscode/src/vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner.ts similarity index 100% rename from lib/vscode/src/vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner.ts rename to src/vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner.ts diff --git a/lib/vscode/src/vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner.ts similarity index 94% rename from lib/vscode/src/vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner.ts rename to src/vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner.ts index fdb9aa7bb40c..a6afc6976170 100644 --- a/lib/vscode/src/vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner.ts +++ b/src/vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner.ts @@ -3,11 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { promises } from 'fs'; import { basename, dirname, join } from 'vs/base/common/path'; import { onUnexpectedError } from 'vs/base/common/errors'; import { toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { readdir, rimraf } from 'vs/base/node/pfs'; +import { Promises, readdir, rimraf } from 'vs/base/node/pfs'; import { IProductService } from 'vs/platform/product/common/productService'; export class NodeCachedDataCleaner { @@ -56,7 +55,7 @@ export class NodeCachedDataCleaner { if (entry !== nodeCachedDataCurrent) { const path = join(nodeCachedDataRootDir, entry); - deletes.push(promises.stat(path).then(stats => { + deletes.push(Promises.stat(path).then(stats => { // stat check // * only directories // * only when old enough diff --git a/lib/vscode/src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts similarity index 94% rename from lib/vscode/src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts rename to src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts index fc26cb229c3c..120557549707 100644 --- a/lib/vscode/src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts +++ b/src/vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner.ts @@ -3,10 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { promises } from 'fs'; import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; import { join } from 'vs/base/common/path'; -import { readdir, rimraf } from 'vs/base/node/pfs'; +import { Promises, readdir, 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/node/backup'; @@ -33,7 +32,7 @@ export class StorageDataCleaner extends Disposable { try { // Leverage the backup workspace file to find out which empty workspace is currently in use to // determine which empty workspace storage can safely be deleted - const contents = await promises.readFile(this.backupWorkspacesPath, 'utf8'); + const contents = await Promises.readFile(this.backupWorkspacesPath, 'utf8'); const workspaces = JSON.parse(contents) as IBackupWorkspacesFormat; const emptyWorkspaces = workspaces.emptyWorkspaceInfos.map(info => info.backupFolder); diff --git a/lib/vscode/src/vs/code/electron-browser/sharedProcess/sharedProcess.html b/src/vs/code/electron-browser/sharedProcess/sharedProcess.html similarity index 100% rename from lib/vscode/src/vs/code/electron-browser/sharedProcess/sharedProcess.html rename to src/vs/code/electron-browser/sharedProcess/sharedProcess.html diff --git a/lib/vscode/src/vs/code/electron-browser/sharedProcess/sharedProcess.js b/src/vs/code/electron-browser/sharedProcess/sharedProcess.js similarity index 90% rename from lib/vscode/src/vs/code/electron-browser/sharedProcess/sharedProcess.js rename to src/vs/code/electron-browser/sharedProcess/sharedProcess.js index 6c6e3f8cf5e0..c9651466d39e 100644 --- a/lib/vscode/src/vs/code/electron-browser/sharedProcess/sharedProcess.js +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcess.js @@ -46,10 +46,7 @@ * forceEnableDeveloperKeybindings?: boolean, * disallowReloadKeybinding?: boolean, * removeDeveloperKeybindingsAfterLoad?: boolean - * }, - * canModifyDOM?: (config: ISandboxConfiguration) => void, - * beforeLoaderConfig?: (loaderConfig: object) => void, - * beforeRequire?: () => void + * } * } * ) => Promise * }} diff --git a/lib/vscode/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts similarity index 98% rename from lib/vscode/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts rename to src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 0f2a79cac7df..5b0ee538150f 100644 --- a/lib/vscode/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -77,7 +77,7 @@ import { LocalizationsUpdater } from 'vs/code/electron-browser/sharedProcess/con import { DeprecatedExtensionsCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/deprecatedExtensionsCleaner'; import { onUnexpectedError, setUnexpectedErrorHandler } from 'vs/base/common/errors'; import { toErrorMessage } from 'vs/base/common/errorMessage'; -import { TerminalIpcChannels } from 'vs/platform/terminal/common/terminal'; +import { LocalReconnectConstants, TerminalIpcChannels } from 'vs/platform/terminal/common/terminal'; import { PtyHostService } from 'vs/platform/terminal/node/ptyHostService'; import { ILocalPtyService } from 'vs/platform/terminal/electron-sandbox/terminal'; import { UserDataSyncChannel } from 'vs/platform/userDataSync/common/userDataSyncServiceIpc'; @@ -272,7 +272,19 @@ class SharedProcessMain extends Disposable { services.set(IUserDataSyncService, new SyncDescriptor(UserDataSyncService)); // Terminal - services.set(ILocalPtyService, this._register(new PtyHostService(logService, telemetryService))); + services.set( + ILocalPtyService, + this._register( + new PtyHostService({ + GraceTime: LocalReconnectConstants.GraceTime, + ShortGraceTime: LocalReconnectConstants.ShortGraceTime + }, + configurationService, + logService, + telemetryService + ) + ) + ); return new InstantiationService(services); } diff --git a/lib/vscode/src/vs/code/electron-browser/workbench/workbench.html b/src/vs/code/electron-browser/workbench/workbench.html similarity index 79% rename from lib/vscode/src/vs/code/electron-browser/workbench/workbench.html rename to src/vs/code/electron-browser/workbench/workbench.html index 2933be273644..38405e41e15b 100644 --- a/lib/vscode/src/vs/code/electron-browser/workbench/workbench.html +++ b/src/vs/code/electron-browser/workbench/workbench.html @@ -4,7 +4,7 @@ - + diff --git a/lib/vscode/src/vs/code/electron-browser/workbench/workbench.js b/src/vs/code/electron-browser/workbench/workbench.js similarity index 86% rename from lib/vscode/src/vs/code/electron-browser/workbench/workbench.js rename to src/vs/code/electron-browser/workbench/workbench.js index 6a92a3c203e0..2d6fec36d122 100644 --- a/lib/vscode/src/vs/code/electron-browser/workbench/workbench.js +++ b/src/vs/code/electron-browser/workbench/workbench.js @@ -43,7 +43,7 @@ }; }, canModifyDOM: function (windowConfig) { - showPartsSplash(windowConfig); + showSplash(windowConfig); }, beforeLoaderConfig: function (loaderConfig) { loaderConfig.recordStats = true; @@ -89,19 +89,20 @@ /** * @typedef {import('../../../platform/windows/common/windows').INativeWindowConfiguration} INativeWindowConfiguration + * @typedef {import('../../../platform/environment/common/argv').NativeParsedArgs} NativeParsedArgs * * @returns {{ * load: ( * modules: string[], - * resultCallback: (result, configuration: INativeWindowConfiguration) => unknown, + * resultCallback: (result, configuration: INativeWindowConfiguration & NativeParsedArgs) => unknown, * options?: { - * configureDeveloperSettings?: (config: INativeWindowConfiguration & object) => { + * configureDeveloperSettings?: (config: INativeWindowConfiguration & NativeParsedArgs) => { * forceDisableShowDevtoolsOnError?: boolean, * forceEnableDeveloperKeybindings?: boolean, * disallowReloadKeybinding?: boolean, * removeDeveloperKeybindingsAfterLoad?: boolean * }, - * canModifyDOM?: (config: INativeWindowConfiguration & object) => void, + * canModifyDOM?: (config: INativeWindowConfiguration & NativeParsedArgs) => void, * beforeLoaderConfig?: (loaderConfig: object) => void, * beforeRequire?: () => void * } @@ -114,28 +115,15 @@ } /** - * @param {{ - * partsSplashPath?: string, - * colorScheme: ('light' | 'dark' | 'hc'), - * autoDetectHighContrast?: boolean, - * extensionDevelopmentPath?: string[], - * workspace?: import('../../../platform/workspaces/common/workspaces').IWorkspaceIdentifier | import('../../../platform/workspaces/common/workspaces').ISingleFolderWorkspaceIdentifier - * }} configuration + * @param {INativeWindowConfiguration & NativeParsedArgs} configuration */ - function showPartsSplash(configuration) { + function showSplash(configuration) { performance.mark('code/willShowPartsSplash'); - let data; - if (typeof configuration.partsSplashPath === 'string') { - try { - data = JSON.parse(require.__$__nodeRequire('fs').readFileSync(configuration.partsSplashPath, 'utf8')); - } catch (e) { - // ignore - } - } + let data = configuration.partsSplash; // high contrast mode has been turned on from the outside, e.g. OS -> ignore stored colors and layouts - const isHighContrast = configuration.colorScheme === 'hc' /* ColorScheme.HIGH_CONTRAST */ && configuration.autoDetectHighContrast; + const isHighContrast = configuration.colorScheme.highContrast && configuration.autoDetectHighContrast; if (data && isHighContrast && data.baseTheme !== 'hc-black') { data = undefined; } @@ -160,16 +148,18 @@ shellBackground = '#1E1E1E'; shellForeground = '#CCCCCC'; } + const style = document.createElement('style'); style.className = 'initialShellColors'; document.head.appendChild(style); style.textContent = `body { background-color: ${shellBackground}; color: ${shellForeground}; margin: 0; padding: 0; }`; - if (data && data.layoutInfo) { - // restore parts if possible (we might not always store layout info) - const { id, layoutInfo, colorInfo } = data; + // restore parts if possible (we might not always store layout info) + if (data?.layoutInfo) { + const { layoutInfo, colorInfo } = data; + const splash = document.createElement('div'); - splash.id = id; + splash.id = 'monaco-parts-splash'; splash.className = baseTheme; if (layoutInfo.windowBorder) { @@ -198,8 +188,8 @@ splash.appendChild(activityDiv); // part: side bar (only when opening workspace/folder) + // folder or workspace -> status bar color, sidebar if (configuration.workspace) { - // folder or workspace -> status bar color, sidebar const sideDiv = document.createElement('div'); sideDiv.setAttribute('style', `position: absolute; height: calc(100% - ${layoutInfo.titleBarHeight}px); top: ${layoutInfo.titleBarHeight}px; ${layoutInfo.sideBarSide}: ${layoutInfo.activityBarWidth}px; width: ${layoutInfo.sideBarWidth}px; background-color: ${colorInfo.sideBarBackground};`); splash.appendChild(sideDiv); diff --git a/lib/vscode/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts similarity index 93% rename from lib/vscode/src/vs/code/electron-main/app.ts rename to src/vs/code/electron-main/app.ts index 28fc931cd21f..630c577a6403 100644 --- a/lib/vscode/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -23,7 +23,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ILoggerService, ILogService } from 'vs/platform/log/common/log'; -import { IStateService } from 'vs/platform/state/node/state'; +import { IStateMainService } from 'vs/platform/state/electron-main/state'; import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IOpenURLOptions, IURLService } from 'vs/platform/url/common/url'; @@ -81,12 +81,14 @@ import { IKeyboardLayoutMainService, KeyboardLayoutMainService } from 'vs/platfo import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { isLaunchedFromCli } from 'vs/platform/environment/node/argvHelper'; import { isEqualOrParent } from 'vs/base/common/extpath'; -import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; +import { RunOnceScheduler } from 'vs/base/common/async'; import { IExtensionUrlTrustService } from 'vs/platform/extensionManagement/common/extensionUrlTrust'; import { ExtensionUrlTrustService } from 'vs/platform/extensionManagement/node/extensionUrlTrustService'; import { once } from 'vs/base/common/functional'; import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts'; import { ISignService } from 'vs/platform/sign/common/sign'; +import { IExternalTerminalMainService } from 'vs/platform/externalTerminal/common/externalTerminal'; +import { LinuxExternalTerminalService, MacExternalTerminalService, WindowsExternalTerminalService } from 'vs/platform/externalTerminal/node/externalTerminalService'; /** * The main VS Code application. There will only ever be one instance, @@ -105,7 +107,7 @@ export class CodeApplication extends Disposable { @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService, @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IStateService private readonly stateService: IStateService, + @IStateMainService private readonly stateMainService: IStateMainService, @IFileService private readonly fileService: IFileService, @IProductService private readonly productService: IProductService ) { @@ -247,7 +249,7 @@ export class CodeApplication extends Disposable { //#endregion let macOpenFileURIs: IWindowOpenable[] = []; - let runningTimeout: NodeJS.Timeout | null = null; + let runningTimeout: NodeJS.Timeout | undefined = undefined; app.on('open-file', (event, path) => { this.logService.trace('app#open-file: ', path); event.preventDefault(); @@ -256,9 +258,9 @@ export class CodeApplication extends Disposable { macOpenFileURIs.push(this.getWindowOpenableFromPathSync(path)); // Clear previous handler if any - if (runningTimeout !== null) { + if (runningTimeout !== undefined) { clearTimeout(runningTimeout); - runningTimeout = null; + runningTimeout = undefined; } // Handle paths delayed in case more are coming! @@ -272,7 +274,7 @@ export class CodeApplication extends Disposable { }); macOpenFileURIs = []; - runningTimeout = null; + runningTimeout = undefined; }, 100); }); @@ -282,71 +284,29 @@ export class CodeApplication extends Disposable { //#region Bootstrap IPC Handlers - let slowShellResolveWarningShown = false; ipcMain.handle('vscode:fetchShellEnv', event => { - return new Promise(async resolve => { - // DO NOT remove: not only usual windows are fetching the - // shell environment but also shared process, issue reporter - // etc, so we need to reply via `webContents` always - const webContents = event.sender; - - let replied = false; - - function acceptShellEnv(env: IProcessEnvironment): void { - clearTimeout(shellEnvSlowWarningHandle); - clearTimeout(shellEnvTimeoutErrorHandle); - - if (!replied) { - replied = true; - - if (!webContents.isDestroyed()) { - resolve(env); - } - } - } - - // Handle slow shell environment resolve calls: - // - a warning after 3s but continue to resolve (only once in active window) - // - an error after 10s and stop trying to resolve (in every window where this happens) - const cts = new CancellationTokenSource(); - - const shellEnvSlowWarningHandle = setTimeout(() => { - if (!slowShellResolveWarningShown) { - this.windowsMainService?.sendToFocused('vscode:showShellEnvSlowWarning', cts.token); - slowShellResolveWarningShown = true; - } - }, 3000); - - const window = this.windowsMainService?.getWindowByWebContents(event.sender); // Note: this can be `undefined` for the shared process!! - const shellEnvTimeoutErrorHandle = setTimeout(() => { - cts.dispose(true); - window?.sendWhenReady('vscode:showShellEnvTimeoutError', CancellationToken.None); - acceptShellEnv({}); - }, 10000); - - // Prefer to use the args and env from the target window - // when resolving the shell env. It is possible that - // a first window was opened from the UI but a second - // from the CLI and that has implications for whether to - // resolve the shell environment or not. - // - // Window can be undefined for e.g. the shared process - // that is not part of our windows registry! - let args: NativeParsedArgs; - let env: IProcessEnvironment; - if (window?.config) { - args = window.config; - env = { ...process.env, ...window.config.userEnv }; - } else { - args = this.environmentMainService.args; - env = process.env; - } + // Prefer to use the args and env from the target window + // when resolving the shell env. It is possible that + // a first window was opened from the UI but a second + // from the CLI and that has implications for whether to + // resolve the shell environment or not. + // + // Window can be undefined for e.g. the shared process + // that is not part of our windows registry! + const window = this.windowsMainService?.getWindowByWebContents(event.sender); // Note: this can be `undefined` for the shared process + let args: NativeParsedArgs; + let env: IProcessEnvironment; + if (window?.config) { + args = window.config; + env = { ...process.env, ...window.config.userEnv }; + } else { + args = this.environmentMainService.args; + env = process.env; + } - // Resolve shell env - const shellEnv = await resolveShellEnv(this.logService, args, env); - acceptShellEnv(shellEnv); - }); + // Resolve shell env + return resolveShellEnv(this.logService, args, env); }); ipcMain.handle('vscode:writeNlsFile', (event, path: unknown, data: unknown) => { @@ -498,11 +458,11 @@ export class CodeApplication extends Disposable { // We cache the machineId for faster lookups on startup // and resolve it only once initially if not cached or we need to replace the macOS iBridge device - let machineId = this.stateService.getItem(machineIdKey); + let machineId = this.stateMainService.getItem(machineIdKey); if (!machineId || (isMacintosh && machineId === '6c9d2bc8f91b89624add29c0abeae7fb42bf539fa1cdb2e3e57cd668fa9bcead')) { machineId = await getMachineId(); - this.stateService.setItem(machineIdKey, machineId); + this.stateMainService.setItem(machineIdKey, machineId); } return machineId; @@ -593,6 +553,15 @@ export class CodeApplication extends Disposable { // Storage services.set(IStorageMainService, new SyncDescriptor(StorageMainService)); + // External terminal + if (isWindows) { + services.set(IExternalTerminalMainService, new SyncDescriptor(WindowsExternalTerminalService)); + } else if (isMacintosh) { + services.set(IExternalTerminalMainService, new SyncDescriptor(MacExternalTerminalService)); + } else if (isLinux) { + services.set(IExternalTerminalMainService, new SyncDescriptor(LinuxExternalTerminalService)); + } + // Backups const backupMainService = new BackupMainService(this.environmentMainService, this.configurationService, this.logService); services.set(IBackupMainService, backupMainService); @@ -679,6 +648,10 @@ export class CodeApplication extends Disposable { mainProcessElectronServer.registerChannel('storage', storageChannel); sharedProcessClient.then(client => client.registerChannel('storage', storageChannel)); + // External Terminal + const externalTerminalChannel = ProxyChannel.fromService(accessor.get(IExternalTerminalMainService)); + mainProcessElectronServer.registerChannel('externalTerminal', externalTerminalChannel); + // Log Level (main & shared process) const logLevelChannel = new LogLevelChannel(accessor.get(ILogService)); mainProcessElectronServer.registerChannel('logLevel', logLevelChannel); @@ -744,8 +717,16 @@ export class CodeApplication extends Disposable { // protocol invocations outside of VSCode. const app = this; const environmentService = this.environmentMainService; + const productService = this.productService; urlService.registerHandler({ async handleURL(uri: URI, options?: IOpenURLOptions): Promise { + if (uri.scheme === productService.urlProtocol && uri.path === 'workspace') { + uri = uri.with({ + authority: 'file', + path: URI.parse(uri.query).path, + query: '' + }); + } // If URI should be blocked, behave as if it's handled if (app.shouldBlockURI(uri)) { @@ -960,7 +941,7 @@ export class CodeApplication extends Disposable { if (typeof details === 'string') { message = details; } else { - message = `SharedProcess: crashed (detail: ${details.reason})`; + message = `SharedProcess: crashed (detail: ${details.reason}, code: ${details.exitCode})`; } onUnexpectedError(new Error(message)); @@ -1012,7 +993,16 @@ export class CodeApplication extends Disposable { } // Start to fetch shell environment (if needed) after window has opened - resolveShellEnv(this.logService, this.environmentMainService.args, process.env); + // Since this operation can take a long time, we want to warm it up while + // the window is opening. + // We also print a warning if the resolution takes longer than 10s. + (async () => { + const slowResolveShellEnvWarning = this._register(new RunOnceScheduler(() => this.logService.warn('Resolving your shell environment is taking more than 10s. Please review your shell configuration. Learn more at https://go.microsoft.com/fwlink/?linkid=2149667.'), 10000)); + slowResolveShellEnvWarning.schedule(); + + await resolveShellEnv(this.logService, this.environmentMainService.args, process.env); + slowResolveShellEnvWarning.dispose(); + })(); // If enable-crash-reporter argv is undefined then this is a fresh start, // based on telemetry.enableCrashreporter settings, generate a UUID which diff --git a/lib/vscode/src/vs/code/electron-main/auth.ts b/src/vs/code/electron-main/auth.ts similarity index 100% rename from lib/vscode/src/vs/code/electron-main/auth.ts rename to src/vs/code/electron-main/auth.ts diff --git a/lib/vscode/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts similarity index 91% rename from lib/vscode/src/vs/code/electron-main/main.ts rename to src/vs/code/electron-main/main.ts index b4650d50702c..8c9be0c67f0c 100644 --- a/lib/vscode/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -5,7 +5,8 @@ import 'vs/platform/update/common/update.config.contribution'; import { app, dialog } from 'electron'; -import { promises, unlinkSync } from 'fs'; +import { unlinkSync } from 'fs'; +import { Promises as FSPromises } from 'vs/base/node/pfs'; import { localize } from 'vs/nls'; import { isWindows, IProcessEnvironment, isMacintosh } from 'vs/base/common/platform'; import { mark } from 'vs/base/common/performance'; @@ -22,8 +23,8 @@ import { InstantiationService } from 'vs/platform/instantiation/common/instantia import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ILogService, ConsoleMainLogger, MultiplexLogService, getLogLevel, ILoggerService } from 'vs/platform/log/common/log'; -import { StateService } from 'vs/platform/state/node/stateService'; -import { IStateService } from 'vs/platform/state/node/state'; +import { StateMainService } from 'vs/platform/state/electron-main/stateMainService'; +import { IStateMainService } from 'vs/platform/state/electron-main/state'; import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ConfigurationService } from 'vs/platform/configuration/common/configurationService'; @@ -57,6 +58,7 @@ import { LoggerService } from 'vs/platform/log/node/loggerService'; import { cwd } from 'vs/base/common/process'; import { IProtocolMainService } from 'vs/platform/protocol/electron-main/protocol'; import { ProtocolMainService } from 'vs/platform/protocol/electron-main/protocolMainService'; +import { Promises } from 'vs/base/common/async'; /** * The main VS Code entry point. @@ -84,17 +86,17 @@ class CodeMain { setUnexpectedErrorHandler(err => console.error(err)); // Create services - const [instantiationService, instanceEnvironment, environmentService, configurationService, stateService, bufferLogService, productService] = this.createServices(); + const [instantiationService, instanceEnvironment, environmentMainService, configurationService, stateMainService, bufferLogService, productService] = this.createServices(); try { // Init services try { - await this.initServices(environmentService, configurationService, stateService); + await this.initServices(environmentMainService, configurationService, stateMainService); } catch (error) { // Show a dialog for errors that can be resolved by the user - this.handleStartupDataDirError(environmentService, productService.nameLong, error); + this.handleStartupDataDirError(environmentMainService, productService.nameLong, error); throw error; } @@ -108,10 +110,10 @@ class CodeMain { // Create the main IPC server by trying to be the server // If this throws an error it means we are not the first // instance of VS Code running and so we would quit. - const mainProcessNodeIpcServer = await this.claimInstance(logService, environmentService, lifecycleMainService, instantiationService, productService, true); + const mainProcessNodeIpcServer = await this.claimInstance(logService, environmentMainService, lifecycleMainService, instantiationService, productService, true); // Delay creation of spdlog for perf reasons (https://github.com/microsoft/vscode/issues/72906) - bufferLogService.logger = new SpdLogLogger('main', join(environmentService.logsPath, 'main.log'), true, bufferLogService.getLevel()); + bufferLogService.logger = new SpdLogLogger('main', join(environmentMainService.logsPath, 'main.log'), true, bufferLogService.getLevel()); // Lifecycle once(lifecycleMainService.onWillShutdown)(() => { @@ -126,7 +128,7 @@ class CodeMain { } } - private createServices(): [IInstantiationService, IProcessEnvironment, IEnvironmentMainService, ConfigurationService, StateService, BufferLogService, IProductService] { + private createServices(): [IInstantiationService, IProcessEnvironment, IEnvironmentMainService, ConfigurationService, StateMainService, BufferLogService, IProductService] { const services = new ServiceCollection(); // Product @@ -163,8 +165,8 @@ class CodeMain { services.set(ILifecycleMainService, new SyncDescriptor(LifecycleMainService)); // State - const stateService = new StateService(environmentMainService, logService); - services.set(IStateService, stateService); + const stateMainService = new StateMainService(environmentMainService, logService, fileService); + services.set(IStateMainService, stateMainService); // Request services.set(IRequestService, new SyncDescriptor(RequestMainService)); @@ -181,7 +183,7 @@ class CodeMain { // Protocol services.set(IProtocolMainService, new SyncDescriptor(ProtocolMainService)); - return [new InstantiationService(services, true), instanceEnvironment, environmentMainService, configurationService, stateService, bufferLogService, productService]; + return [new InstantiationService(services, true), instanceEnvironment, environmentMainService, configurationService, stateMainService, bufferLogService, productService]; } private patchEnvironment(environmentMainService: IEnvironmentMainService): IProcessEnvironment { @@ -201,25 +203,25 @@ class CodeMain { return instanceEnvironment; } - private initServices(environmentMainService: IEnvironmentMainService, configurationService: ConfigurationService, stateService: StateService): Promise { - - // Environment service (paths) - const environmentServiceInitialization = Promise.all([ - environmentMainService.extensionsPath, - environmentMainService.nodeCachedDataDir, - environmentMainService.logsPath, - environmentMainService.globalStorageHome.fsPath, - environmentMainService.workspaceStorageHome.fsPath, - environmentMainService.backupHome - ].map(path => path ? promises.mkdir(path, { recursive: true }) : undefined)); - - // Configuration service - const configurationServiceInitialization = configurationService.initialize(); - - // State service - const stateServiceInitialization = stateService.init(); - - return Promise.all([environmentServiceInitialization, configurationServiceInitialization, stateServiceInitialization]); + private initServices(environmentMainService: IEnvironmentMainService, configurationService: ConfigurationService, stateMainService: StateMainService): Promise { + return Promises.settled([ + + // Environment service (paths) + Promise.all([ + environmentMainService.extensionsPath, + environmentMainService.nodeCachedDataDir, + environmentMainService.logsPath, + environmentMainService.globalStorageHome.fsPath, + environmentMainService.workspaceStorageHome.fsPath, + environmentMainService.backupHome + ].map(path => path ? FSPromises.mkdir(path, { recursive: true }) : undefined)), + + // Configuration service + configurationService.initialize(), + + // State service + stateMainService.init() + ]); } private async claimInstance(logService: ILogService, environmentMainService: IEnvironmentMainService, lifecycleMainService: ILifecycleMainService, instantiationService: IInstantiationService, productService: IProductService, retry: boolean): Promise { diff --git a/lib/vscode/src/vs/code/electron-sandbox/issue/issueReporter.html b/src/vs/code/electron-sandbox/issue/issueReporter.html similarity index 100% rename from lib/vscode/src/vs/code/electron-sandbox/issue/issueReporter.html rename to src/vs/code/electron-sandbox/issue/issueReporter.html diff --git a/lib/vscode/src/vs/code/electron-sandbox/issue/issueReporter.js b/src/vs/code/electron-sandbox/issue/issueReporter.js similarity index 89% rename from lib/vscode/src/vs/code/electron-sandbox/issue/issueReporter.js rename to src/vs/code/electron-sandbox/issue/issueReporter.js index caa0b29f95b3..b486c703057b 100644 --- a/lib/vscode/src/vs/code/electron-sandbox/issue/issueReporter.js +++ b/src/vs/code/electron-sandbox/issue/issueReporter.js @@ -35,10 +35,7 @@ * forceEnableDeveloperKeybindings?: boolean, * disallowReloadKeybinding?: boolean, * removeDeveloperKeybindingsAfterLoad?: boolean - * }, - * canModifyDOM?: (config: ISandboxConfiguration) => void, - * beforeLoaderConfig?: (loaderConfig: object) => void, - * beforeRequire?: () => void + * } * } * ) => Promise * }} diff --git a/lib/vscode/src/vs/code/electron-sandbox/issue/issueReporterMain.ts b/src/vs/code/electron-sandbox/issue/issueReporterMain.ts similarity index 98% rename from lib/vscode/src/vs/code/electron-sandbox/issue/issueReporterMain.ts rename to src/vs/code/electron-sandbox/issue/issueReporterMain.ts index ad1abc732a4e..26c871d3449b 100644 --- a/lib/vscode/src/vs/code/electron-sandbox/issue/issueReporterMain.ts +++ b/src/vs/code/electron-sandbox/issue/issueReporterMain.ts @@ -11,6 +11,7 @@ import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals'; import { applyZoom, zoomIn, zoomOut } from 'vs/platform/windows/electron-sandbox/window'; import { $, reset, safeInnerHtml, windowOpenNoOpener } from 'vs/base/browser/dom'; import { Button } from 'vs/base/browser/ui/button/button'; +import { Delayer } from 'vs/base/common/async'; import { groupBy } from 'vs/base/common/collections'; import { debounce } from 'vs/base/common/decorators'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -62,6 +63,7 @@ export class IssueReporter extends Disposable { private receivedPerformanceInfo = false; private shouldQueueSearch = false; private hasBeenSubmitted = false; + private delayedSubmit = new Delayer(300); private readonly previewButton!: Button; @@ -85,6 +87,7 @@ export class IssueReporter extends Disposable { const issueReporterElement = this.getElementById('issue-reporter'); if (issueReporterElement) { this.previewButton = new Button(issueReporterElement); + this.updatePreviewButtonState(); } const issueTitle = configuration.data.issueTitle; @@ -137,6 +140,7 @@ export class IssueReporter extends Disposable { this.applyStyles(configuration.data.styles); this.handleExtensionData(configuration.data.enabledExtensions); this.updateExperimentsInfo(configuration.data.experiments); + this.updateRestrictedMode(configuration.data.restrictedMode); } render(): void { @@ -355,7 +359,11 @@ export class IssueReporter extends Disposable { this.searchIssues(title, fileOnExtension, fileOnMarketplace); }); - this.previewButton.onDidClick(() => this.createIssue()); + this.previewButton.onDidClick(async () => { + this.delayedSubmit.trigger(async () => { + this.createIssue(); + }); + }); function sendWorkbenchCommand(commandId: string) { ipcRenderer.send('vscode:workbenchCommand', { id: commandId, from: 'issueReporter' }); @@ -382,9 +390,11 @@ export class IssueReporter extends Disposable { const cmdOrCtrlKey = isMacintosh ? e.metaKey : e.ctrlKey; // Cmd/Ctrl+Enter previews issue and closes window if (cmdOrCtrlKey && e.keyCode === 13) { - if (await this.createIssue()) { - ipcRenderer.send('vscode:closeIssueReporter'); - } + this.delayedSubmit.trigger(async () => { + if (await this.createIssue()) { + ipcRenderer.send('vscode:closeIssueReporter'); + } + }); } // Cmd/Ctrl + w closes issue window @@ -1150,6 +1160,10 @@ export class IssueReporter extends Disposable { } } + private updateRestrictedMode(restrictedMode: boolean) { + this.issueReporterModel.update({ restrictedMode }); + } + private updateExperimentsInfo(experimentInfo: string | undefined) { this.issueReporterModel.update({ experimentInfo }); const target = document.querySelector('.block-experiments .block-info'); diff --git a/lib/vscode/src/vs/code/electron-sandbox/issue/issueReporterModel.ts b/src/vs/code/electron-sandbox/issue/issueReporterModel.ts similarity index 98% rename from lib/vscode/src/vs/code/electron-sandbox/issue/issueReporterModel.ts rename to src/vs/code/electron-sandbox/issue/issueReporterModel.ts index 04a8ac509e53..63de037bc44b 100644 --- a/lib/vscode/src/vs/code/electron-sandbox/issue/issueReporterModel.ts +++ b/src/vs/code/electron-sandbox/issue/issueReporterModel.ts @@ -32,6 +32,7 @@ export interface IssueReporterData { query?: string; filterResultCount?: number; experimentInfo?: string; + restrictedMode?: boolean; } export class IssueReporterModel { @@ -67,6 +68,7 @@ ${this._data.issueDescription} ${this.getExtensionVersion()} VS Code version: ${this._data.versionInfo && this._data.versionInfo.vscodeVersion} OS version: ${this._data.versionInfo && this._data.versionInfo.os} +Restricted Mode: ${this._data.restrictedMode ? 'Yes' : 'No'} ${this.getRemoteOSes()} ${this.getInfos()} `; diff --git a/lib/vscode/src/vs/code/electron-sandbox/issue/issueReporterPage.ts b/src/vs/code/electron-sandbox/issue/issueReporterPage.ts similarity index 100% rename from lib/vscode/src/vs/code/electron-sandbox/issue/issueReporterPage.ts rename to src/vs/code/electron-sandbox/issue/issueReporterPage.ts diff --git a/lib/vscode/src/vs/code/electron-sandbox/issue/media/issueReporter.css b/src/vs/code/electron-sandbox/issue/media/issueReporter.css similarity index 100% rename from lib/vscode/src/vs/code/electron-sandbox/issue/media/issueReporter.css rename to src/vs/code/electron-sandbox/issue/media/issueReporter.css diff --git a/lib/vscode/src/vs/code/electron-sandbox/issue/test/testReporterModel.test.ts b/src/vs/code/electron-sandbox/issue/test/testReporterModel.test.ts similarity index 98% rename from lib/vscode/src/vs/code/electron-sandbox/issue/test/testReporterModel.test.ts rename to src/vs/code/electron-sandbox/issue/test/testReporterModel.test.ts index 769fcd02ac8b..5e8cfb05f6e3 100644 --- a/lib/vscode/src/vs/code/electron-sandbox/issue/test/testReporterModel.test.ts +++ b/src/vs/code/electron-sandbox/issue/test/testReporterModel.test.ts @@ -33,6 +33,7 @@ undefined VS Code version: undefined OS version: undefined +Restricted Mode: No Extensions: none `); @@ -63,6 +64,7 @@ undefined VS Code version: undefined OS version: undefined +Restricted Mode: No
    System Info @@ -106,6 +108,7 @@ undefined VS Code version: undefined OS version: undefined +Restricted Mode: No
    System Info @@ -160,6 +163,7 @@ undefined VS Code version: undefined OS version: undefined +Restricted Mode: No
    System Info @@ -216,6 +220,7 @@ undefined VS Code version: undefined OS version: undefined +Restricted Mode: No Remote OS version: Linux x64 4.18.0
    @@ -264,6 +269,7 @@ undefined VS Code version: undefined OS version: undefined +Restricted Mode: No
    System Info diff --git a/lib/vscode/src/vs/code/electron-sandbox/processExplorer/media/processExplorer.css b/src/vs/code/electron-sandbox/processExplorer/media/processExplorer.css similarity index 98% rename from lib/vscode/src/vs/code/electron-sandbox/processExplorer/media/processExplorer.css rename to src/vs/code/electron-sandbox/processExplorer/media/processExplorer.css index 095663c05d02..0129b721f773 100644 --- a/lib/vscode/src/vs/code/electron-sandbox/processExplorer/media/processExplorer.css +++ b/src/vs/code/electron-sandbox/processExplorer/media/processExplorer.css @@ -49,6 +49,10 @@ body { width: 90px; } +.monaco-list:focus { + outline: 0; +} + .monaco-list-row:first-of-type { border-bottom: 1px solid; } diff --git a/lib/vscode/src/vs/code/electron-sandbox/processExplorer/processExplorer.html b/src/vs/code/electron-sandbox/processExplorer/processExplorer.html similarity index 100% rename from lib/vscode/src/vs/code/electron-sandbox/processExplorer/processExplorer.html rename to src/vs/code/electron-sandbox/processExplorer/processExplorer.html diff --git a/lib/vscode/src/vs/code/electron-sandbox/processExplorer/processExplorer.js b/src/vs/code/electron-sandbox/processExplorer/processExplorer.js similarity index 89% rename from lib/vscode/src/vs/code/electron-sandbox/processExplorer/processExplorer.js rename to src/vs/code/electron-sandbox/processExplorer/processExplorer.js index 7aeb6f35d806..8234b734d06c 100644 --- a/lib/vscode/src/vs/code/electron-sandbox/processExplorer/processExplorer.js +++ b/src/vs/code/electron-sandbox/processExplorer/processExplorer.js @@ -32,10 +32,7 @@ * forceEnableDeveloperKeybindings?: boolean, * disallowReloadKeybinding?: boolean, * removeDeveloperKeybindingsAfterLoad?: boolean - * }, - * canModifyDOM?: (config: ISandboxConfiguration) => void, - * beforeLoaderConfig?: (loaderConfig: object) => void, - * beforeRequire?: () => void + * } * } * ) => Promise * }} diff --git a/lib/vscode/src/vs/code/electron-sandbox/processExplorer/processExplorerMain.ts b/src/vs/code/electron-sandbox/processExplorer/processExplorerMain.ts similarity index 86% rename from lib/vscode/src/vs/code/electron-sandbox/processExplorer/processExplorerMain.ts rename to src/vs/code/electron-sandbox/processExplorer/processExplorerMain.ts index 546c167d93b0..3c2e84a386ad 100644 --- a/lib/vscode/src/vs/code/electron-sandbox/processExplorer/processExplorerMain.ts +++ b/src/vs/code/electron-sandbox/processExplorer/processExplorerMain.ts @@ -14,13 +14,15 @@ import { applyZoom, zoomIn, zoomOut } from 'vs/platform/windows/electron-sandbox import { IContextMenuItem } from 'vs/base/parts/contextmenu/common/contextmenu'; import { popup } from 'vs/base/parts/contextmenu/electron-sandbox/contextmenu'; import { ProcessItem } from 'vs/base/common/processes'; -import { append, $ } from 'vs/base/browser/dom'; +import { append, $, createStyleSheet } from 'vs/base/browser/dom'; import { isRemoteDiagnosticError, IRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics'; import { ElectronIPCMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService'; import { ByteSize } from 'vs/platform/files/common/files'; import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { IDataSource, ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree'; import { DataTree } from 'vs/base/browser/ui/tree/dataTree'; +import { getIconsStyleSheet } from 'vs/platform/theme/browser/iconsStyleSheet'; +import { RunOnceScheduler } from 'vs/base/common/async'; const DEBUG_FLAGS_PATTERN = /\s--(inspect|debug)(-brk|port)?=(\d+)?/; const DEBUG_PORT_PATTERN = /\s--(inspect|debug)-port=(\d+)/; @@ -310,8 +312,7 @@ class ProcessExplorer { renderers, new ProcessTreeDataSource(), { - identityProvider: - { + identityProvider: { getId: (element: ProcessTree | ProcessItem | MachineProcessInformation | ProcessInformation | IRemoteDiagnosticError) => { if (isProcessItem(element)) { return element.pid.toString(); @@ -331,7 +332,7 @@ class ProcessExplorer { return 'header'; } - } + }, }); this.tree.setInput({ processes: { processRoots } }); @@ -378,21 +379,45 @@ class ProcessExplorer { } private applyStyles(styles: ProcessExplorerStyles): void { - const styleTag = document.createElement('style'); + const styleElement = createStyleSheet(); const content: string[] = []; - if (styles.hoverBackground) { - content.push(`.monaco-list-row:hover { background-color: ${styles.hoverBackground}; }`); + if (styles.listFocusBackground) { + content.push(`.monaco-list:focus .monaco-list-row.focused { background-color: ${styles.listFocusBackground}; }`); + content.push(`.monaco-list:focus .monaco-list-row.focused:hover { background-color: ${styles.listFocusBackground}; }`); + } + + if (styles.listFocusForeground) { + content.push(`.monaco-list:focus .monaco-list-row.focused { color: ${styles.listFocusForeground}; }`); + } + + if (styles.listActiveSelectionBackground) { + content.push(`.monaco-list:focus .monaco-list-row.selected { background-color: ${styles.listActiveSelectionBackground}; }`); + content.push(`.monaco-list:focus .monaco-list-row.selected:hover { background-color: ${styles.listActiveSelectionBackground}; }`); + } + + if (styles.listActiveSelectionForeground) { + content.push(`.monaco-list:focus .monaco-list-row.selected { color: ${styles.listActiveSelectionForeground}; }`); + } + + if (styles.listHoverBackground) { + content.push(`.monaco-list-row:hover:not(.selected):not(.focused) { background-color: ${styles.listHoverBackground}; }`); } - if (styles.hoverForeground) { - content.push(`.monaco-list-row:hover { color: ${styles.hoverForeground}; }`); + if (styles.listHoverForeground) { + content.push(`.monaco-list-row:hover:not(.selected):not(.focused) { color: ${styles.listHoverForeground}; }`); } - styleTag.textContent = content.join('\n'); - if (document.head) { - document.head.appendChild(styleTag); + if (styles.listFocusOutline) { + content.push(`.monaco-list:focus .monaco-list-row.focused { outline: 1px solid ${styles.listFocusOutline}; outline-offset: -1px; }`); } + + if (styles.listHoverOutline) { + content.push(`.monaco-list-row:hover { outline: 1px dashed ${styles.listHoverOutline}; outline-offset: -1px; }`); + } + + styleElement.textContent = content.join('\n'); + if (styles.color) { document.body.style.color = styles.color; } @@ -475,9 +500,24 @@ class ProcessExplorer { } } +function createCodiconStyleSheet() { + const codiconStyleSheet = createStyleSheet(); + codiconStyleSheet.id = 'codiconStyles'; + + const iconsStyleSheet = getIconsStyleSheet(); + function updateAll() { + codiconStyleSheet.textContent = iconsStyleSheet.getCSS(); + } + + const delayer = new RunOnceScheduler(updateAll, 0); + iconsStyleSheet.onDidChange(() => delayer.schedule()); + delayer.schedule(); +} + export function startup(configuration: ProcessExplorerWindowConfiguration): void { const platformClass = configuration.data.platform === 'win32' ? 'windows' : configuration.data.platform === 'linux' ? 'linux' : 'mac'; document.body.classList.add(platformClass); // used by our fonts + createCodiconStyleSheet(); applyZoom(configuration.data.zoomLevel); new ProcessExplorer(configuration.windowId, configuration.data); diff --git a/lib/vscode/src/vs/code/electron-sandbox/workbench/workbench.html b/src/vs/code/electron-sandbox/workbench/workbench.html similarity index 79% rename from lib/vscode/src/vs/code/electron-sandbox/workbench/workbench.html rename to src/vs/code/electron-sandbox/workbench/workbench.html index 2933be273644..38405e41e15b 100644 --- a/lib/vscode/src/vs/code/electron-sandbox/workbench/workbench.html +++ b/src/vs/code/electron-sandbox/workbench/workbench.html @@ -4,7 +4,7 @@ - + diff --git a/src/vs/code/electron-sandbox/workbench/workbench.js b/src/vs/code/electron-sandbox/workbench/workbench.js new file mode 100644 index 000000000000..c42f3aadbfbc --- /dev/null +++ b/src/vs/code/electron-sandbox/workbench/workbench.js @@ -0,0 +1,210 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/// + +//@ts-check +(function () { + 'use strict'; + + const bootstrapWindow = bootstrapWindowLib(); + + // Add a perf entry right from the top + performance.mark('code/didStartRenderer'); + + // Load workbench main JS, CSS and NLS all in parallel. This is an + // optimization to prevent a waterfall of loading to happen, because + // we know for a fact that workbench.desktop.sandbox.main will depend on + // the related CSS and NLS counterparts. + bootstrapWindow.load([ + 'vs/workbench/workbench.desktop.sandbox.main', + 'vs/nls!vs/workbench/workbench.desktop.main', + 'vs/css!vs/workbench/workbench.desktop.main' + ], + function (_, configuration) { + + // Mark start of workbench + performance.mark('code/didLoadWorkbenchMain'); + + // @ts-ignore + return require('vs/workbench/electron-sandbox/desktop.main').main(configuration); + }, + { + configureDeveloperSettings: function (windowConfig) { + return { + // disable automated devtools opening on error when running extension tests + // as this can lead to undeterministic test exectuion (devtools steals focus) + forceDisableShowDevtoolsOnError: typeof windowConfig.extensionTestsPath === 'string', + // enable devtools keybindings in extension development window + forceEnableDeveloperKeybindings: Array.isArray(windowConfig.extensionDevelopmentPath) && windowConfig.extensionDevelopmentPath.length > 0, + removeDeveloperKeybindingsAfterLoad: true + }; + }, + canModifyDOM: function (windowConfig) { + showSplash(windowConfig); + }, + beforeLoaderConfig: function (loaderConfig) { + loaderConfig.recordStats = true; + }, + beforeRequire: function () { + performance.mark('code/willLoadWorkbenchMain'); + + // It looks like browsers only lazily enable + // the element when needed. Since we + // leverage canvas elements in our code in many + // locations, we try to help the browser to + // initialize canvas when it is idle, right + // before we wait for the scripts to be loaded. + // @ts-ignore + window.requestIdleCallback(() => { + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + context.clearRect(0, 0, canvas.width, canvas.height); + canvas.remove(); + }, { timeout: 50 }); + } + } + ); + + // add default trustedTypes-policy for logging and to workaround + // lib/platform limitations + window.trustedTypes?.createPolicy('default', { + createHTML(value) { + // see https://github.com/electron/electron/issues/27211 + // Electron webviews use a static innerHTML default value and + // that isn't trusted. We use a default policy to check for the + // exact value of that innerHTML-string and only allow that. + if (value === '') { + return value; + } + throw new Error('UNTRUSTED html usage, default trusted types policy should NEVER be reached'); + // console.trace('UNTRUSTED html usage, default trusted types policy should NEVER be reached'); + // return value; + } + }); + + //#region Helpers + + /** + * @typedef {import('../../../platform/windows/common/windows').INativeWindowConfiguration} INativeWindowConfiguration + * @typedef {import('../../../platform/environment/common/argv').NativeParsedArgs} NativeParsedArgs + * + * @returns {{ + * load: ( + * modules: string[], + * resultCallback: (result, configuration: INativeWindowConfiguration & NativeParsedArgs) => unknown, + * options?: { + * configureDeveloperSettings?: (config: INativeWindowConfiguration & NativeParsedArgs) => { + * forceDisableShowDevtoolsOnError?: boolean, + * forceEnableDeveloperKeybindings?: boolean, + * disallowReloadKeybinding?: boolean, + * removeDeveloperKeybindingsAfterLoad?: boolean + * }, + * canModifyDOM?: (config: INativeWindowConfiguration & NativeParsedArgs) => void, + * beforeLoaderConfig?: (loaderConfig: object) => void, + * beforeRequire?: () => void + * } + * ) => Promise + * }} + */ + function bootstrapWindowLib() { + // @ts-ignore (defined in bootstrap-window.js) + return window.MonacoBootstrapWindow; + } + + /** + * @param {INativeWindowConfiguration & NativeParsedArgs} configuration + */ + function showSplash(configuration) { + performance.mark('code/willShowPartsSplash'); + + let data = configuration.partsSplash; + + // high contrast mode has been turned on from the outside, e.g. OS -> ignore stored colors and layouts + const isHighContrast = configuration.colorScheme.highContrast && configuration.autoDetectHighContrast; + if (data && isHighContrast && data.baseTheme !== 'hc-black') { + data = undefined; + } + + // developing an extension -> ignore stored layouts + if (data && configuration.extensionDevelopmentPath) { + data.layoutInfo = undefined; + } + + // minimal color configuration (works with or without persisted data) + let baseTheme, shellBackground, shellForeground; + if (data) { + baseTheme = data.baseTheme; + shellBackground = data.colorInfo.editorBackground; + shellForeground = data.colorInfo.foreground; + } else if (isHighContrast) { + baseTheme = 'hc-black'; + shellBackground = '#000000'; + shellForeground = '#FFFFFF'; + } else { + baseTheme = 'vs-dark'; + shellBackground = '#1E1E1E'; + shellForeground = '#CCCCCC'; + } + + const style = document.createElement('style'); + style.className = 'initialShellColors'; + document.head.appendChild(style); + style.textContent = `body { background-color: ${shellBackground}; color: ${shellForeground}; margin: 0; padding: 0; }`; + + // restore parts if possible (we might not always store layout info) + if (data?.layoutInfo) { + const { layoutInfo, colorInfo } = data; + + const splash = document.createElement('div'); + splash.id = 'monaco-parts-splash'; + splash.className = baseTheme; + + if (layoutInfo.windowBorder) { + splash.style.position = 'relative'; + splash.style.height = 'calc(100vh - 2px)'; + splash.style.width = 'calc(100vw - 2px)'; + splash.style.border = '1px solid var(--window-border-color)'; + splash.style.setProperty('--window-border-color', colorInfo.windowBorder); + + if (layoutInfo.windowBorderRadius) { + splash.style.borderRadius = layoutInfo.windowBorderRadius; + } + } + + // ensure there is enough space + layoutInfo.sideBarWidth = Math.min(layoutInfo.sideBarWidth, window.innerWidth - (layoutInfo.activityBarWidth + layoutInfo.editorPartMinWidth)); + + // part: title + const titleDiv = document.createElement('div'); + titleDiv.setAttribute('style', `position: absolute; width: 100%; left: 0; top: 0; height: ${layoutInfo.titleBarHeight}px; background-color: ${colorInfo.titleBarBackground}; -webkit-app-region: drag;`); + splash.appendChild(titleDiv); + + // part: activity bar + const activityDiv = document.createElement('div'); + activityDiv.setAttribute('style', `position: absolute; height: calc(100% - ${layoutInfo.titleBarHeight}px); top: ${layoutInfo.titleBarHeight}px; ${layoutInfo.sideBarSide}: 0; width: ${layoutInfo.activityBarWidth}px; background-color: ${colorInfo.activityBarBackground};`); + splash.appendChild(activityDiv); + + // part: side bar (only when opening workspace/folder) + // folder or workspace -> status bar color, sidebar + if (configuration.workspace) { + const sideDiv = document.createElement('div'); + sideDiv.setAttribute('style', `position: absolute; height: calc(100% - ${layoutInfo.titleBarHeight}px); top: ${layoutInfo.titleBarHeight}px; ${layoutInfo.sideBarSide}: ${layoutInfo.activityBarWidth}px; width: ${layoutInfo.sideBarWidth}px; background-color: ${colorInfo.sideBarBackground};`); + splash.appendChild(sideDiv); + } + + // part: statusbar + const statusDiv = document.createElement('div'); + statusDiv.setAttribute('style', `position: absolute; width: 100%; bottom: 0; left: 0; height: ${layoutInfo.statusBarHeight}px; background-color: ${configuration.workspace ? colorInfo.statusBarBackground : colorInfo.statusBarNoFolderBackground};`); + splash.appendChild(statusDiv); + + document.body.appendChild(splash); + } + + performance.mark('code/didShowPartsSplash'); + } + + //#endregion +}()); diff --git a/lib/vscode/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts similarity index 97% rename from lib/vscode/src/vs/code/node/cli.ts rename to src/vs/code/node/cli.ts index 0ce6c5ee5be4..2e7b324ed1d1 100644 --- a/lib/vscode/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -13,8 +13,9 @@ import { createWaitMarkerFile } from 'vs/platform/environment/node/wait'; import product from 'vs/platform/product/common/product'; import { isAbsolute, join } from 'vs/base/common/path'; import { whenDeleted, writeFileSync } from 'vs/base/node/pfs'; -import { findFreePort, randomPort } from 'vs/base/node/ports'; -import { isWindows, isLinux, IProcessEnvironment } from 'vs/base/common/platform'; +import { findFreePort } from 'vs/base/node/ports'; +import { randomPort } from 'vs/base/common/ports'; +import { isWindows, IProcessEnvironment } from 'vs/base/common/platform'; import type { ProfilingSession, Target } from 'v8-inspect-profiler'; import { isString } from 'vs/base/common/types'; import { hasStdinWithoutTty, stdinDataListener, getStdinFilePath, readFromStdin } from 'vs/platform/environment/node/stdin'; @@ -318,10 +319,6 @@ 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) { diff --git a/lib/vscode/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts similarity index 92% rename from lib/vscode/src/vs/code/node/cliProcessMain.ts rename to src/vs/code/node/cliProcessMain.ts index 11716b334bc9..ade2dd627372 100644 --- a/lib/vscode/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -6,6 +6,7 @@ import { release, hostname } from 'os'; import * as fs from 'fs'; import { gracefulify } from 'graceful-fs'; +import { Promises } from 'vs/base/node/pfs'; import { isAbsolute, join } from 'vs/base/common/path'; import { raceTimeout } from 'vs/base/common/async'; import product from 'vs/platform/product/common/product'; @@ -19,7 +20,7 @@ import { NativeEnvironmentService } from 'vs/platform/environment/node/environme import { IExtensionManagementService, IExtensionGalleryService, IExtensionManagementCLIService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { ITelemetryService, machineIdKey } from 'vs/platform/telemetry/common/telemetry'; import { combinedAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProperties'; @@ -28,8 +29,6 @@ import { RequestService } from 'vs/platform/request/node/requestService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ConfigurationService } from 'vs/platform/configuration/common/configurationService'; import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender'; -import { IStateService } from 'vs/platform/state/node/state'; -import { StateService } from 'vs/platform/state/node/stateService'; import { ILogService, getLogLevel, LogLevel, ConsoleLogger, MultiplexLogService, ILogger } from 'vs/platform/log/common/log'; import { Schemas } from 'vs/base/common/network'; import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog'; @@ -104,7 +103,7 @@ class CliMain extends Disposable { services.set(INativeEnvironmentService, environmentService); // Init folders - await Promise.all([environmentService.appSettingsHome.fsPath, environmentService.extensionsPath].map(path => path ? fs.promises.mkdir(path, { recursive: true }) : undefined)); + await Promise.all([environmentService.appSettingsHome.fsPath, environmentService.extensionsPath].map(path => path ? Promises.mkdir(path, { recursive: true }) : undefined)); // Log const logLevel = getLogLevel(environmentService); @@ -131,10 +130,6 @@ class CliMain extends Disposable { // Init config await configurationService.initialize(); - // State - const stateService = new StateService(environmentService, logService); - services.set(IStateService, stateService); - // Request services.set(IRequestService, new SyncDescriptor(RequestService)); @@ -158,7 +153,19 @@ class CliMain extends Disposable { const config: ITelemetryServiceConfig = { appender: combinedAppender(...appenders), sendErrorTelemetry: false, - commonProperties: resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, stateService.getItem('telemetry.machineId'), productService.msftInternalDomains, installSourcePath), + commonProperties: (async () => { + let machineId: string | undefined = undefined; + try { + const storageContents = await Promises.readFile(join(environmentService.userDataPath, 'storage.json')); + machineId = JSON.parse(storageContents.toString())[machineIdKey]; + } catch (error) { + if (error.code !== 'ENOENT') { + logService.error(error); + } + } + + return resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version, machineId, productService.msftInternalDomains, installSourcePath); + })(), piiPaths: [appRoot, extensionsPath] }; diff --git a/lib/vscode/src/vs/css.build.js b/src/vs/css.build.js similarity index 100% rename from lib/vscode/src/vs/css.build.js rename to src/vs/css.build.js diff --git a/lib/vscode/src/vs/css.d.ts b/src/vs/css.d.ts similarity index 100% rename from lib/vscode/src/vs/css.d.ts rename to src/vs/css.d.ts diff --git a/lib/vscode/src/vs/css.js b/src/vs/css.js similarity index 100% rename from lib/vscode/src/vs/css.js rename to src/vs/css.js diff --git a/lib/vscode/src/vs/editor/browser/config/charWidthReader.ts b/src/vs/editor/browser/config/charWidthReader.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/config/charWidthReader.ts rename to src/vs/editor/browser/config/charWidthReader.ts diff --git a/lib/vscode/src/vs/editor/browser/config/configuration.ts b/src/vs/editor/browser/config/configuration.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/config/configuration.ts rename to src/vs/editor/browser/config/configuration.ts diff --git a/lib/vscode/src/vs/editor/browser/config/elementSizeObserver.ts b/src/vs/editor/browser/config/elementSizeObserver.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/config/elementSizeObserver.ts rename to src/vs/editor/browser/config/elementSizeObserver.ts diff --git a/lib/vscode/src/vs/editor/browser/controller/coreCommands.ts b/src/vs/editor/browser/controller/coreCommands.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/controller/coreCommands.ts rename to src/vs/editor/browser/controller/coreCommands.ts diff --git a/lib/vscode/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/controller/mouseHandler.ts rename to src/vs/editor/browser/controller/mouseHandler.ts diff --git a/lib/vscode/src/vs/editor/browser/controller/mouseTarget.ts b/src/vs/editor/browser/controller/mouseTarget.ts similarity index 88% rename from lib/vscode/src/vs/editor/browser/controller/mouseTarget.ts rename to src/vs/editor/browser/controller/mouseTarget.ts index d2af49b222f6..3d766b78764d 100644 --- a/lib/vscode/src/vs/editor/browser/controller/mouseTarget.ts +++ b/src/vs/editor/browser/controller/mouseTarget.ts @@ -40,54 +40,40 @@ export interface IEmptyContentData { horizontalDistanceToText?: number; } -interface IETextRange { - boundingHeight: number; - boundingLeft: number; - boundingTop: number; - boundingWidth: number; - htmlText: string; - offsetLeft: number; - offsetTop: number; - text: string; - collapse(start?: boolean): void; - compareEndPoints(how: string, sourceRange: IETextRange): number; - duplicate(): IETextRange; - execCommand(cmdID: string, showUI?: boolean, value?: any): boolean; - execCommandShowHelp(cmdID: string): boolean; - expand(Unit: string): boolean; - findText(string: string, count?: number, flags?: number): boolean; - getBookmark(): string; - getBoundingClientRect(): ClientRect; - getClientRects(): ClientRectList; - inRange(range: IETextRange): boolean; - isEqual(range: IETextRange): boolean; - move(unit: string, count?: number): number; - moveEnd(unit: string, count?: number): number; - moveStart(unit: string, count?: number): number; - moveToBookmark(bookmark: string): boolean; - moveToElementText(element: Element): void; - moveToPoint(x: number, y: number): void; - parentElement(): Element; - pasteHTML(html: string): void; - queryCommandEnabled(cmdID: string): boolean; - queryCommandIndeterm(cmdID: string): boolean; - queryCommandState(cmdID: string): boolean; - queryCommandSupported(cmdID: string): boolean; - queryCommandText(cmdID: string): string; - queryCommandValue(cmdID: string): any; - scrollIntoView(fStart?: boolean): void; - select(): void; - setEndPoint(how: string, SourceRange: IETextRange): void; +export interface ITextContentData { + mightBeForeignElement: boolean; } -declare const IETextRange: { - prototype: IETextRange; - new(): IETextRange; -}; +const enum HitTestResultType { + Unknown = 0, + Content = 1, +} -interface IHitTestResult { - position: Position | null; - hitTarget: Element | null; +class UnknownHitTestResult { + readonly type = HitTestResultType.Unknown; + constructor( + readonly hitTarget: Element | null = null + ) { } +} + +class ContentHitTestResult { + readonly type = HitTestResultType.Content; + constructor( + readonly position: Position, + readonly spanNode: HTMLElement + ) { } +} + +type HitTestResult = UnknownHitTestResult | ContentHitTestResult; + +namespace HitTestResult { + export function createFromDOMInfo(ctx: HitTestContext, spanNode: HTMLElement, offset: number): HitTestResult { + const position = ctx.getPositionFromDOMInfo(spanNode, offset); + if (position) { + return new ContentHitTestResult(position, spanNode); + } + return new UnknownHitTestResult(spanNode); + } } export class PointerHandlerLastRenderData { @@ -426,6 +412,17 @@ class HitTestRequest extends BareHitTestRequest { return `pos(${this.pos.x},${this.pos.y}), editorPos(${this.editorPos.x},${this.editorPos.y}), mouseVerticalOffset: ${this.mouseVerticalOffset}, mouseContentHorizontalOffset: ${this.mouseContentHorizontalOffset}\n\ttarget: ${this.target ? (this.target).outerHTML : null}`; } + public fulfill(type: MouseTargetType.UNKNOWN, position?: Position | null, range?: EditorRange | null): MouseTarget; + public fulfill(type: MouseTargetType.TEXTAREA, position: Position | null): MouseTarget; + public fulfill(type: MouseTargetType.GUTTER_GLYPH_MARGIN | MouseTargetType.GUTTER_LINE_NUMBERS | MouseTargetType.GUTTER_LINE_DECORATIONS, position: Position, range: EditorRange, detail: IMarginData): MouseTarget; + public fulfill(type: MouseTargetType.GUTTER_VIEW_ZONE | MouseTargetType.CONTENT_VIEW_ZONE, position: Position, range: null, detail: IViewZoneData): MouseTarget; + public fulfill(type: MouseTargetType.CONTENT_TEXT, position: Position | null, range: EditorRange | null, detail: ITextContentData): MouseTarget; + public fulfill(type: MouseTargetType.CONTENT_EMPTY, position: Position | null, range: EditorRange | null, detail: IEmptyContentData): MouseTarget; + public fulfill(type: MouseTargetType.CONTENT_WIDGET, position: null, range: null, detail: string): MouseTarget; + public fulfill(type: MouseTargetType.SCROLLBAR, position: Position): MouseTarget; + public fulfill(type: MouseTargetType.OVERLAY_WIDGET, position: null, range: null, detail: string): MouseTarget; + // public fulfill(type: MouseTargetType.OVERVIEW_RULER, position?: Position | null, range?: EditorRange | null, detail?: any): MouseTarget; + // public fulfill(type: MouseTargetType.OUTSIDE_EDITOR, position?: Position | null, range?: EditorRange | null, detail?: any): MouseTarget; public fulfill(type: MouseTargetType, position: Position | null = null, range: EditorRange | null = null, detail: any = null): MouseTarget { let mouseColumn = this.mouseColumn; if (position && position.column < this._ctx.model.getLineMaxColumn(position.lineNumber)) { @@ -506,8 +503,8 @@ export class MouseTargetFactory { const hitTestResult = MouseTargetFactory._doHitTest(ctx, request); - if (hitTestResult.position) { - return MouseTargetFactory.createMouseTargetFromHitTestPosition(ctx, request, hitTestResult.position.lineNumber, hitTestResult.position.column); + if (hitTestResult.type === HitTestResultType.Content) { + return MouseTargetFactory.createMouseTargetFromHitTestPosition(ctx, request, hitTestResult.spanNode, hitTestResult.position); } return this._createMouseTarget(ctx, request.withTarget(hitTestResult.hitTarget), true); @@ -567,7 +564,7 @@ export class MouseTargetFactory { for (const d of lastViewCursorsRenderData) { if (request.target === d.domNode) { - return request.fulfill(MouseTargetType.CONTENT_TEXT, d.position); + return request.fulfill(MouseTargetType.CONTENT_TEXT, d.position, null, { mightBeForeignElement: false }); } } } @@ -599,7 +596,7 @@ export class MouseTargetFactory { cursorVerticalOffset <= mouseVerticalOffset && mouseVerticalOffset <= cursorVerticalOffset + d.height ) { - return request.fulfill(MouseTargetType.CONTENT_TEXT, d.position); + return request.fulfill(MouseTargetType.CONTENT_TEXT, d.position, null, { mightBeForeignElement: false }); } } } @@ -621,7 +618,7 @@ export class MouseTargetFactory { // Is it the textarea? if (ElementPath.isTextArea(request.targetPath)) { if (ctx.lastRenderData.lastTextareaPosition) { - return request.fulfill(MouseTargetType.CONTENT_TEXT, ctx.lastRenderData.lastTextareaPosition); + return request.fulfill(MouseTargetType.CONTENT_TEXT, ctx.lastRenderData.lastTextareaPosition, null, { mightBeForeignElement: false }); } return request.fulfill(MouseTargetType.TEXTAREA, ctx.lastRenderData.lastTextareaPosition); } @@ -667,7 +664,7 @@ export class MouseTargetFactory { } if (ctx.isInTopPadding(request.mouseVerticalOffset)) { - return request.fulfill(MouseTargetType.CONTENT_EMPTY, new Position(1, 1), undefined, EMPTY_CONTENT_AFTER_LINES); + return request.fulfill(MouseTargetType.CONTENT_EMPTY, new Position(1, 1), null, EMPTY_CONTENT_AFTER_LINES); } // Check if it is below any lines and any view zones @@ -675,7 +672,7 @@ export class MouseTargetFactory { // This most likely indicates it happened after the last view-line const lineCount = ctx.model.getLineCount(); const maxLineColumn = ctx.model.getLineMaxColumn(lineCount); - return request.fulfill(MouseTargetType.CONTENT_EMPTY, new Position(lineCount, maxLineColumn), undefined, EMPTY_CONTENT_AFTER_LINES); + return request.fulfill(MouseTargetType.CONTENT_EMPTY, new Position(lineCount, maxLineColumn), null, EMPTY_CONTENT_AFTER_LINES); } if (domHitTestExecuted) { @@ -686,14 +683,14 @@ export class MouseTargetFactory { if (ctx.model.getLineLength(lineNumber) === 0) { const lineWidth = ctx.getLineWidth(lineNumber); const detail = createEmptyContentDataInLines(request.mouseContentHorizontalOffset - lineWidth); - return request.fulfill(MouseTargetType.CONTENT_EMPTY, new Position(lineNumber, 1), undefined, detail); + return request.fulfill(MouseTargetType.CONTENT_EMPTY, new Position(lineNumber, 1), null, detail); } const lineWidth = ctx.getLineWidth(lineNumber); if (request.mouseContentHorizontalOffset >= lineWidth) { const detail = createEmptyContentDataInLines(request.mouseContentHorizontalOffset - lineWidth); const pos = new Position(lineNumber, ctx.model.getLineMaxColumn(lineNumber)); - return request.fulfill(MouseTargetType.CONTENT_EMPTY, pos, undefined, detail); + return request.fulfill(MouseTargetType.CONTENT_EMPTY, pos, null, detail); } } @@ -703,8 +700,8 @@ export class MouseTargetFactory { const hitTestResult = MouseTargetFactory._doHitTest(ctx, request); - if (hitTestResult.position) { - return MouseTargetFactory.createMouseTargetFromHitTestPosition(ctx, request, hitTestResult.position.lineNumber, hitTestResult.position.column); + if (hitTestResult.type === HitTestResultType.Content) { + return MouseTargetFactory.createMouseTargetFromHitTestPosition(ctx, request, hitTestResult.spanNode, hitTestResult.position); } return this._createMouseTarget(ctx, request.withTarget(hitTestResult.hitTarget), true); @@ -760,14 +757,15 @@ export class MouseTargetFactory { return (chars + 1); } - private static createMouseTargetFromHitTestPosition(ctx: HitTestContext, request: HitTestRequest, lineNumber: number, column: number): MouseTarget { - const pos = new Position(lineNumber, column); + private static createMouseTargetFromHitTestPosition(ctx: HitTestContext, request: HitTestRequest, spanNode: HTMLElement, pos: Position): MouseTarget { + const lineNumber = pos.lineNumber; + const column = pos.column; const lineWidth = ctx.getLineWidth(lineNumber); if (request.mouseContentHorizontalOffset > lineWidth) { const detail = createEmptyContentDataInLines(request.mouseContentHorizontalOffset - lineWidth); - return request.fulfill(MouseTargetType.CONTENT_EMPTY, pos, undefined, detail); + return request.fulfill(MouseTargetType.CONTENT_EMPTY, pos, null, detail); } const visibleRange = ctx.visibleRangeForPosition(lineNumber, column); @@ -779,7 +777,7 @@ export class MouseTargetFactory { const columnHorizontalOffset = visibleRange.left; if (request.mouseContentHorizontalOffset === columnHorizontalOffset) { - return request.fulfill(MouseTargetType.CONTENT_TEXT, pos); + return request.fulfill(MouseTargetType.CONTENT_TEXT, pos, null, { mightBeForeignElement: false }); } // Let's define a, b, c and check if the offset is in between them... @@ -803,21 +801,25 @@ export class MouseTargetFactory { points.sort((a, b) => a.offset - b.offset); + const mouseCoordinates = request.pos.toClientCoordinates(); + const spanNodeClientRect = spanNode.getBoundingClientRect(); + const mouseIsOverSpanNode = (spanNodeClientRect.left <= mouseCoordinates.clientX && mouseCoordinates.clientX <= spanNodeClientRect.right); + for (let i = 1; i < points.length; i++) { const prev = points[i - 1]; const curr = points[i]; if (prev.offset <= request.mouseContentHorizontalOffset && request.mouseContentHorizontalOffset <= curr.offset) { const rng = new EditorRange(lineNumber, prev.column, lineNumber, curr.column); - return request.fulfill(MouseTargetType.CONTENT_TEXT, pos, rng); + return request.fulfill(MouseTargetType.CONTENT_TEXT, pos, rng, { mightBeForeignElement: !mouseIsOverSpanNode }); } } - return request.fulfill(MouseTargetType.CONTENT_TEXT, pos); + return request.fulfill(MouseTargetType.CONTENT_TEXT, pos, null, { mightBeForeignElement: !mouseIsOverSpanNode }); } /** * Most probably WebKit browsers and Edge */ - private static _doHitTestWithCaretRangeFromPoint(ctx: HitTestContext, request: BareHitTestRequest): IHitTestResult { + private static _doHitTestWithCaretRangeFromPoint(ctx: HitTestContext, request: BareHitTestRequest): HitTestResult { // In Chrome, especially on Linux it is possible to click between lines, // so try to adjust the `hity` below so that it lands in the center of a line @@ -836,7 +838,7 @@ export class MouseTargetFactory { const adjustedPage = new PageCoordinates(request.pos.x, adjustedPageY); const r = this._actualDoHitTestWithCaretRangeFromPoint(ctx, adjustedPage.toClientCoordinates()); - if (r.position) { + if (r.type === HitTestResultType.Content) { return r; } @@ -844,7 +846,7 @@ export class MouseTargetFactory { return this._actualDoHitTestWithCaretRangeFromPoint(ctx, request.pos.toClientCoordinates()); } - private static _actualDoHitTestWithCaretRangeFromPoint(ctx: HitTestContext, coords: ClientCoordinates): IHitTestResult { + private static _actualDoHitTestWithCaretRangeFromPoint(ctx: HitTestContext, coords: ClientCoordinates): HitTestResult { const shadowRoot = dom.getShadowRoot(ctx.viewDomNode); let range: Range; if (shadowRoot) { @@ -858,15 +860,11 @@ export class MouseTargetFactory { } if (!range || !range.startContainer) { - return { - position: null, - hitTarget: null - }; + return new UnknownHitTestResult(); } // Chrome always hits a TEXT_NODE, while Edge sometimes hits a token span const startContainer = range.startContainer; - let hitTarget: HTMLElement | null = null; if (startContainer.nodeType === startContainer.TEXT_NODE) { // startContainer is expected to be the token text @@ -876,13 +874,9 @@ export class MouseTargetFactory { const parent3ClassName = parent3 && parent3.nodeType === parent3.ELEMENT_NODE ? (parent3).className : null; if (parent3ClassName === ViewLine.CLASS_NAME) { - const p = ctx.getPositionFromDOMInfo(parent1, range.startOffset); - return { - position: p, - hitTarget: null - }; + return HitTestResult.createFromDOMInfo(ctx, parent1, range.startOffset); } else { - hitTarget = startContainer.parentNode; + return new UnknownHitTestResult(startContainer.parentNode); } } else if (startContainer.nodeType === startContainer.ELEMENT_NODE) { // startContainer is expected to be the token span @@ -891,26 +885,19 @@ export class MouseTargetFactory { const parent2ClassName = parent2 && parent2.nodeType === parent2.ELEMENT_NODE ? (parent2).className : null; if (parent2ClassName === ViewLine.CLASS_NAME) { - const p = ctx.getPositionFromDOMInfo(startContainer, (startContainer).textContent!.length); - return { - position: p, - hitTarget: null - }; + return HitTestResult.createFromDOMInfo(ctx, startContainer, (startContainer).textContent!.length); } else { - hitTarget = startContainer; + return new UnknownHitTestResult(startContainer); } } - return { - position: null, - hitTarget: hitTarget - }; + return new UnknownHitTestResult(); } /** * Most probably Gecko */ - private static _doHitTestWithCaretPositionFromPoint(ctx: HitTestContext, coords: ClientCoordinates): IHitTestResult { + private static _doHitTestWithCaretPositionFromPoint(ctx: HitTestContext, coords: ClientCoordinates): HitTestResult { const hitResult: { offsetNode: Node; offset: number; } = (document).caretPositionFromPoint(coords.clientX, coords.clientY); if (hitResult.offsetNode.nodeType === hitResult.offsetNode.TEXT_NODE) { @@ -921,16 +908,9 @@ export class MouseTargetFactory { const parent3ClassName = parent3 && parent3.nodeType === parent3.ELEMENT_NODE ? (parent3).className : null; if (parent3ClassName === ViewLine.CLASS_NAME) { - const p = ctx.getPositionFromDOMInfo(hitResult.offsetNode.parentNode, hitResult.offset); - return { - position: p, - hitTarget: null - }; + return HitTestResult.createFromDOMInfo(ctx, hitResult.offsetNode.parentNode, hitResult.offset); } else { - return { - position: null, - hitTarget: hitResult.offsetNode.parentNode - }; + return new UnknownHitTestResult(hitResult.offsetNode.parentNode); } } @@ -946,26 +926,15 @@ export class MouseTargetFactory { // it returned the `` of the line and the offset is the `` with the inline decoration const tokenSpan = hitResult.offsetNode.childNodes[Math.min(hitResult.offset, hitResult.offsetNode.childNodes.length - 1)]; if (tokenSpan) { - const p = ctx.getPositionFromDOMInfo(tokenSpan, 0); - return { - position: p, - hitTarget: null - }; + return HitTestResult.createFromDOMInfo(ctx, tokenSpan, 0); } } else if (parent2ClassName === ViewLine.CLASS_NAME) { // it returned the `` with the inline decoration - const p = ctx.getPositionFromDOMInfo(hitResult.offsetNode, 0); - return { - position: p, - hitTarget: null - }; + return HitTestResult.createFromDOMInfo(ctx, hitResult.offsetNode, 0); } } - return { - position: null, - hitTarget: hitResult.offsetNode - }; + return new UnknownHitTestResult(hitResult.offsetNode); } private static _snapToSoftTabBoundary(position: Position, viewModel: IViewModel): Position { @@ -978,22 +947,17 @@ export class MouseTargetFactory { return position; } - private static _doHitTest(ctx: HitTestContext, request: BareHitTestRequest): IHitTestResult { + private static _doHitTest(ctx: HitTestContext, request: BareHitTestRequest): HitTestResult { - let result: IHitTestResult; + let result: HitTestResult = new UnknownHitTestResult(); if (typeof document.caretRangeFromPoint === 'function') { result = this._doHitTestWithCaretRangeFromPoint(ctx, request); } else if ((document).caretPositionFromPoint) { result = this._doHitTestWithCaretPositionFromPoint(ctx, request.pos.toClientCoordinates()); - } else { - result = { - position: null, - hitTarget: null - }; } // Snap to the nearest soft tab boundary if atomic soft tabs are enabled. - if (result.position && ctx.stickyTabStops) { - result.position = this._snapToSoftTabBoundary(result.position, ctx.model); + if (result.type === HitTestResultType.Content && ctx.stickyTabStops) { + result = new ContentHitTestResult(this._snapToSoftTabBoundary(result.position, ctx.model), result.spanNode); } return result; } diff --git a/lib/vscode/src/vs/editor/browser/controller/pointerHandler.ts b/src/vs/editor/browser/controller/pointerHandler.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/controller/pointerHandler.ts rename to src/vs/editor/browser/controller/pointerHandler.ts diff --git a/lib/vscode/src/vs/editor/browser/controller/textAreaHandler.css b/src/vs/editor/browser/controller/textAreaHandler.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/controller/textAreaHandler.css rename to src/vs/editor/browser/controller/textAreaHandler.css diff --git a/lib/vscode/src/vs/editor/browser/controller/textAreaHandler.ts b/src/vs/editor/browser/controller/textAreaHandler.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/controller/textAreaHandler.ts rename to src/vs/editor/browser/controller/textAreaHandler.ts diff --git a/lib/vscode/src/vs/editor/browser/controller/textAreaInput.ts b/src/vs/editor/browser/controller/textAreaInput.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/controller/textAreaInput.ts rename to src/vs/editor/browser/controller/textAreaInput.ts diff --git a/lib/vscode/src/vs/editor/browser/controller/textAreaState.ts b/src/vs/editor/browser/controller/textAreaState.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/controller/textAreaState.ts rename to src/vs/editor/browser/controller/textAreaState.ts diff --git a/lib/vscode/src/vs/editor/browser/core/editorState.ts b/src/vs/editor/browser/core/editorState.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/core/editorState.ts rename to src/vs/editor/browser/core/editorState.ts diff --git a/lib/vscode/src/vs/editor/browser/core/keybindingCancellation.ts b/src/vs/editor/browser/core/keybindingCancellation.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/core/keybindingCancellation.ts rename to src/vs/editor/browser/core/keybindingCancellation.ts diff --git a/lib/vscode/src/vs/editor/browser/core/markdownRenderer.ts b/src/vs/editor/browser/core/markdownRenderer.ts similarity index 96% rename from lib/vscode/src/vs/editor/browser/core/markdownRenderer.ts rename to src/vs/editor/browser/core/markdownRenderer.ts index f8422e25374c..b6bc211f5c3a 100644 --- a/lib/vscode/src/vs/editor/browser/core/markdownRenderer.ts +++ b/src/vs/editor/browser/core/markdownRenderer.ts @@ -52,18 +52,18 @@ export class MarkdownRenderer { } render(markdown: IMarkdownString | undefined, options?: MarkdownRenderOptions, markedOptions?: MarkedOptions): IMarkdownRenderResult { - const disposeables = new DisposableStore(); + const disposables = new DisposableStore(); let element: HTMLElement; if (!markdown) { element = document.createElement('span'); } else { - element = renderMarkdown(markdown, { ...this._getRenderOptions(markdown, disposeables), ...options }, markedOptions); + element = renderMarkdown(markdown, { ...this._getRenderOptions(markdown, disposables), ...options }, markedOptions); } return { element, - dispose: () => disposeables.dispose() + dispose: () => disposables.dispose() }; } diff --git a/lib/vscode/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts similarity index 99% rename from lib/vscode/src/vs/editor/browser/editorBrowser.ts rename to src/vs/editor/browser/editorBrowser.ts index bfa07b8dcf9a..39ecb3745b0d 100644 --- a/lib/vscode/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -622,13 +622,13 @@ export interface ICodeEditor extends editorCommon.IEditor { /** * Get value of the current model attached to this editor. - * @see `ITextModel.getValue` + * @see {@link ITextModel.getValue} */ getValue(options?: { preserveBOM: boolean; lineEnding: string; }): string; /** * Set the value of the current model attached to this editor. - * @see `ITextModel.setValue` + * @see {@link ITextModel.setValue} */ setValue(newValue: string): void; @@ -726,14 +726,14 @@ export interface ICodeEditor extends editorCommon.IEditor { /** * All decorations added through this call will get the ownerId of this editor. - * @see `ITextModel.deltaDecorations` + * @see {@link ITextModel.deltaDecorations} */ deltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[]; /** * @internal */ - setDecorations(decorationTypeKey: string, ranges: editorCommon.IDecorationOptions[]): void; + setDecorations(description: string, decorationTypeKey: string, ranges: editorCommon.IDecorationOptions[]): void; /** * @internal @@ -975,7 +975,7 @@ export interface IDiffEditor extends editorCommon.IEditor { readonly maxComputationTime: number; /** - * @see ICodeEditor.getDomNode + * @see {@link ICodeEditor.getDomNode} */ getDomNode(): HTMLElement; diff --git a/lib/vscode/src/vs/editor/browser/editorDom.ts b/src/vs/editor/browser/editorDom.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/editorDom.ts rename to src/vs/editor/browser/editorDom.ts diff --git a/lib/vscode/src/vs/editor/browser/editorExtensions.ts b/src/vs/editor/browser/editorExtensions.ts similarity index 93% rename from lib/vscode/src/vs/editor/browser/editorExtensions.ts rename to src/vs/editor/browser/editorExtensions.ts index 0ba2633acc47..9cf6d8db06e7 100644 --- a/lib/vscode/src/vs/editor/browser/editorExtensions.ts +++ b/src/vs/editor/browser/editorExtensions.ts @@ -61,14 +61,14 @@ export interface ICommandMenuOptions { export interface ICommandOptions { id: string; precondition: ContextKeyExpression | undefined; - kbOpts?: ICommandKeybindingsOptions; + kbOpts?: ICommandKeybindingsOptions | ICommandKeybindingsOptions[]; description?: ICommandHandlerDescription; menuOpts?: ICommandMenuOptions | ICommandMenuOptions[]; } export abstract class Command { public readonly id: string; public readonly precondition: ContextKeyExpression | undefined; - private readonly _kbOpts: ICommandKeybindingsOptions | undefined; + private readonly _kbOpts: ICommandKeybindingsOptions | ICommandKeybindingsOptions[] | undefined; private readonly _menuOpts: ICommandMenuOptions | ICommandMenuOptions[] | undefined; private readonly _description: ICommandHandlerDescription | undefined; @@ -89,37 +89,38 @@ export abstract class Command { } if (this._kbOpts) { - let kbWhen = this._kbOpts.kbExpr; - if (this.precondition) { - if (kbWhen) { - kbWhen = ContextKeyExpr.and(kbWhen, this.precondition); - } else { - kbWhen = this.precondition; + const kbOptsArr = Array.isArray(this._kbOpts) ? this._kbOpts : [this._kbOpts]; + for (const kbOpts of kbOptsArr) { + let kbWhen = kbOpts.kbExpr; + if (this.precondition) { + if (kbWhen) { + kbWhen = ContextKeyExpr.and(kbWhen, this.precondition); + } else { + kbWhen = this.precondition; + } } - } - - KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: this.id, - handler: (accessor, args) => this.runCommand(accessor, args), - weight: this._kbOpts.weight, - args: this._kbOpts.args, - when: kbWhen, - primary: this._kbOpts.primary, - secondary: this._kbOpts.secondary, - win: this._kbOpts.win, - linux: this._kbOpts.linux, - mac: this._kbOpts.mac, - description: this._description - }); - - } else { - CommandsRegistry.registerCommand({ - id: this.id, - handler: (accessor, args) => this.runCommand(accessor, args), - description: this._description - }); + const desc = { + id: this.id, + weight: kbOpts.weight, + args: kbOpts.args, + when: kbWhen, + primary: kbOpts.primary, + secondary: kbOpts.secondary, + win: kbOpts.win, + linux: kbOpts.linux, + mac: kbOpts.mac, + }; + + KeybindingsRegistry.registerKeybindingRule(desc); + } } + + CommandsRegistry.registerCommand({ + id: this.id, + handler: (accessor, args) => this.runCommand(accessor, args), + description: this._description + }); } private _registerMenuItem(item: ICommandMenuOptions): void { @@ -348,14 +349,16 @@ export abstract class EditorAction extends EditorCommand { public abstract run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void | Promise; } +export type EditorActionImplementation = (accessor: ServicesAccessor, editor: ICodeEditor, args: any) => boolean | Promise; + export class MultiEditorAction extends EditorAction { - private readonly _implementations: [number, CommandImplementation][] = []; + private readonly _implementations: [number, EditorActionImplementation][] = []; /** * A higher priority gets to be looked at first */ - public addImplementation(priority: number, implementation: CommandImplementation): IDisposable { + public addImplementation(priority: number, implementation: EditorActionImplementation): IDisposable { this._implementations.push([priority, implementation]); this._implementations.sort((a, b) => b[0] - a[0]); return { @@ -372,7 +375,7 @@ export class MultiEditorAction extends EditorAction { public run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void | Promise { for (const impl of this._implementations) { - const result = impl[1](accessor, args); + const result = impl[1](accessor, editor, args); if (result) { if (typeof result === 'boolean') { return; diff --git a/lib/vscode/src/vs/editor/browser/services/abstractCodeEditorService.ts b/src/vs/editor/browser/services/abstractCodeEditorService.ts similarity index 97% rename from lib/vscode/src/vs/editor/browser/services/abstractCodeEditorService.ts rename to src/vs/editor/browser/services/abstractCodeEditorService.ts index 3ebb6454bb86..c6f58e65c6fa 100644 --- a/lib/vscode/src/vs/editor/browser/services/abstractCodeEditorService.ts +++ b/src/vs/editor/browser/services/abstractCodeEditorService.ts @@ -92,7 +92,7 @@ export abstract class AbstractCodeEditorService extends Disposable implements IC return editorWithWidgetFocus; } - abstract registerDecorationType(key: string, options: IDecorationRenderOptions, parentTypeKey?: string, editor?: ICodeEditor): void; + abstract registerDecorationType(description: string, key: string, options: IDecorationRenderOptions, parentTypeKey?: string, editor?: ICodeEditor): void; abstract removeDecorationType(key: string): void; abstract resolveDecorationOptions(decorationTypeKey: string | undefined, writable: boolean): IModelDecorationOptions; abstract resolveDecorationCSSRules(decorationTypeKey: string): CSSRuleList | null; diff --git a/lib/vscode/src/vs/editor/browser/services/bulkEditService.ts b/src/vs/editor/browser/services/bulkEditService.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/services/bulkEditService.ts rename to src/vs/editor/browser/services/bulkEditService.ts diff --git a/lib/vscode/src/vs/editor/browser/services/codeEditorService.ts b/src/vs/editor/browser/services/codeEditorService.ts similarity index 86% rename from lib/vscode/src/vs/editor/browser/services/codeEditorService.ts rename to src/vs/editor/browser/services/codeEditorService.ts index 8665de00275a..b56596939a8f 100644 --- a/lib/vscode/src/vs/editor/browser/services/codeEditorService.ts +++ b/src/vs/editor/browser/services/codeEditorService.ts @@ -7,7 +7,7 @@ import { Event } from 'vs/base/common/event'; import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { IDecorationRenderOptions } from 'vs/editor/common/editorCommon'; import { IModelDecorationOptions, ITextModel } from 'vs/editor/common/model'; -import { IResourceEditorInput } from 'vs/platform/editor/common/editor'; +import { ITextResourceEditorInput } from 'vs/platform/editor/common/editor'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { URI } from 'vs/base/common/uri'; @@ -39,7 +39,7 @@ export interface ICodeEditorService { */ getFocusedCodeEditor(): ICodeEditor | null; - registerDecorationType(key: string, options: IDecorationRenderOptions, parentTypeKey?: string, editor?: ICodeEditor): void; + registerDecorationType(description: string, key: string, options: IDecorationRenderOptions, parentTypeKey?: string, editor?: ICodeEditor): void; removeDecorationType(key: string): void; resolveDecorationOptions(typeKey: string, writable: boolean): IModelDecorationOptions; resolveDecorationCSSRules(decorationTypeKey: string): CSSRuleList | null; @@ -52,5 +52,5 @@ export interface ICodeEditorService { getTransientModelProperties(model: ITextModel): [string, any][] | undefined; getActiveCodeEditor(): ICodeEditor | null; - openCodeEditor(input: IResourceEditorInput, source: ICodeEditor | null, sideBySide?: boolean): Promise; + openCodeEditor(input: ITextResourceEditorInput, source: ICodeEditor | null, sideBySide?: boolean): Promise; } diff --git a/lib/vscode/src/vs/editor/browser/services/codeEditorServiceImpl.ts b/src/vs/editor/browser/services/codeEditorServiceImpl.ts similarity index 97% rename from lib/vscode/src/vs/editor/browser/services/codeEditorServiceImpl.ts rename to src/vs/editor/browser/services/codeEditorServiceImpl.ts index 1451ddac061c..7e7ddddee847 100644 --- a/lib/vscode/src/vs/editor/browser/services/codeEditorServiceImpl.ts +++ b/src/vs/editor/browser/services/codeEditorServiceImpl.ts @@ -123,7 +123,7 @@ export abstract class CodeEditorServiceImpl extends AbstractCodeEditorService { this._editorStyleSheets.delete(editorId); } - public registerDecorationType(key: string, options: IDecorationRenderOptions, parentTypeKey?: string, editor?: ICodeEditor): void { + public registerDecorationType(description: string, key: string, options: IDecorationRenderOptions, parentTypeKey?: string, editor?: ICodeEditor): void { let provider = this._decorationOptionProviders.get(key); if (!provider) { const styleSheet = this._getOrCreateStyleSheet(editor); @@ -134,7 +134,7 @@ export abstract class CodeEditorServiceImpl extends AbstractCodeEditorService { options: options || Object.create(null) }; if (!parentTypeKey) { - provider = new DecorationTypeOptionsProvider(this._themeService, styleSheet, providerArgs); + provider = new DecorationTypeOptionsProvider(description, this._themeService, styleSheet, providerArgs); } else { provider = new DecorationSubTypeOptionsProvider(this._themeService, styleSheet, providerArgs); } @@ -240,6 +240,7 @@ export class DecorationTypeOptionsProvider implements IModelDecorationOptionsPro private readonly _styleSheet: GlobalStyleSheet | RefCountedStyleSheet; public refCount: number; + public description: string; public className: string | undefined; public inlineClassName: string | undefined; public inlineClassNameAffectsLetterSpacing: boolean | undefined; @@ -250,7 +251,9 @@ export class DecorationTypeOptionsProvider implements IModelDecorationOptionsPro public overviewRuler: IModelDecorationOverviewRulerOptions | undefined; public stickiness: TrackedRangeStickiness | undefined; - constructor(themeService: IThemeService, styleSheet: GlobalStyleSheet | RefCountedStyleSheet, providerArgs: ProviderArguments) { + constructor(description: string, themeService: IThemeService, styleSheet: GlobalStyleSheet | RefCountedStyleSheet, providerArgs: ProviderArguments) { + this.description = description; + this._styleSheet = styleSheet; this._styleSheet.ref(); this.refCount = 0; @@ -305,6 +308,7 @@ export class DecorationTypeOptionsProvider implements IModelDecorationOptionsPro return this; } return { + description: this.description, inlineClassName: this.inlineClassName, beforeContentClassName: this.beforeContentClassName, afterContentClassName: this.afterContentClassName, diff --git a/lib/vscode/src/vs/editor/browser/services/markerDecorations.ts b/src/vs/editor/browser/services/markerDecorations.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/services/markerDecorations.ts rename to src/vs/editor/browser/services/markerDecorations.ts diff --git a/lib/vscode/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts similarity index 92% rename from lib/vscode/src/vs/editor/browser/services/openerService.ts rename to src/vs/editor/browser/services/openerService.ts index bc54879c7dc8..0a3b27961270 100644 --- a/lib/vscode/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -191,31 +191,41 @@ export class OpenerService implements IOpenerService { async resolveExternalUri(resource: URI, options?: ResolveExternalUriOptions): Promise { for (const resolver of this._resolvers) { - const result = await resolver.resolveExternalUri(resource, options); - if (result) { - if (!this._resolvedUriTargets.has(result.resolved)) { - this._resolvedUriTargets.set(result.resolved, resource); + try { + const result = await resolver.resolveExternalUri(resource, options); + if (result) { + if (!this._resolvedUriTargets.has(result.resolved)) { + this._resolvedUriTargets.set(result.resolved, resource); + } + return result; } - return result; + } catch { + // noop } } - return { resolved: resource, dispose: () => { } }; + throw new Error('Could not resolve external URI: ' + resource.toString()); } private async _doOpenExternal(resource: URI | string, options: OpenOptions | undefined): Promise { //todo@jrieken IExternalUriResolver should support `uri: URI | string` const uri = typeof resource === 'string' ? URI.parse(resource) : resource; - const { resolved } = await this.resolveExternalUri(uri, options); + let externalUri: URI; + + try { + externalUri = (await this.resolveExternalUri(uri, options)).resolved; + } catch { + externalUri = uri; + } let href: string; - if (typeof resource === 'string' && uri.toString() === resolved.toString()) { + if (typeof resource === 'string' && uri.toString() === externalUri.toString()) { // open the url-string AS IS href = resource; } else { // open URI using the toString(noEncode)+encodeURI-trick - href = encodeURI(resolved.toString(true)); + href = encodeURI(externalUri.toString(true)); } if (options?.allowContributedOpeners) { diff --git a/lib/vscode/src/vs/editor/browser/view/domLineBreaksComputer.ts b/src/vs/editor/browser/view/domLineBreaksComputer.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/view/domLineBreaksComputer.ts rename to src/vs/editor/browser/view/domLineBreaksComputer.ts diff --git a/lib/vscode/src/vs/editor/browser/view/dynamicViewOverlay.ts b/src/vs/editor/browser/view/dynamicViewOverlay.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/view/dynamicViewOverlay.ts rename to src/vs/editor/browser/view/dynamicViewOverlay.ts diff --git a/lib/vscode/src/vs/editor/browser/view/viewController.ts b/src/vs/editor/browser/view/viewController.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/view/viewController.ts rename to src/vs/editor/browser/view/viewController.ts diff --git a/lib/vscode/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/view/viewImpl.ts rename to src/vs/editor/browser/view/viewImpl.ts diff --git a/lib/vscode/src/vs/editor/browser/view/viewLayer.ts b/src/vs/editor/browser/view/viewLayer.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/view/viewLayer.ts rename to src/vs/editor/browser/view/viewLayer.ts diff --git a/lib/vscode/src/vs/editor/browser/view/viewOverlays.ts b/src/vs/editor/browser/view/viewOverlays.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/view/viewOverlays.ts rename to src/vs/editor/browser/view/viewOverlays.ts diff --git a/lib/vscode/src/vs/editor/browser/view/viewPart.ts b/src/vs/editor/browser/view/viewPart.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/view/viewPart.ts rename to src/vs/editor/browser/view/viewPart.ts diff --git a/lib/vscode/src/vs/editor/browser/view/viewUserInputEvents.ts b/src/vs/editor/browser/view/viewUserInputEvents.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/view/viewUserInputEvents.ts rename to src/vs/editor/browser/view/viewUserInputEvents.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts rename to src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.css b/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.css rename to src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.css diff --git a/lib/vscode/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts b/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts rename to src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/decorations/decorations.css b/src/vs/editor/browser/viewParts/decorations/decorations.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/decorations/decorations.css rename to src/vs/editor/browser/viewParts/decorations/decorations.css diff --git a/lib/vscode/src/vs/editor/browser/viewParts/decorations/decorations.ts b/src/vs/editor/browser/viewParts/decorations/decorations.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/decorations/decorations.ts rename to src/vs/editor/browser/viewParts/decorations/decorations.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts b/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts rename to src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.css b/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.css rename to src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.css diff --git a/lib/vscode/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts b/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts rename to src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/indentGuides/indentGuides.css b/src/vs/editor/browser/viewParts/indentGuides/indentGuides.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/indentGuides/indentGuides.css rename to src/vs/editor/browser/viewParts/indentGuides/indentGuides.css diff --git a/lib/vscode/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts b/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts rename to src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.css b/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.css rename to src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.css diff --git a/lib/vscode/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts b/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts rename to src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/lines/rangeUtil.ts b/src/vs/editor/browser/viewParts/lines/rangeUtil.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/lines/rangeUtil.ts rename to src/vs/editor/browser/viewParts/lines/rangeUtil.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/lines/viewLine.ts b/src/vs/editor/browser/viewParts/lines/viewLine.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/lines/viewLine.ts rename to src/vs/editor/browser/viewParts/lines/viewLine.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/lines/viewLines.css b/src/vs/editor/browser/viewParts/lines/viewLines.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/lines/viewLines.css rename to src/vs/editor/browser/viewParts/lines/viewLines.css diff --git a/lib/vscode/src/vs/editor/browser/viewParts/lines/viewLines.ts b/src/vs/editor/browser/viewParts/lines/viewLines.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/lines/viewLines.ts rename to src/vs/editor/browser/viewParts/lines/viewLines.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.css b/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.css rename to src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.css diff --git a/lib/vscode/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts b/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts rename to src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/margin/margin.ts b/src/vs/editor/browser/viewParts/margin/margin.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/margin/margin.ts rename to src/vs/editor/browser/viewParts/margin/margin.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.css b/src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.css rename to src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.css diff --git a/lib/vscode/src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.ts b/src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.ts rename to src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/minimap/minimap.css b/src/vs/editor/browser/viewParts/minimap/minimap.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/minimap/minimap.css rename to src/vs/editor/browser/viewParts/minimap/minimap.css diff --git a/lib/vscode/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts similarity index 99% rename from lib/vscode/src/vs/editor/browser/viewParts/minimap/minimap.ts rename to src/vs/editor/browser/viewParts/minimap/minimap.ts index 0ea038e6b890..454d7b4e15e5 100644 --- a/lib/vscode/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -1120,7 +1120,7 @@ class InnerMinimap extends Disposable { } if (this._model.options.size !== 'proportional') { if (e.leftButton && this._lastRenderData) { - // pretend the click occured in the center of the slider + // pretend the click occurred in the center of the slider const position = dom.getDomNodePagePosition(this._slider.domNode); const initialPosY = position.top + position.height / 2; this._startSliderDragging(e.buttons, e.posx, initialPosY, e.posy, this._lastRenderData.renderedLayout); diff --git a/lib/vscode/src/vs/editor/browser/viewParts/minimap/minimapCharRenderer.ts b/src/vs/editor/browser/viewParts/minimap/minimapCharRenderer.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/minimap/minimapCharRenderer.ts rename to src/vs/editor/browser/viewParts/minimap/minimapCharRenderer.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/minimap/minimapCharRendererFactory.ts b/src/vs/editor/browser/viewParts/minimap/minimapCharRendererFactory.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/minimap/minimapCharRendererFactory.ts rename to src/vs/editor/browser/viewParts/minimap/minimapCharRendererFactory.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/minimap/minimapCharSheet.ts b/src/vs/editor/browser/viewParts/minimap/minimapCharSheet.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/minimap/minimapCharSheet.ts rename to src/vs/editor/browser/viewParts/minimap/minimapCharSheet.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/minimap/minimapPreBaked.ts b/src/vs/editor/browser/viewParts/minimap/minimapPreBaked.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/minimap/minimapPreBaked.ts rename to src/vs/editor/browser/viewParts/minimap/minimapPreBaked.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.css b/src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.css rename to src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.css diff --git a/lib/vscode/src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.ts b/src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.ts rename to src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts b/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts rename to src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts b/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts rename to src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/rulers/rulers.css b/src/vs/editor/browser/viewParts/rulers/rulers.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/rulers/rulers.css rename to src/vs/editor/browser/viewParts/rulers/rulers.css diff --git a/lib/vscode/src/vs/editor/browser/viewParts/rulers/rulers.ts b/src/vs/editor/browser/viewParts/rulers/rulers.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/rulers/rulers.ts rename to src/vs/editor/browser/viewParts/rulers/rulers.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.css b/src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.css rename to src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.css diff --git a/lib/vscode/src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.ts b/src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.ts rename to src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/selections/selections.css b/src/vs/editor/browser/viewParts/selections/selections.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/selections/selections.css rename to src/vs/editor/browser/viewParts/selections/selections.css diff --git a/lib/vscode/src/vs/editor/browser/viewParts/selections/selections.ts b/src/vs/editor/browser/viewParts/selections/selections.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/selections/selections.ts rename to src/vs/editor/browser/viewParts/selections/selections.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts b/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts rename to src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/viewCursors/viewCursors.css b/src/vs/editor/browser/viewParts/viewCursors/viewCursors.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/viewCursors/viewCursors.css rename to src/vs/editor/browser/viewParts/viewCursors/viewCursors.css diff --git a/lib/vscode/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts b/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts rename to src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts diff --git a/lib/vscode/src/vs/editor/browser/viewParts/viewZones/viewZones.ts b/src/vs/editor/browser/viewParts/viewZones/viewZones.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/viewParts/viewZones/viewZones.ts rename to src/vs/editor/browser/viewParts/viewZones/viewZones.ts diff --git a/lib/vscode/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts similarity index 97% rename from lib/vscode/src/vs/editor/browser/widget/codeEditorWidget.ts rename to src/vs/editor/browser/widget/codeEditorWidget.ts index 9d89b72db24f..977e55d180ba 100644 --- a/lib/vscode/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -217,8 +217,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE private readonly _id: number; private readonly _configuration: editorCommon.IConfiguration; - protected readonly _contributions: { [key: string]: editorCommon.IEditorContribution; }; - protected readonly _actions: { [key: string]: editorCommon.IEditorAction; }; + protected _contributions: { [key: string]: editorCommon.IEditorContribution; }; + protected _actions: { [key: string]: editorCommon.IEditorAction; }; // --- Members logically associated to a model protected _modelData: ModelData | null; @@ -226,14 +226,14 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE protected readonly _instantiationService: IInstantiationService; protected readonly _contextKeyService: IContextKeyService; private readonly _notificationService: INotificationService; - private readonly _codeEditorService: ICodeEditorService; + protected readonly _codeEditorService: ICodeEditorService; private readonly _commandService: ICommandService; private readonly _themeService: IThemeService; private readonly _focusTracker: CodeEditorWidgetFocusTracker; - private readonly _contentWidgets: { [key: string]: IContentWidgetData; }; - private readonly _overlayWidgets: { [key: string]: IOverlayWidgetData; }; + private _contentWidgets: { [key: string]: IContentWidgetData; }; + private _overlayWidgets: { [key: string]: IOverlayWidgetData; }; /** * map from "parent" decoration type to live decoration ids. @@ -307,6 +307,10 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE contributions = EditorExtensionsRegistry.getEditorContributions(); } for (const desc of contributions) { + if (this._contributions[desc.id]) { + onUnexpectedError(new Error(`Cannot have two contributions with the same id ${desc.id}`)); + continue; + } try { const contribution = this._instantiationService.createInstance(desc.ctor, this); this._contributions[desc.id] = contribution; @@ -316,6 +320,10 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } EditorExtensionsRegistry.getEditorActions().forEach((action) => { + if (this._actions[action.id]) { + onUnexpectedError(new Error(`Cannot have two actions with the same id ${action.id}`)); + return; + } const internalAction = new InternalEditorAction( action.id, action.label, @@ -356,6 +364,10 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE const contributionId = keys[i]; this._contributions[contributionId].dispose(); } + this._contributions = {}; + this._actions = {}; + this._contentWidgets = {}; + this._overlayWidgets = {}; this._removeDecorationTypes(); this._postDetachModelCleanup(this._detachModel()); @@ -1036,6 +1048,10 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE return; } + this._triggerCommand(handlerId, payload); + } + + protected _triggerCommand(handlerId: string, payload: any): void { this._commandService.executeCommand(handlerId, payload); } @@ -1205,7 +1221,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE return this._modelData.model.deltaDecorations(oldDecorations, newDecorations, this._id); } - public setDecorations(decorationTypeKey: string, decorationOptions: editorCommon.IDecorationOptions[]): void { + public setDecorations(description: string, decorationTypeKey: string, decorationOptions: editorCommon.IDecorationOptions[]): void { const newDecorationsSubTypes: { [key: string]: boolean } = {}; const oldDecorationsSubTypes = this._decorationTypeSubtypes[decorationTypeKey] || {}; @@ -1224,7 +1240,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE typeKey = decorationTypeKey + '-' + subType; if (!oldDecorationsSubTypes[subType] && !newDecorationsSubTypes[subType]) { // decoration type did not exist before, register new one - this._registerDecorationType(typeKey, decorationOption.renderOptions, decorationTypeKey); + this._registerDecorationType(description, typeKey, decorationOption.renderOptions, decorationTypeKey); } newDecorationsSubTypes[subType] = true; } @@ -1685,8 +1701,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE return model; } - private _registerDecorationType(key: string, options: editorCommon.IDecorationRenderOptions, parentTypeKey?: string): void { - this._codeEditorService.registerDecorationType(key, options, parentTypeKey, this); + private _registerDecorationType(description: string, key: string, options: editorCommon.IDecorationRenderOptions, parentTypeKey?: string): void { + this._codeEditorService.registerDecorationType(description, key, options, parentTypeKey, this); } private _removeDecorationType(key: string): void { @@ -1849,7 +1865,7 @@ export class EditorModeContext extends Disposable { private readonly _hasMultipleDocumentFormattingProvider: IContextKey; private readonly _hasMultipleDocumentSelectionFormattingProvider: IContextKey; private readonly _hasSignatureHelpProvider: IContextKey; - private readonly _hasInlineHintsProvider: IContextKey; + private readonly _hasInlayHintsProvider: IContextKey; private readonly _isInWalkThrough: IContextKey; constructor( @@ -1872,7 +1888,7 @@ export class EditorModeContext extends Disposable { this._hasReferenceProvider = EditorContextKeys.hasReferenceProvider.bindTo(_contextKeyService); this._hasRenameProvider = EditorContextKeys.hasRenameProvider.bindTo(_contextKeyService); this._hasSignatureHelpProvider = EditorContextKeys.hasSignatureHelpProvider.bindTo(_contextKeyService); - this._hasInlineHintsProvider = EditorContextKeys.hasInlineHintsProvider.bindTo(_contextKeyService); + this._hasInlayHintsProvider = EditorContextKeys.hasInlayHintsProvider.bindTo(_contextKeyService); this._hasDocumentFormattingProvider = EditorContextKeys.hasDocumentFormattingProvider.bindTo(_contextKeyService); this._hasDocumentSelectionFormattingProvider = EditorContextKeys.hasDocumentSelectionFormattingProvider.bindTo(_contextKeyService); this._hasMultipleDocumentFormattingProvider = EditorContextKeys.hasMultipleDocumentFormattingProvider.bindTo(_contextKeyService); @@ -1901,7 +1917,7 @@ export class EditorModeContext extends Disposable { this._register(modes.DocumentFormattingEditProviderRegistry.onDidChange(update)); this._register(modes.DocumentRangeFormattingEditProviderRegistry.onDidChange(update)); this._register(modes.SignatureHelpProviderRegistry.onDidChange(update)); - this._register(modes.InlineHintsProviderRegistry.onDidChange(update)); + this._register(modes.InlayHintsProviderRegistry.onDidChange(update)); update(); } @@ -1953,7 +1969,7 @@ export class EditorModeContext extends Disposable { this._hasReferenceProvider.set(modes.ReferenceProviderRegistry.has(model)); this._hasRenameProvider.set(modes.RenameProviderRegistry.has(model)); this._hasSignatureHelpProvider.set(modes.SignatureHelpProviderRegistry.has(model)); - this._hasInlineHintsProvider.set(modes.InlineHintsProviderRegistry.has(model)); + this._hasInlayHintsProvider.set(modes.InlayHintsProviderRegistry.has(model)); this._hasDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.has(model) || modes.DocumentRangeFormattingEditProviderRegistry.has(model)); this._hasDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.has(model)); this._hasMultipleDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.all(model).length + modes.DocumentRangeFormattingEditProviderRegistry.all(model).length > 1); diff --git a/lib/vscode/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts similarity index 99% rename from lib/vscode/src/vs/editor/browser/widget/diffEditorWidget.ts rename to src/vs/editor/browser/widget/diffEditorWidget.ts index 19170cfe8280..ec7c270000f4 100644 --- a/lib/vscode/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -1775,27 +1775,33 @@ function createDecoration(startLineNumber: number, startColumn: number, endLineN const DECORATIONS = { charDelete: ModelDecorationOptions.register({ + description: 'diff-editor-char-delete', className: 'char-delete' }), charDeleteWholeLine: ModelDecorationOptions.register({ + description: 'diff-editor-char-delete-whole-line', className: 'char-delete', isWholeLine: true }), charInsert: ModelDecorationOptions.register({ + description: 'diff-editor-char-insert', className: 'char-insert' }), charInsertWholeLine: ModelDecorationOptions.register({ + description: 'diff-editor-char-insert-whole-line', className: 'char-insert', isWholeLine: true }), lineInsert: ModelDecorationOptions.register({ + description: 'diff-editor-line-insert', className: 'line-insert', marginClassName: 'line-insert', isWholeLine: true }), lineInsertWithSign: ModelDecorationOptions.register({ + description: 'diff-editor-line-insert-with-sign', className: 'line-insert', linesDecorationsClassName: 'insert-sign ' + ThemeIcon.asClassName(diffInsertIcon), marginClassName: 'line-insert', @@ -1803,11 +1809,13 @@ const DECORATIONS = { }), lineDelete: ModelDecorationOptions.register({ + description: 'diff-editor-line-delete', className: 'line-delete', marginClassName: 'line-delete', isWholeLine: true }), lineDeleteWithSign: ModelDecorationOptions.register({ + description: 'diff-editor-line-delete-with-sign', className: 'line-delete', linesDecorationsClassName: 'delete-sign ' + ThemeIcon.asClassName(diffRemoveIcon), marginClassName: 'line-delete', @@ -1815,6 +1823,7 @@ const DECORATIONS = { }), lineDeleteMargin: ModelDecorationOptions.register({ + description: 'diff-editor-line-delete-margin', marginClassName: 'line-delete', }) diff --git a/lib/vscode/src/vs/editor/browser/widget/diffNavigator.ts b/src/vs/editor/browser/widget/diffNavigator.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/widget/diffNavigator.ts rename to src/vs/editor/browser/widget/diffNavigator.ts diff --git a/lib/vscode/src/vs/editor/browser/widget/diffReview.ts b/src/vs/editor/browser/widget/diffReview.ts similarity index 98% rename from lib/vscode/src/vs/editor/browser/widget/diffReview.ts rename to src/vs/editor/browser/widget/diffReview.ts index 8a568c82136e..3d27ade5911a 100644 --- a/lib/vscode/src/vs/editor/browser/widget/diffReview.ts +++ b/src/vs/editor/browser/widget/diffReview.ts @@ -22,7 +22,6 @@ import { LineTokens } from 'vs/editor/common/core/lineTokens'; import { Position } from 'vs/editor/common/core/position'; import { ILineChange, ScrollType } from 'vs/editor/common/editorCommon'; import { ITextModel, TextModelResolvedOptions } from 'vs/editor/common/model'; -import { ColorId, FontStyle, MetadataConsts } from 'vs/editor/common/modes'; import { editorLineNumbers } from 'vs/editor/common/view/editorColorRegistry'; import { RenderLineInput, renderViewLine2 as renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; import { ViewLineRenderingData } from 'vs/editor/common/viewModel/viewModel'; @@ -777,19 +776,7 @@ export class DiffReview extends Disposable { private static _renderLine(model: ITextModel, options: IComputedEditorOptions, tabSize: number, lineNumber: number): string { const lineContent = model.getLineContent(lineNumber); const fontInfo = options.get(EditorOption.fontInfo); - - const defaultMetadata = ( - (FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET) - | (ColorId.DefaultForeground << MetadataConsts.FOREGROUND_OFFSET) - | (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET) - ) >>> 0; - - const tokens = new Uint32Array(2); - tokens[0] = lineContent.length; - tokens[1] = defaultMetadata; - - const lineTokens = new LineTokens(tokens, lineContent); - + const lineTokens = LineTokens.createEmpty(lineContent); const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, model.mightContainNonBasicASCII()); const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, model.mightContainRTL()); const r = renderViewLine(new RenderLineInput( diff --git a/lib/vscode/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts b/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts rename to src/vs/editor/browser/widget/embeddedCodeEditorWidget.ts diff --git a/lib/vscode/src/vs/editor/browser/widget/inlineDiffMargin.ts b/src/vs/editor/browser/widget/inlineDiffMargin.ts similarity index 100% rename from lib/vscode/src/vs/editor/browser/widget/inlineDiffMargin.ts rename to src/vs/editor/browser/widget/inlineDiffMargin.ts diff --git a/lib/vscode/src/vs/editor/browser/widget/media/diffEditor.css b/src/vs/editor/browser/widget/media/diffEditor.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/widget/media/diffEditor.css rename to src/vs/editor/browser/widget/media/diffEditor.css diff --git a/lib/vscode/src/vs/editor/browser/widget/media/diffReview.css b/src/vs/editor/browser/widget/media/diffReview.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/widget/media/diffReview.css rename to src/vs/editor/browser/widget/media/diffReview.css diff --git a/lib/vscode/src/vs/editor/browser/widget/media/editor.css b/src/vs/editor/browser/widget/media/editor.css similarity index 100% rename from lib/vscode/src/vs/editor/browser/widget/media/editor.css rename to src/vs/editor/browser/widget/media/editor.css diff --git a/lib/vscode/src/vs/editor/common/commands/replaceCommand.ts b/src/vs/editor/common/commands/replaceCommand.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/commands/replaceCommand.ts rename to src/vs/editor/common/commands/replaceCommand.ts diff --git a/lib/vscode/src/vs/editor/common/commands/shiftCommand.ts b/src/vs/editor/common/commands/shiftCommand.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/commands/shiftCommand.ts rename to src/vs/editor/common/commands/shiftCommand.ts diff --git a/lib/vscode/src/vs/editor/common/commands/surroundSelectionCommand.ts b/src/vs/editor/common/commands/surroundSelectionCommand.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/commands/surroundSelectionCommand.ts rename to src/vs/editor/common/commands/surroundSelectionCommand.ts diff --git a/lib/vscode/src/vs/editor/common/commands/trimTrailingWhitespaceCommand.ts b/src/vs/editor/common/commands/trimTrailingWhitespaceCommand.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/commands/trimTrailingWhitespaceCommand.ts rename to src/vs/editor/common/commands/trimTrailingWhitespaceCommand.ts diff --git a/lib/vscode/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts similarity index 99% rename from lib/vscode/src/vs/editor/common/config/commonEditorConfig.ts rename to src/vs/editor/common/config/commonEditorConfig.ts index 4a888eb21e78..3ec9a2093e79 100644 --- a/lib/vscode/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -204,6 +204,7 @@ function migrateOptions(options: IEditorOptions): void { mapping['method'] = 'showMethods'; mapping['function'] = 'showFunctions'; mapping['constructor'] = 'showConstructors'; + mapping['deprecated'] = 'showDeprecated'; mapping['field'] = 'showFields'; mapping['variable'] = 'showVariables'; mapping['class'] = 'showClasses'; diff --git a/lib/vscode/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts similarity index 97% rename from lib/vscode/src/vs/editor/common/config/editorOptions.ts rename to src/vs/editor/common/config/editorOptions.ts index ee5f4095357a..4d45c26f8fa6 100644 --- a/lib/vscode/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -382,8 +382,9 @@ export interface IEditorOptions { * Suggest options. */ suggest?: ISuggestOptions; + inlineSuggest?: IInlineSuggestOptions; /** - * Smart select opptions; + * Smart select options. */ smartSelect?: ISmartSelectOptions; /** @@ -637,7 +638,11 @@ export interface IEditorOptions { /** * Control the behavior and rendering of the inline hints. */ - inlineHints?: IEditorInlineHintsOptions; + inlayHints?: IEditorInlayHintsOptions; + /** + * Control if the editor should use shadow DOM. + */ + useShadowDOM?: boolean; } /** @@ -2396,12 +2401,12 @@ class EditorLightbulb extends BaseEditorOption>; +export type EditorInlayHintsOptions = Readonly>; -class EditorInlineHints extends BaseEditorOption { +class EditorInlayHints extends BaseEditorOption { constructor() { - const defaults: EditorInlineHintsOptions = { enabled: true, fontSize: 0, fontFamily: EDITOR_FONT_DEFAULTS.fontFamily }; + const defaults: EditorInlayHintsOptions = { enabled: true, fontSize: 0, fontFamily: EDITOR_FONT_DEFAULTS.fontFamily }; super( - EditorOption.inlineHints, 'inlineHints', defaults, + EditorOption.inlayHints, 'inlayHints', defaults, { - 'editor.inlineHints.enabled': { + 'editor.inlayHints.enabled': { type: 'boolean', default: defaults.enabled, - description: nls.localize('inlineHints.enable', "Enables the inline hints in the editor.") + description: nls.localize('inlayHints.enable', "Enables the inlay hints in the editor.") }, - 'editor.inlineHints.fontSize': { + 'editor.inlayHints.fontSize': { type: 'number', default: defaults.fontSize, - description: nls.localize('inlineHints.fontSize', "Controls font size of inline hints in the editor. When set to `0`, the 90% of `#editor.fontSize#` is used.") + description: nls.localize('inlayHints.fontSize', "Controls font size of inlay hints in the editor. When set to `0`, the 90% of `#editor.fontSize#` is used.") }, - 'editor.inlineHints.fontFamily': { + 'editor.inlayHints.fontFamily': { type: 'string', default: defaults.fontFamily, - description: nls.localize('inlineHints.fontFamily', "Controls font family of inline hints in the editor.") + description: nls.localize('inlayHints.fontFamily', "Controls font family of inlay hints in the editor.") }, } ); } - public validate(_input: any): EditorInlineHintsOptions { + public validate(_input: any): EditorInlayHintsOptions { if (!_input || typeof _input !== 'object') { return this.defaultValue; } - const input = _input as IEditorInlineHintsOptions; + const input = _input as IEditorInlayHintsOptions; return { enabled: boolean(input.enabled, this.defaultValue.enabled), fontSize: EditorIntOption.clampedInt(input.fontSize, this.defaultValue.fontSize, 0, 100), @@ -3136,6 +3141,51 @@ class EditorScrollbar extends BaseEditorOption>; + +/** + * Configuration options for inline suggestions + */ +class InlineEditorSuggest extends BaseEditorOption { + constructor() { + const defaults: InternalInlineSuggestOptions = { + enabled: false + }; + + super( + EditorOption.inlineSuggest, 'inlineSuggest', defaults, + { + 'editor.inlineSuggest.enabled': { + type: 'boolean', + default: defaults.enabled, + description: nls.localize('inlineSuggest.enabled', "Controls whether to automatically show inline suggestions in the editor.") + }, + } + ); + } + + public validate(_input: any): InternalInlineSuggestOptions { + if (!_input || typeof _input !== 'object') { + return this.defaultValue; + } + const input = _input as IInlineSuggestOptions; + return { + enabled: boolean(input.enabled, this.defaultValue.enabled), + }; + } +} + +//#endregion + //#region suggest /** @@ -3170,6 +3220,10 @@ export interface ISuggestOptions { * Enable or disable the suggest status bar. */ showStatusBar?: boolean; + /** + * Enable or disable the rendering of the suggestion preview. + */ + preview?: boolean; /** * Show details inline with the label. Defaults to true. */ @@ -3186,6 +3240,10 @@ export interface ISuggestOptions { * Show constructor-suggestions. */ showConstructors?: boolean; + /** + * Show deprecated-suggestions. + */ + showDeprecated?: boolean; /** * Show field-suggestions. */ @@ -3297,10 +3355,12 @@ class EditorSuggest extends BaseEditorOption(); + result.push(-1); + let pos = 0; + let i = 0; + while (i < endOffset) { + const codePoint = strings.getNextCodePoint(lineContent, endOffset, i); + i += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + + result.push(pos); + if (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN) { + result.push(pos); + } + + if (codePoint === CharCode.Tab) { + pos = CursorColumns.nextRenderTabStop(pos, tabSize); + } else { + let graphemeBreakType = strings.getGraphemeBreakType(codePoint); + while (i < endOffset) { + const nextCodePoint = strings.getNextCodePoint(lineContent, endOffset, i); + const nextGraphemeBreakType = strings.getGraphemeBreakType(nextCodePoint); + if (strings.breakBetweenGraphemeBreakType(graphemeBreakType, nextGraphemeBreakType)) { + break; + } + i += (nextCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + + result.push(pos); + if (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN) { + result.push(pos); + } + + graphemeBreakType = nextGraphemeBreakType; + } + if (strings.isFullWidthCharacter(codePoint) || strings.isEmojiImprecise(codePoint)) { + pos = pos + 2; + } else { + pos = pos + 1; + } + } + } + result.push(pos); + return result; + } + public static toStatusbarColumn(lineContent: string, column: number, tabSize: number): number { const lineContentLength = lineContent.length; const endOffset = column - 1 < lineContentLength ? column - 1 : lineContentLength; diff --git a/lib/vscode/src/vs/editor/common/controller/cursorDeleteOperations.ts b/src/vs/editor/common/controller/cursorDeleteOperations.ts similarity index 78% rename from lib/vscode/src/vs/editor/common/controller/cursorDeleteOperations.ts rename to src/vs/editor/common/controller/cursorDeleteOperations.ts index 1d0fdd265762..5b799220d594 100644 --- a/lib/vscode/src/vs/editor/common/controller/cursorDeleteOperations.ts +++ b/src/vs/editor/common/controller/cursorDeleteOperations.ts @@ -12,6 +12,7 @@ import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import { ICommand } from 'vs/editor/common/editorCommon'; import { StandardAutoClosingPairConditional } from 'vs/editor/common/modes/languageConfiguration'; +import { Position } from 'vs/editor/common/core/position'; export class DeleteOperations { @@ -25,7 +26,7 @@ export class DeleteOperations { if (deleteSelection.isEmpty()) { let position = selection.getPosition(); - let rightOfPosition = MoveOperations.right(config, model, position.lineNumber, position.column); + let rightOfPosition = MoveOperations.right(config, model, position); deleteSelection = new Range( rightOfPosition.lineNumber, rightOfPosition.column, @@ -141,63 +142,72 @@ export class DeleteOperations { } public static deleteLeft(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[], autoClosedCharacters: Range[]): [boolean, Array] { - if (this.isAutoClosingPairDelete(config.autoClosingDelete, config.autoClosingBrackets, config.autoClosingQuotes, config.autoClosingPairs.autoClosingPairsOpenByEnd, model, selections, autoClosedCharacters)) { return this._runAutoClosingPairDelete(config, model, selections); } - let commands: Array = []; + const commands: Array = []; let shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.DeletingLeft); for (let i = 0, len = selections.length; i < len; i++) { - const selection = selections[i]; - - let deleteSelection: Range = selection; - - if (deleteSelection.isEmpty()) { - let position = selection.getPosition(); - - if (config.useTabStops && position.column > 1) { - let lineContent = model.getLineContent(position.lineNumber); - - let firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent); - let lastIndentationColumn = ( - firstNonWhitespaceIndex === -1 - ? /* entire string is whitespace */lineContent.length + 1 - : firstNonWhitespaceIndex + 1 - ); - - if (position.column <= lastIndentationColumn) { - let fromVisibleColumn = CursorColumns.visibleColumnFromColumn2(config, model, position); - let toVisibleColumn = CursorColumns.prevIndentTabStop(fromVisibleColumn, config.indentSize); - let toColumn = CursorColumns.columnFromVisibleColumn2(config, model, position.lineNumber, toVisibleColumn); - deleteSelection = new Range(position.lineNumber, toColumn, position.lineNumber, position.column); - } else { - deleteSelection = new Range(position.lineNumber, position.column - 1, position.lineNumber, position.column); - } - } else { - let leftOfPosition = MoveOperations.left(config, model, position.lineNumber, position.column); - deleteSelection = new Range( - leftOfPosition.lineNumber, - leftOfPosition.column, - position.lineNumber, - position.column - ); - } - } + let deleteRange = DeleteOperations.getDeleteRange(selections[i], model, config); - if (deleteSelection.isEmpty()) { - // Probably at beginning of file => ignore + // Ignore empty delete ranges, as they have no effect + // They happen if the cursor is at the beginning of the file. + if (deleteRange.isEmpty()) { commands[i] = null; continue; } - if (deleteSelection.startLineNumber !== deleteSelection.endLineNumber) { + if (deleteRange.startLineNumber !== deleteRange.endLineNumber) { shouldPushStackElementBefore = true; } - commands[i] = new ReplaceCommand(deleteSelection, ''); + commands[i] = new ReplaceCommand(deleteRange, ''); } return [shouldPushStackElementBefore, commands]; + + } + + private static getDeleteRange(selection: Selection, model: ICursorSimpleModel, config: CursorConfiguration,): Range { + if (!selection.isEmpty()) { + return selection; + } + + const position = selection.getPosition(); + + // Unintend when using tab stops and cursor is within indentation + if (config.useTabStops && position.column > 1) { + const lineContent = model.getLineContent(position.lineNumber); + + const firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent); + const lastIndentationColumn = ( + firstNonWhitespaceIndex === -1 + ? /* entire string is whitespace */ lineContent.length + 1 + : firstNonWhitespaceIndex + 1 + ); + + if (position.column <= lastIndentationColumn) { + const fromVisibleColumn = CursorColumns.visibleColumnFromColumn2(config, model, position); + const toVisibleColumn = CursorColumns.prevIndentTabStop(fromVisibleColumn, config.indentSize); + const toColumn = CursorColumns.columnFromVisibleColumn2(config, model, position.lineNumber, toVisibleColumn); + return new Range(position.lineNumber, toColumn, position.lineNumber, position.column); + } + } + + return Range.fromPositions(DeleteOperations.getPositionAfterDeleteLeft(position, model), position); + } + + private static getPositionAfterDeleteLeft(position: Position, model: ICursorSimpleModel): Position { + if (position.column > 1) { + // Convert 1-based columns to 0-based offsets and back. + const idx = strings.getLeftDeleteOffset(position.column - 1, model.getLineContent(position.lineNumber)); + return position.with(undefined, idx + 1); + } else if (position.lineNumber > 1) { + const newLine = position.lineNumber - 1; + return new Position(newLine, model.getLineMaxColumn(newLine)); + } else { + return position; + } } public static cut(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): EditOperationResult { diff --git a/lib/vscode/src/vs/editor/common/controller/cursorEvents.ts b/src/vs/editor/common/controller/cursorEvents.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/controller/cursorEvents.ts rename to src/vs/editor/common/controller/cursorEvents.ts diff --git a/lib/vscode/src/vs/editor/common/controller/cursorMoveCommands.ts b/src/vs/editor/common/controller/cursorMoveCommands.ts similarity index 93% rename from lib/vscode/src/vs/editor/common/controller/cursorMoveCommands.ts rename to src/vs/editor/common/controller/cursorMoveCommands.ts index 2ae510c30a05..a07173f2eede 100644 --- a/lib/vscode/src/vs/editor/common/controller/cursorMoveCommands.ts +++ b/src/vs/editor/common/controller/cursorMoveCommands.ts @@ -419,29 +419,11 @@ export class CursorMoveCommands { } private static _moveLeft(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, noOfColumns: number): PartialCursorState[] { - const hasMultipleCursors = (cursors.length > 1); - let result: PartialCursorState[] = []; - for (let i = 0, len = cursors.length; i < len; i++) { - const cursor = cursors[i]; - const skipWrappingPointStop = hasMultipleCursors || !cursor.viewState.hasSelection(); - let newViewState = MoveOperations.moveLeft(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns); - - if (skipWrappingPointStop - && noOfColumns === 1 - && cursor.viewState.position.column === viewModel.getLineMinColumn(cursor.viewState.position.lineNumber) - && newViewState.position.lineNumber !== cursor.viewState.position.lineNumber - ) { - // moved over to the previous view line - const newViewModelPosition = viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position); - if (newViewModelPosition.lineNumber === cursor.modelState.position.lineNumber) { - // stayed on the same model line => pass wrapping point where 2 view positions map to a single model position - newViewState = MoveOperations.moveLeft(viewModel.cursorConfig, viewModel, newViewState, inSelectionMode, 1); - } - } - - result[i] = CursorState.fromViewState(newViewState); - } - return result; + return cursors.map(cursor => + CursorState.fromViewState( + MoveOperations.moveLeft(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns) + ) + ); } private static _moveHalfLineLeft(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] { @@ -456,29 +438,11 @@ export class CursorMoveCommands { } private static _moveRight(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, noOfColumns: number): PartialCursorState[] { - const hasMultipleCursors = (cursors.length > 1); - let result: PartialCursorState[] = []; - for (let i = 0, len = cursors.length; i < len; i++) { - const cursor = cursors[i]; - const skipWrappingPointStop = hasMultipleCursors || !cursor.viewState.hasSelection(); - let newViewState = MoveOperations.moveRight(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns); - - if (skipWrappingPointStop - && noOfColumns === 1 - && cursor.viewState.position.column === viewModel.getLineMaxColumn(cursor.viewState.position.lineNumber) - && newViewState.position.lineNumber !== cursor.viewState.position.lineNumber - ) { - // moved over to the next view line - const newViewModelPosition = viewModel.coordinatesConverter.convertViewPositionToModelPosition(newViewState.position); - if (newViewModelPosition.lineNumber === cursor.modelState.position.lineNumber) { - // stayed on the same model line => pass wrapping point where 2 view positions map to a single model position - newViewState = MoveOperations.moveRight(viewModel.cursorConfig, viewModel, newViewState, inSelectionMode, 1); - } - } - - result[i] = CursorState.fromViewState(newViewState); - } - return result; + return cursors.map(cursor => + CursorState.fromViewState( + MoveOperations.moveRight(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns) + ) + ); } private static _moveHalfLineRight(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] { diff --git a/lib/vscode/src/vs/editor/common/controller/cursorMoveOperations.ts b/src/vs/editor/common/controller/cursorMoveOperations.ts similarity index 75% rename from lib/vscode/src/vs/editor/common/controller/cursorMoveOperations.ts rename to src/vs/editor/common/controller/cursorMoveOperations.ts index 7d94c4374349..7fa58fa5c09a 100644 --- a/lib/vscode/src/vs/editor/common/controller/cursorMoveOperations.ts +++ b/src/vs/editor/common/controller/cursorMoveOperations.ts @@ -9,6 +9,7 @@ import { Range } from 'vs/editor/common/core/range'; import * as strings from 'vs/base/common/strings'; import { Constants } from 'vs/base/common/uint'; import { AtomicTabMoveOperations, Direction } from 'vs/editor/common/controller/cursorAtomicMoveOperations'; +import { PositionNormalizationAffinity } from 'vs/editor/common/model'; export class CursorPosition { _cursorPositionBrand: void; @@ -25,51 +26,86 @@ export class CursorPosition { } export class MoveOperations { - - public static leftPosition(model: ICursorSimpleModel, lineNumber: number, column: number): Position { - if (column > model.getLineMinColumn(lineNumber)) { - column = column - strings.prevCharLength(model.getLineContent(lineNumber), column - 1); - } else if (lineNumber > 1) { - lineNumber = lineNumber - 1; - column = model.getLineMaxColumn(lineNumber); + public static leftPosition(model: ICursorSimpleModel, position: Position): Position { + if (position.column > model.getLineMinColumn(position.lineNumber)) { + return position.delta(undefined, -strings.prevCharLength(model.getLineContent(position.lineNumber), position.column - 1)); + } else if (position.lineNumber > 1) { + const newLineNumber = position.lineNumber - 1; + return new Position(newLineNumber, model.getLineMaxColumn(newLineNumber)); + } else { + return position; } - return new Position(lineNumber, column); } - public static leftPositionAtomicSoftTabs(model: ICursorSimpleModel, lineNumber: number, column: number, tabSize: number): Position { - const minColumn = model.getLineMinColumn(lineNumber); - const lineContent = model.getLineContent(lineNumber); - const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - 1, tabSize, Direction.Left); - if (newPosition === -1 || newPosition + 1 < minColumn) { - return this.leftPosition(model, lineNumber, column); + private static leftPositionAtomicSoftTabs(model: ICursorSimpleModel, position: Position, tabSize: number): Position { + if (position.column <= model.getLineIndentColumn(position.lineNumber)) { + const minColumn = model.getLineMinColumn(position.lineNumber); + const lineContent = model.getLineContent(position.lineNumber); + const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, position.column - 1, tabSize, Direction.Left); + if (newPosition !== -1 && newPosition + 1 >= minColumn) { + return new Position(position.lineNumber, newPosition + 1); + } } - return new Position(lineNumber, newPosition + 1); + return this.leftPosition(model, position); } - public static left(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition { + private static left(config: CursorConfiguration, model: ICursorSimpleModel, position: Position): CursorPosition { const pos = config.stickyTabStops - ? MoveOperations.leftPositionAtomicSoftTabs(model, lineNumber, column, config.tabSize) - : MoveOperations.leftPosition(model, lineNumber, column); + ? MoveOperations.leftPositionAtomicSoftTabs(model, position, config.tabSize) + : MoveOperations.leftPosition(model, position); return new CursorPosition(pos.lineNumber, pos.column, 0); } + /** + * @param noOfColumns Must be either `1` + * or `Math.round(viewModel.getLineContent(viewLineNumber).length / 2)` (for half lines). + */ public static moveLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, noOfColumns: number): SingleCursorState { let lineNumber: number, column: number; if (cursor.hasSelection() && !inSelectionMode) { - // If we are in selection mode, move left without selection cancels selection and puts cursor at the beginning of the selection + // If the user has a selection and does not want to extend it, + // put the cursor at the beginning of the selection. lineNumber = cursor.selection.startLineNumber; column = cursor.selection.startColumn; } else { - let r = MoveOperations.left(config, model, cursor.position.lineNumber, cursor.position.column - (noOfColumns - 1)); - lineNumber = r.lineNumber; - column = r.column; + // This has no effect if noOfColumns === 1. + // It is ok to do so in the half-line scenario. + const pos = cursor.position.delta(undefined, -(noOfColumns - 1)); + // We clip the position before normalization, as normalization is not defined + // for possibly negative columns. + const normalizedPos = model.normalizePosition(MoveOperations.clipPositionColumn(pos, model), PositionNormalizationAffinity.Left); + const p = MoveOperations.left(config, model, normalizedPos); + + lineNumber = p.lineNumber; + column = p.column; } return cursor.move(inSelectionMode, lineNumber, column, 0); } + /** + * Adjusts the column so that it is within min/max of the line. + */ + private static clipPositionColumn(position: Position, model: ICursorSimpleModel): Position { + return new Position( + position.lineNumber, + MoveOperations.clipRange(position.column, model.getLineMinColumn(position.lineNumber), + model.getLineMaxColumn(position.lineNumber)) + ); + } + + private static clipRange(value: number, min: number, max: number): number { + if (value < min) { + return min; + } + if (value > max) { + return max; + } + return value; + } + public static rightPosition(model: ICursorSimpleModel, lineNumber: number, column: number): Position { if (column < model.getLineMaxColumn(lineNumber)) { column = column + strings.nextCharLength(model.getLineContent(lineNumber), column - 1); @@ -81,18 +117,20 @@ export class MoveOperations { } public static rightPositionAtomicSoftTabs(model: ICursorSimpleModel, lineNumber: number, column: number, tabSize: number, indentSize: number): Position { - const lineContent = model.getLineContent(lineNumber); - const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - 1, tabSize, Direction.Right); - if (newPosition === -1) { - return this.rightPosition(model, lineNumber, column); + if (column < model.getLineIndentColumn(lineNumber)) { + const lineContent = model.getLineContent(lineNumber); + const newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - 1, tabSize, Direction.Right); + if (newPosition !== -1) { + return new Position(lineNumber, newPosition + 1); + } } - return new Position(lineNumber, newPosition + 1); + return this.rightPosition(model, lineNumber, column); } - public static right(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition { + public static right(config: CursorConfiguration, model: ICursorSimpleModel, position: Position): CursorPosition { const pos = config.stickyTabStops - ? MoveOperations.rightPositionAtomicSoftTabs(model, lineNumber, column, config.tabSize, config.indentSize) - : MoveOperations.rightPosition(model, lineNumber, column); + ? MoveOperations.rightPositionAtomicSoftTabs(model, position.lineNumber, position.column, config.tabSize, config.indentSize) + : MoveOperations.rightPosition(model, position.lineNumber, position.column); return new CursorPosition(pos.lineNumber, pos.column, 0); } @@ -105,7 +143,9 @@ export class MoveOperations { lineNumber = cursor.selection.endLineNumber; column = cursor.selection.endColumn; } else { - let r = MoveOperations.right(config, model, cursor.position.lineNumber, cursor.position.column + (noOfColumns - 1)); + const pos = cursor.position.delta(undefined, noOfColumns - 1); + const normalizedPos = model.normalizePosition(MoveOperations.clipPositionColumn(pos, model), PositionNormalizationAffinity.Right); + const r = MoveOperations.right(config, model, normalizedPos); lineNumber = r.lineNumber; column = r.column; } diff --git a/lib/vscode/src/vs/editor/common/controller/cursorTypeOperations.ts b/src/vs/editor/common/controller/cursorTypeOperations.ts similarity index 93% rename from lib/vscode/src/vs/editor/common/controller/cursorTypeOperations.ts rename to src/vs/editor/common/controller/cursorTypeOperations.ts index 4acc0ae72be2..3f2e81ed0e1b 100644 --- a/lib/vscode/src/vs/editor/common/controller/cursorTypeOperations.ts +++ b/src/vs/editor/common/controller/cursorTypeOperations.ts @@ -260,8 +260,8 @@ export class TypeOperations { public static compositionType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number): EditOperationResult { const commands = selections.map(selection => this._compositionType(model, selection, text, replacePrevCharCnt, replaceNextCharCnt, positionDelta)); - return new EditOperationResult(EditOperationType.Typing, commands, { - shouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing), + return new EditOperationResult(EditOperationType.TypingOther, commands, { + shouldPushStackElementBefore: shouldPushStackElementBetween(prevEditOperationType, EditOperationType.TypingOther), shouldPushStackElementAfter: false }); } @@ -484,8 +484,8 @@ export class TypeOperations { const typeSelection = new Range(position.lineNumber, position.column, position.lineNumber, position.column + 1); commands[i] = new ReplaceCommand(typeSelection, ch); } - return new EditOperationResult(EditOperationType.Typing, commands, { - shouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing), + return new EditOperationResult(EditOperationType.TypingOther, commands, { + shouldPushStackElementBefore: shouldPushStackElementBetween(prevEditOperationType, EditOperationType.TypingOther), shouldPushStackElementAfter: false }); } @@ -636,7 +636,7 @@ export class TypeOperations { const selection = selections[i]; commands[i] = new TypeWithAutoClosingCommand(selection, ch, insertOpenCharacter, autoClosingPairClose); } - return new EditOperationResult(EditOperationType.Typing, commands, { + return new EditOperationResult(EditOperationType.TypingOther, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: false }); @@ -762,7 +762,7 @@ export class TypeOperations { let typeSelection = new Range(position.lineNumber, 1, position.lineNumber, position.column); const command = new ReplaceCommand(typeSelection, typeText); - return new EditOperationResult(EditOperationType.Typing, [command], { + return new EditOperationResult(getTypingOperation(typeText, prevEditOperationType), [command], { shouldPushStackElementBefore: false, shouldPushStackElementAfter: true }); @@ -803,7 +803,7 @@ export class TypeOperations { if (this._isAutoClosingOvertype(config, model, selections, autoClosedCharacters, ch)) { // Unfortunately, the close character is at this point "doubled", so we need to delete it... const commands = selections.map(s => new ReplaceCommand(new Range(s.positionLineNumber, s.positionColumn, s.positionLineNumber, s.positionColumn + 1), '', false)); - return new EditOperationResult(EditOperationType.Typing, commands, { + return new EditOperationResult(EditOperationType.TypingOther, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: false }); @@ -824,7 +824,7 @@ export class TypeOperations { for (let i = 0, len = selections.length; i < len; i++) { commands[i] = TypeOperations._enter(config, model, false, selections[i]); } - return new EditOperationResult(EditOperationType.Typing, commands, { + return new EditOperationResult(EditOperationType.TypingOther, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: false, }); @@ -841,7 +841,7 @@ export class TypeOperations { } } if (!autoIndentFails) { - return new EditOperationResult(EditOperationType.Typing, commands, { + return new EditOperationResult(EditOperationType.TypingOther, commands, { shouldPushStackElementBefore: true, shouldPushStackElementAfter: false, }); @@ -877,12 +877,10 @@ export class TypeOperations { for (let i = 0, len = selections.length; i < len; i++) { commands[i] = new ReplaceCommand(selections[i], ch); } - let shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.Typing); - if (ch === ' ') { - shouldPushStackElementBefore = true; - } - return new EditOperationResult(EditOperationType.Typing, commands, { - shouldPushStackElementBefore: shouldPushStackElementBefore, + + const opType = getTypingOperation(ch, prevEditOperationType); + return new EditOperationResult(opType, commands, { + shouldPushStackElementBefore: shouldPushStackElementBetween(prevEditOperationType, opType), shouldPushStackElementAfter: false }); } @@ -892,8 +890,9 @@ export class TypeOperations { for (let i = 0, len = selections.length; i < len; i++) { commands[i] = new ReplaceCommand(selections[i], str); } - return new EditOperationResult(EditOperationType.Typing, commands, { - shouldPushStackElementBefore: (prevEditOperationType !== EditOperationType.Typing), + const opType = getTypingOperation(str, prevEditOperationType); + return new EditOperationResult(opType, commands, { + shouldPushStackElementBefore: shouldPushStackElementBetween(prevEditOperationType, opType), shouldPushStackElementAfter: false }); } @@ -965,3 +964,40 @@ export class TypeWithAutoClosingCommand extends ReplaceCommandWithOffsetCursorSt return super.computeCursorState(model, helper); } } + +function getTypingOperation(typedText: string, previousTypingOperation: EditOperationType): EditOperationType { + if (typedText === ' ') { + return previousTypingOperation === EditOperationType.TypingFirstSpace + || previousTypingOperation === EditOperationType.TypingConsecutiveSpace + ? EditOperationType.TypingConsecutiveSpace + : EditOperationType.TypingFirstSpace; + } + + return EditOperationType.TypingOther; +} + +function shouldPushStackElementBetween(previousTypingOperation: EditOperationType, typingOperation: EditOperationType): boolean { + if (isTypingOperation(previousTypingOperation) && !isTypingOperation(typingOperation)) { + // Always set an undo stop before non-type operations + return true; + } + if (previousTypingOperation === EditOperationType.TypingFirstSpace) { + // `abc |d`: No undo stop + // `abc |d`: Undo stop + return false; + } + // Insert undo stop between different operation types + return normalizeOperationType(previousTypingOperation) !== normalizeOperationType(typingOperation); +} + +function normalizeOperationType(type: EditOperationType): EditOperationType | 'space' { + return (type === EditOperationType.TypingConsecutiveSpace || type === EditOperationType.TypingFirstSpace) + ? 'space' + : type; +} + +function isTypingOperation(type: EditOperationType): boolean { + return type === EditOperationType.TypingOther + || type === EditOperationType.TypingFirstSpace + || type === EditOperationType.TypingConsecutiveSpace; +} diff --git a/lib/vscode/src/vs/editor/common/controller/cursorWordOperations.ts b/src/vs/editor/common/controller/cursorWordOperations.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/controller/cursorWordOperations.ts rename to src/vs/editor/common/controller/cursorWordOperations.ts diff --git a/lib/vscode/src/vs/editor/common/controller/oneCursor.ts b/src/vs/editor/common/controller/oneCursor.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/controller/oneCursor.ts rename to src/vs/editor/common/controller/oneCursor.ts diff --git a/lib/vscode/src/vs/editor/common/controller/wordCharacterClassifier.ts b/src/vs/editor/common/controller/wordCharacterClassifier.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/controller/wordCharacterClassifier.ts rename to src/vs/editor/common/controller/wordCharacterClassifier.ts diff --git a/lib/vscode/src/vs/editor/common/core/characterClassifier.ts b/src/vs/editor/common/core/characterClassifier.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/core/characterClassifier.ts rename to src/vs/editor/common/core/characterClassifier.ts diff --git a/lib/vscode/src/vs/editor/common/core/editOperation.ts b/src/vs/editor/common/core/editOperation.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/core/editOperation.ts rename to src/vs/editor/common/core/editOperation.ts diff --git a/lib/vscode/src/vs/editor/common/core/lineTokens.ts b/src/vs/editor/common/core/lineTokens.ts similarity index 91% rename from lib/vscode/src/vs/editor/common/core/lineTokens.ts rename to src/vs/editor/common/core/lineTokens.ts index 51aa6a93ca83..66d9e3678178 100644 --- a/lib/vscode/src/vs/editor/common/core/lineTokens.ts +++ b/src/vs/editor/common/core/lineTokens.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ColorId, LanguageId, StandardTokenType, TokenMetadata } from 'vs/editor/common/modes'; +import { ColorId, FontStyle, LanguageId, MetadataConsts, StandardTokenType, TokenMetadata } from 'vs/editor/common/modes'; export interface IViewLineTokens { equals(other: IViewLineTokens): boolean; @@ -22,6 +22,20 @@ export class LineTokens implements IViewLineTokens { private readonly _tokensCount: number; private readonly _text: string; + public static createEmpty(lineContent: string): LineTokens { + const defaultMetadata = ( + (FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET) + | (ColorId.DefaultForeground << MetadataConsts.FOREGROUND_OFFSET) + | (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET) + ) >>> 0; + + const tokens = new Uint32Array(2); + tokens[0] = lineContent.length; + tokens[1] = defaultMetadata; + + return new LineTokens(tokens, lineContent); + } + constructor(tokens: Uint32Array, text: string) { this._tokens = tokens; this._tokensCount = (this._tokens.length >>> 1); diff --git a/lib/vscode/src/vs/editor/common/core/position.ts b/src/vs/editor/common/core/position.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/core/position.ts rename to src/vs/editor/common/core/position.ts diff --git a/lib/vscode/src/vs/editor/common/core/range.ts b/src/vs/editor/common/core/range.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/core/range.ts rename to src/vs/editor/common/core/range.ts diff --git a/lib/vscode/src/vs/editor/common/core/rgba.ts b/src/vs/editor/common/core/rgba.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/core/rgba.ts rename to src/vs/editor/common/core/rgba.ts diff --git a/lib/vscode/src/vs/editor/common/core/selection.ts b/src/vs/editor/common/core/selection.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/core/selection.ts rename to src/vs/editor/common/core/selection.ts diff --git a/lib/vscode/src/vs/editor/common/core/stringBuilder.ts b/src/vs/editor/common/core/stringBuilder.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/core/stringBuilder.ts rename to src/vs/editor/common/core/stringBuilder.ts diff --git a/lib/vscode/src/vs/editor/common/core/token.ts b/src/vs/editor/common/core/token.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/core/token.ts rename to src/vs/editor/common/core/token.ts diff --git a/lib/vscode/src/vs/editor/common/diff/diffComputer.ts b/src/vs/editor/common/diff/diffComputer.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/diff/diffComputer.ts rename to src/vs/editor/common/diff/diffComputer.ts diff --git a/lib/vscode/src/vs/editor/common/editorAction.ts b/src/vs/editor/common/editorAction.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/editorAction.ts rename to src/vs/editor/common/editorAction.ts diff --git a/lib/vscode/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts similarity index 99% rename from lib/vscode/src/vs/editor/common/editorCommon.ts rename to src/vs/editor/common/editorCommon.ts index 962a78885a10..fd38dafbd887 100644 --- a/lib/vscode/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -503,7 +503,7 @@ export interface IEditor { * Change the decorations. All decorations added through this changeAccessor * will get the ownerId of the editor (meaning they will not show up in other * editors). - * @see `ITextModel.changeDecorations` + * @see {@link ITextModel.changeDecorations} * @internal */ changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any; @@ -639,6 +639,7 @@ export interface IContentDecorationRenderOptions { textDecoration?: string; color?: string | ThemeColor; backgroundColor?: string | ThemeColor; + opacity?: string; margin?: string; padding?: string; diff --git a/lib/vscode/src/vs/editor/common/editorContextKeys.ts b/src/vs/editor/common/editorContextKeys.ts similarity index 97% rename from lib/vscode/src/vs/editor/common/editorContextKeys.ts rename to src/vs/editor/common/editorContextKeys.ts index 58beda673801..11c78368665a 100644 --- a/lib/vscode/src/vs/editor/common/editorContextKeys.ts +++ b/src/vs/editor/common/editorContextKeys.ts @@ -62,7 +62,7 @@ export namespace EditorContextKeys { export const hasReferenceProvider = new RawContextKey('editorHasReferenceProvider', false, nls.localize('editorHasReferenceProvider', "Whether the editor has a reference provider")); export const hasRenameProvider = new RawContextKey('editorHasRenameProvider', false, nls.localize('editorHasRenameProvider', "Whether the editor has a rename provider")); export const hasSignatureHelpProvider = new RawContextKey('editorHasSignatureHelpProvider', false, nls.localize('editorHasSignatureHelpProvider', "Whether the editor has a signature help provider")); - export const hasInlineHintsProvider = new RawContextKey('editorHasInlineHintsProvider', false, nls.localize('editorHasInlineHintsProvider', "Whether the editor has an inline hints provider")); + export const hasInlayHintsProvider = new RawContextKey('editorHasInlayHintsProvider', false, nls.localize('editorHasInlayHintsProvider', "Whether the editor has an inline hints provider")); // -- mode context keys: formatting export const hasDocumentFormattingProvider = new RawContextKey('editorHasDocumentFormattingProvider', false, nls.localize('editorHasDocumentFormattingProvider', "Whether the editor has a document formatting provider")); diff --git a/lib/vscode/src/vs/editor/common/model.ts b/src/vs/editor/common/model.ts similarity index 98% rename from lib/vscode/src/vs/editor/common/model.ts rename to src/vs/editor/common/model.ts index 3f1a239dcbf8..a10d22ba6300 100644 --- a/lib/vscode/src/vs/editor/common/model.ts +++ b/src/vs/editor/common/model.ts @@ -73,6 +73,11 @@ export interface IModelDecorationMinimapOptions extends IDecorationOptions { * Options for a model decoration. */ export interface IModelDecorationOptions { + /** + * A debug description that can be used for inspecting model decorations. + * @internal + */ + description: string; /** * Customize the growing behavior of the decoration when typing at the edges of the decoration. * Defaults to TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges @@ -1220,7 +1225,6 @@ export interface ITextModel { /** * An event emitted when the model has been attached to the first editor or detached from the last editor. * @event - * @internal */ onDidChangeAttached(listener: () => void): IDisposable; /** @@ -1247,7 +1251,6 @@ export interface ITextModel { /** * Returns if this model is attached to an editor or not. - * @internal */ isAttachedToEditor(): boolean; @@ -1256,6 +1259,33 @@ export interface ITextModel { * @internal */ getAttachedEditorCount(): number; + + /** + * Among all positions that are projected to the same position in the underlying text model as + * the given position, select a unique position as indicated by the affinity. + * @internal + */ + normalizePosition(position: Position, affinity: PositionNormalizationAffinity): Position; + + /** + * Gets the column at which indentation stops at a given line. + * @internal + */ + getLineIndentColumn(lineNumber: number): number; +} + +/** + * @internal + */ +export const enum PositionNormalizationAffinity { + /** + * Prefers the left most position. + */ + Left = 0, + /** + * Prefers the right most position. + */ + Right = 1, } /** diff --git a/lib/vscode/src/vs/editor/common/model/editStack.ts b/src/vs/editor/common/model/editStack.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/model/editStack.ts rename to src/vs/editor/common/model/editStack.ts diff --git a/lib/vscode/src/vs/editor/common/model/indentationGuesser.ts b/src/vs/editor/common/model/indentationGuesser.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/model/indentationGuesser.ts rename to src/vs/editor/common/model/indentationGuesser.ts diff --git a/lib/vscode/src/vs/editor/common/model/intervalTree.ts b/src/vs/editor/common/model/intervalTree.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/model/intervalTree.ts rename to src/vs/editor/common/model/intervalTree.ts diff --git a/lib/vscode/src/vs/editor/common/model/mirrorTextModel.ts b/src/vs/editor/common/model/mirrorTextModel.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/model/mirrorTextModel.ts rename to src/vs/editor/common/model/mirrorTextModel.ts diff --git a/lib/vscode/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts b/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts rename to src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts diff --git a/lib/vscode/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts b/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts rename to src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts diff --git a/lib/vscode/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder.ts b/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder.ts rename to src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder.ts diff --git a/lib/vscode/src/vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase.ts b/src/vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase.ts rename to src/vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase.ts diff --git a/lib/vscode/src/vs/editor/common/model/textChange.ts b/src/vs/editor/common/model/textChange.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/model/textChange.ts rename to src/vs/editor/common/model/textChange.ts diff --git a/lib/vscode/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts similarity index 98% rename from lib/vscode/src/vs/editor/common/model/textModel.ts rename to src/vs/editor/common/model/textModel.ts index 61452e16c782..d4b415295910 100644 --- a/lib/vscode/src/vs/editor/common/model/textModel.ts +++ b/src/vs/editor/common/model/textModel.ts @@ -3028,6 +3028,30 @@ export class TextModel extends Disposable implements model.ITextModel { } //#endregion + normalizePosition(position: Position, affinity: model.PositionNormalizationAffinity): Position { + return position; + } + + /** + * Gets the column at which indentation stops at a given line. + * @internal + */ + public getLineIndentColumn(lineNumber: number): number { + // Columns start with 1. + return indentOfLine(this.getLineContent(lineNumber)) + 1; + } +} + +function indentOfLine(line: string): number { + let indent = 0; + for (const c of line) { + if (c === ' ' || c === '\t') { + indent++; + } else { + break; + } + } + return indent; } //#region Decorations @@ -3205,6 +3229,7 @@ export class ModelDecorationOptions implements model.IModelDecorationOptions { return new ModelDecorationOptions(options); } + readonly description: string; readonly stickiness: model.TrackedRangeStickiness; readonly zIndex: number; readonly className: string | null; @@ -3225,6 +3250,7 @@ export class ModelDecorationOptions implements model.IModelDecorationOptions { readonly afterContentClassName: string | null; private constructor(options: model.IModelDecorationOptions) { + this.description = options.description; this.stickiness = options.stickiness || model.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges; this.zIndex = options.zIndex || 0; this.className = options.className ? cleanClassName(options.className) : null; @@ -3245,16 +3271,16 @@ export class ModelDecorationOptions implements model.IModelDecorationOptions { this.afterContentClassName = options.afterContentClassName ? cleanClassName(options.afterContentClassName) : null; } } -ModelDecorationOptions.EMPTY = ModelDecorationOptions.register({}); +ModelDecorationOptions.EMPTY = ModelDecorationOptions.register({ description: 'empty' }); /** * The order carefully matches the values of the enum. */ const TRACKED_RANGE_OPTIONS = [ - ModelDecorationOptions.register({ stickiness: model.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges }), - ModelDecorationOptions.register({ stickiness: model.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges }), - ModelDecorationOptions.register({ stickiness: model.TrackedRangeStickiness.GrowsOnlyWhenTypingBefore }), - ModelDecorationOptions.register({ stickiness: model.TrackedRangeStickiness.GrowsOnlyWhenTypingAfter }), + ModelDecorationOptions.register({ description: 'tracked-range-always-grows-when-typing-at-edges', stickiness: model.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges }), + ModelDecorationOptions.register({ description: 'tracked-range-never-grows-when-typing-at-edges', stickiness: model.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges }), + ModelDecorationOptions.register({ description: 'tracked-range-grows-only-when-typing-before', stickiness: model.TrackedRangeStickiness.GrowsOnlyWhenTypingBefore }), + ModelDecorationOptions.register({ description: 'tracked-range-grows-only-when-typing-after', stickiness: model.TrackedRangeStickiness.GrowsOnlyWhenTypingAfter }), ]; function _normalizeOptions(options: model.IModelDecorationOptions): ModelDecorationOptions { diff --git a/lib/vscode/src/vs/editor/common/model/textModelEvents.ts b/src/vs/editor/common/model/textModelEvents.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/model/textModelEvents.ts rename to src/vs/editor/common/model/textModelEvents.ts diff --git a/lib/vscode/src/vs/editor/common/model/textModelSearch.ts b/src/vs/editor/common/model/textModelSearch.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/model/textModelSearch.ts rename to src/vs/editor/common/model/textModelSearch.ts diff --git a/lib/vscode/src/vs/editor/common/model/textModelTokens.ts b/src/vs/editor/common/model/textModelTokens.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/model/textModelTokens.ts rename to src/vs/editor/common/model/textModelTokens.ts diff --git a/lib/vscode/src/vs/editor/common/model/tokensStore.ts b/src/vs/editor/common/model/tokensStore.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/model/tokensStore.ts rename to src/vs/editor/common/model/tokensStore.ts diff --git a/lib/vscode/src/vs/editor/common/model/wordHelper.ts b/src/vs/editor/common/model/wordHelper.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/model/wordHelper.ts rename to src/vs/editor/common/model/wordHelper.ts diff --git a/lib/vscode/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts similarity index 92% rename from lib/vscode/src/vs/editor/common/modes.ts rename to src/vs/editor/common/modes.ts index a60bb77be2ae..f42c4ee03075 100644 --- a/lib/vscode/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -9,7 +9,7 @@ import { Event } from 'vs/base/common/event'; import { IMarkdownString } from 'vs/base/common/htmlContent'; import { IDisposable } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; -import { Position } from 'vs/editor/common/core/position'; +import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import { TokenizationResult, TokenizationResult2 } from 'vs/editor/common/core/token'; @@ -227,7 +227,7 @@ export interface IState { } /** - * A provider result represents the values a provider, like the [`HoverProvider`](#HoverProvider), + * A provider result represents the values a provider, like the {@link HoverProvider}, * may return. For once this is the actual result type `T`, like `Hover`, or a thenable that resolves * to that type `T`. In addition, `null` and `undefined` can be returned - either directly or from a * thenable. @@ -557,13 +557,13 @@ export interface CompletionItem { documentation?: string | IMarkdownString; /** * A string that should be used when comparing this item - * with other items. When `falsy` the [label](#CompletionItem.label) + * with other items. When `falsy` the {@link CompletionItem.label label} * is used. */ sortText?: string; /** * A string that should be used when filtering a set of - * completion items. When `falsy` the [label](#CompletionItem.label) + * completion items. When `falsy` the {@link CompletionItem.label label} * is used. */ filterText?: string; @@ -587,11 +587,11 @@ export interface CompletionItem { /** * A range of text that should be replaced by this completion item. * - * Defaults to a range from the start of the [current word](#TextDocument.getWordRangeAtPosition) to the + * Defaults to a range from the start of the {@link TextDocument.getWordRangeAtPosition current word} to the * current position. * - * *Note:* The range must be a [single line](#Range.isSingleLine) and it must - * [contain](#Range.contains) the position at which completion has been [requested](#CompletionItemProvider.provideCompletionItems). + * *Note:* The range must be a {@link Range.isSingleLine single line} and it must + * {@link Range.contains contain} the position at which completion has been {@link CompletionItemProvider.provideCompletionItems requested}. */ range: IRange | { insert: IRange, replace: IRange }; /** @@ -638,7 +638,7 @@ export const enum CompletionTriggerKind { } /** * Contains additional information about the context in which - * [completion provider](#CompletionItemProvider.provideCompletionItems) is triggered. + * {@link CompletionItemProvider.provideCompletionItems completion provider} is triggered. */ export interface CompletionContext { /** @@ -658,10 +658,10 @@ export interface CompletionContext { * * When computing *complete* completion items is expensive, providers can optionally implement * the `resolveCompletionItem`-function. In that case it is enough to return completion - * items with a [label](#CompletionItem.label) from the - * [provideCompletionItems](#CompletionItemProvider.provideCompletionItems)-function. Subsequently, + * items with a {@link CompletionItem.label label} from the + * {@link CompletionItemProvider.provideCompletionItems provideCompletionItems}-function. Subsequently, * when a completion item is shown in the UI and gains focus this provider is asked to resolve - * the item, like adding [doc-comment](#CompletionItem.documentation) or [details](#CompletionItem.detail). + * the item, like adding {@link CompletionItem.documentation doc-comment} or {@link CompletionItem.detail details}. */ export interface CompletionItemProvider { @@ -677,14 +677,73 @@ export interface CompletionItemProvider { provideCompletionItems(model: model.ITextModel, position: Position, context: CompletionContext, token: CancellationToken): ProviderResult; /** - * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) - * or [details](#CompletionItem.detail). + * Given a completion item fill in more data, like {@link CompletionItem.documentation doc-comment} + * or {@link CompletionItem.detail details}. * * The editor will only resolve a completion item once. */ resolveCompletionItem?(item: CompletionItem, token: CancellationToken): ProviderResult; } +/** + * How an {@link InlineCompletionsProvider inline completion provider} was triggered. + */ +export enum InlineCompletionTriggerKind { + /** + * Completion was triggered automatically while editing. + * It is sufficient to return a single completion item in this case. + */ + Automatic = 0, + + /** + * Completion was triggered explicitly by a user gesture. + * Return multiple completion items to enable cycling through them. + */ + Explicit = 1, +} + +export interface InlineCompletionContext { + /** + * How the completion was triggered. + */ + readonly triggerKind: InlineCompletionTriggerKind; +} + +export interface InlineCompletion { + /** + * The text to insert. + * If the text contains a line break, the range must end at the end of a line. + * If existing text should be replaced, the existing text must be a prefix of the text to insert. + */ + readonly text: string; + + /** + * The range to replace. + * Must begin and end on the same line. + */ + readonly range?: IRange; + + readonly command?: Command; +} + +export interface InlineCompletions { + readonly items: readonly TItem[]; +} + +export interface InlineCompletionsProvider { + provideInlineCompletions(model: model.ITextModel, position: Position, context: InlineCompletionContext, token: CancellationToken): ProviderResult; + + /** + * Will be called when an item is shown. + */ + handleItemDidShow?(completions: T, item: T['items'][number]): void; + + /** + * Will be called when a completions list is no longer in use and can be garbage-collected. + */ + freeInlineCompletions(completions: T): void; +} + export interface CodeAction { title: string; command?: Command; @@ -870,7 +929,7 @@ export interface DocumentHighlight { */ range: IRange; /** - * The highlight kind, default is [text](#DocumentHighlightKind.Text). + * The highlight kind, default is {@link DocumentHighlightKind.Text text}. */ kind?: DocumentHighlightKind; } @@ -1323,12 +1382,12 @@ export interface IColorPresentation { */ label: string; /** - * An [edit](#TextEdit) which is applied to a document when selecting + * An {@link TextEdit edit} which is applied to a document when selecting * this presentation for the color. */ textEdit?: TextEdit; /** - * An optional array of additional [text edits](#TextEdit) that are applied when + * An optional array of additional {@link TextEdit text edits} that are applied when * selecting this color presentation. */ additionalTextEdits?: TextEdit[]; @@ -1406,10 +1465,10 @@ export interface FoldingRange { end: number; /** - * Describes the [Kind](#FoldingRangeKind) of the folding range such as [Comment](#FoldingRangeKind.Comment) or - * [Region](#FoldingRangeKind.Region). The kind is used to categorize folding ranges and used by commands + * Describes the {@link FoldingRangeKind Kind} of the folding range such as {@link FoldingRangeKind.Comment Comment} or + * {@link FoldingRangeKind.Region Region}. The kind is used to categorize folding ranges and used by commands * like 'Fold all comments'. See - * [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds. + * {@link FoldingRangeKind} for an enumeration of standardized kinds. */ kind?: FoldingRangeKind; } @@ -1429,7 +1488,7 @@ export class FoldingRangeKind { static readonly Region = new FoldingRangeKind('region'); /** - * Creates a new [FoldingRangeKind](#FoldingRangeKind). + * Creates a new {@link FoldingRangeKind}. * * @param value of the kind. */ @@ -1701,24 +1760,23 @@ export interface CodeLensProvider { } -export enum InlineHintKind { +export enum InlayHintKind { Other = 0, Type = 1, Parameter = 2, } -export interface InlineHint { +export interface InlayHint { text: string; - range: IRange; - kind: InlineHintKind; - description?: string | IMarkdownString; + position: IPosition; + kind: InlayHintKind; whitespaceBefore?: boolean; whitespaceAfter?: boolean; } -export interface InlineHintsProvider { - onDidChangeInlineHints?: Event | undefined; - provideInlineHints(model: model.ITextModel, range: Range, token: CancellationToken): ProviderResult; +export interface InlayHintsProvider { + onDidChangeInlayHints?: Event | undefined; + provideInlayHints(model: model.ITextModel, range: Range, token: CancellationToken): ProviderResult; } export interface SemanticTokensLegend { @@ -1771,6 +1829,11 @@ export const RenameProviderRegistry = new LanguageFeatureRegistry(); +/** + * @internal + */ +export const InlineCompletionsProviderRegistry = new LanguageFeatureRegistry(); + /** * @internal */ @@ -1834,7 +1897,7 @@ export const CodeLensProviderRegistry = new LanguageFeatureRegistry(); +export const InlayHintsProviderRegistry = new LanguageFeatureRegistry(); /** * @internal diff --git a/lib/vscode/src/vs/editor/common/modes/abstractMode.ts b/src/vs/editor/common/modes/abstractMode.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/modes/abstractMode.ts rename to src/vs/editor/common/modes/abstractMode.ts diff --git a/lib/vscode/src/vs/editor/common/modes/languageConfiguration.ts b/src/vs/editor/common/modes/languageConfiguration.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/modes/languageConfiguration.ts rename to src/vs/editor/common/modes/languageConfiguration.ts diff --git a/lib/vscode/src/vs/editor/common/modes/languageConfigurationRegistry.ts b/src/vs/editor/common/modes/languageConfigurationRegistry.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/modes/languageConfigurationRegistry.ts rename to src/vs/editor/common/modes/languageConfigurationRegistry.ts diff --git a/lib/vscode/src/vs/editor/common/modes/languageFeatureRegistry.ts b/src/vs/editor/common/modes/languageFeatureRegistry.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/modes/languageFeatureRegistry.ts rename to src/vs/editor/common/modes/languageFeatureRegistry.ts diff --git a/lib/vscode/src/vs/editor/common/modes/languageSelector.ts b/src/vs/editor/common/modes/languageSelector.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/modes/languageSelector.ts rename to src/vs/editor/common/modes/languageSelector.ts diff --git a/lib/vscode/src/vs/editor/common/modes/linkComputer.ts b/src/vs/editor/common/modes/linkComputer.ts similarity index 99% rename from lib/vscode/src/vs/editor/common/modes/linkComputer.ts rename to src/vs/editor/common/modes/linkComputer.ts index c0ca979fb9b9..c6249cb323ae 100644 --- a/lib/vscode/src/vs/editor/common/modes/linkComputer.ts +++ b/src/vs/editor/common/modes/linkComputer.ts @@ -154,7 +154,7 @@ function getClassifier(): CharacterClassifier { if (_classifier === null) { _classifier = new CharacterClassifier(CharacterClass.None); - const FORCE_TERMINATION_CHARACTERS = ' \t<>\'\"、。。、,.:;‘“〈《「『【〔([{「」}])〕】』」》〉”’`~…'; + const FORCE_TERMINATION_CHARACTERS = ' \t<>\'\"、。。、,.:;‘〈「『〔([{「」}])〕』」〉’`~…'; for (let i = 0; i < FORCE_TERMINATION_CHARACTERS.length; i++) { _classifier.set(FORCE_TERMINATION_CHARACTERS.charCodeAt(i), CharacterClass.ForceTermination); } diff --git a/lib/vscode/src/vs/editor/common/modes/modesRegistry.ts b/src/vs/editor/common/modes/modesRegistry.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/modes/modesRegistry.ts rename to src/vs/editor/common/modes/modesRegistry.ts diff --git a/lib/vscode/src/vs/editor/common/modes/nullMode.ts b/src/vs/editor/common/modes/nullMode.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/modes/nullMode.ts rename to src/vs/editor/common/modes/nullMode.ts diff --git a/lib/vscode/src/vs/editor/common/modes/supports.ts b/src/vs/editor/common/modes/supports.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/modes/supports.ts rename to src/vs/editor/common/modes/supports.ts diff --git a/lib/vscode/src/vs/editor/common/modes/supports/characterPair.ts b/src/vs/editor/common/modes/supports/characterPair.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/modes/supports/characterPair.ts rename to src/vs/editor/common/modes/supports/characterPair.ts diff --git a/lib/vscode/src/vs/editor/common/modes/supports/electricCharacter.ts b/src/vs/editor/common/modes/supports/electricCharacter.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/modes/supports/electricCharacter.ts rename to src/vs/editor/common/modes/supports/electricCharacter.ts diff --git a/lib/vscode/src/vs/editor/common/modes/supports/indentRules.ts b/src/vs/editor/common/modes/supports/indentRules.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/modes/supports/indentRules.ts rename to src/vs/editor/common/modes/supports/indentRules.ts diff --git a/lib/vscode/src/vs/editor/common/modes/supports/inplaceReplaceSupport.ts b/src/vs/editor/common/modes/supports/inplaceReplaceSupport.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/modes/supports/inplaceReplaceSupport.ts rename to src/vs/editor/common/modes/supports/inplaceReplaceSupport.ts diff --git a/lib/vscode/src/vs/editor/common/modes/supports/onEnter.ts b/src/vs/editor/common/modes/supports/onEnter.ts similarity index 96% rename from lib/vscode/src/vs/editor/common/modes/supports/onEnter.ts rename to src/vs/editor/common/modes/supports/onEnter.ts index c03b524394c1..4e868fbef155 100644 --- a/lib/vscode/src/vs/editor/common/modes/supports/onEnter.ts +++ b/src/vs/editor/common/modes/supports/onEnter.ts @@ -64,7 +64,12 @@ export class OnEnterSupport { reg: rule.previousLineText, text: previousLineText }].every((obj): boolean => { - return obj.reg ? obj.reg.test(obj.text) : true; + if (!obj.reg) { + return true; + } + + obj.reg.lastIndex = 0; // To disable the effect of the "g" flag. + return obj.reg.test(obj.text); }); if (regResult) { diff --git a/lib/vscode/src/vs/editor/common/modes/supports/richEditBrackets.ts b/src/vs/editor/common/modes/supports/richEditBrackets.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/modes/supports/richEditBrackets.ts rename to src/vs/editor/common/modes/supports/richEditBrackets.ts diff --git a/lib/vscode/src/vs/editor/common/modes/supports/tokenization.ts b/src/vs/editor/common/modes/supports/tokenization.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/modes/supports/tokenization.ts rename to src/vs/editor/common/modes/supports/tokenization.ts diff --git a/lib/vscode/src/vs/editor/common/modes/textToHtmlTokenizer.ts b/src/vs/editor/common/modes/textToHtmlTokenizer.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/modes/textToHtmlTokenizer.ts rename to src/vs/editor/common/modes/textToHtmlTokenizer.ts diff --git a/lib/vscode/src/vs/editor/common/modes/tokenization/typescript.ts b/src/vs/editor/common/modes/tokenization/typescript.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/modes/tokenization/typescript.ts rename to src/vs/editor/common/modes/tokenization/typescript.ts diff --git a/lib/vscode/src/vs/editor/common/modes/tokenizationRegistry.ts b/src/vs/editor/common/modes/tokenizationRegistry.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/modes/tokenizationRegistry.ts rename to src/vs/editor/common/modes/tokenizationRegistry.ts diff --git a/lib/vscode/src/vs/editor/common/services/editorSimpleWorker.ts b/src/vs/editor/common/services/editorSimpleWorker.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/editorSimpleWorker.ts rename to src/vs/editor/common/services/editorSimpleWorker.ts diff --git a/lib/vscode/src/vs/editor/common/services/editorWorkerService.ts b/src/vs/editor/common/services/editorWorkerService.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/editorWorkerService.ts rename to src/vs/editor/common/services/editorWorkerService.ts diff --git a/lib/vscode/src/vs/editor/common/services/editorWorkerServiceImpl.ts b/src/vs/editor/common/services/editorWorkerServiceImpl.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/editorWorkerServiceImpl.ts rename to src/vs/editor/common/services/editorWorkerServiceImpl.ts diff --git a/lib/vscode/src/vs/editor/common/services/getIconClasses.ts b/src/vs/editor/common/services/getIconClasses.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/getIconClasses.ts rename to src/vs/editor/common/services/getIconClasses.ts diff --git a/lib/vscode/src/vs/editor/common/services/getSemanticTokens.ts b/src/vs/editor/common/services/getSemanticTokens.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/getSemanticTokens.ts rename to src/vs/editor/common/services/getSemanticTokens.ts diff --git a/lib/vscode/src/vs/editor/common/services/languagesRegistry.ts b/src/vs/editor/common/services/languagesRegistry.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/languagesRegistry.ts rename to src/vs/editor/common/services/languagesRegistry.ts diff --git a/lib/vscode/src/vs/editor/common/services/markerDecorationsServiceImpl.ts b/src/vs/editor/common/services/markerDecorationsServiceImpl.ts similarity index 99% rename from lib/vscode/src/vs/editor/common/services/markerDecorationsServiceImpl.ts rename to src/vs/editor/common/services/markerDecorationsServiceImpl.ts index 939470195c94..2e0cddcc5fb8 100644 --- a/lib/vscode/src/vs/editor/common/services/markerDecorationsServiceImpl.ts +++ b/src/vs/editor/common/services/markerDecorationsServiceImpl.ts @@ -239,6 +239,7 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor } return { + description: 'marker-decoration', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className, showIfCollapsed: true, diff --git a/lib/vscode/src/vs/editor/common/services/markersDecorationService.ts b/src/vs/editor/common/services/markersDecorationService.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/markersDecorationService.ts rename to src/vs/editor/common/services/markersDecorationService.ts diff --git a/lib/vscode/src/vs/editor/common/services/modeService.ts b/src/vs/editor/common/services/modeService.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/modeService.ts rename to src/vs/editor/common/services/modeService.ts diff --git a/lib/vscode/src/vs/editor/common/services/modeServiceImpl.ts b/src/vs/editor/common/services/modeServiceImpl.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/modeServiceImpl.ts rename to src/vs/editor/common/services/modeServiceImpl.ts diff --git a/lib/vscode/src/vs/editor/common/services/modelService.ts b/src/vs/editor/common/services/modelService.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/modelService.ts rename to src/vs/editor/common/services/modelService.ts diff --git a/lib/vscode/src/vs/editor/common/services/modelServiceImpl.ts b/src/vs/editor/common/services/modelServiceImpl.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/modelServiceImpl.ts rename to src/vs/editor/common/services/modelServiceImpl.ts diff --git a/lib/vscode/src/vs/editor/common/services/modelUndoRedoParticipant.ts b/src/vs/editor/common/services/modelUndoRedoParticipant.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/modelUndoRedoParticipant.ts rename to src/vs/editor/common/services/modelUndoRedoParticipant.ts diff --git a/lib/vscode/src/vs/editor/common/services/resolverService.ts b/src/vs/editor/common/services/resolverService.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/resolverService.ts rename to src/vs/editor/common/services/resolverService.ts diff --git a/lib/vscode/src/vs/editor/common/services/semanticTokensDto.ts b/src/vs/editor/common/services/semanticTokensDto.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/semanticTokensDto.ts rename to src/vs/editor/common/services/semanticTokensDto.ts diff --git a/lib/vscode/src/vs/editor/common/services/semanticTokensProviderStyling.ts b/src/vs/editor/common/services/semanticTokensProviderStyling.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/semanticTokensProviderStyling.ts rename to src/vs/editor/common/services/semanticTokensProviderStyling.ts diff --git a/lib/vscode/src/vs/editor/common/services/textResourceConfigurationService.ts b/src/vs/editor/common/services/textResourceConfigurationService.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/textResourceConfigurationService.ts rename to src/vs/editor/common/services/textResourceConfigurationService.ts diff --git a/lib/vscode/src/vs/editor/common/services/textResourceConfigurationServiceImpl.ts b/src/vs/editor/common/services/textResourceConfigurationServiceImpl.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/textResourceConfigurationServiceImpl.ts rename to src/vs/editor/common/services/textResourceConfigurationServiceImpl.ts diff --git a/lib/vscode/src/vs/editor/common/services/webWorker.ts b/src/vs/editor/common/services/webWorker.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/services/webWorker.ts rename to src/vs/editor/common/services/webWorker.ts diff --git a/lib/vscode/src/vs/editor/common/standalone/standaloneBase.ts b/src/vs/editor/common/standalone/standaloneBase.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/standalone/standaloneBase.ts rename to src/vs/editor/common/standalone/standaloneBase.ts diff --git a/lib/vscode/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts similarity index 85% rename from lib/vscode/src/vs/editor/common/standalone/standaloneEnums.ts rename to src/vs/editor/common/standalone/standaloneEnums.ts index 9860ffa9285d..c8389af9446a 100644 --- a/lib/vscode/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -219,82 +219,84 @@ export enum EditorOption { highlightActiveIndentGuide = 49, hover = 50, inDiffEditor = 51, - letterSpacing = 52, - lightbulb = 53, - lineDecorationsWidth = 54, - lineHeight = 55, - lineNumbers = 56, - lineNumbersMinChars = 57, - linkedEditing = 58, - links = 59, - matchBrackets = 60, - minimap = 61, - mouseStyle = 62, - mouseWheelScrollSensitivity = 63, - mouseWheelZoom = 64, - multiCursorMergeOverlapping = 65, - multiCursorModifier = 66, - multiCursorPaste = 67, - occurrencesHighlight = 68, - overviewRulerBorder = 69, - overviewRulerLanes = 70, - padding = 71, - parameterHints = 72, - peekWidgetDefaultFocus = 73, - definitionLinkOpensInPeek = 74, - quickSuggestions = 75, - quickSuggestionsDelay = 76, - readOnly = 77, - renameOnType = 78, - renderControlCharacters = 79, - renderIndentGuides = 80, - renderFinalNewline = 81, - renderLineHighlight = 82, - renderLineHighlightOnlyWhenFocus = 83, - renderValidationDecorations = 84, - renderWhitespace = 85, - revealHorizontalRightPadding = 86, - roundedSelection = 87, - rulers = 88, - scrollbar = 89, - scrollBeyondLastColumn = 90, - scrollBeyondLastLine = 91, - scrollPredominantAxis = 92, - selectionClipboard = 93, - selectionHighlight = 94, - selectOnLineNumbers = 95, - showFoldingControls = 96, - showUnused = 97, - snippetSuggestions = 98, - smartSelect = 99, - smoothScrolling = 100, - stickyTabStops = 101, - stopRenderingLineAfter = 102, - suggest = 103, - suggestFontSize = 104, - suggestLineHeight = 105, - suggestOnTriggerCharacters = 106, - suggestSelection = 107, - tabCompletion = 108, - tabIndex = 109, - unusualLineTerminators = 110, - useTabStops = 111, - wordSeparators = 112, - wordWrap = 113, - wordWrapBreakAfterCharacters = 114, - wordWrapBreakBeforeCharacters = 115, - wordWrapColumn = 116, - wordWrapOverride1 = 117, - wordWrapOverride2 = 118, - wrappingIndent = 119, - wrappingStrategy = 120, - showDeprecated = 121, - inlineHints = 122, - editorClassName = 123, - pixelRatio = 124, - tabFocusMode = 125, - layoutInfo = 126, - wrappingInfo = 127 + inlineSuggest = 52, + letterSpacing = 53, + lightbulb = 54, + lineDecorationsWidth = 55, + lineHeight = 56, + lineNumbers = 57, + lineNumbersMinChars = 58, + linkedEditing = 59, + links = 60, + matchBrackets = 61, + minimap = 62, + mouseStyle = 63, + mouseWheelScrollSensitivity = 64, + mouseWheelZoom = 65, + multiCursorMergeOverlapping = 66, + multiCursorModifier = 67, + multiCursorPaste = 68, + occurrencesHighlight = 69, + overviewRulerBorder = 70, + overviewRulerLanes = 71, + padding = 72, + parameterHints = 73, + peekWidgetDefaultFocus = 74, + definitionLinkOpensInPeek = 75, + quickSuggestions = 76, + quickSuggestionsDelay = 77, + readOnly = 78, + renameOnType = 79, + renderControlCharacters = 80, + renderIndentGuides = 81, + renderFinalNewline = 82, + renderLineHighlight = 83, + renderLineHighlightOnlyWhenFocus = 84, + renderValidationDecorations = 85, + renderWhitespace = 86, + revealHorizontalRightPadding = 87, + roundedSelection = 88, + rulers = 89, + scrollbar = 90, + scrollBeyondLastColumn = 91, + scrollBeyondLastLine = 92, + scrollPredominantAxis = 93, + selectionClipboard = 94, + selectionHighlight = 95, + selectOnLineNumbers = 96, + showFoldingControls = 97, + showUnused = 98, + snippetSuggestions = 99, + smartSelect = 100, + smoothScrolling = 101, + stickyTabStops = 102, + stopRenderingLineAfter = 103, + suggest = 104, + suggestFontSize = 105, + suggestLineHeight = 106, + suggestOnTriggerCharacters = 107, + suggestSelection = 108, + tabCompletion = 109, + tabIndex = 110, + unusualLineTerminators = 111, + useShadowDOM = 112, + useTabStops = 113, + wordSeparators = 114, + wordWrap = 115, + wordWrapBreakAfterCharacters = 116, + wordWrapBreakBeforeCharacters = 117, + wordWrapColumn = 118, + wordWrapOverride1 = 119, + wordWrapOverride2 = 120, + wrappingIndent = 121, + wrappingStrategy = 122, + showDeprecated = 123, + inlayHints = 124, + editorClassName = 125, + pixelRatio = 126, + tabFocusMode = 127, + layoutInfo = 128, + wrappingInfo = 129 } /** @@ -353,12 +355,28 @@ export enum IndentAction { Outdent = 3 } -export enum InlineHintKind { +export enum InlayHintKind { Other = 0, Type = 1, Parameter = 2 } +/** + * How an {@link InlineCompletionsProvider inline completion provider} was triggered. + */ +export enum InlineCompletionTriggerKind { + /** + * Completion was triggered automatically while editing. + * It is sufficient to return a single completion item in this case. + */ + Automatic = 0, + /** + * Completion was triggered explicitly by a user gesture. + * Return multiple completion items to enable cycling through them. + */ + Explicit = 1 +} + /** * Virtual Key Codes, the value does not hold any inherent meaning. * Inspired somewhat from https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx diff --git a/lib/vscode/src/vs/editor/common/standaloneStrings.ts b/src/vs/editor/common/standaloneStrings.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/standaloneStrings.ts rename to src/vs/editor/common/standaloneStrings.ts diff --git a/lib/vscode/src/vs/editor/common/view/editorColorRegistry.ts b/src/vs/editor/common/view/editorColorRegistry.ts similarity index 95% rename from lib/vscode/src/vs/editor/common/view/editorColorRegistry.ts rename to src/vs/editor/common/view/editorColorRegistry.ts index 89c3c90dc59f..b5acf0adac58 100644 --- a/lib/vscode/src/vs/editor/common/view/editorColorRegistry.ts +++ b/src/vs/editor/common/view/editorColorRegistry.ts @@ -43,6 +43,9 @@ export const editorGutter = registerColor('editorGutter.background', { dark: edi export const editorUnnecessaryCodeBorder = registerColor('editorUnnecessaryCode.border', { dark: null, light: null, hc: Color.fromHex('#fff').transparent(0.8) }, nls.localize('unnecessaryCodeBorder', 'Border color of unnecessary (unused) source code in the editor.')); export const editorUnnecessaryCodeOpacity = registerColor('editorUnnecessaryCode.opacity', { dark: Color.fromHex('#000a'), light: Color.fromHex('#0007'), hc: null }, nls.localize('unnecessaryCodeOpacity', 'Opacity of unnecessary (unused) source code in the editor. For example, "#000000c0" will render the code with 75% opacity. For high contrast themes, use the \'editorUnnecessaryCode.border\' theme color to underline unnecessary code instead of fading it out.')); +export const ghostTextBorder = registerColor('editorGhostText.border', { dark: null, light: null, hc: Color.fromHex('#fff').transparent(0.8) }, nls.localize('editorGhostTextBorder', 'Border color of ghost text in the editor.')); +export const ghostTextForeground = registerColor('editorGhostText.foreground', { dark: Color.fromHex('#FFFa'), light: Color.fromHex('#0007'), hc: null }, nls.localize('editorGhostTextForeground', 'Foreground color of the ghost text in the editor.')); + const rulerRangeDefault = new Color(new RGBA(0, 122, 204, 0.6)); export const overviewRulerRangeHighlight = registerColor('editorOverviewRuler.rangeHighlightForeground', { dark: rulerRangeDefault, light: rulerRangeDefault, hc: rulerRangeDefault }, nls.localize('overviewRulerRangeHighlight', 'Overview ruler marker color for range highlights. The color must not be opaque so as not to hide underlying decorations.'), true); export const overviewRulerError = registerColor('editorOverviewRuler.errorForeground', { dark: new Color(new RGBA(255, 18, 18, 0.7)), light: new Color(new RGBA(255, 18, 18, 0.7)), hc: new Color(new RGBA(255, 50, 50, 1)) }, nls.localize('overviewRuleError', 'Overview ruler marker color for errors.')); diff --git a/lib/vscode/src/vs/editor/common/view/overviewZoneManager.ts b/src/vs/editor/common/view/overviewZoneManager.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/view/overviewZoneManager.ts rename to src/vs/editor/common/view/overviewZoneManager.ts diff --git a/lib/vscode/src/vs/editor/common/view/renderingContext.ts b/src/vs/editor/common/view/renderingContext.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/view/renderingContext.ts rename to src/vs/editor/common/view/renderingContext.ts diff --git a/lib/vscode/src/vs/editor/common/view/viewContext.ts b/src/vs/editor/common/view/viewContext.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/view/viewContext.ts rename to src/vs/editor/common/view/viewContext.ts diff --git a/lib/vscode/src/vs/editor/common/view/viewEvents.ts b/src/vs/editor/common/view/viewEvents.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/view/viewEvents.ts rename to src/vs/editor/common/view/viewEvents.ts diff --git a/lib/vscode/src/vs/editor/common/viewLayout/lineDecorations.ts b/src/vs/editor/common/viewLayout/lineDecorations.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/viewLayout/lineDecorations.ts rename to src/vs/editor/common/viewLayout/lineDecorations.ts diff --git a/lib/vscode/src/vs/editor/common/viewLayout/linesLayout.ts b/src/vs/editor/common/viewLayout/linesLayout.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/viewLayout/linesLayout.ts rename to src/vs/editor/common/viewLayout/linesLayout.ts diff --git a/lib/vscode/src/vs/editor/common/viewLayout/viewLayout.ts b/src/vs/editor/common/viewLayout/viewLayout.ts similarity index 100% rename from lib/vscode/src/vs/editor/common/viewLayout/viewLayout.ts rename to src/vs/editor/common/viewLayout/viewLayout.ts diff --git a/lib/vscode/src/vs/editor/common/viewLayout/viewLineRenderer.ts b/src/vs/editor/common/viewLayout/viewLineRenderer.ts similarity index 97% rename from lib/vscode/src/vs/editor/common/viewLayout/viewLineRenderer.ts rename to src/vs/editor/common/viewLayout/viewLineRenderer.ts index 5a6540d79610..76f0fc654307 100644 --- a/lib/vscode/src/vs/editor/common/viewLayout/viewLineRenderer.ts +++ b/src/vs/editor/common/viewLayout/viewLineRenderer.ts @@ -47,6 +47,10 @@ class LinePart { public isWhitespace(): boolean { return (this.metadata & LinePartMetadata.IS_WHITESPACE_MASK ? true : false); } + + public isPseudoAfter(): boolean { + return (this.metadata & LinePartMetadata.PSEUDO_AFTER_MASK ? true : false); + } } export class LineRange { @@ -792,14 +796,11 @@ function _applyInlineDecorations(lineContent: string, len: number, tokens: LineP const lastTokenEndIndex = tokens[tokens.length - 1].endIndex; if (lineDecorationIndex < lineDecorationsLen && lineDecorations[lineDecorationIndex].startOffset === lastTokenEndIndex) { - let classNames: string[] = []; - let metadata = 0; while (lineDecorationIndex < lineDecorationsLen && lineDecorations[lineDecorationIndex].startOffset === lastTokenEndIndex) { - classNames.push(lineDecorations[lineDecorationIndex].className); - metadata |= lineDecorations[lineDecorationIndex].metadata; + const lineDecoration = lineDecorations[lineDecorationIndex]; + result[resultLen++] = new LinePart(lastResultEndIndex, lineDecoration.className, lineDecoration.metadata); lineDecorationIndex++; } - result[resultLen++] = new LinePart(lastResultEndIndex, classNames.join(' '), metadata); } return result; @@ -827,6 +828,7 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render const renderControlCharacters = input.renderControlCharacters; const characterMapping = new CharacterMapping(len + 1, parts.length); + let lastCharacterMappingDefined = false; let charIndex = 0; let visibleColumn = startVisibleColumn; @@ -850,7 +852,7 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render const partType = part.type; const partRendersWhitespace = (renderWhitespace !== RenderWhitespace.None && part.isWhitespace()); const partRendersWhitespaceWithWidth = partRendersWhitespace && !fontIsMonospace && (partType === 'mtkw'/*only whitespace*/ || !containsForeignElements); - const partIsEmptyAndHasPseudoAfter = (charIndex === partEndIndex && part.metadata === LinePartMetadata.PSEUDO_AFTER); + const partIsEmptyAndHasPseudoAfter = (charIndex === partEndIndex && part.isPseudoAfter()); charOffsetInPart = 0; sb.appendASCIIString(' anchor, getActions: () => menuActions, onHide: () => { diff --git a/lib/vscode/src/vs/editor/contrib/codeAction/codeActionModel.ts b/src/vs/editor/contrib/codeAction/codeActionModel.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/codeAction/codeActionModel.ts rename to src/vs/editor/contrib/codeAction/codeActionModel.ts diff --git a/lib/vscode/src/vs/editor/contrib/codeAction/codeActionUi.ts b/src/vs/editor/contrib/codeAction/codeActionUi.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/codeAction/codeActionUi.ts rename to src/vs/editor/contrib/codeAction/codeActionUi.ts diff --git a/lib/vscode/src/vs/editor/contrib/codeAction/lightBulbWidget.css b/src/vs/editor/contrib/codeAction/lightBulbWidget.css similarity index 100% rename from lib/vscode/src/vs/editor/contrib/codeAction/lightBulbWidget.css rename to src/vs/editor/contrib/codeAction/lightBulbWidget.css diff --git a/lib/vscode/src/vs/editor/contrib/codeAction/lightBulbWidget.ts b/src/vs/editor/contrib/codeAction/lightBulbWidget.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/codeAction/lightBulbWidget.ts rename to src/vs/editor/contrib/codeAction/lightBulbWidget.ts diff --git a/lib/vscode/src/vs/editor/contrib/codeAction/test/codeAction.test.ts b/src/vs/editor/contrib/codeAction/test/codeAction.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/codeAction/test/codeAction.test.ts rename to src/vs/editor/contrib/codeAction/test/codeAction.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/codeAction/test/codeActionKeybindingResolver.test.ts b/src/vs/editor/contrib/codeAction/test/codeActionKeybindingResolver.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/codeAction/test/codeActionKeybindingResolver.test.ts rename to src/vs/editor/contrib/codeAction/test/codeActionKeybindingResolver.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/codeAction/test/codeActionModel.test.ts b/src/vs/editor/contrib/codeAction/test/codeActionModel.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/codeAction/test/codeActionModel.test.ts rename to src/vs/editor/contrib/codeAction/test/codeActionModel.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/codeAction/types.ts b/src/vs/editor/contrib/codeAction/types.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/codeAction/types.ts rename to src/vs/editor/contrib/codeAction/types.ts diff --git a/lib/vscode/src/vs/editor/contrib/codelens/codeLensCache.ts b/src/vs/editor/contrib/codelens/codeLensCache.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/codelens/codeLensCache.ts rename to src/vs/editor/contrib/codelens/codeLensCache.ts diff --git a/lib/vscode/src/vs/editor/contrib/codelens/codelens.ts b/src/vs/editor/contrib/codelens/codelens.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/codelens/codelens.ts rename to src/vs/editor/contrib/codelens/codelens.ts diff --git a/lib/vscode/src/vs/editor/contrib/codelens/codelensController.ts b/src/vs/editor/contrib/codelens/codelensController.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/codelens/codelensController.ts rename to src/vs/editor/contrib/codelens/codelensController.ts diff --git a/lib/vscode/src/vs/editor/contrib/codelens/codelensWidget.css b/src/vs/editor/contrib/codelens/codelensWidget.css similarity index 100% rename from lib/vscode/src/vs/editor/contrib/codelens/codelensWidget.css rename to src/vs/editor/contrib/codelens/codelensWidget.css diff --git a/lib/vscode/src/vs/editor/contrib/codelens/codelensWidget.ts b/src/vs/editor/contrib/codelens/codelensWidget.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/codelens/codelensWidget.ts rename to src/vs/editor/contrib/codelens/codelensWidget.ts diff --git a/lib/vscode/src/vs/editor/contrib/colorPicker/color.ts b/src/vs/editor/contrib/colorPicker/color.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/colorPicker/color.ts rename to src/vs/editor/contrib/colorPicker/color.ts diff --git a/lib/vscode/src/vs/editor/contrib/colorPicker/colorContributions.ts b/src/vs/editor/contrib/colorPicker/colorContributions.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/colorPicker/colorContributions.ts rename to src/vs/editor/contrib/colorPicker/colorContributions.ts diff --git a/lib/vscode/src/vs/editor/contrib/colorPicker/colorDetector.ts b/src/vs/editor/contrib/colorPicker/colorDetector.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/colorPicker/colorDetector.ts rename to src/vs/editor/contrib/colorPicker/colorDetector.ts index 4579e3c2daf9..50ca4ec1f56e 100644 --- a/lib/vscode/src/vs/editor/contrib/colorPicker/colorDetector.ts +++ b/src/vs/editor/contrib/colorPicker/colorDetector.ts @@ -178,7 +178,7 @@ export class ColorDetector extends Disposable implements IEditorContribution { let key = 'colorBox-' + subKey; if (!this._decorationsTypes.has(key) && !newDecorationsTypes[key]) { - this._codeEditorService.registerDecorationType(key, { + this._codeEditorService.registerDecorationType('color-detector-color', key, { before: { contentText: ' ', border: 'solid 0.1em #000', diff --git a/lib/vscode/src/vs/editor/contrib/colorPicker/colorPicker.css b/src/vs/editor/contrib/colorPicker/colorPicker.css similarity index 100% rename from lib/vscode/src/vs/editor/contrib/colorPicker/colorPicker.css rename to src/vs/editor/contrib/colorPicker/colorPicker.css diff --git a/lib/vscode/src/vs/editor/contrib/colorPicker/colorPickerModel.ts b/src/vs/editor/contrib/colorPicker/colorPickerModel.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/colorPicker/colorPickerModel.ts rename to src/vs/editor/contrib/colorPicker/colorPickerModel.ts diff --git a/lib/vscode/src/vs/editor/contrib/colorPicker/colorPickerWidget.ts b/src/vs/editor/contrib/colorPicker/colorPickerWidget.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/colorPicker/colorPickerWidget.ts rename to src/vs/editor/contrib/colorPicker/colorPickerWidget.ts diff --git a/lib/vscode/src/vs/editor/contrib/colorPicker/images/opacity-background.png b/src/vs/editor/contrib/colorPicker/images/opacity-background.png similarity index 100% rename from lib/vscode/src/vs/editor/contrib/colorPicker/images/opacity-background.png rename to src/vs/editor/contrib/colorPicker/images/opacity-background.png diff --git a/lib/vscode/src/vs/editor/contrib/comment/blockCommentCommand.ts b/src/vs/editor/contrib/comment/blockCommentCommand.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/comment/blockCommentCommand.ts rename to src/vs/editor/contrib/comment/blockCommentCommand.ts diff --git a/lib/vscode/src/vs/editor/contrib/comment/comment.ts b/src/vs/editor/contrib/comment/comment.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/comment/comment.ts rename to src/vs/editor/contrib/comment/comment.ts diff --git a/lib/vscode/src/vs/editor/contrib/comment/lineCommentCommand.ts b/src/vs/editor/contrib/comment/lineCommentCommand.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/comment/lineCommentCommand.ts rename to src/vs/editor/contrib/comment/lineCommentCommand.ts diff --git a/lib/vscode/src/vs/editor/contrib/comment/test/blockCommentCommand.test.ts b/src/vs/editor/contrib/comment/test/blockCommentCommand.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/comment/test/blockCommentCommand.test.ts rename to src/vs/editor/contrib/comment/test/blockCommentCommand.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts b/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts rename to src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/contextmenu/contextmenu.ts b/src/vs/editor/contrib/contextmenu/contextmenu.ts similarity index 96% rename from lib/vscode/src/vs/editor/contrib/contextmenu/contextmenu.ts rename to src/vs/editor/contrib/contextmenu/contextmenu.ts index 8a2a53b8dde0..a325a4086335 100644 --- a/lib/vscode/src/vs/editor/contrib/contextmenu/contextmenu.ts +++ b/src/vs/editor/contrib/contextmenu/contextmenu.ts @@ -23,6 +23,7 @@ import { ITextModel } from 'vs/editor/common/model'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; +import { isIOS } from 'vs/base/common/platform'; export class ContextMenuController implements IEditorContribution { @@ -135,7 +136,8 @@ export class ContextMenuController implements IEditorContribution { } // Find actions available for menu - const menuActions = this._getMenuActions(this._editor.getModel(), MenuId.EditorContext); + const menuActions = this._getMenuActions(this._editor.getModel(), + this._editor.isSimpleWidget ? MenuId.SimpleEditorContext : MenuId.EditorContext); // Show menu if we have actions to show if (menuActions.length > 0) { @@ -208,10 +210,12 @@ export class ContextMenuController implements IEditorContribution { anchor = { x: posx, y: posy }; } + const useShadowDOM = this._editor.getOption(EditorOption.useShadowDOM) && !isIOS; // Do not use shadow dom on IOS #122035 + // Show menu this._contextMenuIsBeingShownCount++; this._contextMenuService.showContextMenu({ - domForShadowRoot: this._editor.getDomNode(), + domForShadowRoot: useShadowDOM ? this._editor.getDomNode() : undefined, getAnchor: () => anchor!, diff --git a/lib/vscode/src/vs/editor/contrib/cursorUndo/cursorUndo.ts b/src/vs/editor/contrib/cursorUndo/cursorUndo.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/cursorUndo/cursorUndo.ts rename to src/vs/editor/contrib/cursorUndo/cursorUndo.ts diff --git a/lib/vscode/src/vs/editor/contrib/cursorUndo/test/cursorUndo.test.ts b/src/vs/editor/contrib/cursorUndo/test/cursorUndo.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/cursorUndo/test/cursorUndo.test.ts rename to src/vs/editor/contrib/cursorUndo/test/cursorUndo.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/dnd/dnd.css b/src/vs/editor/contrib/dnd/dnd.css similarity index 100% rename from lib/vscode/src/vs/editor/contrib/dnd/dnd.css rename to src/vs/editor/contrib/dnd/dnd.css diff --git a/lib/vscode/src/vs/editor/contrib/dnd/dnd.ts b/src/vs/editor/contrib/dnd/dnd.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/dnd/dnd.ts rename to src/vs/editor/contrib/dnd/dnd.ts index 1f15af6828a9..4596072c0325 100644 --- a/lib/vscode/src/vs/editor/contrib/dnd/dnd.ts +++ b/src/vs/editor/contrib/dnd/dnd.ts @@ -204,6 +204,7 @@ export class DragAndDropController extends Disposable implements IEditorContribu } private static readonly _DECORATION_OPTIONS = ModelDecorationOptions.register({ + description: 'dnd-target', className: 'dnd-target' }); diff --git a/lib/vscode/src/vs/editor/contrib/dnd/dragAndDropCommand.ts b/src/vs/editor/contrib/dnd/dragAndDropCommand.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/dnd/dragAndDropCommand.ts rename to src/vs/editor/contrib/dnd/dragAndDropCommand.ts diff --git a/lib/vscode/src/vs/editor/contrib/documentSymbols/documentSymbols.ts b/src/vs/editor/contrib/documentSymbols/documentSymbols.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/documentSymbols/documentSymbols.ts rename to src/vs/editor/contrib/documentSymbols/documentSymbols.ts diff --git a/lib/vscode/src/vs/editor/contrib/documentSymbols/outlineModel.ts b/src/vs/editor/contrib/documentSymbols/outlineModel.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/documentSymbols/outlineModel.ts rename to src/vs/editor/contrib/documentSymbols/outlineModel.ts diff --git a/lib/vscode/src/vs/editor/contrib/documentSymbols/test/outlineModel.test.ts b/src/vs/editor/contrib/documentSymbols/test/outlineModel.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/documentSymbols/test/outlineModel.test.ts rename to src/vs/editor/contrib/documentSymbols/test/outlineModel.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/find/findController.ts b/src/vs/editor/contrib/find/findController.ts similarity index 94% rename from lib/vscode/src/vs/editor/contrib/find/findController.ts rename to src/vs/editor/contrib/find/findController.ts index 596463ecae3c..b7f3bba4aef2 100644 --- a/lib/vscode/src/vs/editor/contrib/find/findController.ts +++ b/src/vs/editor/contrib/find/findController.ts @@ -26,7 +26,6 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag import { IThemeService } from 'vs/platform/theme/common/themeService'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; -import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; const SEARCH_STRING_MAX_LENGTH = 524288; @@ -502,12 +501,7 @@ export const StartFindAction = registerMultiEditorAction(new MultiEditorAction({ } })); -StartFindAction.addImplementation(0, (accessor: ServicesAccessor, args: any): boolean | Promise => { - const codeEditorService = accessor.get(ICodeEditorService); - const editor = codeEditorService.getFocusedCodeEditor() || codeEditorService.getActiveCodeEditor(); - if (!editor) { - return false; - } +StartFindAction.addImplementation(0, (accessor: ServicesAccessor, editor: ICodeEditor, args: any): boolean | Promise => { const controller = CommonFindController.get(editor); if (!controller) { return false; @@ -587,39 +581,16 @@ export class NextMatchFindAction extends MatchFindAction { label: nls.localize('findNextMatchAction', "Find Next"), alias: 'Find Next', precondition: undefined, - kbOpts: { + kbOpts: [{ kbExpr: EditorContextKeys.focus, primary: KeyCode.F3, mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_G, secondary: [KeyCode.F3] }, weight: KeybindingWeight.EditorContrib - } - }); - } - - protected _run(controller: CommonFindController): boolean { - const result = controller.moveToNextMatch(); - if (result) { - controller.editor.pushUndoStop(); - return true; - } - - return false; - } -} - -export class NextMatchFindAction2 extends MatchFindAction { - - constructor() { - super({ - id: FIND_IDS.NextMatchFindAction, - label: nls.localize('findNextMatchAction', "Find Next"), - alias: 'Find Next', - precondition: undefined, - kbOpts: { + }, { kbExpr: ContextKeyExpr.and(EditorContextKeys.focus, CONTEXT_FIND_INPUT_FOCUSED), primary: KeyCode.Enter, weight: KeybindingWeight.EditorContrib - } + }] }); } @@ -642,33 +613,17 @@ export class PreviousMatchFindAction extends MatchFindAction { label: nls.localize('findPreviousMatchAction', "Find Previous"), alias: 'Find Previous', precondition: undefined, - kbOpts: { + kbOpts: [{ kbExpr: EditorContextKeys.focus, primary: KeyMod.Shift | KeyCode.F3, mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G, secondary: [KeyMod.Shift | KeyCode.F3] }, weight: KeybindingWeight.EditorContrib - } - }); - } - - protected _run(controller: CommonFindController): boolean { - return controller.moveToPrevMatch(); - } -} - -export class PreviousMatchFindAction2 extends MatchFindAction { - - constructor() { - super({ - id: FIND_IDS.PreviousMatchFindAction, - label: nls.localize('findPreviousMatchAction', "Find Previous"), - alias: 'Find Previous', - precondition: undefined, - kbOpts: { + }, { kbExpr: ContextKeyExpr.and(EditorContextKeys.focus, CONTEXT_FIND_INPUT_FOCUSED), primary: KeyMod.Shift | KeyCode.Enter, weight: KeybindingWeight.EditorContrib } + ] }); } @@ -765,10 +720,8 @@ export const StartFindReplaceAction = registerMultiEditorAction(new MultiEditorA } })); -StartFindReplaceAction.addImplementation(0, (accessor: ServicesAccessor, args: any): boolean | Promise => { - const codeEditorService = accessor.get(ICodeEditorService); - const editor = codeEditorService.getFocusedCodeEditor() || codeEditorService.getActiveCodeEditor(); - if (!editor || !editor.hasModel() || editor.getOption(EditorOption.readOnly)) { +StartFindReplaceAction.addImplementation(0, (accessor: ServicesAccessor, editor: ICodeEditor, args: any): boolean | Promise => { + if (!editor.hasModel() || editor.getOption(EditorOption.readOnly)) { return false; } const controller = CommonFindController.get(editor); @@ -808,9 +761,7 @@ registerEditorContribution(CommonFindController.ID, FindController); registerEditorAction(StartFindWithSelectionAction); registerEditorAction(NextMatchFindAction); -registerEditorAction(NextMatchFindAction2); registerEditorAction(PreviousMatchFindAction); -registerEditorAction(PreviousMatchFindAction2); registerEditorAction(NextSelectionMatchFindAction); registerEditorAction(PreviousSelectionMatchFindAction); diff --git a/lib/vscode/src/vs/editor/contrib/find/findDecorations.ts b/src/vs/editor/contrib/find/findDecorations.ts similarity index 98% rename from lib/vscode/src/vs/editor/contrib/find/findDecorations.ts rename to src/vs/editor/contrib/find/findDecorations.ts index c6b966e77c19..08b1bc807e55 100644 --- a/lib/vscode/src/vs/editor/contrib/find/findDecorations.ts +++ b/src/vs/editor/contrib/find/findDecorations.ts @@ -276,6 +276,7 @@ export class FindDecorations implements IDisposable { } public static readonly _CURRENT_FIND_MATCH_DECORATION = ModelDecorationOptions.register({ + description: 'current-find-match', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, zIndex: 13, className: 'currentFindMatch', @@ -291,6 +292,7 @@ export class FindDecorations implements IDisposable { }); public static readonly _FIND_MATCH_DECORATION = ModelDecorationOptions.register({ + description: 'find-match', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'findMatch', showIfCollapsed: true, @@ -305,12 +307,14 @@ export class FindDecorations implements IDisposable { }); public static readonly _FIND_MATCH_NO_OVERVIEW_DECORATION = ModelDecorationOptions.register({ + description: 'find-match-no-overview', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'findMatch', showIfCollapsed: true }); private static readonly _FIND_MATCH_ONLY_OVERVIEW_DECORATION = ModelDecorationOptions.register({ + description: 'find-match-only-overview', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, overviewRuler: { color: themeColorFromId(overviewRulerFindMatchForeground), @@ -319,12 +323,14 @@ export class FindDecorations implements IDisposable { }); private static readonly _RANGE_HIGHLIGHT_DECORATION = ModelDecorationOptions.register({ + description: 'find-range-highlight', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'rangeHighlight', isWholeLine: true }); private static readonly _FIND_SCOPE_DECORATION = ModelDecorationOptions.register({ + description: 'find-scope', className: 'findScope', isWholeLine: true }); diff --git a/lib/vscode/src/vs/editor/contrib/find/findModel.ts b/src/vs/editor/contrib/find/findModel.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/find/findModel.ts rename to src/vs/editor/contrib/find/findModel.ts diff --git a/lib/vscode/src/vs/editor/contrib/find/findOptionsWidget.ts b/src/vs/editor/contrib/find/findOptionsWidget.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/find/findOptionsWidget.ts rename to src/vs/editor/contrib/find/findOptionsWidget.ts diff --git a/lib/vscode/src/vs/editor/contrib/find/findState.ts b/src/vs/editor/contrib/find/findState.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/find/findState.ts rename to src/vs/editor/contrib/find/findState.ts diff --git a/lib/vscode/src/vs/editor/contrib/find/findWidget.css b/src/vs/editor/contrib/find/findWidget.css similarity index 100% rename from lib/vscode/src/vs/editor/contrib/find/findWidget.css rename to src/vs/editor/contrib/find/findWidget.css diff --git a/lib/vscode/src/vs/editor/contrib/find/findWidget.ts b/src/vs/editor/contrib/find/findWidget.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/find/findWidget.ts rename to src/vs/editor/contrib/find/findWidget.ts diff --git a/lib/vscode/src/vs/editor/contrib/find/replaceAllCommand.ts b/src/vs/editor/contrib/find/replaceAllCommand.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/find/replaceAllCommand.ts rename to src/vs/editor/contrib/find/replaceAllCommand.ts diff --git a/lib/vscode/src/vs/editor/contrib/find/replacePattern.ts b/src/vs/editor/contrib/find/replacePattern.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/find/replacePattern.ts rename to src/vs/editor/contrib/find/replacePattern.ts diff --git a/lib/vscode/src/vs/editor/contrib/find/test/find.test.ts b/src/vs/editor/contrib/find/test/find.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/find/test/find.test.ts rename to src/vs/editor/contrib/find/test/find.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/find/test/findController.test.ts b/src/vs/editor/contrib/find/test/findController.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/find/test/findController.test.ts rename to src/vs/editor/contrib/find/test/findController.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/find/test/findModel.test.ts b/src/vs/editor/contrib/find/test/findModel.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/find/test/findModel.test.ts rename to src/vs/editor/contrib/find/test/findModel.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/find/test/replacePattern.test.ts b/src/vs/editor/contrib/find/test/replacePattern.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/find/test/replacePattern.test.ts rename to src/vs/editor/contrib/find/test/replacePattern.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/folding/folding.css b/src/vs/editor/contrib/folding/folding.css similarity index 100% rename from lib/vscode/src/vs/editor/contrib/folding/folding.css rename to src/vs/editor/contrib/folding/folding.css diff --git a/lib/vscode/src/vs/editor/contrib/folding/folding.ts b/src/vs/editor/contrib/folding/folding.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/folding/folding.ts rename to src/vs/editor/contrib/folding/folding.ts index c6396a556db8..de52951d6e04 100644 --- a/lib/vscode/src/vs/editor/contrib/folding/folding.ts +++ b/src/vs/editor/contrib/folding/folding.ts @@ -51,7 +51,7 @@ interface FoldingStateMemento { export class FoldingController extends Disposable implements IEditorContribution { - public static ID = 'editor.contrib.folding'; + public static readonly ID = 'editor.contrib.folding'; static readonly MAX_FOLDING_REGIONS = 5000; diff --git a/lib/vscode/src/vs/editor/contrib/folding/foldingDecorations.ts b/src/vs/editor/contrib/folding/foldingDecorations.ts similarity index 92% rename from lib/vscode/src/vs/editor/contrib/folding/foldingDecorations.ts rename to src/vs/editor/contrib/folding/foldingDecorations.ts index 22601d1298e8..bbca380a7480 100644 --- a/lib/vscode/src/vs/editor/contrib/folding/foldingDecorations.ts +++ b/src/vs/editor/contrib/folding/foldingDecorations.ts @@ -17,6 +17,7 @@ export const foldingCollapsedIcon = registerIcon('folding-collapsed', Codicon.ch export class FoldingDecorationProvider implements IDecorationProvider { private static readonly COLLAPSED_VISUAL_DECORATION = ModelDecorationOptions.register({ + description: 'folding-collapsed-visual-decoration', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, afterContentClassName: 'inline-folded', isWholeLine: true, @@ -24,6 +25,7 @@ export class FoldingDecorationProvider implements IDecorationProvider { }); private static readonly COLLAPSED_HIGHLIGHTED_VISUAL_DECORATION = ModelDecorationOptions.register({ + description: 'folding-collapsed-highlighted-visual-decoration', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, afterContentClassName: 'inline-folded', className: 'folded-background', @@ -32,18 +34,21 @@ export class FoldingDecorationProvider implements IDecorationProvider { }); private static readonly EXPANDED_AUTO_HIDE_VISUAL_DECORATION = ModelDecorationOptions.register({ + description: 'folding-expanded-auto-hide-visual-decoration', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, isWholeLine: true, firstLineDecorationClassName: ThemeIcon.asClassName(foldingExpandedIcon) }); private static readonly EXPANDED_VISUAL_DECORATION = ModelDecorationOptions.register({ + description: 'folding-expanded-visual-decoration', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, isWholeLine: true, firstLineDecorationClassName: 'alwaysShowFoldIcons ' + ThemeIcon.asClassName(foldingExpandedIcon) }); private static readonly HIDDEN_RANGE_DECORATION = ModelDecorationOptions.register({ + description: 'folding-hidden-range-decoration', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges }); diff --git a/lib/vscode/src/vs/editor/contrib/folding/foldingModel.ts b/src/vs/editor/contrib/folding/foldingModel.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/folding/foldingModel.ts rename to src/vs/editor/contrib/folding/foldingModel.ts diff --git a/lib/vscode/src/vs/editor/contrib/folding/foldingRanges.ts b/src/vs/editor/contrib/folding/foldingRanges.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/folding/foldingRanges.ts rename to src/vs/editor/contrib/folding/foldingRanges.ts diff --git a/lib/vscode/src/vs/editor/contrib/folding/hiddenRangeModel.ts b/src/vs/editor/contrib/folding/hiddenRangeModel.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/folding/hiddenRangeModel.ts rename to src/vs/editor/contrib/folding/hiddenRangeModel.ts diff --git a/lib/vscode/src/vs/editor/contrib/folding/indentRangeProvider.ts b/src/vs/editor/contrib/folding/indentRangeProvider.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/folding/indentRangeProvider.ts rename to src/vs/editor/contrib/folding/indentRangeProvider.ts diff --git a/lib/vscode/src/vs/editor/contrib/folding/intializingRangeProvider.ts b/src/vs/editor/contrib/folding/intializingRangeProvider.ts similarity index 97% rename from lib/vscode/src/vs/editor/contrib/folding/intializingRangeProvider.ts rename to src/vs/editor/contrib/folding/intializingRangeProvider.ts index 754ac39f0483..9064c178be51 100644 --- a/lib/vscode/src/vs/editor/contrib/folding/intializingRangeProvider.ts +++ b/src/vs/editor/contrib/folding/intializingRangeProvider.ts @@ -28,6 +28,7 @@ export class InitializingRangeProvider implements RangeProvider { endColumn: editorModel.getLineLength(range.endLineNumber) }, options: { + description: 'folding-initializing-range-provider', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges } }; diff --git a/lib/vscode/src/vs/editor/contrib/folding/syntaxRangeProvider.ts b/src/vs/editor/contrib/folding/syntaxRangeProvider.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/folding/syntaxRangeProvider.ts rename to src/vs/editor/contrib/folding/syntaxRangeProvider.ts diff --git a/lib/vscode/src/vs/editor/contrib/folding/test/foldingModel.test.ts b/src/vs/editor/contrib/folding/test/foldingModel.test.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/folding/test/foldingModel.test.ts rename to src/vs/editor/contrib/folding/test/foldingModel.test.ts index 317f12223dd2..fb8275939e65 100644 --- a/lib/vscode/src/vs/editor/contrib/folding/test/foldingModel.test.ts +++ b/src/vs/editor/contrib/folding/test/foldingModel.test.ts @@ -29,16 +29,19 @@ interface ExpectedDecoration { export class TestDecorationProvider { private static readonly collapsedDecoration = ModelDecorationOptions.register({ + description: 'test', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, linesDecorationsClassName: 'folding' }); private static readonly expandedDecoration = ModelDecorationOptions.register({ + description: 'test', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, linesDecorationsClassName: 'folding' }); private static readonly hiddenDecoration = ModelDecorationOptions.register({ + description: 'test', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, linesDecorationsClassName: 'folding' }); diff --git a/lib/vscode/src/vs/editor/contrib/folding/test/foldingRanges.test.ts b/src/vs/editor/contrib/folding/test/foldingRanges.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/folding/test/foldingRanges.test.ts rename to src/vs/editor/contrib/folding/test/foldingRanges.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/folding/test/hiddenRangeModel.test.ts b/src/vs/editor/contrib/folding/test/hiddenRangeModel.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/folding/test/hiddenRangeModel.test.ts rename to src/vs/editor/contrib/folding/test/hiddenRangeModel.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/folding/test/indentFold.test.ts b/src/vs/editor/contrib/folding/test/indentFold.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/folding/test/indentFold.test.ts rename to src/vs/editor/contrib/folding/test/indentFold.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/folding/test/indentRangeProvider.test.ts b/src/vs/editor/contrib/folding/test/indentRangeProvider.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/folding/test/indentRangeProvider.test.ts rename to src/vs/editor/contrib/folding/test/indentRangeProvider.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/folding/test/syntaxFold.test.ts b/src/vs/editor/contrib/folding/test/syntaxFold.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/folding/test/syntaxFold.test.ts rename to src/vs/editor/contrib/folding/test/syntaxFold.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/fontZoom/fontZoom.ts b/src/vs/editor/contrib/fontZoom/fontZoom.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/fontZoom/fontZoom.ts rename to src/vs/editor/contrib/fontZoom/fontZoom.ts diff --git a/lib/vscode/src/vs/editor/contrib/format/format.ts b/src/vs/editor/contrib/format/format.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/format/format.ts rename to src/vs/editor/contrib/format/format.ts diff --git a/lib/vscode/src/vs/editor/contrib/format/formatActions.ts b/src/vs/editor/contrib/format/formatActions.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/format/formatActions.ts rename to src/vs/editor/contrib/format/formatActions.ts diff --git a/lib/vscode/src/vs/editor/contrib/format/formattingEdit.ts b/src/vs/editor/contrib/format/formattingEdit.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/format/formattingEdit.ts rename to src/vs/editor/contrib/format/formattingEdit.ts diff --git a/lib/vscode/src/vs/editor/contrib/gotoError/gotoError.ts b/src/vs/editor/contrib/gotoError/gotoError.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/gotoError/gotoError.ts rename to src/vs/editor/contrib/gotoError/gotoError.ts diff --git a/lib/vscode/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts b/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts rename to src/vs/editor/contrib/gotoError/gotoErrorWidget.ts diff --git a/lib/vscode/src/vs/editor/contrib/gotoError/markerNavigationService.ts b/src/vs/editor/contrib/gotoError/markerNavigationService.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/gotoError/markerNavigationService.ts rename to src/vs/editor/contrib/gotoError/markerNavigationService.ts diff --git a/lib/vscode/src/vs/editor/contrib/gotoError/media/gotoErrorWidget.css b/src/vs/editor/contrib/gotoError/media/gotoErrorWidget.css similarity index 100% rename from lib/vscode/src/vs/editor/contrib/gotoError/media/gotoErrorWidget.css rename to src/vs/editor/contrib/gotoError/media/gotoErrorWidget.css diff --git a/lib/vscode/src/vs/editor/contrib/gotoSymbol/goToCommands.ts b/src/vs/editor/contrib/gotoSymbol/goToCommands.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/gotoSymbol/goToCommands.ts rename to src/vs/editor/contrib/gotoSymbol/goToCommands.ts index 2152693b449e..1218703746d8 100644 --- a/lib/vscode/src/vs/editor/contrib/gotoSymbol/goToCommands.ts +++ b/src/vs/editor/contrib/gotoSymbol/goToCommands.ts @@ -190,7 +190,7 @@ abstract class SymbolNavigationAction extends EditorAction { if (highlight) { const modelNow = targetEditor.getModel(); - const ids = targetEditor.deltaDecorations([], [{ range, options: { className: 'symbolHighlight' } }]); + const ids = targetEditor.deltaDecorations([], [{ range, options: { description: 'symbol-navigate-action-highlight', className: 'symbolHighlight' } }]); setTimeout(() => { if (targetEditor.getModel() === modelNow) { targetEditor.deltaDecorations(ids, []); diff --git a/lib/vscode/src/vs/editor/contrib/gotoSymbol/goToSymbol.ts b/src/vs/editor/contrib/gotoSymbol/goToSymbol.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/gotoSymbol/goToSymbol.ts rename to src/vs/editor/contrib/gotoSymbol/goToSymbol.ts diff --git a/lib/vscode/src/vs/editor/contrib/gotoSymbol/link/clickLinkGesture.ts b/src/vs/editor/contrib/gotoSymbol/link/clickLinkGesture.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/gotoSymbol/link/clickLinkGesture.ts rename to src/vs/editor/contrib/gotoSymbol/link/clickLinkGesture.ts diff --git a/lib/vscode/src/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.css b/src/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.css similarity index 100% rename from lib/vscode/src/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.css rename to src/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.css diff --git a/lib/vscode/src/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.ts b/src/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.ts rename to src/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.ts index 68c3275a7a4a..5a4c164cd52c 100644 --- a/lib/vscode/src/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.ts +++ b/src/vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition.ts @@ -305,6 +305,7 @@ export class GotoDefinitionAtPositionEditorContribution implements IEditorContri const newDecorations: IModelDeltaDecoration = { range: range, options: { + description: 'goto-definition-link', inlineClassName: 'goto-definition-link', hoverMessage } diff --git a/lib/vscode/src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts b/src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts rename to src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts diff --git a/lib/vscode/src/vs/editor/contrib/gotoSymbol/peek/referencesTree.ts b/src/vs/editor/contrib/gotoSymbol/peek/referencesTree.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/gotoSymbol/peek/referencesTree.ts rename to src/vs/editor/contrib/gotoSymbol/peek/referencesTree.ts diff --git a/lib/vscode/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.css b/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.css similarity index 100% rename from lib/vscode/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.css rename to src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.css diff --git a/lib/vscode/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts b/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts rename to src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts index 9f93856f7da5..f1a11176a8b7 100644 --- a/lib/vscode/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts +++ b/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts @@ -40,6 +40,7 @@ import { KeyCode } from 'vs/base/common/keyCodes'; class DecorationsManager implements IDisposable { private static readonly DecorationOptions = ModelDecorationOptions.register({ + description: 'reference-decoration', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'reference-decoration' }); diff --git a/lib/vscode/src/vs/editor/contrib/gotoSymbol/referencesModel.ts b/src/vs/editor/contrib/gotoSymbol/referencesModel.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/gotoSymbol/referencesModel.ts rename to src/vs/editor/contrib/gotoSymbol/referencesModel.ts diff --git a/lib/vscode/src/vs/editor/contrib/gotoSymbol/symbolNavigation.ts b/src/vs/editor/contrib/gotoSymbol/symbolNavigation.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/gotoSymbol/symbolNavigation.ts rename to src/vs/editor/contrib/gotoSymbol/symbolNavigation.ts diff --git a/lib/vscode/src/vs/editor/contrib/gotoSymbol/test/referencesModel.test.ts b/src/vs/editor/contrib/gotoSymbol/test/referencesModel.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/gotoSymbol/test/referencesModel.test.ts rename to src/vs/editor/contrib/gotoSymbol/test/referencesModel.test.ts diff --git a/src/vs/editor/contrib/hover/colorHoverParticipant.ts b/src/vs/editor/contrib/hover/colorHoverParticipant.ts new file mode 100644 index 000000000000..0c17aa895268 --- /dev/null +++ b/src/vs/editor/contrib/hover/colorHoverParticipant.ts @@ -0,0 +1,153 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { Range } from 'vs/editor/common/core/range'; +import { DocumentColorProvider, IColorInformation } from 'vs/editor/common/modes'; +import { IIdentifiedSingleEditOperation, IModelDecoration, ITextModel, TrackedRangeStickiness } from 'vs/editor/common/model'; +import { HoverAnchor, HoverAnchorType, IEditorHover, IEditorHoverParticipant, IEditorHoverStatusBar, IHoverPart } from 'vs/editor/contrib/hover/hoverTypes'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { getColorPresentations } from 'vs/editor/contrib/colorPicker/color'; +import { ColorDetector } from 'vs/editor/contrib/colorPicker/colorDetector'; +import { Color, RGBA } from 'vs/base/common/color'; +import { ColorPickerModel } from 'vs/editor/contrib/colorPicker/colorPickerModel'; +import { ColorPickerWidget } from 'vs/editor/contrib/colorPicker/colorPickerWidget'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; + +export class ColorHover implements IHoverPart { + + /** + * Force the hover to always be rendered at this specific range, + * even in the case of multiple hover parts. + */ + public readonly forceShowAtRange: boolean = true; + + constructor( + public readonly owner: IEditorHoverParticipant, + public readonly range: Range, + public readonly model: ColorPickerModel, + public readonly provider: DocumentColorProvider + ) { } + + public isValidForHoverAnchor(anchor: HoverAnchor): boolean { + return ( + anchor.type === HoverAnchorType.Range + && this.range.startColumn <= anchor.range.startColumn + && this.range.endColumn >= anchor.range.endColumn + ); + } +} + +export class ColorHoverParticipant implements IEditorHoverParticipant { + + constructor( + private readonly _editor: ICodeEditor, + private readonly _hover: IEditorHover, + @IThemeService private readonly _themeService: IThemeService, + ) { } + + public computeSync(anchor: HoverAnchor, lineDecorations: IModelDecoration[]): ColorHover[] { + return []; + } + + public async computeAsync(anchor: HoverAnchor, lineDecorations: IModelDecoration[], token: CancellationToken): Promise { + if (!this._editor.hasModel()) { + return []; + } + const colorDetector = ColorDetector.get(this._editor); + for (const d of lineDecorations) { + const colorData = colorDetector.getColorData(d.range.getStartPosition()); + if (colorData) { + const colorHover = await this._createColorHover(this._editor.getModel(), colorData.colorInfo, colorData.provider); + return [colorHover]; + } + } + return []; + } + + private async _createColorHover(editorModel: ITextModel, colorInfo: IColorInformation, provider: DocumentColorProvider): Promise { + const originalText = editorModel.getValueInRange(colorInfo.range); + const { red, green, blue, alpha } = colorInfo.color; + const rgba = new RGBA(Math.round(red * 255), Math.round(green * 255), Math.round(blue * 255), alpha); + const color = new Color(rgba); + + const colorPresentations = await getColorPresentations(editorModel, colorInfo, provider, CancellationToken.None); + const model = new ColorPickerModel(color, [], 0); + model.colorPresentations = colorPresentations || []; + model.guessColorPresentation(color, originalText); + + return new ColorHover(this, Range.lift(colorInfo.range), model, provider); + } + + public renderHoverParts(hoverParts: ColorHover[], fragment: DocumentFragment, statusBar: IEditorHoverStatusBar): IDisposable { + if (hoverParts.length === 0 || !this._editor.hasModel()) { + return Disposable.None; + } + + const disposables = new DisposableStore(); + const colorHover = hoverParts[0]; + const editorModel = this._editor.getModel(); + const model = colorHover.model; + const widget = disposables.add(new ColorPickerWidget(fragment, model, this._editor.getOption(EditorOption.pixelRatio), this._themeService)); + + let range = new Range(colorHover.range.startLineNumber, colorHover.range.startColumn, colorHover.range.endLineNumber, colorHover.range.endColumn); + + const updateEditorModel = () => { + let textEdits: IIdentifiedSingleEditOperation[]; + let newRange: Range; + if (model.presentation.textEdit) { + textEdits = [model.presentation.textEdit as IIdentifiedSingleEditOperation]; + newRange = new Range( + model.presentation.textEdit.range.startLineNumber, + model.presentation.textEdit.range.startColumn, + model.presentation.textEdit.range.endLineNumber, + model.presentation.textEdit.range.endColumn + ); + const trackedRange = this._editor.getModel()!._setTrackedRange(null, newRange, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter); + this._editor.pushUndoStop(); + this._editor.executeEdits('colorpicker', textEdits); + newRange = this._editor.getModel()!._getTrackedRange(trackedRange) || newRange; + } else { + textEdits = [{ identifier: null, range, text: model.presentation.label, forceMoveMarkers: false }]; + newRange = range.setEndPosition(range.endLineNumber, range.startColumn + model.presentation.label.length); + this._editor.pushUndoStop(); + this._editor.executeEdits('colorpicker', textEdits); + } + + if (model.presentation.additionalTextEdits) { + textEdits = [...model.presentation.additionalTextEdits as IIdentifiedSingleEditOperation[]]; + this._editor.executeEdits('colorpicker', textEdits); + this._hover.hide(); + } + this._editor.pushUndoStop(); + range = newRange; + }; + + const updateColorPresentations = (color: Color) => { + return getColorPresentations(editorModel, { + range: range, + color: { + red: color.rgba.r / 255, + green: color.rgba.g / 255, + blue: color.rgba.b / 255, + alpha: color.rgba.a + } + }, colorHover.provider, CancellationToken.None).then((colorPresentations) => { + model.colorPresentations = colorPresentations || []; + }); + }; + + disposables.add(model.onColorFlushed((color: Color) => { + updateColorPresentations(color).then(updateEditorModel); + })); + disposables.add(model.onDidChangeColor(updateColorPresentations)); + + this._hover.setColorPicker(widget); + + return disposables; + } +} diff --git a/lib/vscode/src/vs/editor/contrib/hover/getHover.ts b/src/vs/editor/contrib/hover/getHover.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/hover/getHover.ts rename to src/vs/editor/contrib/hover/getHover.ts diff --git a/lib/vscode/src/vs/editor/contrib/hover/hover.ts b/src/vs/editor/contrib/hover/hover.ts similarity index 83% rename from lib/vscode/src/vs/editor/contrib/hover/hover.ts rename to src/vs/editor/contrib/hover/hover.ts index 276ad87a8ffe..9d8a6c8ee370 100644 --- a/lib/vscode/src/vs/editor/contrib/hover/hover.ts +++ b/src/vs/editor/contrib/hover/hover.ts @@ -7,7 +7,6 @@ import * as nls from 'vs/nls'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { IEmptyContentData } from 'vs/editor/browser/controller/mouseTarget'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; @@ -21,7 +20,7 @@ import { ModesGlyphHoverWidget } from 'vs/editor/contrib/hover/modesGlyphHover'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { editorHoverBackground, editorHoverBorder, editorHoverHighlight, textCodeBlockBackground, textLinkForeground, editorHoverStatusBarBackground, editorHoverForeground } from 'vs/platform/theme/common/colorRegistry'; -import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { GotoDefinitionAtPositionEditorContribution } from 'vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -52,7 +51,6 @@ export class ModesHoverController implements IEditorContribution { @IInstantiationService private readonly _instantiationService: IInstantiationService, @IOpenerService private readonly _openerService: IOpenerService, @IModeService private readonly _modeService: IModeService, - @IThemeService private readonly _themeService: IThemeService, @IContextKeyService _contextKeyService: IContextKeyService ) { this._isMouseDown = false; @@ -166,45 +164,27 @@ export class ModesHoverController implements IEditorContribution { return; } - if (targetType === MouseTargetType.CONTENT_EMPTY) { - const epsilon = this._editor.getOption(EditorOption.fontInfo).typicalHalfwidthCharacterWidth / 2; - const data = mouseEvent.target.detail; - if (data && !data.isAfterLines && typeof data.horizontalDistanceToText === 'number' && data.horizontalDistanceToText < epsilon) { - // Let hover kick in even when the mouse is technically in the empty area after a line, given the distance is small enough - targetType = MouseTargetType.CONTENT_TEXT; - } + if (!this._isHoverEnabled) { + this._hideWidgets(); + return; } - if (targetType === MouseTargetType.CONTENT_TEXT) { + const contentWidget = this._getOrCreateContentWidget(); + if (contentWidget.maybeShowAt(mouseEvent)) { this._glyphWidget?.hide(); + return; + } - if (this._isHoverEnabled && mouseEvent.target.range) { - // TODO@rebornix. This should be removed if we move Color Picker out of Hover component. - // Check if mouse is hovering on color decorator - const hoverOnColorDecorator = [...mouseEvent.target.element?.classList.values() || []].find(className => className.startsWith('ced-colorBox')) - && mouseEvent.target.range.endColumn - mouseEvent.target.range.startColumn === 1; - const showAtRange = ( - hoverOnColorDecorator // shift the mouse focus by one as color decorator is a `before` decoration of next character. - ? new Range(mouseEvent.target.range.startLineNumber, mouseEvent.target.range.startColumn + 1, mouseEvent.target.range.endLineNumber, mouseEvent.target.range.endColumn + 1) - : mouseEvent.target.range - ); - if (!this._contentWidget) { - this._contentWidget = new ModesContentHoverWidget(this._editor, this._hoverVisibleKey, this._instantiationService, this._themeService); - } - this._contentWidget.startShowingAt(showAtRange, HoverStartMode.Delayed, false); - } - } else if (targetType === MouseTargetType.GUTTER_GLYPH_MARGIN) { + if (targetType === MouseTargetType.GUTTER_GLYPH_MARGIN && mouseEvent.target.position) { this._contentWidget?.hide(); - - if (this._isHoverEnabled && mouseEvent.target.position) { - if (!this._glyphWidget) { - this._glyphWidget = new ModesGlyphHoverWidget(this._editor, this._modeService, this._openerService); - } - this._glyphWidget.startShowingAt(mouseEvent.target.position.lineNumber); + if (!this._glyphWidget) { + this._glyphWidget = new ModesGlyphHoverWidget(this._editor, this._modeService, this._openerService); } - } else { - this._hideWidgets(); + this._glyphWidget.startShowingAt(mouseEvent.target.position.lineNumber); + return; } + + this._hideWidgets(); } private _onKeyDown(e: IKeyboardEvent): void { @@ -224,15 +204,19 @@ export class ModesHoverController implements IEditorContribution { this._contentWidget?.hide(); } + private _getOrCreateContentWidget(): ModesContentHoverWidget { + if (!this._contentWidget) { + this._contentWidget = this._instantiationService.createInstance(ModesContentHoverWidget, this._editor, this._hoverVisibleKey); + } + return this._contentWidget; + } + public isColorPickerVisible(): boolean { return this._contentWidget?.isColorPickerVisible() || false; } public showContentHover(range: Range, mode: HoverStartMode, focus: boolean): void { - if (!this._contentWidget) { - this._contentWidget = new ModesContentHoverWidget(this._editor, this._hoverVisibleKey, this._instantiationService, this._themeService); - } - this._contentWidget.startShowingAt(range, mode, focus); + this._getOrCreateContentWidget().startShowingAtRange(range, mode, focus); } public dispose(): void { diff --git a/lib/vscode/src/vs/editor/contrib/hover/hoverOperation.ts b/src/vs/editor/contrib/hover/hoverOperation.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/hover/hoverOperation.ts rename to src/vs/editor/contrib/hover/hoverOperation.ts diff --git a/src/vs/editor/contrib/hover/hoverTypes.ts b/src/vs/editor/contrib/hover/hoverTypes.ts new file mode 100644 index 000000000000..2515385bfa48 --- /dev/null +++ b/src/vs/editor/contrib/hover/hoverTypes.ts @@ -0,0 +1,87 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { CancellationToken } from 'vs/base/common/cancellation'; +import { IDisposable } from 'vs/base/common/lifecycle'; +import { IEditorMouseEvent } from 'vs/editor/browser/editorBrowser'; +import { Position } from 'vs/editor/common/core/position'; +import { Range } from 'vs/editor/common/core/range'; +import { ColorPickerWidget } from 'vs/editor/contrib/colorPicker/colorPickerWidget'; +import { IModelDecoration } from 'vs/editor/common/model'; + +export interface IHoverPart { + /** + * The creator of this hover part. + */ + readonly owner: IEditorHoverParticipant; + /** + * The range where this hover part applies. + */ + readonly range: Range; + /** + * Force the hover to always be rendered at this specific range, + * even in the case of multiple hover parts. + */ + readonly forceShowAtRange?: boolean; + + isValidForHoverAnchor(anchor: HoverAnchor): boolean; +} + +export interface IEditorHover { + hide(): void; + onContentsChanged(): void; + setColorPicker(widget: ColorPickerWidget): void; +} + +export const enum HoverAnchorType { + Range = 1, + ForeignElement = 2 +} + +export class HoverRangeAnchor { + public readonly type = HoverAnchorType.Range; + constructor( + public readonly priority: number, + public readonly range: Range + ) { + } + public equals(other: HoverAnchor) { + return (other.type === HoverAnchorType.Range && this.range.equalsRange(other.range)); + } + public canAdoptVisibleHover(lastAnchor: HoverAnchor, showAtPosition: Position): boolean { + return (lastAnchor.type === HoverAnchorType.Range && showAtPosition.lineNumber === this.range.startLineNumber); + } +} + +export class HoverForeignElementAnchor { + public readonly type = HoverAnchorType.ForeignElement; + constructor( + public readonly priority: number, + public readonly owner: IEditorHoverParticipant, + public readonly range: Range + ) { + } + public equals(other: HoverAnchor) { + return (other.type === HoverAnchorType.ForeignElement && this.owner === other.owner); + } + public canAdoptVisibleHover(lastAnchor: HoverAnchor, showAtPosition: Position): boolean { + return (lastAnchor.type === HoverAnchorType.ForeignElement && this.owner === lastAnchor.owner); + } +} + +export type HoverAnchor = HoverRangeAnchor | HoverForeignElementAnchor; + +export interface IEditorHoverStatusBar { + addAction(actionOptions: { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }): void; + append(element: HTMLElement): HTMLElement; +} + +export interface IEditorHoverParticipant { + suggestHoverAnchor?(mouseEvent: IEditorMouseEvent): HoverAnchor | null; + computeSync(anchor: HoverAnchor, lineDecorations: IModelDecoration[]): T[]; + computeAsync?(anchor: HoverAnchor, lineDecorations: IModelDecoration[], token: CancellationToken): Promise; + createLoadingMessage?(anchor: HoverAnchor): T | null; + renderHoverParts(hoverParts: T[], fragment: DocumentFragment, statusBar: IEditorHoverStatusBar): IDisposable; +} diff --git a/lib/vscode/src/vs/editor/contrib/hover/hoverWidgets.ts b/src/vs/editor/contrib/hover/hoverWidgets.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/hover/hoverWidgets.ts rename to src/vs/editor/contrib/hover/hoverWidgets.ts diff --git a/lib/vscode/src/vs/editor/contrib/hover/markdownHoverParticipant.ts b/src/vs/editor/contrib/hover/markdownHoverParticipant.ts similarity index 67% rename from lib/vscode/src/vs/editor/contrib/hover/markdownHoverParticipant.ts rename to src/vs/editor/contrib/hover/markdownHoverParticipant.ts index ec4442dbd5a7..ee67c5c3e420 100644 --- a/lib/vscode/src/vs/editor/contrib/hover/markdownHoverParticipant.ts +++ b/src/vs/editor/contrib/hover/markdownHoverParticipant.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import * as dom from 'vs/base/browser/dom'; -import { IMarkdownString, MarkdownString, isEmptyMarkdownString, markedStringsEquals } from 'vs/base/common/htmlContent'; +import { IMarkdownString, MarkdownString, isEmptyMarkdownString } from 'vs/base/common/htmlContent'; import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Range } from 'vs/editor/common/core/range'; @@ -14,7 +14,7 @@ import { asArray } from 'vs/base/common/arrays'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IModelDecoration } from 'vs/editor/common/model'; -import { IEditorHover, IEditorHoverParticipant, IHoverPart } from 'vs/editor/contrib/hover/modesContentHover'; +import { HoverAnchor, HoverAnchorType, IEditorHover, IEditorHoverParticipant, IEditorHoverStatusBar, IHoverPart } from 'vs/editor/contrib/hover/hoverTypes'; import { HoverProviderRegistry } from 'vs/editor/common/modes'; import { getHover } from 'vs/editor/contrib/hover/getHover'; import { Position } from 'vs/editor/common/core/position'; @@ -25,15 +25,17 @@ const $ = dom.$; export class MarkdownHover implements IHoverPart { constructor( + public readonly owner: IEditorHoverParticipant, public readonly range: Range, public readonly contents: IMarkdownString[] ) { } - public equals(other: IHoverPart): boolean { - if (other instanceof MarkdownHover) { - return markedStringsEquals(this.contents, other.contents); - } - return false; + public isValidForHoverAnchor(anchor: HoverAnchor): boolean { + return ( + anchor.type === HoverAnchorType.Range + && this.range.startColumn <= anchor.range.startColumn + && this.range.endColumn >= anchor.range.endColumn + ); } } @@ -46,17 +48,20 @@ export class MarkdownHoverParticipant implements IEditorHoverParticipant { - if (!this._editor.hasModel() || !range) { + public async computeAsync(anchor: HoverAnchor, lineDecorations: IModelDecoration[], token: CancellationToken): Promise { + if (!this._editor.hasModel() || anchor.type !== HoverAnchorType.Range) { return Promise.resolve([]); } @@ -87,8 +92,8 @@ export class MarkdownHoverParticipant implements IEditorHoverParticipant, public readonly range: Range, public readonly marker: IMarker, ) { } - public equals(other: IHoverPart): boolean { - if (other instanceof MarkerHover) { - return IMarkerData.makeKey(this.marker) === IMarkerData.makeKey(other.marker); - } - return false; + public isValidForHoverAnchor(anchor: HoverAnchor): boolean { + return ( + anchor.type === HoverAnchorType.Range + && this.range.startColumn <= anchor.range.startColumn + && this.range.endColumn >= anchor.range.endColumn + ); } } @@ -58,17 +58,16 @@ export class MarkerHoverParticipant implements IEditorHoverParticipant fragment.appendChild(this.renderMarkerHover(msg, disposables))); const markerHoverForStatusbar = hoverParts.length === 1 ? hoverParts[0] : hoverParts.sort((a, b) => MarkerSeverity.compare(a.marker.severity, b.marker.severity))[0]; - fragment.appendChild(this.renderMarkerStatusbar(markerHoverForStatusbar, disposables)); + this.renderMarkerStatusbar(markerHoverForStatusbar, statusBar, disposables); return disposables; } @@ -165,11 +164,9 @@ export class MarkerHoverParticipant implements IEditorHoverParticipant { @@ -177,11 +174,11 @@ export class MarkerHoverParticipant implements IEditorHoverParticipant { @@ -231,17 +228,9 @@ export class MarkerHoverParticipant implements IEditorHoverParticipant void, commandId: string }): IDisposable { - const keybinding = this._keybindingService.lookupKeybinding(actionOptions.commandId); - const keybindingLabel = keybinding ? keybinding.getLabel() : null; - return renderHoverAction(parent, actionOptions, keybindingLabel); } private getCodeActions(marker: IMarker): CancelablePromise { diff --git a/src/vs/editor/contrib/hover/modesContentHover.ts b/src/vs/editor/contrib/hover/modesContentHover.ts new file mode 100644 index 000000000000..8512b9261e79 --- /dev/null +++ b/src/vs/editor/contrib/hover/modesContentHover.ts @@ -0,0 +1,586 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as dom from 'vs/base/browser/dom'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; +import { ContentWidgetPositionPreference, IActiveCodeEditor, ICodeEditor, IContentWidget, IContentWidgetPosition, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; +import { Position } from 'vs/editor/common/core/position'; +import { Range } from 'vs/editor/common/core/range'; +import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; +import { TokenizationRegistry } from 'vs/editor/common/modes'; +import { ColorPickerWidget } from 'vs/editor/contrib/colorPicker/colorPickerWidget'; +import { HoverOperation, HoverStartMode, IHoverComputer } from 'vs/editor/contrib/hover/hoverOperation'; +import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { coalesce, flatten } from 'vs/base/common/arrays'; +import { IModelDecoration } from 'vs/editor/common/model'; +import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; +import { Constants } from 'vs/base/common/uint'; +import { textLinkForeground } from 'vs/platform/theme/common/colorRegistry'; +import { IContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { Widget } from 'vs/base/browser/ui/widget'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { HoverWidget, renderHoverAction } from 'vs/base/browser/ui/hover/hoverWidget'; +import { MarkerHoverParticipant } from 'vs/editor/contrib/hover/markerHoverParticipant'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { MarkdownHoverParticipant } from 'vs/editor/contrib/hover/markdownHoverParticipant'; +import { InlineCompletionsHoverParticipant } from 'vs/editor/contrib/inlineCompletions/inlineCompletionsHoverParticipant'; +import { ColorHoverParticipant } from 'vs/editor/contrib/hover/colorHoverParticipant'; +import { IEmptyContentData } from 'vs/editor/browser/controller/mouseTarget'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { IEditorHoverStatusBar, IHoverPart, HoverAnchor, IEditorHoverParticipant, HoverAnchorType, IEditorHover, HoverRangeAnchor } from 'vs/editor/contrib/hover/hoverTypes'; + +const $ = dom.$; + +class EditorHoverStatusBar extends Disposable implements IEditorHoverStatusBar { + + public readonly hoverElement: HTMLElement; + private readonly actionsElement: HTMLElement; + private _hasContent: boolean = false; + + public get hasContent() { + return this._hasContent; + } + + constructor( + @IKeybindingService private readonly _keybindingService: IKeybindingService, + ) { + super(); + this.hoverElement = $('div.hover-row.status-bar'); + this.actionsElement = dom.append(this.hoverElement, $('div.actions')); + } + + public addAction(actionOptions: { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }): void { + const keybinding = this._keybindingService.lookupKeybinding(actionOptions.commandId); + const keybindingLabel = keybinding ? keybinding.getLabel() : null; + this._register(renderHoverAction(this.actionsElement, actionOptions, keybindingLabel)); + this._hasContent = true; + } + + public append(element: HTMLElement): HTMLElement { + const result = dom.append(this.actionsElement, element); + this._hasContent = true; + return result; + } +} + +class ModesContentComputer implements IHoverComputer { + + private readonly _editor: ICodeEditor; + private _result: IHoverPart[]; + private _anchor: HoverAnchor | null; + + constructor( + editor: ICodeEditor, + private readonly _participants: readonly IEditorHoverParticipant[] + ) { + this._editor = editor; + this._result = []; + this._anchor = null; + } + + public setAnchor(anchor: HoverAnchor): void { + this._anchor = anchor; + this._result = []; + } + + public clearResult(): void { + this._result = []; + } + + private static _getLineDecorations(editor: IActiveCodeEditor, anchor: HoverAnchor): IModelDecoration[] { + if (anchor.type !== HoverAnchorType.Range) { + return []; + } + + const model = editor.getModel(); + const lineNumber = anchor.range.startLineNumber; + const maxColumn = model.getLineMaxColumn(lineNumber); + return editor.getLineDecorations(lineNumber).filter((d) => { + if (d.options.isWholeLine) { + return true; + } + + const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1; + const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn; + if (startColumn > anchor.range.startColumn || anchor.range.endColumn > endColumn) { + return false; + } + return true; + }); + } + + public async computeAsync(token: CancellationToken): Promise { + const anchor = this._anchor; + + if (!this._editor.hasModel() || !anchor) { + return Promise.resolve([]); + } + + const lineDecorations = ModesContentComputer._getLineDecorations(this._editor, anchor); + + const allResults = await Promise.all(this._participants.map(p => this._computeAsync(p, lineDecorations, anchor, token))); + return flatten(allResults); + } + + private async _computeAsync(participant: IEditorHoverParticipant, lineDecorations: IModelDecoration[], anchor: HoverAnchor, token: CancellationToken): Promise { + if (!participant.computeAsync) { + return []; + } + return participant.computeAsync(anchor, lineDecorations, token); + } + + public computeSync(): IHoverPart[] { + if (!this._editor.hasModel() || !this._anchor) { + return []; + } + + const lineDecorations = ModesContentComputer._getLineDecorations(this._editor, this._anchor); + + let result: IHoverPart[] = []; + for (const participant of this._participants) { + result = result.concat(participant.computeSync(this._anchor, lineDecorations)); + } + + return coalesce(result); + } + + public onResult(result: IHoverPart[], isFromSynchronousComputation: boolean): void { + // Always put synchronous messages before asynchronous ones + if (isFromSynchronousComputation) { + this._result = result.concat(this._result); + } else { + this._result = this._result.concat(result); + } + } + + public getResult(): IHoverPart[] { + return this._result.slice(0); + } + + public getResultWithLoadingMessage(): IHoverPart[] { + if (this._anchor) { + for (const participant of this._participants) { + if (participant.createLoadingMessage) { + const loadingMessage = participant.createLoadingMessage(this._anchor); + if (loadingMessage) { + return this._result.slice(0).concat([loadingMessage]); + } + } + } + } + return this._result.slice(0); + } +} + +export class ModesContentHoverWidget extends Widget implements IContentWidget, IEditorHover { + + static readonly ID = 'editor.contrib.modesContentHoverWidget'; + + private readonly _participants: IEditorHoverParticipant[]; + + private readonly _hover: HoverWidget; + private readonly _id: string; + private readonly _editor: ICodeEditor; + private _isVisible: boolean; + private _showAtPosition: Position | null; + private _showAtRange: Range | null; + private _stoleFocus: boolean; + + // IContentWidget.allowEditorOverflow + public readonly allowEditorOverflow = true; + + private _messages: IHoverPart[]; + private _lastAnchor: HoverAnchor | null; + private readonly _computer: ModesContentComputer; + private readonly _hoverOperation: HoverOperation; + private _highlightDecorations: string[]; + private _isChangingDecorations: boolean; + private _shouldFocus: boolean; + private _colorPicker: ColorPickerWidget | null; + private _renderDisposable: IDisposable | null; + + constructor( + editor: ICodeEditor, + private readonly _hoverVisibleKey: IContextKey, + @IInstantiationService instantiationService: IInstantiationService, + @IKeybindingService private readonly _keybindingService: IKeybindingService, + ) { + super(); + + this._participants = [ + instantiationService.createInstance(ColorHoverParticipant, editor, this), + instantiationService.createInstance(MarkdownHoverParticipant, editor, this), + instantiationService.createInstance(InlineCompletionsHoverParticipant, editor, this), + instantiationService.createInstance(MarkerHoverParticipant, editor, this), + ]; + + this._hover = this._register(new HoverWidget()); + this._id = ModesContentHoverWidget.ID; + this._editor = editor; + this._isVisible = false; + this._stoleFocus = false; + this._renderDisposable = null; + + this.onkeydown(this._hover.containerDomNode, (e: IKeyboardEvent) => { + if (e.equals(KeyCode.Escape)) { + this.hide(); + } + }); + + this._register(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { + if (e.hasChanged(EditorOption.fontInfo)) { + this._updateFont(); + } + })); + + this._editor.onDidLayoutChange(() => this.layout()); + + this.layout(); + this._editor.addContentWidget(this); + this._showAtPosition = null; + this._showAtRange = null; + this._stoleFocus = false; + + this._messages = []; + this._lastAnchor = null; + this._computer = new ModesContentComputer(this._editor, this._participants); + this._highlightDecorations = []; + this._isChangingDecorations = false; + this._shouldFocus = false; + this._colorPicker = null; + + this._hoverOperation = new HoverOperation( + this._computer, + result => this._withResult(result, true), + null, + result => this._withResult(result, false), + this._editor.getOption(EditorOption.hover).delay + ); + + this._register(dom.addStandardDisposableListener(this.getDomNode(), dom.EventType.FOCUS, () => { + if (this._colorPicker) { + this.getDomNode().classList.add('colorpicker-hover'); + } + })); + this._register(dom.addStandardDisposableListener(this.getDomNode(), dom.EventType.BLUR, () => { + this.getDomNode().classList.remove('colorpicker-hover'); + })); + this._register(editor.onDidChangeConfiguration(() => { + this._hoverOperation.setHoverTime(this._editor.getOption(EditorOption.hover).delay); + })); + this._register(TokenizationRegistry.onDidChange(() => { + if (this._isVisible && this._lastAnchor && this._messages.length > 0) { + this._hover.contentsDomNode.textContent = ''; + this._renderMessages(this._lastAnchor, this._messages); + } + })); + } + + public override dispose(): void { + this._hoverOperation.cancel(); + this._editor.removeContentWidget(this); + super.dispose(); + } + + public getId(): string { + return this._id; + } + + public getDomNode(): HTMLElement { + return this._hover.containerDomNode; + } + + private _shouldShowAt(mouseEvent: IEditorMouseEvent): boolean { + const targetType = mouseEvent.target.type; + if (targetType === MouseTargetType.CONTENT_TEXT) { + return true; + } + + if (targetType === MouseTargetType.CONTENT_EMPTY) { + const epsilon = this._editor.getOption(EditorOption.fontInfo).typicalHalfwidthCharacterWidth / 2; + const data = mouseEvent.target.detail; + if (data && !data.isAfterLines && typeof data.horizontalDistanceToText === 'number' && data.horizontalDistanceToText < epsilon) { + // Let hover kick in even when the mouse is technically in the empty area after a line, given the distance is small enough + return true; + } + } + + return false; + } + + public maybeShowAt(mouseEvent: IEditorMouseEvent): boolean { + const anchorCandidates: HoverAnchor[] = []; + + for (const participant of this._participants) { + if (typeof participant.suggestHoverAnchor === 'function') { + const anchor = participant.suggestHoverAnchor(mouseEvent); + if (anchor) { + anchorCandidates.push(anchor); + } + } + } + + if (this._shouldShowAt(mouseEvent) && mouseEvent.target.range) { + // TODO@rebornix. This should be removed if we move Color Picker out of Hover component. + // Check if mouse is hovering on color decorator + const hoverOnColorDecorator = [...mouseEvent.target.element?.classList.values() || []].find(className => className.startsWith('ced-colorBox')) + && mouseEvent.target.range.endColumn - mouseEvent.target.range.startColumn === 1; + const showAtRange = ( + hoverOnColorDecorator // shift the mouse focus by one as color decorator is a `before` decoration of next character. + ? new Range(mouseEvent.target.range.startLineNumber, mouseEvent.target.range.startColumn + 1, mouseEvent.target.range.endLineNumber, mouseEvent.target.range.endColumn + 1) + : mouseEvent.target.range + ); + anchorCandidates.push(new HoverRangeAnchor(0, showAtRange)); + } + + if (anchorCandidates.length === 0) { + return false; + } + + anchorCandidates.sort((a, b) => b.priority - a.priority); + this._startShowingAt(anchorCandidates[0], HoverStartMode.Delayed, false); + + return true; + } + + private _showAt(position: Position, range: Range | null, focus: boolean): void { + // Position has changed + this._showAtPosition = position; + this._showAtRange = range; + this._hoverVisibleKey.set(true); + this._isVisible = true; + this._hover.containerDomNode.classList.toggle('hidden', !this._isVisible); + + this._editor.layoutContentWidget(this); + // Simply force a synchronous render on the editor + // such that the widget does not really render with left = '0px' + this._editor.render(); + this._stoleFocus = focus; + if (focus) { + this._hover.containerDomNode.focus(); + } + } + + public getPosition(): IContentWidgetPosition | null { + if (this._isVisible) { + return { + position: this._showAtPosition, + range: this._showAtRange, + preference: [ + ContentWidgetPositionPreference.ABOVE, + ContentWidgetPositionPreference.BELOW + ] + }; + } + return null; + } + + private _updateFont(): void { + const codeClasses: HTMLElement[] = Array.prototype.slice.call(this._hover.contentsDomNode.getElementsByClassName('code')); + codeClasses.forEach(node => this._editor.applyFontInfo(node)); + } + + private _updateContents(node: Node): void { + this._hover.contentsDomNode.textContent = ''; + this._hover.contentsDomNode.appendChild(node); + this._updateFont(); + + this._editor.layoutContentWidget(this); + this._hover.onContentsChanged(); + } + + private layout(): void { + const height = Math.max(this._editor.getLayoutInfo().height / 4, 250); + const { fontSize, lineHeight } = this._editor.getOption(EditorOption.fontInfo); + + this._hover.contentsDomNode.style.fontSize = `${fontSize}px`; + this._hover.contentsDomNode.style.lineHeight = `${lineHeight}px`; + this._hover.contentsDomNode.style.maxHeight = `${height}px`; + this._hover.contentsDomNode.style.maxWidth = `${Math.max(this._editor.getLayoutInfo().width * 0.66, 500)}px`; + } + + public onModelDecorationsChanged(): void { + if (this._isChangingDecorations) { + return; + } + if (this._isVisible) { + // The decorations have changed and the hover is visible, + // we need to recompute the displayed text + this._hoverOperation.cancel(); + this._computer.clearResult(); + + if (!this._colorPicker) { // TODO@Michel ensure that displayed text for other decorations is computed even if color picker is in place + this._hoverOperation.start(HoverStartMode.Delayed); + } + } + } + + public startShowingAtRange(range: Range, mode: HoverStartMode, focus: boolean): void { + this._startShowingAt(new HoverRangeAnchor(0, range), mode, focus); + } + + private _startShowingAt(anchor: HoverAnchor, mode: HoverStartMode, focus: boolean): void { + if (this._lastAnchor && this._lastAnchor.equals(anchor)) { + // We have to show the widget at the exact same range as before, so no work is needed + return; + } + + this._hoverOperation.cancel(); + + if (this._isVisible) { + // The range might have changed, but the hover is visible + // Instead of hiding it completely, filter out messages that are still in the new range and + // kick off a new computation + if (!this._showAtPosition || !this._lastAnchor || !anchor.canAdoptVisibleHover(this._lastAnchor, this._showAtPosition)) { + this.hide(); + } else { + const filteredMessages = this._messages.filter((m) => m.isValidForHoverAnchor(anchor)); + if (filteredMessages.length === 0) { + this.hide(); + } else if (filteredMessages.length === this._messages.length) { + // no change + return; + } else { + this._renderMessages(anchor, filteredMessages); + } + } + } + + this._lastAnchor = anchor; + this._computer.setAnchor(anchor); + this._shouldFocus = focus; + this._hoverOperation.start(mode); + } + + public hide(): void { + this._lastAnchor = null; + this._hoverOperation.cancel(); + + if (this._isVisible) { + setTimeout(() => { + // Give commands a chance to see the key + if (!this._isVisible) { + this._hoverVisibleKey.set(false); + } + }, 0); + this._isVisible = false; + this._hover.containerDomNode.classList.toggle('hidden', !this._isVisible); + + this._editor.layoutContentWidget(this); + if (this._stoleFocus) { + this._editor.focus(); + } + } + + this._isChangingDecorations = true; + this._highlightDecorations = this._editor.deltaDecorations(this._highlightDecorations, []); + this._isChangingDecorations = false; + if (this._renderDisposable) { + this._renderDisposable.dispose(); + this._renderDisposable = null; + } + this._colorPicker = null; + } + + public isColorPickerVisible(): boolean { + return !!this._colorPicker; + } + + public setColorPicker(widget: ColorPickerWidget): void { + this._colorPicker = widget; + } + + public onContentsChanged(): void { + this._hover.onContentsChanged(); + } + + private _withResult(result: IHoverPart[], complete: boolean): void { + this._messages = result; + + if (this._lastAnchor && this._messages.length > 0) { + this._renderMessages(this._lastAnchor, this._messages); + } else if (complete) { + this.hide(); + } + } + + private _renderMessages(anchor: HoverAnchor, messages: IHoverPart[]): void { + if (this._renderDisposable) { + this._renderDisposable.dispose(); + this._renderDisposable = null; + } + this._colorPicker = null as ColorPickerWidget | null; // TODO: TypeScript thinks this is always null + + // update column from which to show + let renderColumn = Constants.MAX_SAFE_SMALL_INTEGER; + let highlightRange: Range = messages[0].range; + let forceShowAtRange: Range | null = null; + let fragment = document.createDocumentFragment(); + + const disposables = new DisposableStore(); + const hoverParts = new Map(); + for (const msg of messages) { + renderColumn = Math.min(renderColumn, msg.range.startColumn); + highlightRange = Range.plusRange(highlightRange, msg.range); + + if (msg.forceShowAtRange) { + forceShowAtRange = msg.range; + } + + if (!hoverParts.has(msg.owner)) { + hoverParts.set(msg.owner, []); + } + const dest = hoverParts.get(msg.owner)!; + dest.push(msg); + } + + const statusBar = disposables.add(new EditorHoverStatusBar(this._keybindingService)); + + for (const [participant, participantHoverParts] of hoverParts) { + disposables.add(participant.renderHoverParts(participantHoverParts, fragment, statusBar)); + } + + if (statusBar.hasContent) { + fragment.appendChild(statusBar.hoverElement); + } + + this._renderDisposable = disposables; + + // show + + if (fragment.hasChildNodes()) { + if (forceShowAtRange) { + this._showAt(forceShowAtRange.getStartPosition(), forceShowAtRange, this._shouldFocus); + } else { + this._showAt(new Position(anchor.range.startLineNumber, renderColumn), highlightRange, this._shouldFocus); + } + this._updateContents(fragment); + } + if (this._colorPicker) { + this._colorPicker.layout(); + } + + this._isChangingDecorations = true; + this._highlightDecorations = this._editor.deltaDecorations(this._highlightDecorations, highlightRange ? [{ + range: highlightRange, + options: ModesContentHoverWidget._DECORATION_OPTIONS + }] : []); + this._isChangingDecorations = false; + } + + private static readonly _DECORATION_OPTIONS = ModelDecorationOptions.register({ + description: 'content-hover-highlight', + className: 'hoverHighlight' + }); +} + +registerThemingParticipant((theme, collector) => { + const linkFg = theme.getColor(textLinkForeground); + if (linkFg) { + collector.addRule(`.monaco-hover .hover-contents a.code-link span:hover { color: ${linkFg}; }`); + } +}); diff --git a/lib/vscode/src/vs/editor/contrib/hover/modesGlyphHover.ts b/src/vs/editor/contrib/hover/modesGlyphHover.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/hover/modesGlyphHover.ts rename to src/vs/editor/contrib/hover/modesGlyphHover.ts diff --git a/lib/vscode/src/vs/editor/contrib/inPlaceReplace/inPlaceReplace.ts b/src/vs/editor/contrib/inPlaceReplace/inPlaceReplace.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/inPlaceReplace/inPlaceReplace.ts rename to src/vs/editor/contrib/inPlaceReplace/inPlaceReplace.ts index 70f9fbf73ccc..ab6f08971214 100644 --- a/lib/vscode/src/vs/editor/contrib/inPlaceReplace/inPlaceReplace.ts +++ b/src/vs/editor/contrib/inPlaceReplace/inPlaceReplace.ts @@ -31,6 +31,7 @@ class InPlaceReplaceController implements IEditorContribution { } private static readonly DECORATION = ModelDecorationOptions.register({ + description: 'in-place-replace', className: 'valueSetReplacement' }); diff --git a/lib/vscode/src/vs/editor/contrib/inPlaceReplace/inPlaceReplaceCommand.ts b/src/vs/editor/contrib/inPlaceReplace/inPlaceReplaceCommand.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/inPlaceReplace/inPlaceReplaceCommand.ts rename to src/vs/editor/contrib/inPlaceReplace/inPlaceReplaceCommand.ts diff --git a/lib/vscode/src/vs/editor/contrib/indentation/indentUtils.ts b/src/vs/editor/contrib/indentation/indentUtils.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/indentation/indentUtils.ts rename to src/vs/editor/contrib/indentation/indentUtils.ts diff --git a/lib/vscode/src/vs/editor/contrib/indentation/indentation.ts b/src/vs/editor/contrib/indentation/indentation.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/indentation/indentation.ts rename to src/vs/editor/contrib/indentation/indentation.ts diff --git a/lib/vscode/src/vs/editor/contrib/indentation/test/indentation.test.ts b/src/vs/editor/contrib/indentation/test/indentation.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/indentation/test/indentation.test.ts rename to src/vs/editor/contrib/indentation/test/indentation.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/inlineHints/inlineHintsController.ts b/src/vs/editor/contrib/inlayHints/inlayHintsController.ts similarity index 68% rename from lib/vscode/src/vs/editor/contrib/inlineHints/inlineHintsController.ts rename to src/vs/editor/contrib/inlayHints/inlayHintsController.ts index db9477d28b50..f1e4f4b09553 100644 --- a/lib/vscode/src/vs/editor/contrib/inlineHints/inlineHintsController.ts +++ b/src/vs/editor/contrib/inlayHints/inlayHintsController.ts @@ -12,32 +12,32 @@ import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IContentDecorationRenderOptions, IEditorContribution } from 'vs/editor/common/editorCommon'; import { IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model'; -import { InlineHintsProvider, InlineHintsProviderRegistry, InlineHint } from 'vs/editor/common/modes'; +import { InlayHintsProvider, InlayHintsProviderRegistry, InlayHint } from 'vs/editor/common/modes'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { flatten } from 'vs/base/common/arrays'; -import { editorInlineHintForeground, editorInlineHintBackground } from 'vs/platform/theme/common/colorRegistry'; +import { editorInlayHintForeground, editorInlayHintBackground } from 'vs/platform/theme/common/colorRegistry'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { Range } from 'vs/editor/common/core/range'; import { LanguageFeatureRequestDelays } from 'vs/editor/common/modes/languageFeatureRegistry'; -import { MarkdownString } from 'vs/base/common/htmlContent'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { URI } from 'vs/base/common/uri'; import { IRange } from 'vs/base/common/range'; import { assertType } from 'vs/base/common/types'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; +import { Position } from 'vs/editor/common/core/position'; const MAX_DECORATORS = 500; -export interface InlineHintsData { - list: InlineHint[]; - provider: InlineHintsProvider; +export interface InlayHintsData { + list: InlayHint[]; + provider: InlayHintsProvider; } -export async function getInlineHints(model: ITextModel, ranges: Range[], token: CancellationToken): Promise { - const datas: InlineHintsData[] = []; - const providers = InlineHintsProviderRegistry.ordered(model).reverse(); - const promises = flatten(providers.map(provider => ranges.map(range => Promise.resolve(provider.provideInlineHints(model, range, token)).then(result => { +export async function getInlayHints(model: ITextModel, ranges: Range[], token: CancellationToken): Promise { + const datas: InlayHintsData[] = []; + const providers = InlayHintsProviderRegistry.ordered(model).reverse(); + const promises = flatten(providers.map(provider => ranges.map(range => Promise.resolve(provider.provideInlayHints(model, range, token)).then(result => { if (result) { datas.push({ list: result, provider }); } @@ -50,17 +50,13 @@ export async function getInlineHints(model: ITextModel, ranges: Range[], token: return datas; } -export class InlineHintsController implements IEditorContribution { +export class InlayHintsController implements IEditorContribution { - static readonly ID: string = 'editor.contrib.InlineHints'; - - // static get(editor: ICodeEditor): InlineHintsController { - // return editor.getContribution(this.ID); - // } + static readonly ID: string = 'editor.contrib.InlayHints'; private readonly _disposables = new DisposableStore(); private readonly _sessionDisposables = new DisposableStore(); - private readonly _getInlineHintsDelays = new LanguageFeatureRequestDelays(InlineHintsProviderRegistry, 250, 2500); + private readonly _getInlayHintsDelays = new LanguageFeatureRequestDelays(InlayHintsProviderRegistry, 250, 2500); private _decorationsTypeIds: string[] = []; private _decorationIds: string[] = []; @@ -70,12 +66,12 @@ export class InlineHintsController implements IEditorContribution { @ICodeEditorService private readonly _codeEditorService: ICodeEditorService, @IThemeService private readonly _themeService: IThemeService, ) { - this._disposables.add(InlineHintsProviderRegistry.onDidChange(() => this._update())); + this._disposables.add(InlayHintsProviderRegistry.onDidChange(() => this._update())); this._disposables.add(_themeService.onDidColorThemeChange(() => this._update())); this._disposables.add(_editor.onDidChangeModel(() => this._update())); this._disposables.add(_editor.onDidChangeModelLanguage(() => this._update())); this._disposables.add(_editor.onDidChangeConfiguration(e => { - if (e.hasChanged(EditorOption.inlineHints)) { + if (e.hasChanged(EditorOption.inlayHints)) { this._update(); } })); @@ -92,13 +88,13 @@ export class InlineHintsController implements IEditorContribution { private _update(): void { this._sessionDisposables.clear(); - if (!this._editor.getOption(EditorOption.inlineHints).enabled) { + if (!this._editor.getOption(EditorOption.inlayHints).enabled) { this._removeAllDecorations(); return; } const model = this._editor.getModel(); - if (!model || !InlineHintsProviderRegistry.has(model)) { + if (!model || !InlayHintsProviderRegistry.has(model)) { this._removeAllDecorations(); return; } @@ -110,16 +106,16 @@ export class InlineHintsController implements IEditorContribution { this._sessionDisposables.add(toDisposable(() => cts.dispose(true))); const visibleRanges = this._editor.getVisibleRangesPlusViewportAboveBelow(); - const result = await getInlineHints(model, visibleRanges, cts.token); + const result = await getInlayHints(model, visibleRanges, cts.token); // update moving average - const newDelay = this._getInlineHintsDelays.update(model, Date.now() - t1); + const newDelay = this._getInlayHintsDelays.update(model, Date.now() - t1); scheduler.delay = newDelay; // render hints this._updateHintsDecorators(result); - }, this._getInlineHintsDelays.get(model)); + }, this._getInlayHintsDelays.get(model)); this._sessionDisposables.add(scheduler); @@ -131,28 +127,28 @@ export class InlineHintsController implements IEditorContribution { // update inline hints when any any provider fires an event const providerListener = new DisposableStore(); this._sessionDisposables.add(providerListener); - for (const provider of InlineHintsProviderRegistry.all(model)) { - if (typeof provider.onDidChangeInlineHints === 'function') { - providerListener.add(provider.onDidChangeInlineHints(() => scheduler.schedule())); + for (const provider of InlayHintsProviderRegistry.all(model)) { + if (typeof provider.onDidChangeInlayHints === 'function') { + providerListener.add(provider.onDidChangeInlayHints(() => scheduler.schedule())); } } } - private _updateHintsDecorators(hintsData: InlineHintsData[]): void { + private _updateHintsDecorators(hintsData: InlayHintsData[]): void { const { fontSize, fontFamily } = this._getLayoutInfo(); - const backgroundColor = this._themeService.getColorTheme().getColor(editorInlineHintBackground); - const fontColor = this._themeService.getColorTheme().getColor(editorInlineHintForeground); + const backgroundColor = this._themeService.getColorTheme().getColor(editorInlayHintBackground); + const fontColor = this._themeService.getColorTheme().getColor(editorInlayHintForeground); const newDecorationsTypeIds: string[] = []; const newDecorationsData: IModelDeltaDecoration[] = []; - const fontFamilyVar = '--inlineHintsFontFamily'; + const fontFamilyVar = '--inlayHintsFontFamily'; this._editor.getContainerDomNode().style.setProperty(fontFamilyVar, fontFamily); for (const { list: hints } of hintsData) { for (let j = 0; j < hints.length && newDecorationsData.length < MAX_DECORATORS; j++) { - const { text, range, description: hoverMessage, whitespaceBefore, whitespaceAfter } = hints[j]; + const { text, position, whitespaceBefore, whitespaceAfter } = hints[j]; const marginBefore = whitespaceBefore ? (fontSize / 3) | 0 : 0; const marginAfter = whitespaceAfter ? (fontSize / 3) | 0 : 0; @@ -166,22 +162,16 @@ export class InlineHintsController implements IEditorContribution { padding: `0px ${(fontSize / 4) | 0}px`, borderRadius: `${(fontSize / 4) | 0}px`, }; - const key = 'inlineHints-' + hash(before).toString(16); - this._codeEditorService.registerDecorationType(key, { before }, undefined, this._editor); + const key = 'inlayHints-' + hash(before).toString(16); + this._codeEditorService.registerDecorationType('inlay-hints-controller', key, { before }, undefined, this._editor); // decoration types are ref-counted which means we only need to // call register und remove equally often newDecorationsTypeIds.push(key); const options = this._codeEditorService.resolveDecorationOptions(key, true); - if (typeof hoverMessage === 'string') { - options.hoverMessage = new MarkdownString().appendText(hoverMessage); - } else if (hoverMessage) { - options.hoverMessage = hoverMessage; - } - newDecorationsData.push({ - range, + range: Range.fromPositions(position), options }); } @@ -194,7 +184,7 @@ export class InlineHintsController implements IEditorContribution { } private _getLayoutInfo() { - const options = this._editor.getOption(EditorOption.inlineHints); + const options = this._editor.getOption(EditorOption.inlayHints); const editorFontSize = this._editor.getOption(EditorOption.fontSize); let fontSize = options.fontSize; if (!fontSize || fontSize < 5 || fontSize > editorFontSize) { @@ -211,9 +201,9 @@ export class InlineHintsController implements IEditorContribution { } } -registerEditorContribution(InlineHintsController.ID, InlineHintsController); +registerEditorContribution(InlayHintsController.ID, InlayHintsController); -CommandsRegistry.registerCommand('_executeInlineHintProvider', async (accessor, ...args: [URI, IRange]): Promise => { +CommandsRegistry.registerCommand('_executeInlayHintProvider', async (accessor, ...args: [URI, IRange]): Promise => { const [uri, range] = args; assertType(URI.isUri(uri)); @@ -221,8 +211,8 @@ CommandsRegistry.registerCommand('_executeInlineHintProvider', async (accessor, const ref = await accessor.get(ITextModelService).createModelReference(uri); try { - const data = await getInlineHints(ref.object.textEditorModel, [Range.lift(range)], CancellationToken.None); - return flatten(data.map(item => item.list)).sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range)); + const data = await getInlayHints(ref.object.textEditorModel, [Range.lift(range)], CancellationToken.None); + return flatten(data.map(item => item.list)).sort((a, b) => Position.compare(a.position, b.position)); } finally { ref.dispose(); diff --git a/src/vs/editor/contrib/inlineCompletions/ghostText.css b/src/vs/editor/contrib/inlineCompletions/ghostText.css new file mode 100644 index 000000000000..009f27cef75d --- /dev/null +++ b/src/vs/editor/contrib/inlineCompletions/ghostText.css @@ -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. + *--------------------------------------------------------------------------------------------*/ + +.monaco-editor .suggest-preview-additional-widget { + white-space: nowrap; +} + +.monaco-editor .suggest-preview-additional-widget .content-spacer { + color: transparent; + white-space: pre; +} + +.monaco-editor .suggest-preview-additional-widget .button { + display: inline-block; + cursor: pointer; + text-decoration: underline; + text-underline-position: under; +} diff --git a/src/vs/editor/contrib/inlineCompletions/ghostTextController.ts b/src/vs/editor/contrib/inlineCompletions/ghostTextController.ts new file mode 100644 index 000000000000..f7de4aa6484a --- /dev/null +++ b/src/vs/editor/contrib/inlineCompletions/ghostTextController.ts @@ -0,0 +1,339 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { Range } from 'vs/editor/common/core/range'; +import { Disposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { EditorAction, EditorCommand, registerEditorAction, registerEditorCommand, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; +import { GhostTextWidget } from 'vs/editor/contrib/inlineCompletions/ghostTextWidget'; +import { InlineCompletionsModel } from 'vs/editor/contrib/inlineCompletions/inlineCompletionsModel'; +import { SuggestWidgetAdapterModel } from 'vs/editor/contrib/inlineCompletions/suggestWidgetAdapterModel'; +import * as nls from 'vs/nls'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { ContextKeyExpr, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; + +export class GhostTextController extends Disposable { + public static readonly inlineSuggestionVisible = new RawContextKey('inlineSuggestionVisible ', false, nls.localize('inlineSuggestionVisible', "Whether an inline suggestion is visible")); + public static readonly inlineSuggestionHasIndentation = new RawContextKey('inlineSuggestionHasIndentation', false, nls.localize('inlineSuggestionHasIndentation', "Whether the inline suggestion starts with whitespace")); + + static ID = 'editor.contrib.ghostTextController'; + + public static get(editor: ICodeEditor): GhostTextController { + return editor.getContribution(GhostTextController.ID); + } + + private readonly widget: GhostTextWidget; + private readonly activeController = this._register(new MutableDisposable()); + private readonly contextKeys: GhostTextContextKeys; + private triggeredExplicitly = false; + + constructor( + private readonly editor: ICodeEditor, + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IContextKeyService contextKeyService: IContextKeyService, + ) { + super(); + this.contextKeys = new GhostTextContextKeys(contextKeyService); + + this.widget = this._register(instantiationService.createInstance(GhostTextWidget, this.editor)); + + this._register(this.editor.onDidChangeModel(() => { + this.updateModelController(); + })); + this._register(this.editor.onDidChangeConfiguration((e) => { + if (e.hasChanged(EditorOption.suggest)) { + this.updateModelController(); + } + })); + this.updateModelController(); + } + + // Don't call this method when not neccessary. It will recreate the activeController. + private updateModelController(): void { + const suggestOptions = this.editor.getOption(EditorOption.suggest); + const inlineSuggestOptions = this.editor.getOption(EditorOption.inlineSuggest); + + this.activeController.value = undefined; + // ActiveGhostTextController is only created if one of those settings is set or if the inline completions are triggered explicitly. + this.activeController.value = + this.editor.hasModel() && (suggestOptions.preview || inlineSuggestOptions.enabled || this.triggeredExplicitly) + ? this.instantiationService.createInstance( + ActiveGhostTextController, + this.editor, + this.widget, + this.contextKeys + ) + : undefined; + } + + public shouldShowHoverAt(hoverRange: Range): boolean { + return this.activeController.value?.shouldShowHoverAt(hoverRange) || false; + } + + public shouldShowHoverAtViewZone(viewZoneId: string): boolean { + return this.widget.shouldShowHoverAtViewZone(viewZoneId); + } + + public trigger(): void { + this.triggeredExplicitly = true; + if (!this.activeController.value) { + this.updateModelController(); + } + this.activeController.value?.triggerInlineCompletion(); + } + + public commit(): void { + this.activeController.value?.commitInlineCompletion(); + } + + public hide(): void { + this.activeController.value?.hideInlineCompletion(); + } + + public showNextInlineCompletion(): void { + this.activeController.value?.showNextInlineCompletion(); + } + + public showPreviousInlineCompletion(): void { + this.activeController.value?.showPreviousInlineCompletion(); + } +} + +// TODO: This should be local state to the editor. +// The global state should depend on the local state of the currently focused editor. +// Currently the global state is updated directly, which may lead to conflicts if multiple ghost texts are active. +class GhostTextContextKeys { + private lastInlineCompletionVisibleValue = false; + private readonly inlineCompletionVisible = GhostTextController.inlineSuggestionVisible.bindTo(this.contextKeyService); + + private lastInlineCompletionSuggestsIndentationValue = false; + private readonly inlineCompletionSuggestsIndentation = GhostTextController.inlineSuggestionHasIndentation.bindTo(this.contextKeyService); + + constructor(private readonly contextKeyService: IContextKeyService) { + } + + public setInlineCompletionVisible(value: boolean): void { + // Only modify the context key if we actually changed it. + // Thus, we don't overwrite values set by someone else. + if (value !== this.lastInlineCompletionVisibleValue) { + this.inlineCompletionVisible.set(value); + this.lastInlineCompletionVisibleValue = value; + } + } + + public setInlineCompletionSuggestsIndentation(value: boolean): void { + if (value !== this.lastInlineCompletionSuggestsIndentationValue) { + this.inlineCompletionSuggestsIndentation.set(value); + this.lastInlineCompletionSuggestsIndentationValue = value; + } + } +} + +/** + * The controller for a text editor with an initialized text model. +*/ +export class ActiveGhostTextController extends Disposable { + private readonly suggestWidgetAdapterModel = this._register(new SuggestWidgetAdapterModel(this.editor)); + private readonly inlineCompletionsModel = this._register(new InlineCompletionsModel(this.editor, this.commandService)); + + private get activeInlineCompletionsModel(): InlineCompletionsModel | undefined { + if (this.widget.model === this.inlineCompletionsModel) { + return this.inlineCompletionsModel; + } + return undefined; + } + + constructor( + private readonly editor: IActiveCodeEditor, + private readonly widget: GhostTextWidget, + private readonly contextKeys: GhostTextContextKeys, + @ICommandService private readonly commandService: ICommandService, + ) { + super(); + + this._register(this.suggestWidgetAdapterModel.onDidChange(() => { + this.updateModel(); + })); + this.updateModel(); + + this._register(toDisposable(() => { + if (widget.model === this.suggestWidgetAdapterModel || widget.model === this.inlineCompletionsModel) { + widget.setModel(undefined); + } + this.contextKeys.setInlineCompletionVisible(false); + this.contextKeys.setInlineCompletionSuggestsIndentation(false); + })); + + if (this.inlineCompletionsModel) { + this._register(this.inlineCompletionsModel.onDidChange(() => { + this.updateContextKeys(); + })); + } + } + + private updateContextKeys(): void { + this.contextKeys.setInlineCompletionVisible( + this.activeInlineCompletionsModel?.ghostText !== undefined + ); + + if (this.inlineCompletionsModel?.ghostText) { + const firstLine = this.inlineCompletionsModel.ghostText.lines[0] || ''; + const suggestionStartsWithWs = firstLine.startsWith(' ') || firstLine.startsWith('\t'); + const p = this.inlineCompletionsModel.ghostText.position; + const indentationEndColumn = this.editor.getModel().getLineIndentColumn(p.lineNumber); + const inIndentation = p.column <= indentationEndColumn; + + this.contextKeys.setInlineCompletionSuggestsIndentation( + this.widget.model === this.inlineCompletionsModel + && suggestionStartsWithWs && inIndentation + ); + } else { + this.contextKeys.setInlineCompletionSuggestsIndentation(false); + } + } + + public shouldShowHoverAt(hoverRange: Range): boolean { + const ghostText = this.activeInlineCompletionsModel?.ghostText; + if (ghostText) { + return hoverRange.containsPosition(ghostText.position); + } + return false; + } + + public triggerInlineCompletion(): void { + this.activeInlineCompletionsModel?.startSession(); + } + + public commitInlineCompletion(): void { + this.activeInlineCompletionsModel?.commitCurrentSuggestion(); + } + + public hideInlineCompletion(): void { + this.activeInlineCompletionsModel?.hide(); + } + + public showNextInlineCompletion(): void { + this.activeInlineCompletionsModel?.showNext(); + } + + public showPreviousInlineCompletion(): void { + this.activeInlineCompletionsModel?.showPrevious(); + } + + private updateModel() { + this.widget.setModel( + this.suggestWidgetAdapterModel.isActive + ? this.suggestWidgetAdapterModel + : this.inlineCompletionsModel + ); + this.inlineCompletionsModel?.setActive(this.widget.model === this.inlineCompletionsModel); + } +} + +const GhostTextCommand = EditorCommand.bindToContribution(GhostTextController.get); + +export const commitInlineSuggestionAction = new GhostTextCommand({ + id: 'editor.action.inlineSuggest.commit', + precondition: ContextKeyExpr.and( + GhostTextController.inlineSuggestionVisible, + GhostTextController.inlineSuggestionHasIndentation.toNegated(), + EditorContextKeys.tabMovesFocus.toNegated() + ), + kbOpts: { + weight: 100, + primary: KeyCode.Tab, + }, + handler(x) { + x.commit(); + } +}); +registerEditorCommand(commitInlineSuggestionAction); + +registerEditorCommand(new GhostTextCommand({ + id: 'editor.action.inlineSuggest.hide', + precondition: GhostTextController.inlineSuggestionVisible, + kbOpts: { + weight: 100, + primary: KeyCode.Escape, + }, + handler(x) { + x.hide(); + } +})); + +export class ShowNextInlineSuggestionAction extends EditorAction { + public static ID = 'editor.action.inlineSuggest.showNext'; + constructor() { + super({ + id: ShowNextInlineSuggestionAction.ID, + label: nls.localize('action.inlineSuggest.showNext', "Show Next Inline Suggestion"), + alias: 'Show Next Inline Suggestion', + precondition: EditorContextKeys.writable, + kbOpts: { + weight: 100, + primary: KeyMod.Alt | KeyCode.US_CLOSE_SQUARE_BRACKET, + }, + }); + } + + public async run(accessor: ServicesAccessor | undefined, editor: ICodeEditor): Promise { + const controller = GhostTextController.get(editor); + if (controller) { + controller.showNextInlineCompletion(); + editor.focus(); + } + } +} + +export class ShowPreviousInlineSuggestionAction extends EditorAction { + public static ID = 'editor.action.inlineSuggest.showPrevious'; + constructor() { + super({ + id: ShowPreviousInlineSuggestionAction.ID, + label: nls.localize('action.inlineSuggest.showPrevious', "Show Previous Inline Suggestion"), + alias: 'Show Previous Inline Suggestion', + precondition: EditorContextKeys.writable, + kbOpts: { + weight: 100, + primary: KeyMod.Alt | KeyCode.US_OPEN_SQUARE_BRACKET, + }, + }); + } + + public async run(accessor: ServicesAccessor | undefined, editor: ICodeEditor): Promise { + const controller = GhostTextController.get(editor); + if (controller) { + controller.showPreviousInlineCompletion(); + editor.focus(); + } + } +} + +export class TriggerInlineSuggestionAction extends EditorAction { + constructor() { + super({ + id: 'editor.action.inlineSuggest.trigger', + label: nls.localize('action.inlineSuggest.trigger', "Trigger Inline Suggestion"), + alias: 'Trigger Inline Suggestion', + precondition: EditorContextKeys.writable + }); + } + + public async run(accessor: ServicesAccessor | undefined, editor: ICodeEditor): Promise { + const controller = GhostTextController.get(editor); + if (controller) { + controller.trigger(); + } + } +} + +registerEditorContribution(GhostTextController.ID, GhostTextController); +registerEditorAction(TriggerInlineSuggestionAction); +registerEditorAction(ShowNextInlineSuggestionAction); +registerEditorAction(ShowPreviousInlineSuggestionAction); diff --git a/src/vs/editor/contrib/inlineCompletions/ghostTextWidget.ts b/src/vs/editor/contrib/inlineCompletions/ghostTextWidget.ts new file mode 100644 index 000000000000..c2e22b180086 --- /dev/null +++ b/src/vs/editor/contrib/inlineCompletions/ghostTextWidget.ts @@ -0,0 +1,427 @@ +/*--------------------------------------------------------------------------------------------- + * 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!./ghostText'; +import * as dom from 'vs/base/browser/dom'; +import { Disposable, DisposableStore, IDisposable, IReference, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Range } from 'vs/editor/common/core/range'; +import { ContentWidgetPositionPreference, IActiveCodeEditor, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; +import * as strings from 'vs/base/common/strings'; +import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; +import { EditorFontLigatures, EditorOption } from 'vs/editor/common/config/editorOptions'; +import { createStringBuilder } from 'vs/editor/common/core/stringBuilder'; +import { Configuration } from 'vs/editor/browser/config/configuration'; +import { LineTokens } from 'vs/editor/common/core/lineTokens'; +import { Position } from 'vs/editor/common/core/position'; +import { Emitter, Event } from 'vs/base/common/event'; +import { IModelDeltaDecoration } from 'vs/editor/common/model'; +import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { ghostTextBorder, ghostTextForeground } from 'vs/editor/common/view/editorColorRegistry'; +import { RGBA, Color } from 'vs/base/common/color'; +import { CursorColumns } from 'vs/editor/common/controller/cursorCommon'; + +const ttPolicy = window.trustedTypes?.createPolicy('editorGhostText', { createHTML: value => value }); + +export interface GhostTextWidgetModel { + readonly onDidChange: Event; + readonly ghostText: GhostText | undefined; + + setExpanded(expanded: boolean): void; + readonly expanded: boolean; + + readonly minReservedLineCount: number; +} + +export interface GhostText { + readonly lines: string[]; + readonly position: Position; +} + +export abstract class BaseGhostTextWidgetModel extends Disposable implements GhostTextWidgetModel { + public abstract readonly ghostText: GhostText | undefined; + + private _expanded: boolean | undefined = undefined; + + protected readonly onDidChangeEmitter = new Emitter(); + public readonly onDidChange = this.onDidChangeEmitter.event; + + public abstract readonly minReservedLineCount: number; + + public get expanded() { + if (this._expanded === undefined) { + // TODO this should use a global hidden setting. + // See https://github.com/microsoft/vscode/issues/125037. + return true; + } + return this._expanded; + } + + constructor(protected readonly editor: IActiveCodeEditor) { + super(); + + this._register(editor.onDidChangeConfiguration((e) => { + if (e.hasChanged(EditorOption.suggest) && this._expanded === undefined) { + this.onDidChangeEmitter.fire(); + } + })); + } + + public setExpanded(expanded: boolean): void { + this._expanded = true; + this.onDidChangeEmitter.fire(); + } +} + +export class GhostTextWidget extends Disposable { + private static decorationTypeCount = 0; + + private codeEditorDecorationTypeKey: string | null = null; + private readonly modelRef = this._register(new MutableDisposable>()); + private decorationIds: string[] = []; + private viewZoneId: string | null = null; + private viewMoreContentWidget: ViewMoreLinesContentWidget | null = null; + + constructor( + private readonly editor: ICodeEditor, + @ICodeEditorService private readonly _codeEditorService: ICodeEditorService, + @IThemeService private readonly _themeService: IThemeService, + ) { + super(); + + this._register(this.editor.onDidChangeConfiguration((e) => { + if ( + e.hasChanged(EditorOption.disableMonospaceOptimizations) + || e.hasChanged(EditorOption.stopRenderingLineAfter) + || e.hasChanged(EditorOption.renderWhitespace) + || e.hasChanged(EditorOption.renderControlCharacters) + || e.hasChanged(EditorOption.fontLigatures) + || e.hasChanged(EditorOption.fontInfo) + || e.hasChanged(EditorOption.lineHeight) + ) { + this.render(); + } + })); + this._register(toDisposable(() => { + this.setModel(undefined); + })); + } + + public get model(): GhostTextWidgetModel | undefined { + return this.modelRef.value?.object; + } + + public shouldShowHoverAtViewZone(viewZoneId: string): boolean { + return (this.viewZoneId === viewZoneId); + } + + public setModel(model: GhostTextWidgetModel | undefined): void { + if (model === this.model) { return; } + this.modelRef.value = model + ? createDisposableRef(model, model.onDidChange(() => this.render())) + : undefined; + this.render(); + } + + private getRenderData() { + if (!this.editor.hasModel() || !this.model?.ghostText) { + return undefined; + } + + const { minReservedLineCount, expanded } = this.model; + let { position, lines } = this.model.ghostText; + + const textModel = this.editor.getModel(); + const maxColumn = textModel.getLineMaxColumn(position.lineNumber); + const { tabSize } = textModel.getOptions(); + + if (lines.length > 1 && position.column !== maxColumn) { + console.warn('Can only show multiline ghost text at the end of a line'); + lines = []; + position = new Position(position.lineNumber, maxColumn); + } + + return { tabSize, position, lines, minReservedLineCount, expanded }; + } + + private render(): void { + const renderData = this.getRenderData(); + + if (this.codeEditorDecorationTypeKey) { + this._codeEditorService.removeDecorationType(this.codeEditorDecorationTypeKey); + this.codeEditorDecorationTypeKey = null; + } + + if (renderData && renderData.lines.length > 0) { + const foreground = this._themeService.getColorTheme().getColor(ghostTextForeground); + let opacity: string | undefined = undefined; + let color: string | undefined = undefined; + if (foreground) { + function opaque(color: Color): Color { + const { r, b, g } = color.rgba; + return new Color(new RGBA(r, g, b, 255)); + } + + opacity = String(foreground.rgba.a); + color = Color.Format.CSS.format(opaque(foreground))!; + } + + const borderColor = this._themeService.getColorTheme().getColor(ghostTextBorder); + let border: string | undefined = undefined; + if (borderColor) { + border = `2px dashed ${borderColor}`; + } + + // We add 0 to bring it before any other decoration. + this.codeEditorDecorationTypeKey = `0-ghost-text-${++GhostTextWidget.decorationTypeCount}`; + + const line = this.editor.getModel()?.getLineContent(renderData.position.lineNumber) || ''; + const linePrefix = line.substr(0, renderData.position.column - 1); + + // To avoid visual confusion, we don't want to render visible whitespace + const contentText = renderSingleLineText(renderData.lines[0] || '', linePrefix, renderData.tabSize, false); + + this._codeEditorService.registerDecorationType('ghost-text', this.codeEditorDecorationTypeKey, { + after: { + // TODO: escape? + contentText, + opacity, + color, + border, + }, + }); + } + + const newDecorations = new Array(); + if (renderData && this.codeEditorDecorationTypeKey) { + newDecorations.push({ + range: Range.fromPositions(renderData.position, renderData.position), + options: { + ...this._codeEditorService.resolveDecorationOptions(this.codeEditorDecorationTypeKey, true), + } + }); + } + this.decorationIds = this.editor.deltaDecorations(this.decorationIds, newDecorations); + + if (this.viewMoreContentWidget) { + this.viewMoreContentWidget.dispose(); + this.viewMoreContentWidget = null; + } + + this.editor.changeViewZones((changeAccessor) => { + if (this.viewZoneId) { + changeAccessor.removeZone(this.viewZoneId); + this.viewZoneId = null; + } + + if (renderData) { + const remainingLines = renderData.lines.slice(1); + const heightInLines = Math.max(remainingLines.length, renderData.minReservedLineCount); + if (heightInLines > 0) { + if (renderData.expanded) { + const domNode = document.createElement('div'); + this.renderLines(domNode, renderData.tabSize, remainingLines); + + this.viewZoneId = changeAccessor.addZone({ + afterLineNumber: renderData.position.lineNumber, + afterColumn: renderData.position.column, + heightInLines: heightInLines, + domNode, + }); + } else if (remainingLines.length > 0) { + this.viewMoreContentWidget = this.renderViewMoreLines(renderData.position, renderData.lines[0], remainingLines.length); + } + } + } + }); + } + + private renderViewMoreLines(position: Position, firstLineText: string, remainingLinesLength: number): ViewMoreLinesContentWidget { + const fontInfo = this.editor.getOption(EditorOption.fontInfo); + const domNode = document.createElement('div'); + domNode.className = 'suggest-preview-additional-widget'; + Configuration.applyFontInfoSlow(domNode, fontInfo); + + const spacer = document.createElement('span'); + spacer.className = 'content-spacer'; + spacer.append(firstLineText); + domNode.append(spacer); + + const newline = document.createElement('span'); + newline.className = 'content-newline suggest-preview-text'; + newline.append('⏎ '); + domNode.append(newline); + + const disposableStore = new DisposableStore(); + + const button = document.createElement('div'); + button.className = 'button suggest-preview-text'; + button.append(`+${remainingLinesLength} lines…`); + + disposableStore.add(dom.addStandardDisposableListener(button, 'mousedown', (e) => { + this.model?.setExpanded(true); + e.preventDefault(); + this.editor.focus(); + })); + + domNode.append(button); + return new ViewMoreLinesContentWidget(this.editor, position, domNode, disposableStore); + } + + private renderLines(domNode: HTMLElement, tabSize: number, lines: string[]): void { + const opts = this.editor.getOptions(); + const disableMonospaceOptimizations = opts.get(EditorOption.disableMonospaceOptimizations); + const stopRenderingLineAfter = opts.get(EditorOption.stopRenderingLineAfter); + // To avoid visual confusion, we don't want to render visible whitespace + const renderWhitespace = 'none'; + const renderControlCharacters = opts.get(EditorOption.renderControlCharacters); + const fontLigatures = opts.get(EditorOption.fontLigatures); + const fontInfo = opts.get(EditorOption.fontInfo); + const lineHeight = opts.get(EditorOption.lineHeight); + + const sb = createStringBuilder(10000); + sb.appendASCIIString('
    '); + + for (let i = 0, len = lines.length; i < len; i++) { + const line = lines[i]; + sb.appendASCIIString('
    '); + + const isBasicASCII = strings.isBasicASCII(line); + const containsRTL = strings.containsRTL(line); + const lineTokens = LineTokens.createEmpty(line); + + renderViewLine(new RenderLineInput( + (fontInfo.isMonospace && !disableMonospaceOptimizations), + fontInfo.canUseHalfwidthRightwardsArrow, + line, + false, + isBasicASCII, + containsRTL, + 0, + lineTokens, + [], + tabSize, + 0, + fontInfo.spaceWidth, + fontInfo.middotWidth, + fontInfo.wsmiddotWidth, + stopRenderingLineAfter, + renderWhitespace, + renderControlCharacters, + fontLigatures !== EditorFontLigatures.OFF, + null + ), sb); + + sb.appendASCIIString('
    '); + } + sb.appendASCIIString('
    '); + + Configuration.applyFontInfoSlow(domNode, fontInfo); + const html = sb.build(); + const trustedhtml = ttPolicy ? ttPolicy.createHTML(html) : html; + domNode.innerHTML = trustedhtml as string; + } +} + +function renderSingleLineText(text: string, lineStart: string, tabSize: number, renderWhitespace: boolean): string { + const newLine = lineStart + text; + const visibleColumnsByColumns = CursorColumns.visibleColumnsByColumns(newLine, tabSize); + + + let contentText = ''; + let curCol = lineStart.length + 1; + for (const c of text) { + if (c === '\t') { + const width = visibleColumnsByColumns[curCol + 1] - visibleColumnsByColumns[curCol]; + if (renderWhitespace) { + contentText += '→'; + for (let i = 1; i < width; i++) { + contentText += '\xa0'; + } + } else { + for (let i = 0; i < width; i++) { + contentText += '\xa0'; + } + } + } else if (c === ' ') { + if (renderWhitespace) { + contentText += '·'; + } else { + contentText += '\xa0'; + } + } else { + contentText += c; + } + curCol += 1; + } + + return contentText; +} + +class ViewMoreLinesContentWidget extends Disposable implements IContentWidget { + readonly allowEditorOverflow = false; + readonly suppressMouseDown = false; + + constructor( + private editor: ICodeEditor, + private position: Position, + private domNode: HTMLElement, + disposableStore: DisposableStore + ) { + super(); + this._register(disposableStore); + this._register(toDisposable(() => { + this.editor.removeContentWidget(this); + })); + this.editor.addContentWidget(this); + } + + getId(): string { + return 'editor.widget.viewMoreLinesWidget'; + } + + getDomNode(): HTMLElement { + return this.domNode; + } + + getPosition(): IContentWidgetPosition | null { + return { + position: this.position, + preference: [ContentWidgetPositionPreference.EXACT] + }; + } +} + +registerThemingParticipant((theme, collector) => { + const foreground = theme.getColor(ghostTextForeground); + + if (foreground) { + function opaque(color: Color): Color { + const { r, b, g } = color.rgba; + return new Color(new RGBA(r, g, b, 255)); + } + + const opacity = String(foreground.rgba.a); + const color = Color.Format.CSS.format(opaque(foreground))!; + + // We need to override the only used token type .mtk1 + collector.addRule(`.monaco-editor .suggest-preview-text .mtk1 { opacity: ${opacity}; color: ${color}; }`); + } + + const border = theme.getColor(ghostTextBorder); + if (border) { + collector.addRule(`.monaco-editor .suggest-preview-text .mtk1 { border: 2px dashed ${border}; }`); + } +}); + +function createDisposableRef(object: T, disposable: IDisposable): IReference { + return { + object, + dispose: () => disposable.dispose(), + }; +} diff --git a/src/vs/editor/contrib/inlineCompletions/inlineCompletionsHoverParticipant.ts b/src/vs/editor/contrib/inlineCompletions/inlineCompletionsHoverParticipant.ts new file mode 100644 index 000000000000..a7ec7b3aa39b --- /dev/null +++ b/src/vs/editor/contrib/inlineCompletions/inlineCompletionsHoverParticipant.ts @@ -0,0 +1,114 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { HoverAnchor, HoverAnchorType, HoverForeignElementAnchor, IEditorHover, IEditorHoverParticipant, IEditorHoverStatusBar, IHoverPart } from 'vs/editor/contrib/hover/hoverTypes'; +import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; +import { Range } from 'vs/editor/common/core/range'; +import { IModelDecoration } from 'vs/editor/common/model'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { commitInlineSuggestionAction, GhostTextController, ShowNextInlineSuggestionAction, ShowPreviousInlineSuggestionAction } from 'vs/editor/contrib/inlineCompletions/ghostTextController'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ITextContentData, IViewZoneData } from 'vs/editor/browser/controller/mouseTarget'; + +export class InlineCompletionsHover implements IHoverPart { + constructor( + public readonly owner: IEditorHoverParticipant, + public readonly range: Range + ) { } + + public isValidForHoverAnchor(anchor: HoverAnchor): boolean { + return ( + anchor.type === HoverAnchorType.Range + && this.range.startColumn <= anchor.range.startColumn + && this.range.endColumn >= anchor.range.endColumn + ); + } +} + +export class InlineCompletionsHoverParticipant implements IEditorHoverParticipant { + constructor( + private readonly _editor: ICodeEditor, + hover: IEditorHover, + @ICommandService private readonly _commandService: ICommandService, + @IMenuService private readonly _menuService: IMenuService, + @IContextKeyService private readonly _contextKeyService: IContextKeyService, + ) { } + + suggestHoverAnchor(mouseEvent: IEditorMouseEvent): HoverAnchor | null { + const controller = GhostTextController.get(this._editor); + if (!controller) { + return null; + } + if (mouseEvent.target.type === MouseTargetType.CONTENT_VIEW_ZONE) { + // handle the case where the mouse is over the view zone + const viewZoneData = mouseEvent.target.detail; + if (controller.shouldShowHoverAtViewZone(viewZoneData.viewZoneId)) { + return new HoverForeignElementAnchor(1000, this, Range.fromPositions(viewZoneData.positionBefore || viewZoneData.position, viewZoneData.positionBefore || viewZoneData.position)); + } + } + if (mouseEvent.target.type === MouseTargetType.CONTENT_EMPTY && mouseEvent.target.range) { + // handle the case where the mouse is over the empty portion of a line following ghost text + if (controller.shouldShowHoverAt(mouseEvent.target.range)) { + return new HoverForeignElementAnchor(1000, this, mouseEvent.target.range); + } + } + if (mouseEvent.target.type === MouseTargetType.CONTENT_TEXT && mouseEvent.target.range && mouseEvent.target.detail) { + // handle the case where the mouse is directly over ghost text + const mightBeForeignElement = (mouseEvent.target.detail).mightBeForeignElement; + if (mightBeForeignElement && controller.shouldShowHoverAt(mouseEvent.target.range)) { + return new HoverForeignElementAnchor(1000, this, mouseEvent.target.range); + } + } + return null; + } + + computeSync(anchor: HoverAnchor, lineDecorations: IModelDecoration[]): InlineCompletionsHover[] { + const controller = GhostTextController.get(this._editor); + if (controller && controller.shouldShowHoverAt(anchor.range)) { + return [new InlineCompletionsHover(this, anchor.range)]; + } + return []; + } + + renderHoverParts(hoverParts: InlineCompletionsHover[], fragment: DocumentFragment, statusBar: IEditorHoverStatusBar): IDisposable { + const menu = this._menuService.createMenu( + MenuId.InlineCompletionsActions, + this._contextKeyService + ); + + statusBar.addAction({ + label: nls.localize('showNextInlineSuggestion', "Next"), + commandId: ShowNextInlineSuggestionAction.ID, + run: () => this._commandService.executeCommand(ShowNextInlineSuggestionAction.ID) + }); + statusBar.addAction({ + label: nls.localize('showPreviousInlineSuggestion', "Previous"), + commandId: ShowPreviousInlineSuggestionAction.ID, + run: () => this._commandService.executeCommand(ShowPreviousInlineSuggestionAction.ID) + }); + statusBar.addAction({ + label: nls.localize('acceptInlineSuggestion', "Accept"), + commandId: commitInlineSuggestionAction.id, + run: () => this._commandService.executeCommand(commitInlineSuggestionAction.id) + }); + + for (const [_, group] of menu.getActions()) { + for (const action of group) { + if (action instanceof MenuItemAction) { + statusBar.addAction({ + label: action.label, + commandId: action.item.id, + run: () => this._commandService.executeCommand(action.item.id) + }); + } + } + } + + return Disposable.None; + } +} diff --git a/src/vs/editor/contrib/inlineCompletions/inlineCompletionsModel.ts b/src/vs/editor/contrib/inlineCompletions/inlineCompletionsModel.ts new file mode 100644 index 000000000000..026b39f07c42 --- /dev/null +++ b/src/vs/editor/contrib/inlineCompletions/inlineCompletionsModel.ts @@ -0,0 +1,582 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { CancelablePromise, createCancelablePromise, RunOnceScheduler } from 'vs/base/common/async'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { onUnexpectedError, onUnexpectedExternalError } from 'vs/base/common/errors'; +import { Emitter } from 'vs/base/common/event'; +import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import * as strings from 'vs/base/common/strings'; +import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; +import { Position } from 'vs/editor/common/core/position'; +import { Range } from 'vs/editor/common/core/range'; +import { ITextModel } from 'vs/editor/common/model'; +import { InlineCompletion, InlineCompletionContext, InlineCompletions, InlineCompletionsProvider, InlineCompletionsProviderRegistry, InlineCompletionTriggerKind } from 'vs/editor/common/modes'; +import { BaseGhostTextWidgetModel, GhostText, GhostTextWidgetModel } from 'vs/editor/contrib/inlineCompletions/ghostTextWidget'; +import { EditOperation } from 'vs/editor/common/core/editOperation'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { MutableDisposable } from 'vs/editor/contrib/inlineCompletions/utils'; +import { RedoCommand, UndoCommand } from 'vs/editor/browser/editorExtensions'; +import { CoreEditingCommands } from 'vs/editor/browser/controller/coreCommands'; + +export class InlineCompletionsModel extends Disposable implements GhostTextWidgetModel { + protected readonly onDidChangeEmitter = new Emitter(); + public readonly onDidChange = this.onDidChangeEmitter.event; + + private readonly completionSession = this._register(new MutableDisposable()); + + private active: boolean = false; + + constructor( + private readonly editor: IActiveCodeEditor, + private readonly commandService: ICommandService + ) { + super(); + + this._register(commandService.onDidExecuteCommand(e => { + // These commands don't trigger onDidType. + const commands = new Set([ + UndoCommand.id, + RedoCommand.id, + CoreEditingCommands.Tab.id, + CoreEditingCommands.DeleteLeft.id, + CoreEditingCommands.DeleteRight.id + ]); + if (commands.has(e.commandId) && editor.hasTextFocus()) { + this.handleUserInput(); + } + })); + + this._register(this.editor.onDidType((e) => { + this.handleUserInput(); + })); + + this._register(this.editor.onDidChangeCursorPosition((e) => { + if (this.session && !this.session.isValid) { + this.hide(); + } + })); + } + + private handleUserInput() { + if (this.session && !this.session.isValid) { + this.hide(); + } + setTimeout(() => { + // Wait for the cursor update that happens in the same iteration loop iteration + this.startSessionIfTriggered(); + }, 0); + } + + private get session(): InlineCompletionsSession | undefined { + return this.completionSession.value; + } + + public get ghostText(): GhostText | undefined { + return this.session?.ghostText; + } + + public get minReservedLineCount(): number { + return this.session ? this.session.minReservedLineCount : 0; + } + + public get expanded(): boolean { + return this.session ? this.session.expanded : false; + } + + public setExpanded(expanded: boolean): void { + this.session?.setExpanded(expanded); + } + + public setActive(active: boolean) { + this.active = active; + if (active) { + this.session?.scheduleAutomaticUpdate(); + } + } + + private startSessionIfTriggered(): void { + const suggestOptions = this.editor.getOption(EditorOption.inlineSuggest); + if (!suggestOptions.enabled) { + return; + } + + if (this.session && this.session.isValid) { + return; + } + + this.startSession(); + } + + public startSession(): void { + if (this.completionSession.value) { + return; + } + this.completionSession.value = new InlineCompletionsSession(this.editor, this.editor.getPosition(), () => this.active, this.commandService); + this.completionSession.value.takeOwnership( + this.completionSession.value.onDidChange(() => { + this.onDidChangeEmitter.fire(); + }) + ); + } + + public hide(): void { + this.completionSession.clear(); + this.onDidChangeEmitter.fire(); + } + + public commitCurrentSuggestion(): void { + // Don't dispose the session, so that after committing, more suggestions are shown. + this.session?.commitCurrentCompletion(); + } + + public showNext(): void { + this.session?.showNextInlineCompletion(); + } + + public showPrevious(): void { + this.session?.showPreviousInlineCompletion(); + } +} + +class InlineCompletionsSession extends BaseGhostTextWidgetModel { + public readonly minReservedLineCount = 0; + + private readonly updateOperation = this._register(new MutableDisposable()); + private readonly cache = this._register(new MutableDisposable()); + + private updateSoon = this._register(new RunOnceScheduler(() => this.update(InlineCompletionTriggerKind.Automatic), 50)); + private readonly textModel = this.editor.getModel(); + + constructor( + editor: IActiveCodeEditor, + private readonly triggerPosition: Position, + private readonly shouldUpdate: () => boolean, + private readonly commandService: ICommandService, + ) { + super(editor); + + let lastCompletionItem: InlineCompletion | undefined = undefined; + this._register(this.onDidChange(() => { + const currentCompletion = this.currentCompletion; + if (currentCompletion && currentCompletion.sourceInlineCompletion !== lastCompletionItem) { + lastCompletionItem = currentCompletion.sourceInlineCompletion; + + const provider = currentCompletion.sourceProvider; + if (provider.handleItemDidShow) { + provider.handleItemDidShow(currentCompletion.sourceInlineCompletions, lastCompletionItem); + } + } + })); + + this._register(this.editor.onDidChangeModelContent((e) => { + if (this.cache.value) { + let hasChanged = false; + for (const c of this.cache.value.completions) { + const newRange = this.textModel.getDecorationRange(c.decorationId); + if (!newRange) { + onUnexpectedError(new Error('Decoration has no range')); + continue; + } + if (!c.synchronizedRange.equalsRange(newRange)) { + hasChanged = true; + c.synchronizedRange = newRange; + } + } + if (hasChanged) { + this.onDidChangeEmitter.fire(); + } + } + + this.scheduleAutomaticUpdate(); + })); + + this.scheduleAutomaticUpdate(); + } + + //#region Selection + + // We use a semantic id to track the selection even if the cache changes. + private currentlySelectedCompletionId: string | undefined = undefined; + + private fixAndGetIndexOfCurrentSelection(): number { + if (!this.currentlySelectedCompletionId || !this.cache.value) { + return 0; + } + if (this.cache.value.completions.length === 0) { + // don't reset the selection in this case + return 0; + } + + const idx = this.cache.value.completions.findIndex(v => v.semanticId === this.currentlySelectedCompletionId); + if (idx === -1) { + // Reset the selection so that the selection does not jump back when it appears again + this.currentlySelectedCompletionId = undefined; + return 0; + } + return idx; + } + + private get currentCachedCompletion(): CachedInlineCompletion | undefined { + if (!this.cache.value) { + return undefined; + } + return this.cache.value.completions[this.fixAndGetIndexOfCurrentSelection()]; + } + + public async showNextInlineCompletion(): Promise { + await this.ensureUpdateWithExplicitContext(); + + const completions = this.cache.value?.completions || []; + if (completions.length > 0) { + const newIdx = (this.fixAndGetIndexOfCurrentSelection() + 1) % completions.length; + this.currentlySelectedCompletionId = completions[newIdx].semanticId; + } else { + this.currentlySelectedCompletionId = undefined; + } + this.onDidChangeEmitter.fire(); + } + + public async showPreviousInlineCompletion(): Promise { + await this.ensureUpdateWithExplicitContext(); + + const completions = this.cache.value?.completions || []; + if (completions.length > 0) { + const newIdx = (this.fixAndGetIndexOfCurrentSelection() + completions.length - 1) % completions.length; + this.currentlySelectedCompletionId = completions[newIdx].semanticId; + } else { + this.currentlySelectedCompletionId = undefined; + } + this.onDidChangeEmitter.fire(); + } + + private async ensureUpdateWithExplicitContext(): Promise { + if (this.updateOperation.value) { + // Restart or wait for current update operation + if (this.updateOperation.value.triggerKind === InlineCompletionTriggerKind.Explicit) { + await this.updateOperation.value.promise; + } else { + await this.update(InlineCompletionTriggerKind.Explicit); + } + } else if (this.cache.value?.triggerKind !== InlineCompletionTriggerKind.Explicit) { + // Refresh cache + await this.update(InlineCompletionTriggerKind.Explicit); + } + } + + //#endregion + + public get ghostText(): GhostText | undefined { + const currentCompletion = this.currentCompletion; + return currentCompletion ? inlineCompletionToGhostText(currentCompletion, this.editor.getModel()) : undefined; + } + + get currentCompletion(): LiveInlineCompletion | undefined { + const completion = this.currentCachedCompletion; + if (!completion) { + return undefined; + } + return { + text: completion.inlineCompletion.text, + range: completion.synchronizedRange, + command: completion.inlineCompletion.command, + sourceProvider: completion.inlineCompletion.sourceProvider, + sourceInlineCompletions: completion.inlineCompletion.sourceInlineCompletions, + sourceInlineCompletion: completion.inlineCompletion.sourceInlineCompletion, + }; + } + + get isValid(): boolean { + return this.editor.getPosition().lineNumber === this.triggerPosition.lineNumber; + } + + public scheduleAutomaticUpdate(): void { + this.updateSoon.schedule(); + } + + private async update(triggerKind: InlineCompletionTriggerKind): Promise { + if (!this.shouldUpdate()) { + return; + } + + const position = this.editor.getPosition(); + + const promise = createCancelablePromise(async token => { + let result; + try { + result = await provideInlineCompletions(position, + this.editor.getModel(), + { triggerKind }, + token + ); + } catch (e) { + onUnexpectedError(e); + return; + } + + if (token.isCancellationRequested) { + return; + } + + this.cache.value = new SynchronizedInlineCompletionsCache( + this.editor, + result, + () => this.onDidChangeEmitter.fire(), + triggerKind + ); + this.onDidChangeEmitter.fire(); + }); + const operation = new UpdateOperation(promise, triggerKind); + this.updateOperation.value = operation; + await promise; + if (this.updateOperation.value === operation) { + this.updateOperation.clear(); + } + } + + public takeOwnership(disposable: IDisposable): void { + this._register(disposable); + } + + public commitCurrentCompletion(): void { + const completion = this.currentCompletion; + if (completion) { + this.commit(completion); + } + } + + public commit(completion: LiveInlineCompletion): void { + // Mark the cache as stale, but don't dispose it yet, + // otherwise command args might get disposed. + const cache = this.cache.replace(undefined); + + this.editor.executeEdits( + 'inlineSuggestion.accept', + [ + EditOperation.replaceMove(completion.range, completion.text) + ] + ); + if (completion.command) { + this.commandService + .executeCommand(completion.command.id, ...(completion.command.arguments || [])) + .finally(() => { + cache?.dispose(); + }) + .then(undefined, onUnexpectedExternalError); + } + + this.onDidChangeEmitter.fire(); + } +} + +class UpdateOperation implements IDisposable { + constructor(public readonly promise: CancelablePromise, public readonly triggerKind: InlineCompletionTriggerKind) { + } + + dispose() { + this.promise.cancel(); + } +} + +/** + * The cache keeps itself in sync with the editor. + * It also owns the completions result and disposes it when the cache is diposed. +*/ +class SynchronizedInlineCompletionsCache extends Disposable { + public readonly completions: readonly CachedInlineCompletion[]; + + constructor( + editor: IActiveCodeEditor, + completionsSource: LiveInlineCompletions, + onChange: () => void, + public readonly triggerKind: InlineCompletionTriggerKind, + ) { + super(); + + const decorationIds = editor.deltaDecorations( + [], + completionsSource.items.map(i => ({ + range: i.range, + options: { + description: 'inline-completion-tracking-range' + }, + })) + ); + this._register(toDisposable(() => { + editor.deltaDecorations(decorationIds, []); + })); + + this.completions = completionsSource.items.map((c, idx) => new CachedInlineCompletion(c, decorationIds[idx])); + + this._register(editor.onDidChangeModelContent(() => { + let hasChanged = false; + const model = editor.getModel(); + for (const c of this.completions) { + const newRange = model.getDecorationRange(c.decorationId); + if (!newRange) { + onUnexpectedError(new Error('Decoration has no range')); + continue; + } + if (!c.synchronizedRange.equalsRange(newRange)) { + hasChanged = true; + c.synchronizedRange = newRange; + } + } + if (hasChanged) { + onChange(); + } + })); + + this._register(completionsSource); + } +} + +class CachedInlineCompletion { + public readonly semanticId: string = JSON.stringify({ + text: this.inlineCompletion.text, + startLine: this.inlineCompletion.range.startLineNumber, + startColumn: this.inlineCompletion.range.startColumn, + command: this.inlineCompletion.command + }); + /** + * The range, synchronized with text model changes. + */ + public synchronizedRange: Range; + + constructor( + public readonly inlineCompletion: LiveInlineCompletion, + public readonly decorationId: string, + ) { + this.synchronizedRange = inlineCompletion.range; + } +} + +export interface NormalizedInlineCompletion extends InlineCompletion { + range: Range; +} + +function leftTrim(str: string): string { + return str.replace(/^\s+/, ''); +} + +export function inlineCompletionToGhostText(inlineCompletion: NormalizedInlineCompletion, textModel: ITextModel): GhostText | undefined { + // This is a single line string + const valueToBeReplaced = textModel.getValueInRange(inlineCompletion.range); + + let remainingInsertText: string; + + // Consider these cases + // valueToBeReplaced -> inlineCompletion.text + // "\t\tfoo" -> "\t\tfoobar" (+"bar") + // "\t" -> "\t\tfoobar" (+"\tfoobar") + // "\t\tfoo" -> "\t\t\tfoobar" (+"\t", +"bar") + // "\t\tfoo" -> "\tfoobar" (-"\t", +"\bar") + + if (inlineCompletion.text.startsWith(valueToBeReplaced)) { + remainingInsertText = inlineCompletion.text.substr(valueToBeReplaced.length); + } else { + const valueToBeReplacedTrimmed = leftTrim(valueToBeReplaced); + const insertTextTrimmed = leftTrim(inlineCompletion.text); + if (!insertTextTrimmed.startsWith(valueToBeReplacedTrimmed)) { + return undefined; + } + remainingInsertText = insertTextTrimmed.substr(valueToBeReplacedTrimmed.length); + } + + const position = inlineCompletion.range.getEndPosition(); + + const lines = strings.splitLines(remainingInsertText); + + if (lines.length > 1 && textModel.getLineMaxColumn(position.lineNumber) !== position.column) { + // Such ghost text is not supported. + return undefined; + } + + return { + lines, + position + }; +} + +export interface LiveInlineCompletion extends NormalizedInlineCompletion { + sourceProvider: InlineCompletionsProvider; + sourceInlineCompletion: InlineCompletion; + sourceInlineCompletions: InlineCompletions; +} + +/** + * Contains no duplicated items. +*/ +export interface LiveInlineCompletions extends InlineCompletions { + dispose(): void; +} + +function getDefaultRange(position: Position, model: ITextModel): Range { + const word = model.getWordAtPosition(position); + const maxColumn = model.getLineMaxColumn(position.lineNumber); + // By default, always replace up until the end of the current line. + // This default might be subject to change! + return word + ? new Range(position.lineNumber, word.startColumn, position.lineNumber, maxColumn) + : Range.fromPositions(position, position.with(undefined, maxColumn)); +} + +async function provideInlineCompletions( + position: Position, + model: ITextModel, + context: InlineCompletionContext, + token: CancellationToken = CancellationToken.None +): Promise { + const defaultReplaceRange = getDefaultRange(position, model); + + const providers = InlineCompletionsProviderRegistry.all(model); + const results = await Promise.all( + providers.map( + async provider => { + const completions = await provider.provideInlineCompletions(model, position, context, token); + return ({ + completions, + provider, + dispose: () => { + if (completions) { + provider.freeInlineCompletions(completions); + } + } + }); + } + ) + ); + + const itemsByHash = new Map(); + for (const result of results) { + const completions = result.completions; + if (completions) { + for (const item of completions.items.map(item => ({ + text: item.text, + range: item.range ? Range.lift(item.range) : defaultReplaceRange, + command: item.command, + sourceProvider: result.provider, + sourceInlineCompletions: completions, + sourceInlineCompletion: item + }))) { + if (item.range.startLineNumber !== item.range.endLineNumber) { + // Ignore invalid ranges. + continue; + } + itemsByHash.set(JSON.stringify({ text: item.text, range: item.range }), item); + } + } + } + + return { + items: [...itemsByHash.values()], + dispose: () => { + for (const result of results) { + result.dispose(); + } + }, + }; +} diff --git a/src/vs/editor/contrib/inlineCompletions/suggestWidgetAdapterModel.ts b/src/vs/editor/contrib/inlineCompletions/suggestWidgetAdapterModel.ts new file mode 100644 index 000000000000..765d200b5dab --- /dev/null +++ b/src/vs/editor/contrib/inlineCompletions/suggestWidgetAdapterModel.ts @@ -0,0 +1,172 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { toDisposable } from 'vs/base/common/lifecycle'; +import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; +import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { Position } from 'vs/editor/common/core/position'; +import { Range } from 'vs/editor/common/core/range'; +import { CompletionItemInsertTextRule } from 'vs/editor/common/modes'; +import { BaseGhostTextWidgetModel, GhostText } from 'vs/editor/contrib/inlineCompletions/ghostTextWidget'; +import { inlineCompletionToGhostText, NormalizedInlineCompletion } from 'vs/editor/contrib/inlineCompletions/inlineCompletionsModel'; +import { SnippetParser } from 'vs/editor/contrib/snippet/snippetParser'; +import { SnippetSession } from 'vs/editor/contrib/snippet/snippetSession'; +import { SuggestController } from 'vs/editor/contrib/suggest/suggestController'; +import { ISelectedSuggestion } from 'vs/editor/contrib/suggest/suggestWidget'; + +export class SuggestWidgetAdapterModel extends BaseGhostTextWidgetModel { + private isSuggestWidgetVisible: boolean = false; + private currentGhostText: GhostText | undefined = undefined; + + public override minReservedLineCount: number = 0; + + public get isActive() { return this.isSuggestWidgetVisible; } + + constructor( + editor: IActiveCodeEditor + ) { + super(editor); + + const suggestController = SuggestController.get(this.editor); + if (suggestController) { + let isBoundToSuggestWidget = false; + const bindToSuggestWidget = () => { + if (isBoundToSuggestWidget) { + return; + } + isBoundToSuggestWidget = true; + + this._register(suggestController.widget.value.onDidShow(() => { + this.isSuggestWidgetVisible = true; + this.updateFromSuggestion(); + })); + this._register(suggestController.widget.value.onDidHide(() => { + this.isSuggestWidgetVisible = false; + this.minReservedLineCount = 0; + this.updateFromSuggestion(); + })); + this._register(suggestController.widget.value.onDidFocus(() => { + this.isSuggestWidgetVisible = true; + this.updateFromSuggestion(); + })); + }; + + this._register(Event.once(suggestController.model.onDidTrigger)(e => { + bindToSuggestWidget(); + })); + } + this.updateFromSuggestion(); + + this._register(toDisposable(() => { + const suggestController = SuggestController.get(this.editor); + if (suggestController) { + suggestController.stopForceRenderingAbove(); + } + })); + } + + public override setExpanded(expanded: boolean): void { + super.setExpanded(expanded); + this.updateFromSuggestion(); + } + + private isSuggestionPreviewEnabled(): boolean { + const suggestOptions = this.editor.getOption(EditorOption.suggest); + return suggestOptions.preview; + } + + private updateFromSuggestion(): void { + const suggestController = SuggestController.get(this.editor); + if (!suggestController) { + this.setCurrentInlineCompletion(undefined); + return; + } + if (!this.isSuggestWidgetVisible) { + this.setCurrentInlineCompletion(undefined); + return; + } + const focusedItem = suggestController.widget.value.getFocusedItem(); + if (!focusedItem) { + this.setCurrentInlineCompletion(undefined); + return; + } + + // TODO: item.isResolved + this.setCurrentInlineCompletion( + getInlineCompletion( + suggestController, + this.editor.getPosition(), + focusedItem + ) + ); + } + + private setCurrentInlineCompletion(completion: NormalizedInlineCompletion | undefined): void { + this.currentGhostText = completion + ? ( + inlineCompletionToGhostText(completion, this.editor.getModel()) || + // Show an invisible ghost text to reserve space + { + lines: [], + position: completion.range.getEndPosition(), + } + ) : undefined; + + if (this.currentGhostText && this.expanded) { + this.minReservedLineCount = Math.max(this.minReservedLineCount, this.currentGhostText.lines.length - 1); + } + + const suggestController = SuggestController.get(this.editor); + if (suggestController) { + if (this.minReservedLineCount >= 1 && this.isSuggestionPreviewEnabled()) { + suggestController.forceRenderingAbove(); + } else { + suggestController.stopForceRenderingAbove(); + } + } + + this.onDidChangeEmitter.fire(); + } + + public override get ghostText(): GhostText | undefined { + return this.isSuggestionPreviewEnabled() + ? this.currentGhostText + : undefined; + } +} + +function getInlineCompletion(suggestController: SuggestController, position: Position, suggestion: ISelectedSuggestion): NormalizedInlineCompletion { + const item = suggestion.item; + + if (Array.isArray(item.completion.additionalTextEdits)) { + // cannot represent additional text edits + return { + text: '', + range: Range.fromPositions(position, position), + }; + } + + let { insertText } = item.completion; + if (item.completion.insertTextRules! & CompletionItemInsertTextRule.InsertAsSnippet) { + const snippet = new SnippetParser().parse(insertText); + const model = suggestController.editor.getModel()!; + SnippetSession.adjustWhitespace( + model, position, snippet, + true, + true + ); + insertText = snippet.toString(); + } + + const info = suggestController.getOverwriteInfo(item, false); + return { + text: insertText, + range: Range.fromPositions( + position.delta(0, -info.overwriteBefore), + position.delta(0, Math.max(info.overwriteAfter, 0)) + ), + }; +} diff --git a/src/vs/editor/contrib/inlineCompletions/utils.ts b/src/vs/editor/contrib/inlineCompletions/utils.ts new file mode 100644 index 000000000000..9a3b1a074699 --- /dev/null +++ b/src/vs/editor/contrib/inlineCompletions/utils.ts @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IDisposable, trackDisposable } from 'vs/base/common/lifecycle'; + +// TODO: merge this class into Matt's MutableDisposable. +/** + * Manages the lifecycle of a disposable value that may be changed. + * + * This ensures that when the disposable value is changed, the previously held disposable is disposed of. You can + * also register a `MutableDisposable` on a `Disposable` to ensure it is automatically cleaned up. + */ +export class MutableDisposable implements IDisposable { + private _value?: T; + private _isDisposed = false; + + constructor() { + trackDisposable(this); + } + + get value(): T | undefined { + return this._isDisposed ? undefined : this._value; + } + + set value(value: T | undefined) { + if (this._isDisposed || value === this._value) { + return; + } + + this._value?.dispose(); + this._value = value; + } + + clear() { + this.value = undefined; + } + + dispose(): void { + this._isDisposed = true; + this._value?.dispose(); + this._value = undefined; + } + + replace(newValue: T | undefined): T | undefined { + const oldValue = this._value; + this._value = newValue; + return oldValue; + } +} diff --git a/lib/vscode/src/vs/editor/contrib/linesOperations/copyLinesCommand.ts b/src/vs/editor/contrib/linesOperations/copyLinesCommand.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/linesOperations/copyLinesCommand.ts rename to src/vs/editor/contrib/linesOperations/copyLinesCommand.ts diff --git a/lib/vscode/src/vs/editor/contrib/linesOperations/linesOperations.ts b/src/vs/editor/contrib/linesOperations/linesOperations.ts similarity index 96% rename from lib/vscode/src/vs/editor/contrib/linesOperations/linesOperations.ts rename to src/vs/editor/contrib/linesOperations/linesOperations.ts index 64b689a5fc25..99abacb0715c 100644 --- a/lib/vscode/src/vs/editor/contrib/linesOperations/linesOperations.ts +++ b/src/vs/editor/contrib/linesOperations/linesOperations.ts @@ -1045,7 +1045,41 @@ export class TitleCaseAction extends AbstractCaseAction { } } +class BackwardsCompatibleRegExp { + + private _actual: RegExp | null; + private _evaluated: boolean; + + constructor( + private readonly _pattern: string, + private readonly _flags: string + ) { + this._actual = null; + this._evaluated = false; + } + + public get(): RegExp | null { + if (!this._evaluated) { + this._evaluated = true; + try { + this._actual = new RegExp(this._pattern, this._flags); + } catch (err) { + // this browser does not support this regular expression + } + } + return this._actual; + } + + public isSupported(): boolean { + return (this.get() !== null); + } +} + export class SnakeCaseAction extends AbstractCaseAction { + + public static regExp1 = new BackwardsCompatibleRegExp('(\\p{Ll})(\\p{Lu})', 'gmu'); + public static regExp2 = new BackwardsCompatibleRegExp('(\\p{Lu}|\\p{N})(\\p{Lu})(\\p{Ll})', 'gmu'); + constructor() { super({ id: 'editor.action.transformToSnakecase', @@ -1056,9 +1090,15 @@ export class SnakeCaseAction extends AbstractCaseAction { } protected _modifyText(text: string, wordSeparators: string): string { + const regExp1 = SnakeCaseAction.regExp1.get(); + const regExp2 = SnakeCaseAction.regExp2.get(); + if (!regExp1 || !regExp2) { + // cannot support this + return text; + } return (text - .replace(/(\p{Ll})(\p{Lu})/gmu, '$1_$2') - .replace(/(\p{Lu}|\p{N})(\p{Lu})(\p{Ll})/gmu, '$1_$2$3') + .replace(regExp1, '$1_$2') + .replace(regExp2, '$1_$2$3') .toLocaleLowerCase() ); } @@ -1084,4 +1124,7 @@ registerEditorAction(TransposeAction); registerEditorAction(UpperCaseAction); registerEditorAction(LowerCaseAction); registerEditorAction(TitleCaseAction); -registerEditorAction(SnakeCaseAction); + +if (SnakeCaseAction.regExp1.isSupported() && SnakeCaseAction.regExp2.isSupported()) { + registerEditorAction(SnakeCaseAction); +} diff --git a/lib/vscode/src/vs/editor/contrib/linesOperations/moveLinesCommand.ts b/src/vs/editor/contrib/linesOperations/moveLinesCommand.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/linesOperations/moveLinesCommand.ts rename to src/vs/editor/contrib/linesOperations/moveLinesCommand.ts diff --git a/lib/vscode/src/vs/editor/contrib/linesOperations/sortLinesCommand.ts b/src/vs/editor/contrib/linesOperations/sortLinesCommand.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/linesOperations/sortLinesCommand.ts rename to src/vs/editor/contrib/linesOperations/sortLinesCommand.ts diff --git a/lib/vscode/src/vs/editor/contrib/linesOperations/test/copyLinesCommand.test.ts b/src/vs/editor/contrib/linesOperations/test/copyLinesCommand.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/linesOperations/test/copyLinesCommand.test.ts rename to src/vs/editor/contrib/linesOperations/test/copyLinesCommand.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/linesOperations/test/linesOperations.test.ts b/src/vs/editor/contrib/linesOperations/test/linesOperations.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/linesOperations/test/linesOperations.test.ts rename to src/vs/editor/contrib/linesOperations/test/linesOperations.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/linesOperations/test/moveLinesCommand.test.ts b/src/vs/editor/contrib/linesOperations/test/moveLinesCommand.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/linesOperations/test/moveLinesCommand.test.ts rename to src/vs/editor/contrib/linesOperations/test/moveLinesCommand.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/linesOperations/test/sortLinesCommand.test.ts b/src/vs/editor/contrib/linesOperations/test/sortLinesCommand.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/linesOperations/test/sortLinesCommand.test.ts rename to src/vs/editor/contrib/linesOperations/test/sortLinesCommand.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/linkedEditing/linkedEditing.ts b/src/vs/editor/contrib/linkedEditing/linkedEditing.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/linkedEditing/linkedEditing.ts rename to src/vs/editor/contrib/linkedEditing/linkedEditing.ts index 8a586c1b13a0..7b5fa2d99e3e 100644 --- a/lib/vscode/src/vs/editor/contrib/linkedEditing/linkedEditing.ts +++ b/src/vs/editor/contrib/linkedEditing/linkedEditing.ts @@ -39,6 +39,7 @@ export class LinkedEditingContribution extends Disposable implements IEditorCont public static readonly ID = 'editor.contrib.linkedEditing'; private static readonly DECORATION = ModelDecorationOptions.register({ + description: 'linked-editing', stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, className: DECORATION_CLASS_NAME }); diff --git a/lib/vscode/src/vs/editor/contrib/linkedEditing/test/linkedEditing.test..ts b/src/vs/editor/contrib/linkedEditing/test/linkedEditing.test..ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/linkedEditing/test/linkedEditing.test..ts rename to src/vs/editor/contrib/linkedEditing/test/linkedEditing.test..ts diff --git a/lib/vscode/src/vs/editor/contrib/links/getLinks.ts b/src/vs/editor/contrib/links/getLinks.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/links/getLinks.ts rename to src/vs/editor/contrib/links/getLinks.ts diff --git a/lib/vscode/src/vs/editor/contrib/links/links.css b/src/vs/editor/contrib/links/links.css similarity index 100% rename from lib/vscode/src/vs/editor/contrib/links/links.css rename to src/vs/editor/contrib/links/links.css diff --git a/lib/vscode/src/vs/editor/contrib/links/links.ts b/src/vs/editor/contrib/links/links.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/links/links.ts rename to src/vs/editor/contrib/links/links.ts index 5cfe69127dbf..a79bc4d3dd84 100644 --- a/lib/vscode/src/vs/editor/contrib/links/links.ts +++ b/src/vs/editor/contrib/links/links.ts @@ -66,11 +66,13 @@ function getHoverMessage(link: Link, useMetaKey: boolean): MarkdownString { const decoration = { general: ModelDecorationOptions.register({ + description: 'detected-link', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, collapseOnReplaceEdit: true, inlineClassName: 'detected-link' }), active: ModelDecorationOptions.register({ + description: 'detected-link-active', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, collapseOnReplaceEdit: true, inlineClassName: 'detected-link-active' diff --git a/lib/vscode/src/vs/editor/contrib/message/messageController.css b/src/vs/editor/contrib/message/messageController.css similarity index 100% rename from lib/vscode/src/vs/editor/contrib/message/messageController.css rename to src/vs/editor/contrib/message/messageController.css diff --git a/lib/vscode/src/vs/editor/contrib/message/messageController.ts b/src/vs/editor/contrib/message/messageController.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/message/messageController.ts rename to src/vs/editor/contrib/message/messageController.ts diff --git a/lib/vscode/src/vs/editor/contrib/multicursor/multicursor.ts b/src/vs/editor/contrib/multicursor/multicursor.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/multicursor/multicursor.ts rename to src/vs/editor/contrib/multicursor/multicursor.ts index cfbd4b2d2082..5edc94877d74 100644 --- a/lib/vscode/src/vs/editor/contrib/multicursor/multicursor.ts +++ b/src/vs/editor/contrib/multicursor/multicursor.ts @@ -1047,6 +1047,7 @@ export class SelectionHighlighter extends Disposable implements IEditorContribut } private static readonly _SELECTION_HIGHLIGHT_OVERVIEW = ModelDecorationOptions.register({ + description: 'selection-highlight-overview', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'selectionHighlight', overviewRuler: { @@ -1056,6 +1057,7 @@ export class SelectionHighlighter extends Disposable implements IEditorContribut }); private static readonly _SELECTION_HIGHLIGHT = ModelDecorationOptions.register({ + description: 'selection-highlight', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'selectionHighlight', }); diff --git a/lib/vscode/src/vs/editor/contrib/multicursor/test/multicursor.test.ts b/src/vs/editor/contrib/multicursor/test/multicursor.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/multicursor/test/multicursor.test.ts rename to src/vs/editor/contrib/multicursor/test/multicursor.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/parameterHints/parameterHints.css b/src/vs/editor/contrib/parameterHints/parameterHints.css similarity index 100% rename from lib/vscode/src/vs/editor/contrib/parameterHints/parameterHints.css rename to src/vs/editor/contrib/parameterHints/parameterHints.css diff --git a/lib/vscode/src/vs/editor/contrib/parameterHints/parameterHints.ts b/src/vs/editor/contrib/parameterHints/parameterHints.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/parameterHints/parameterHints.ts rename to src/vs/editor/contrib/parameterHints/parameterHints.ts diff --git a/lib/vscode/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts b/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts rename to src/vs/editor/contrib/parameterHints/parameterHintsModel.ts diff --git a/lib/vscode/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts b/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts rename to src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts diff --git a/lib/vscode/src/vs/editor/contrib/parameterHints/provideSignatureHelp.ts b/src/vs/editor/contrib/parameterHints/provideSignatureHelp.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/parameterHints/provideSignatureHelp.ts rename to src/vs/editor/contrib/parameterHints/provideSignatureHelp.ts diff --git a/lib/vscode/src/vs/editor/contrib/parameterHints/test/parameterHintsModel.test.ts b/src/vs/editor/contrib/parameterHints/test/parameterHintsModel.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/parameterHints/test/parameterHintsModel.test.ts rename to src/vs/editor/contrib/parameterHints/test/parameterHintsModel.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/peekView/media/peekViewWidget.css b/src/vs/editor/contrib/peekView/media/peekViewWidget.css similarity index 98% rename from lib/vscode/src/vs/editor/contrib/peekView/media/peekViewWidget.css rename to src/vs/editor/contrib/peekView/media/peekViewWidget.css index ed8f673ab4bc..387852d6214d 100644 --- a/lib/vscode/src/vs/editor/contrib/peekView/media/peekViewWidget.css +++ b/src/vs/editor/contrib/peekView/media/peekViewWidget.css @@ -33,6 +33,7 @@ .monaco-editor .peekview-widget .head .peekview-title .filename { overflow: hidden; text-overflow: ellipsis; + white-space: nowrap; } .monaco-editor .peekview-widget .head .peekview-title .meta:not(:empty)::before { diff --git a/lib/vscode/src/vs/editor/contrib/peekView/peekView.ts b/src/vs/editor/contrib/peekView/peekView.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/peekView/peekView.ts rename to src/vs/editor/contrib/peekView/peekView.ts index 6dbcde25dac0..3df39461d7b5 100644 --- a/lib/vscode/src/vs/editor/contrib/peekView/peekView.ts +++ b/src/vs/editor/contrib/peekView/peekView.ts @@ -219,7 +219,7 @@ export abstract class PeekViewWidget extends ZoneWidget { setTitle(primaryHeading: string, secondaryHeading?: string): void { if (this._primaryHeading && this._secondaryHeading) { this._primaryHeading.innerText = primaryHeading; - this._primaryHeading.setAttribute('aria-label', primaryHeading); + this._primaryHeading.setAttribute('title', primaryHeading); if (secondaryHeading) { this._secondaryHeading.innerText = secondaryHeading; } else { diff --git a/lib/vscode/src/vs/editor/contrib/quickAccess/commandsQuickAccess.ts b/src/vs/editor/contrib/quickAccess/commandsQuickAccess.ts similarity index 91% rename from lib/vscode/src/vs/editor/contrib/quickAccess/commandsQuickAccess.ts rename to src/vs/editor/contrib/quickAccess/commandsQuickAccess.ts index ec7d2ab922e0..90681ff6aac0 100644 --- a/lib/vscode/src/vs/editor/contrib/quickAccess/commandsQuickAccess.ts +++ b/src/vs/editor/contrib/quickAccess/commandsQuickAccess.ts @@ -8,7 +8,7 @@ import { IEditor } from 'vs/editor/common/editorCommon'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { stripIcons } from 'vs/base/common/iconLabels'; @@ -20,9 +20,9 @@ export abstract class AbstractEditorCommandsQuickAccessProvider extends Abstract keybindingService: IKeybindingService, commandService: ICommandService, telemetryService: ITelemetryService, - notificationService: INotificationService + dialogService: IDialogService ) { - super(options, instantiationService, keybindingService, commandService, telemetryService, notificationService); + super(options, instantiationService, keybindingService, commandService, telemetryService, dialogService); } /** diff --git a/lib/vscode/src/vs/editor/contrib/quickAccess/editorNavigationQuickAccess.ts b/src/vs/editor/contrib/quickAccess/editorNavigationQuickAccess.ts similarity index 98% rename from lib/vscode/src/vs/editor/contrib/quickAccess/editorNavigationQuickAccess.ts rename to src/vs/editor/contrib/quickAccess/editorNavigationQuickAccess.ts index ef8cf91b8ab2..d22faaeac288 100644 --- a/lib/vscode/src/vs/editor/contrib/quickAccess/editorNavigationQuickAccess.ts +++ b/src/vs/editor/contrib/quickAccess/editorNavigationQuickAccess.ts @@ -195,6 +195,7 @@ export abstract class AbstractEditorNavigationQuickAccessProvider implements IQu { range, options: { + description: 'quick-access-range-highlight', className: 'rangeHighlight', isWholeLine: true } @@ -204,6 +205,7 @@ export abstract class AbstractEditorNavigationQuickAccessProvider implements IQu { range, options: { + description: 'quick-access-range-highlight-overview', overviewRuler: { color: themeColorFromId(overviewRulerRangeHighlight), position: OverviewRulerLane.Full diff --git a/lib/vscode/src/vs/editor/contrib/quickAccess/gotoLineQuickAccess.ts b/src/vs/editor/contrib/quickAccess/gotoLineQuickAccess.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/quickAccess/gotoLineQuickAccess.ts rename to src/vs/editor/contrib/quickAccess/gotoLineQuickAccess.ts diff --git a/lib/vscode/src/vs/editor/contrib/quickAccess/gotoSymbolQuickAccess.ts b/src/vs/editor/contrib/quickAccess/gotoSymbolQuickAccess.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/quickAccess/gotoSymbolQuickAccess.ts rename to src/vs/editor/contrib/quickAccess/gotoSymbolQuickAccess.ts diff --git a/lib/vscode/src/vs/editor/contrib/rename/rename.ts b/src/vs/editor/contrib/rename/rename.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/rename/rename.ts rename to src/vs/editor/contrib/rename/rename.ts diff --git a/lib/vscode/src/vs/editor/contrib/rename/renameInputField.css b/src/vs/editor/contrib/rename/renameInputField.css similarity index 100% rename from lib/vscode/src/vs/editor/contrib/rename/renameInputField.css rename to src/vs/editor/contrib/rename/renameInputField.css diff --git a/lib/vscode/src/vs/editor/contrib/rename/renameInputField.ts b/src/vs/editor/contrib/rename/renameInputField.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/rename/renameInputField.ts rename to src/vs/editor/contrib/rename/renameInputField.ts diff --git a/lib/vscode/src/vs/editor/contrib/smartSelect/bracketSelections.ts b/src/vs/editor/contrib/smartSelect/bracketSelections.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/smartSelect/bracketSelections.ts rename to src/vs/editor/contrib/smartSelect/bracketSelections.ts diff --git a/lib/vscode/src/vs/editor/contrib/smartSelect/smartSelect.ts b/src/vs/editor/contrib/smartSelect/smartSelect.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/smartSelect/smartSelect.ts rename to src/vs/editor/contrib/smartSelect/smartSelect.ts diff --git a/lib/vscode/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts b/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts rename to src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/smartSelect/wordSelections.ts b/src/vs/editor/contrib/smartSelect/wordSelections.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/smartSelect/wordSelections.ts rename to src/vs/editor/contrib/smartSelect/wordSelections.ts diff --git a/lib/vscode/src/vs/editor/contrib/snippet/snippet.md b/src/vs/editor/contrib/snippet/snippet.md similarity index 100% rename from lib/vscode/src/vs/editor/contrib/snippet/snippet.md rename to src/vs/editor/contrib/snippet/snippet.md diff --git a/lib/vscode/src/vs/editor/contrib/snippet/snippetController2.ts b/src/vs/editor/contrib/snippet/snippetController2.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/snippet/snippetController2.ts rename to src/vs/editor/contrib/snippet/snippetController2.ts index 95bd300f0636..8a686a5d152f 100644 --- a/lib/vscode/src/vs/editor/contrib/snippet/snippetController2.ts +++ b/src/vs/editor/contrib/snippet/snippetController2.ts @@ -43,7 +43,7 @@ const _defaultOptions: ISnippetInsertOptions = { export class SnippetController2 implements IEditorContribution { - public static ID = 'snippetController2'; + public static readonly ID = 'snippetController2'; static get(editor: ICodeEditor): SnippetController2 { return editor.getContribution(SnippetController2.ID); diff --git a/lib/vscode/src/vs/editor/contrib/snippet/snippetParser.ts b/src/vs/editor/contrib/snippet/snippetParser.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/snippet/snippetParser.ts rename to src/vs/editor/contrib/snippet/snippetParser.ts index 8986345e970b..ab85481a3a8a 100644 --- a/lib/vscode/src/vs/editor/contrib/snippet/snippetParser.ts +++ b/src/vs/editor/contrib/snippet/snippetParser.ts @@ -388,11 +388,11 @@ export class FormatString extends Marker { } private _toPascalCase(value: string): string { - const match = value.match(/[a-z]+/gi); + const match = value.match(/[a-z0-9]+/gi); if (!match) { return value; } - return match.map(function (word) { + return match.map(word => { return word.charAt(0).toUpperCase() + word.substr(1).toLowerCase(); }) diff --git a/lib/vscode/src/vs/editor/contrib/snippet/snippetSession.css b/src/vs/editor/contrib/snippet/snippetSession.css similarity index 100% rename from lib/vscode/src/vs/editor/contrib/snippet/snippetSession.css rename to src/vs/editor/contrib/snippet/snippetSession.css diff --git a/lib/vscode/src/vs/editor/contrib/snippet/snippetSession.ts b/src/vs/editor/contrib/snippet/snippetSession.ts similarity index 97% rename from lib/vscode/src/vs/editor/contrib/snippet/snippetSession.ts rename to src/vs/editor/contrib/snippet/snippetSession.ts index 90abafa2549f..9b875e4051fb 100644 --- a/lib/vscode/src/vs/editor/contrib/snippet/snippetSession.ts +++ b/src/vs/editor/contrib/snippet/snippetSession.ts @@ -45,10 +45,10 @@ export class OneSnippet { _nestingLevel: number = 1; private static readonly _decor = { - active: ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, className: 'snippet-placeholder' }), - inactive: ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'snippet-placeholder' }), - activeFinal: ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'finish-snippet-placeholder' }), - inactiveFinal: ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'finish-snippet-placeholder' }), + active: ModelDecorationOptions.register({ description: 'snippet-placeholder-1', stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, className: 'snippet-placeholder' }), + inactive: ModelDecorationOptions.register({ description: 'snippet-placeholder-2', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'snippet-placeholder' }), + activeFinal: ModelDecorationOptions.register({ description: 'snippet-placeholder-3', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'finish-snippet-placeholder' }), + inactiveFinal: ModelDecorationOptions.register({ description: 'snippet-placeholder-4', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'finish-snippet-placeholder' }), }; constructor( diff --git a/lib/vscode/src/vs/editor/contrib/snippet/snippetVariables.ts b/src/vs/editor/contrib/snippet/snippetVariables.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/snippet/snippetVariables.ts rename to src/vs/editor/contrib/snippet/snippetVariables.ts diff --git a/lib/vscode/src/vs/editor/contrib/snippet/test/snippetController2.old.test.ts b/src/vs/editor/contrib/snippet/test/snippetController2.old.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/snippet/test/snippetController2.old.test.ts rename to src/vs/editor/contrib/snippet/test/snippetController2.old.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/snippet/test/snippetController2.test.ts b/src/vs/editor/contrib/snippet/test/snippetController2.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/snippet/test/snippetController2.test.ts rename to src/vs/editor/contrib/snippet/test/snippetController2.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/snippet/test/snippetParser.test.ts b/src/vs/editor/contrib/snippet/test/snippetParser.test.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/snippet/test/snippetParser.test.ts rename to src/vs/editor/contrib/snippet/test/snippetParser.test.ts index a9d41faf92f3..21438244b864 100644 --- a/lib/vscode/src/vs/editor/contrib/snippet/test/snippetParser.test.ts +++ b/src/vs/editor/contrib/snippet/test/snippetParser.test.ts @@ -655,6 +655,7 @@ suite('SnippetParser', () => { assert.strictEqual(new FormatString(1, 'capitalize').resolve('bar'), 'Bar'); assert.strictEqual(new FormatString(1, 'capitalize').resolve('bar no repeat'), 'Bar no repeat'); assert.strictEqual(new FormatString(1, 'pascalcase').resolve('bar-foo'), 'BarFoo'); + assert.strictEqual(new FormatString(1, 'pascalcase').resolve('bar-42-foo'), 'Bar42Foo'); assert.strictEqual(new FormatString(1, 'notKnown').resolve('input'), 'input'); // if diff --git a/lib/vscode/src/vs/editor/contrib/snippet/test/snippetSession.test.ts b/src/vs/editor/contrib/snippet/test/snippetSession.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/snippet/test/snippetSession.test.ts rename to src/vs/editor/contrib/snippet/test/snippetSession.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts b/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts rename to src/vs/editor/contrib/snippet/test/snippetVariables.test.ts diff --git a/lib/vscode/src/vs/editor/contrib/suggest/completionModel.ts b/src/vs/editor/contrib/suggest/completionModel.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/suggest/completionModel.ts rename to src/vs/editor/contrib/suggest/completionModel.ts diff --git a/lib/vscode/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css similarity index 99% rename from lib/vscode/src/vs/editor/contrib/suggest/media/suggest.css rename to src/vs/editor/contrib/suggest/media/suggest.css index 29fa4575fa9f..cf73d2720119 100644 --- a/lib/vscode/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -306,6 +306,10 @@ margin-right: 4px; } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused .suggest-icon { + color: inherit; +} + .monaco-editor .suggest-widget.no-icons .monaco-list .monaco-list-row .icon, .monaco-editor .suggest-widget.no-icons .monaco-list .monaco-list-row .suggest-icon::before { display: none; } diff --git a/lib/vscode/src/vs/editor/contrib/suggest/resizable.ts b/src/vs/editor/contrib/suggest/resizable.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/suggest/resizable.ts rename to src/vs/editor/contrib/suggest/resizable.ts index 88e1e73ed201..f0e7ead560e3 100644 --- a/lib/vscode/src/vs/editor/contrib/suggest/resizable.ts +++ b/src/vs/editor/contrib/suggest/resizable.ts @@ -121,6 +121,8 @@ export class ResizableHTMLElement { this._eastSash.dispose(); this._westSash.dispose(); this._sashListener.dispose(); + this._onDidResize.dispose(); + this._onDidWillResize.dispose(); this.domNode.remove(); } diff --git a/lib/vscode/src/vs/editor/contrib/suggest/suggest.ts b/src/vs/editor/contrib/suggest/suggest.ts similarity index 98% rename from lib/vscode/src/vs/editor/contrib/suggest/suggest.ts rename to src/vs/editor/contrib/suggest/suggest.ts index c8e46227448a..ec192ae88cfe 100644 --- a/lib/vscode/src/vs/editor/contrib/suggest/suggest.ts +++ b/src/vs/editor/contrib/suggest/suggest.ts @@ -155,6 +155,7 @@ export class CompletionOptions { readonly snippetSortOrder = SnippetSortOrder.Bottom, readonly kindFilter = new Set(), readonly providerFilter = new Set(), + readonly showDeprecated = true ) { } } @@ -216,6 +217,10 @@ export async function provideSuggestionItems( } for (let suggestion of container.suggestions) { if (!options.kindFilter.has(suggestion.kind)) { + // skip if not showing deprecated suggestions + if (!options.showDeprecated && suggestion?.tags?.includes(modes.CompletionItemTag.Deprecated)) { + continue; + } // fill in default range when missing if (!suggestion.range) { suggestion.range = defaultRange; diff --git a/lib/vscode/src/vs/editor/contrib/suggest/suggestAlternatives.ts b/src/vs/editor/contrib/suggest/suggestAlternatives.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/suggest/suggestAlternatives.ts rename to src/vs/editor/contrib/suggest/suggestAlternatives.ts diff --git a/lib/vscode/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts b/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts rename to src/vs/editor/contrib/suggest/suggestCommitCharacters.ts diff --git a/lib/vscode/src/vs/editor/contrib/suggest/suggestController.ts b/src/vs/editor/contrib/suggest/suggestController.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/suggest/suggestController.ts rename to src/vs/editor/contrib/suggest/suggestController.ts index bca0fd625576..eff083ad88c0 100644 --- a/lib/vscode/src/vs/editor/contrib/suggest/suggestController.ts +++ b/src/vs/editor/contrib/suggest/suggestController.ts @@ -61,7 +61,7 @@ class LineSuffix { const end = _model.getPositionAt(offset + 1); this._marker = _model.deltaDecorations([], [{ range: Range.fromPositions(_position, end), - options: { stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges } + options: { description: 'suggest-line-suffix', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges } }]); } } @@ -587,6 +587,14 @@ export class SuggestController implements IEditorContribution { resetWidgetSize(): void { this.widget.value.resetPersistedSize(); } + + forceRenderingAbove() { + this.widget.value.forceRenderingAbove(); + } + + stopForceRenderingAbove() { + this.widget.value.stopForceRenderingAbove(); + } } export class TriggerSuggestAction extends EditorAction { diff --git a/lib/vscode/src/vs/editor/contrib/suggest/suggestMemory.ts b/src/vs/editor/contrib/suggest/suggestMemory.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/suggest/suggestMemory.ts rename to src/vs/editor/contrib/suggest/suggestMemory.ts diff --git a/lib/vscode/src/vs/editor/contrib/suggest/suggestModel.ts b/src/vs/editor/contrib/suggest/suggestModel.ts similarity index 98% rename from lib/vscode/src/vs/editor/contrib/suggest/suggestModel.ts rename to src/vs/editor/contrib/suggest/suggestModel.ts index 747f78a4b4c8..1880ef1bd9d1 100644 --- a/lib/vscode/src/vs/editor/contrib/suggest/suggestModel.ts +++ b/src/vs/editor/contrib/suggest/suggestModel.ts @@ -428,13 +428,13 @@ export class SuggestModel implements IDisposable { break; } - const itemKindFilter = SuggestModel._createItemKindFilter(this._editor); + const { itemKind: itemKindFilter, showDeprecated } = SuggestModel._createSuggestFilter(this._editor); const wordDistance = WordDistance.create(this._editorWorkerService, this._editor); const completions = provideSuggestionItems( model, this._editor.getPosition(), - new CompletionOptions(snippetSortOrder, itemKindFilter, onlyFrom), + new CompletionOptions(snippetSortOrder, itemKindFilter, onlyFrom, showDeprecated), suggestCtx, this._requestToken.token ); @@ -502,7 +502,7 @@ export class SuggestModel implements IDisposable { }); } - private static _createItemKindFilter(editor: ICodeEditor): Set { + private static _createSuggestFilter(editor: ICodeEditor): { itemKind: Set; showDeprecated: boolean } { // kind filter and snippet sort rules const result = new Set(); @@ -543,7 +543,7 @@ export class SuggestModel implements IDisposable { if (!suggestOptions.showUsers) { result.add(CompletionItemKind.User); } if (!suggestOptions.showIssues) { result.add(CompletionItemKind.Issue); } - return result; + return { itemKind: result, showDeprecated: suggestOptions.showDeprecated }; } private _onNewContext(ctx: LineContext): void { diff --git a/lib/vscode/src/vs/editor/contrib/suggest/suggestOvertypingCapturer.ts b/src/vs/editor/contrib/suggest/suggestOvertypingCapturer.ts similarity index 100% rename from lib/vscode/src/vs/editor/contrib/suggest/suggestOvertypingCapturer.ts rename to src/vs/editor/contrib/suggest/suggestOvertypingCapturer.ts diff --git a/lib/vscode/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts similarity index 95% rename from lib/vscode/src/vs/editor/contrib/suggest/suggestWidget.ts rename to src/vs/editor/contrib/suggest/suggestWidget.ts index 8e0171cfac7f..2bcba6043b01 100644 --- a/lib/vscode/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -21,7 +21,7 @@ import { Context as SuggestContext, CompletionItem } from './suggest'; import { CompletionModel } from './completionModel'; import { attachListStyler } from 'vs/platform/theme/common/styler'; import { IThemeService, IColorTheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { registerColor, editorWidgetBackground, quickInputListFocusBackground, activeContrastBorder, listHighlightForeground, editorForeground, editorWidgetBorder, focusBorder, textLinkForeground, textCodeBlockBackground } from 'vs/platform/theme/common/colorRegistry'; +import { registerColor, editorWidgetBackground, quickInputListFocusBackground, activeContrastBorder, listHighlightForeground, editorForeground, editorWidgetBorder, focusBorder, textLinkForeground, textCodeBlockBackground, quickInputListFocusForeground, listFocusHighlightForeground } from 'vs/platform/theme/common/colorRegistry'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { TimeoutTimer, CancelablePromise, createCancelablePromise, disposableTimeout } from 'vs/base/common/async'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -40,8 +40,10 @@ import { clamp } from 'vs/base/common/numbers'; export const editorSuggestWidgetBackground = registerColor('editorSuggestWidget.background', { dark: editorWidgetBackground, light: editorWidgetBackground, hc: editorWidgetBackground }, nls.localize('editorSuggestWidgetBackground', 'Background color of the suggest widget.')); export const editorSuggestWidgetBorder = registerColor('editorSuggestWidget.border', { dark: editorWidgetBorder, light: editorWidgetBorder, hc: editorWidgetBorder }, nls.localize('editorSuggestWidgetBorder', 'Border color of the suggest widget.')); export const editorSuggestWidgetForeground = registerColor('editorSuggestWidget.foreground', { dark: editorForeground, light: editorForeground, hc: editorForeground }, nls.localize('editorSuggestWidgetForeground', 'Foreground color of the suggest widget.')); +export const editorSuggestWidgetSelectedForeground = registerColor('editorSuggestWidget.selectedForeground', { dark: quickInputListFocusForeground, light: quickInputListFocusForeground, hc: quickInputListFocusForeground }, nls.localize('editorSuggestWidgetSelectedForeground', 'Foreground color of the selected entry in the suggest widget.')); export const editorSuggestWidgetSelectedBackground = registerColor('editorSuggestWidget.selectedBackground', { dark: quickInputListFocusBackground, light: quickInputListFocusBackground, hc: quickInputListFocusBackground }, nls.localize('editorSuggestWidgetSelectedBackground', 'Background color of the selected entry in the suggest widget.')); export const editorSuggestWidgetHighlightForeground = registerColor('editorSuggestWidget.highlightForeground', { dark: listHighlightForeground, light: listHighlightForeground, hc: listHighlightForeground }, nls.localize('editorSuggestWidgetHighlightForeground', 'Color of the match highlights in the suggest widget.')); +export const editorSuggestWidgetHighlightFocusForeground = registerColor('editorSuggestWidget.focusHighlightForeground', { dark: listFocusHighlightForeground, light: listFocusHighlightForeground, hc: listFocusHighlightForeground }, nls.localize('editorSuggestWidgetFocusHighlightForeground', 'Color of the match highlights in the suggest widget when an item is focused.')); const enum State { Hidden, @@ -104,6 +106,7 @@ export class SuggestWidget implements IDisposable { private _ignoreFocusEvents: boolean = false; private _completionModel?: CompletionModel; private _cappedHeight?: { wanted: number; capped: number; }; + private _forceRenderingAbove: boolean = false; private _explainMode: boolean = false; readonly element: ResizableHTMLElement; @@ -804,7 +807,7 @@ export class SuggestWidget implements IDisposable { height = maxHeight; } - if (height > maxHeightBelow) { + if (height > maxHeightBelow || this._forceRenderingAbove) { this._contentWidget.setPreference(ContentWidgetPositionPreference.ABOVE); this.element.enableSashes(true, true, false, false); maxHeight = maxHeightAbove; @@ -875,6 +878,17 @@ export class SuggestWidget implements IDisposable { private _setDetailsVisible(value: boolean) { this._storageService.store('expandSuggestionDocs', value, StorageScope.GLOBAL, StorageTarget.USER); } + + forceRenderingAbove() { + if (!this._forceRenderingAbove) { + this._forceRenderingAbove = true; + this._layout(this._persistedSize.restore()); + } + } + + stopForceRenderingAbove() { + this._forceRenderingAbove = false; + } } export class SuggestContentWidget implements IContentWidget { @@ -972,11 +986,22 @@ registerThemingParticipant((theme, collector) => { if (matchHighlight) { collector.addRule(`.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-highlighted-label .highlight { color: ${matchHighlight}; }`); } + + const matchHighlightFocus = theme.getColor(editorSuggestWidgetHighlightFocusForeground); + if (matchHighlight) { + collector.addRule(`.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused .monaco-highlighted-label .highlight { color: ${matchHighlightFocus}; }`); + } + const foreground = theme.getColor(editorSuggestWidgetForeground); if (foreground) { collector.addRule(`.monaco-editor .suggest-widget, .monaco-editor .suggest-details { color: ${foreground}; }`); } + const selectedForeground = theme.getColor(editorSuggestWidgetSelectedForeground); + if (selectedForeground) { + collector.addRule(`.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused { color: ${selectedForeground}; }`); + } + const link = theme.getColor(textLinkForeground); if (link) { collector.addRule(`.monaco-editor .suggest-details a { color: ${link}; }`); diff --git a/lib/vscode/src/vs/editor/contrib/suggest/suggestWidgetDetails.ts b/src/vs/editor/contrib/suggest/suggestWidgetDetails.ts similarity index 99% rename from lib/vscode/src/vs/editor/contrib/suggest/suggestWidgetDetails.ts rename to src/vs/editor/contrib/suggest/suggestWidgetDetails.ts index 2734906e876f..148e2b97d1c1 100644 --- a/lib/vscode/src/vs/editor/contrib/suggest/suggestWidgetDetails.ts +++ b/src/vs/editor/contrib/suggest/suggestWidgetDetails.ts @@ -320,6 +320,7 @@ export class SuggestDetailsOverlay implements IOverlayWidget { } dispose(): void { + this._resizable.dispose(); this._disposables.dispose(); this.hide(); } diff --git a/lib/vscode/src/vs/editor/contrib/suggest/suggestWidgetRenderer.ts b/src/vs/editor/contrib/suggest/suggestWidgetRenderer.ts similarity index 95% rename from lib/vscode/src/vs/editor/contrib/suggest/suggestWidgetRenderer.ts rename to src/vs/editor/contrib/suggest/suggestWidgetRenderer.ts index a3763880de2a..0eae16979859 100644 --- a/lib/vscode/src/vs/editor/contrib/suggest/suggestWidgetRenderer.ts +++ b/src/vs/editor/contrib/suggest/suggestWidgetRenderer.ts @@ -209,13 +209,13 @@ export class ItemRenderer implements IListRenderer this.update())); this.update(); } diff --git a/lib/vscode/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-dark.svg b/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-dark.svg similarity index 100% rename from lib/vscode/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-dark.svg rename to src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-dark.svg diff --git a/lib/vscode/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-light.svg b/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-light.svg similarity index 100% rename from lib/vscode/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-light.svg rename to src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-light.svg diff --git a/lib/vscode/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.css b/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.css similarity index 100% rename from lib/vscode/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.css rename to src/vs/editor/standalone/browser/inspectTokens/inspectTokens.css diff --git a/lib/vscode/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts b/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts similarity index 100% rename from lib/vscode/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts rename to src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts diff --git a/lib/vscode/src/vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess.ts b/src/vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess.ts similarity index 93% rename from lib/vscode/src/vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess.ts rename to src/vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess.ts index f4839b34f218..97c3244e8912 100644 --- a/lib/vscode/src/vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess.ts +++ b/src/vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess.ts @@ -15,7 +15,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { EditorAction, registerEditorAction } from 'vs/editor/browser/editorExtensions'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { KeyCode } from 'vs/base/common/keyCodes'; @@ -32,9 +32,9 @@ export class StandaloneCommandsQuickAccessProvider extends AbstractEditorCommand @IKeybindingService keybindingService: IKeybindingService, @ICommandService commandService: ICommandService, @ITelemetryService telemetryService: ITelemetryService, - @INotificationService notificationService: INotificationService + @IDialogService dialogService: IDialogService ) { - super({ showAlias: false }, instantiationService, keybindingService, commandService, telemetryService, notificationService); + super({ showAlias: false }, instantiationService, keybindingService, commandService, telemetryService, dialogService); } protected async getCommandPicks(): Promise> { diff --git a/lib/vscode/src/vs/editor/standalone/browser/quickAccess/standaloneGotoLineQuickAccess.ts b/src/vs/editor/standalone/browser/quickAccess/standaloneGotoLineQuickAccess.ts similarity index 100% rename from lib/vscode/src/vs/editor/standalone/browser/quickAccess/standaloneGotoLineQuickAccess.ts rename to src/vs/editor/standalone/browser/quickAccess/standaloneGotoLineQuickAccess.ts diff --git a/lib/vscode/src/vs/editor/standalone/browser/quickAccess/standaloneGotoSymbolQuickAccess.ts b/src/vs/editor/standalone/browser/quickAccess/standaloneGotoSymbolQuickAccess.ts similarity index 100% rename from lib/vscode/src/vs/editor/standalone/browser/quickAccess/standaloneGotoSymbolQuickAccess.ts rename to src/vs/editor/standalone/browser/quickAccess/standaloneGotoSymbolQuickAccess.ts diff --git a/lib/vscode/src/vs/editor/standalone/browser/quickAccess/standaloneHelpQuickAccess.ts b/src/vs/editor/standalone/browser/quickAccess/standaloneHelpQuickAccess.ts similarity index 100% rename from lib/vscode/src/vs/editor/standalone/browser/quickAccess/standaloneHelpQuickAccess.ts rename to src/vs/editor/standalone/browser/quickAccess/standaloneHelpQuickAccess.ts diff --git a/lib/vscode/src/vs/editor/standalone/browser/quickInput/standaloneQuickInput.css b/src/vs/editor/standalone/browser/quickInput/standaloneQuickInput.css similarity index 88% rename from lib/vscode/src/vs/editor/standalone/browser/quickInput/standaloneQuickInput.css rename to src/vs/editor/standalone/browser/quickInput/standaloneQuickInput.css index f2d4dbcecb2b..c48737cfaf48 100644 --- a/lib/vscode/src/vs/editor/standalone/browser/quickInput/standaloneQuickInput.css +++ b/src/vs/editor/standalone/browser/quickInput/standaloneQuickInput.css @@ -12,6 +12,11 @@ color: #0066BF; } +.vs .quick-input-widget .monaco-list-row.focused .monaco-highlighted-label .highlight, +.vs .quick-input-widget .monaco-list-row.focused .monaco-highlighted-label .highlight { + color: #9DDDFF; +} + .vs-dark .quick-input-widget .monaco-highlighted-label .highlight, .vs-dark .quick-input-widget .monaco-highlighted-label .highlight { color: #0097fb; diff --git a/lib/vscode/src/vs/editor/standalone/browser/quickInput/standaloneQuickInputServiceImpl.ts b/src/vs/editor/standalone/browser/quickInput/standaloneQuickInputServiceImpl.ts similarity index 100% rename from lib/vscode/src/vs/editor/standalone/browser/quickInput/standaloneQuickInputServiceImpl.ts rename to src/vs/editor/standalone/browser/quickInput/standaloneQuickInputServiceImpl.ts diff --git a/lib/vscode/src/vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch.ts b/src/vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch.ts similarity index 100% rename from lib/vscode/src/vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch.ts rename to src/vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch.ts diff --git a/lib/vscode/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts similarity index 100% rename from lib/vscode/src/vs/editor/standalone/browser/simpleServices.ts rename to src/vs/editor/standalone/browser/simpleServices.ts diff --git a/lib/vscode/src/vs/editor/standalone/browser/standalone-tokens.css b/src/vs/editor/standalone/browser/standalone-tokens.css similarity index 100% rename from lib/vscode/src/vs/editor/standalone/browser/standalone-tokens.css rename to src/vs/editor/standalone/browser/standalone-tokens.css diff --git a/lib/vscode/src/vs/editor/standalone/browser/standaloneCodeEditor.ts b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts similarity index 97% rename from lib/vscode/src/vs/editor/standalone/browser/standaloneCodeEditor.ts rename to src/vs/editor/standalone/browser/standaloneCodeEditor.ts index 89dff41d626b..77884d5ffde9 100644 --- a/lib/vscode/src/vs/editor/standalone/browser/standaloneCodeEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts @@ -34,6 +34,7 @@ import { StandaloneThemeServiceImpl } from 'vs/editor/standalone/browser/standal import { IModelService } from 'vs/editor/common/services/modelService'; import { ILanguageSelection, IModeService } from 'vs/editor/common/services/modeService'; import { URI } from 'vs/base/common/uri'; +import { StandaloneCodeEditorServiceImpl } from 'vs/editor/standalone/browser/standaloneCodeServiceImpl'; /** * Description of an action contribution @@ -363,6 +364,20 @@ export class StandaloneCodeEditor extends CodeEditorWidget implements IStandalon return toDispose; } + + protected override _triggerCommand(handlerId: string, payload: any): void { + if (this._codeEditorService instanceof StandaloneCodeEditorServiceImpl) { + // Help commands find this editor as the active editor + try { + this._codeEditorService.setActiveCodeEditor(this); + super._triggerCommand(handlerId, payload); + } finally { + this._codeEditorService.setActiveCodeEditor(null); + } + } else { + super._triggerCommand(handlerId, payload); + } + } } export class StandaloneEditor extends StandaloneCodeEditor implements IStandaloneCodeEditor { diff --git a/lib/vscode/src/vs/editor/standalone/browser/standaloneCodeServiceImpl.ts b/src/vs/editor/standalone/browser/standaloneCodeServiceImpl.ts similarity index 88% rename from lib/vscode/src/vs/editor/standalone/browser/standaloneCodeServiceImpl.ts rename to src/vs/editor/standalone/browser/standaloneCodeServiceImpl.ts index f7808cfa6fc4..8bc8c9d7c103 100644 --- a/lib/vscode/src/vs/editor/standalone/browser/standaloneCodeServiceImpl.ts +++ b/src/vs/editor/standalone/browser/standaloneCodeServiceImpl.ts @@ -12,12 +12,13 @@ import { IRange } from 'vs/editor/common/core/range'; import { ScrollType } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IResourceEditorInput } from 'vs/platform/editor/common/editor'; +import { IResourceEditorInput, ITextResourceEditorInput } from 'vs/platform/editor/common/editor'; import { IThemeService } from 'vs/platform/theme/common/themeService'; export class StandaloneCodeEditorServiceImpl extends CodeEditorServiceImpl { private readonly _editorIsOpen: IContextKey; + private _activeCodeEditor: ICodeEditor | null; constructor( styleSheet: GlobalStyleSheet | null, @@ -28,6 +29,7 @@ export class StandaloneCodeEditorServiceImpl extends CodeEditorServiceImpl { this.onCodeEditorAdd(() => this._checkContextKey()); this.onCodeEditorRemove(() => this._checkContextKey()); this._editorIsOpen = contextKeyService.createKey('editorIsOpen', false); + this._activeCodeEditor = null; } private _checkContextKey(): void { @@ -41,8 +43,12 @@ export class StandaloneCodeEditorServiceImpl extends CodeEditorServiceImpl { this._editorIsOpen.set(hasCodeEditor); } + public setActiveCodeEditor(activeCodeEditor: ICodeEditor | null): void { + this._activeCodeEditor = activeCodeEditor; + } + public getActiveCodeEditor(): ICodeEditor | null { - return null; // not supported in the standalone case + return this._activeCodeEditor; } public openCodeEditor(input: IResourceEditorInput, source: ICodeEditor | null, sideBySide?: boolean): Promise { @@ -53,7 +59,7 @@ export class StandaloneCodeEditorServiceImpl extends CodeEditorServiceImpl { return Promise.resolve(this.doOpenEditor(source, input)); } - private doOpenEditor(editor: ICodeEditor, input: IResourceEditorInput): ICodeEditor | null { + private doOpenEditor(editor: ICodeEditor, input: ITextResourceEditorInput): ICodeEditor | null { const model = this.findModel(editor, input.resource); if (!model) { if (input.resource) { diff --git a/lib/vscode/src/vs/editor/standalone/browser/standaloneEditor.ts b/src/vs/editor/standalone/browser/standaloneEditor.ts similarity index 100% rename from lib/vscode/src/vs/editor/standalone/browser/standaloneEditor.ts rename to src/vs/editor/standalone/browser/standaloneEditor.ts diff --git a/lib/vscode/src/vs/editor/standalone/browser/standaloneLanguages.ts b/src/vs/editor/standalone/browser/standaloneLanguages.ts similarity index 98% rename from lib/vscode/src/vs/editor/standalone/browser/standaloneLanguages.ts rename to src/vs/editor/standalone/browser/standaloneLanguages.ts index dc1125f7f3a8..e4b78662521a 100644 --- a/lib/vscode/src/vs/editor/standalone/browser/standaloneLanguages.ts +++ b/src/vs/editor/standalone/browser/standaloneLanguages.ts @@ -547,6 +547,13 @@ export function registerDocumentRangeSemanticTokensProvider(languageId: string, return modes.DocumentRangeSemanticTokensProviderRegistry.register(languageId, provider); } +/** + * Register an inline completions provider. + */ +export function registerInlineCompletionsProvider(languageId: string, provider: modes.InlineCompletionsProvider): IDisposable { + return modes.InlineCompletionsProviderRegistry.register(languageId, provider); +} + /** * Contains additional diagnostic information about the context in which * a [code action](#CodeActionProvider.provideCodeActions) is run. @@ -613,6 +620,7 @@ export function createMonacoLanguagesAPI(): typeof monaco.languages { registerSelectionRangeProvider: registerSelectionRangeProvider, registerDocumentSemanticTokensProvider: registerDocumentSemanticTokensProvider, registerDocumentRangeSemanticTokensProvider: registerDocumentRangeSemanticTokensProvider, + registerInlineCompletionsProvider: registerInlineCompletionsProvider, // enums DocumentHighlightKind: standaloneEnums.DocumentHighlightKind, @@ -624,7 +632,8 @@ export function createMonacoLanguagesAPI(): typeof monaco.languages { IndentAction: standaloneEnums.IndentAction, CompletionTriggerKind: standaloneEnums.CompletionTriggerKind, SignatureHelpTriggerKind: standaloneEnums.SignatureHelpTriggerKind, - InlineHintKind: standaloneEnums.InlineHintKind, + InlayHintKind: standaloneEnums.InlayHintKind, + InlineCompletionTriggerKind: standaloneEnums.InlineCompletionTriggerKind, // classes FoldingRangeKind: modes.FoldingRangeKind, diff --git a/lib/vscode/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts similarity index 100% rename from lib/vscode/src/vs/editor/standalone/browser/standaloneServices.ts rename to src/vs/editor/standalone/browser/standaloneServices.ts diff --git a/lib/vscode/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts similarity index 99% rename from lib/vscode/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts rename to src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts index 180961e72fdb..ece509fa0d03 100644 --- a/lib/vscode/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts +++ b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts @@ -233,7 +233,7 @@ export class StandaloneThemeServiceImpl extends Disposable implements IStandalon this._updateCSS(); }); - window.matchMedia('(forced-colors: active)').addEventListener('change', () => { + dom.addMatchMediaChangeListener('(forced-colors: active)', () => { this._updateActualTheme(); }); } diff --git a/lib/vscode/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts b/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts similarity index 100% rename from lib/vscode/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts rename to src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts diff --git a/lib/vscode/src/vs/editor/standalone/common/monarch/monarchCommon.ts b/src/vs/editor/standalone/common/monarch/monarchCommon.ts similarity index 100% rename from lib/vscode/src/vs/editor/standalone/common/monarch/monarchCommon.ts rename to src/vs/editor/standalone/common/monarch/monarchCommon.ts diff --git a/lib/vscode/src/vs/editor/standalone/common/monarch/monarchCompile.ts b/src/vs/editor/standalone/common/monarch/monarchCompile.ts similarity index 98% rename from lib/vscode/src/vs/editor/standalone/common/monarch/monarchCompile.ts rename to src/vs/editor/standalone/common/monarch/monarchCompile.ts index 1357baefea74..04dc7241beba 100644 --- a/lib/vscode/src/vs/editor/standalone/common/monarch/monarchCompile.ts +++ b/src/vs/editor/standalone/common/monarch/monarchCompile.ts @@ -86,15 +86,14 @@ function createKeywordMatcher(arr: string[], caseInsensitive: boolean = false): * @example /@@text/ will not be replaced and will become /@text/. */ function compileRegExp(lexer: monarchCommon.ILexerMin, str: string): RegExp { + // @@ must be interpreted as a literal @, so we replace all occurences of @@ with a placeholder character + str = str.replace(/@@/g, `\x01`); + let n = 0; let hadExpansion: boolean; do { hadExpansion = false; - str = str.replace(/(.|^)@(\w+)/g, function (s, charBeforeAtSign, attr?) { - if (charBeforeAtSign === '@') { - // do not expand @@ - return s; - } + str = str.replace(/@(\w+)/g, function (s, attr?) { hadExpansion = true; let sub = ''; if (typeof (lexer[attr]) === 'string') { @@ -108,13 +107,13 @@ function compileRegExp(lexer: monarchCommon.ILexerMin, str: string): RegExp { throw monarchCommon.createError(lexer, 'attribute reference \'' + attr + '\' must be a string, used at: ' + str); } } - return charBeforeAtSign + (monarchCommon.empty(sub) ? '' : '(?:' + sub + ')'); + return (monarchCommon.empty(sub) ? '' : '(?:' + sub + ')'); }); n++; } while (hadExpansion && n < 5); // handle escaped @@ - str = str.replace(/@@/g, '@'); + str = str.replace(/\x01/g, '@'); let flags = (lexer.ignoreCase ? 'i' : '') + (lexer.unicode ? 'u' : ''); return new RegExp(str, flags); diff --git a/lib/vscode/src/vs/editor/standalone/common/monarch/monarchLexer.ts b/src/vs/editor/standalone/common/monarch/monarchLexer.ts similarity index 100% rename from lib/vscode/src/vs/editor/standalone/common/monarch/monarchLexer.ts rename to src/vs/editor/standalone/common/monarch/monarchLexer.ts diff --git a/lib/vscode/src/vs/editor/standalone/common/monarch/monarchTypes.ts b/src/vs/editor/standalone/common/monarch/monarchTypes.ts similarity index 100% rename from lib/vscode/src/vs/editor/standalone/common/monarch/monarchTypes.ts rename to src/vs/editor/standalone/common/monarch/monarchTypes.ts diff --git a/lib/vscode/src/vs/editor/standalone/common/standaloneThemeService.ts b/src/vs/editor/standalone/common/standaloneThemeService.ts similarity index 100% rename from lib/vscode/src/vs/editor/standalone/common/standaloneThemeService.ts rename to src/vs/editor/standalone/common/standaloneThemeService.ts diff --git a/lib/vscode/src/vs/editor/standalone/common/themes.ts b/src/vs/editor/standalone/common/themes.ts similarity index 97% rename from lib/vscode/src/vs/editor/standalone/common/themes.ts rename to src/vs/editor/standalone/common/themes.ts index 9e07df46bac5..cf0b7945091e 100644 --- a/lib/vscode/src/vs/editor/standalone/common/themes.ts +++ b/src/vs/editor/standalone/common/themes.ts @@ -5,7 +5,7 @@ import { editorActiveIndentGuides, editorIndentGuides } from 'vs/editor/common/view/editorColorRegistry'; import { IStandaloneThemeData } from 'vs/editor/standalone/common/standaloneThemeService'; -import { editorBackground, editorForeground, editorInactiveSelection, editorSelectionHighlight } from 'vs/platform/theme/common/colorRegistry'; +import { editorBackground, editorForeground, editorInactiveSelection, editorSelectionHighlight, listFocusHighlightForeground } from 'vs/platform/theme/common/colorRegistry'; /* -------------------------------- Begin vs theme -------------------------------- */ export const vs: IStandaloneThemeData = { @@ -73,7 +73,8 @@ export const vs: IStandaloneThemeData = { [editorInactiveSelection]: '#E5EBF1', [editorIndentGuides]: '#D3D3D3', [editorActiveIndentGuides]: '#939393', - [editorSelectionHighlight]: '#ADD6FF4D' + [editorSelectionHighlight]: '#ADD6FF4D', + [listFocusHighlightForeground]: '#9DDDFF' } }; /* -------------------------------- End vs theme -------------------------------- */ diff --git a/lib/vscode/src/vs/editor/standalone/test/browser/simpleServices.test.ts b/src/vs/editor/standalone/test/browser/simpleServices.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/standalone/test/browser/simpleServices.test.ts rename to src/vs/editor/standalone/test/browser/simpleServices.test.ts diff --git a/lib/vscode/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts b/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts rename to src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts diff --git a/lib/vscode/src/vs/editor/standalone/test/monarch/monarch.test.ts b/src/vs/editor/standalone/test/monarch/monarch.test.ts similarity index 93% rename from lib/vscode/src/vs/editor/standalone/test/monarch/monarch.test.ts rename to src/vs/editor/standalone/test/monarch/monarch.test.ts index fd57288fdca7..95686726d7e2 100644 --- a/lib/vscode/src/vs/editor/standalone/test/monarch/monarch.test.ts +++ b/src/vs/editor/standalone/test/monarch/monarch.test.ts @@ -264,4 +264,31 @@ suite('Monarch', () => { ]); }); + test('microsoft/monaco-editor#2424: Allow to target @@', () => { + const modeService = new ModeServiceImpl(); + + const tokenizer = createMonarchTokenizer(modeService, 'test', { + ignoreCase: false, + tokenizer: { + root: [ + { + regex: /@@@@/, + action: { token: 'ham' } + }, + ], + }, + }); + + const lines = [ + `@@` + ]; + + const actualTokens = getTokens(tokenizer, lines); + assert.deepStrictEqual(actualTokens, [ + [ + new Token(0, 'ham.test', 'test'), + ] + ]); + }); + }); diff --git a/lib/vscode/src/vs/editor/test/browser/commands/shiftCommand.test.ts b/src/vs/editor/test/browser/commands/shiftCommand.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/browser/commands/shiftCommand.test.ts rename to src/vs/editor/test/browser/commands/shiftCommand.test.ts diff --git a/lib/vscode/src/vs/editor/test/browser/commands/sideEditing.test.ts b/src/vs/editor/test/browser/commands/sideEditing.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/browser/commands/sideEditing.test.ts rename to src/vs/editor/test/browser/commands/sideEditing.test.ts diff --git a/lib/vscode/src/vs/editor/test/browser/commands/trimTrailingWhitespaceCommand.test.ts b/src/vs/editor/test/browser/commands/trimTrailingWhitespaceCommand.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/browser/commands/trimTrailingWhitespaceCommand.test.ts rename to src/vs/editor/test/browser/commands/trimTrailingWhitespaceCommand.test.ts diff --git a/lib/vscode/src/vs/editor/test/browser/controller/cursor.test.ts b/src/vs/editor/test/browser/controller/cursor.test.ts similarity index 96% rename from lib/vscode/src/vs/editor/test/browser/controller/cursor.test.ts rename to src/vs/editor/test/browser/controller/cursor.test.ts index c5e45cc8351b..b490ef71c792 100644 --- a/lib/vscode/src/vs/editor/test/browser/controller/cursor.test.ts +++ b/src/vs/editor/test/browser/controller/cursor.test.ts @@ -2608,6 +2608,186 @@ suite('Editor Controller - Regression tests', () => { model.dispose(); }); + + test('issue #122914: Left delete behavior in some languages is changed (useTabStops: false)', () => { + let model = createTextModel( + [ + 'สวัสดี' + ].join('\n') + ); + + withTestCodeEditor(null, { model: model, useTabStops: false }, (editor, viewModel) => { + editor.setSelections([ + new Selection(1, 7, 1, 7) + ]); + + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.strictEqual(model.getValue(EndOfLinePreference.LF), 'สวัสด'); + + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.strictEqual(model.getValue(EndOfLinePreference.LF), 'สวัส'); + + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.strictEqual(model.getValue(EndOfLinePreference.LF), 'สวั'); + + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.strictEqual(model.getValue(EndOfLinePreference.LF), 'สว'); + + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.strictEqual(model.getValue(EndOfLinePreference.LF), 'ส'); + + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.strictEqual(model.getValue(EndOfLinePreference.LF), ''); + }); + + model.dispose(); + }); + + test('issue #99629: Emoji modifiers in text treated separately when using backspace', () => { + const model = createTextModel( + [ + '👶🏾' + ].join('\n') + ); + + withTestCodeEditor(null, { model: model, useTabStops: false }, (editor, viewModel) => { + const len = model.getValueLength(); + editor.setSelections([ + new Selection(1, 1 + len, 1, 1 + len) + ]); + + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.strictEqual(model.getValue(EndOfLinePreference.LF), ''); + }); + + model.dispose(); + }); + + test('issue #99629: Emoji modifiers in text treated separately when using backspace (ZWJ sequence)', () => { + let model = createTextModel( + [ + '👨‍👩🏽‍👧‍👦' + ].join('\n') + ); + + withTestCodeEditor(null, { model: model, useTabStops: false }, (editor, viewModel) => { + const len = model.getValueLength(); + editor.setSelections([ + new Selection(1, 1 + len, 1, 1 + len) + ]); + + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.strictEqual(model.getValue(EndOfLinePreference.LF), '👨‍👩🏽‍👧'); + + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.strictEqual(model.getValue(EndOfLinePreference.LF), '👨‍👩🏽'); + + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.strictEqual(model.getValue(EndOfLinePreference.LF), '👨'); + + CoreEditingCommands.DeleteLeft.runEditorCommand(null, editor, null); + assert.strictEqual(model.getValue(EndOfLinePreference.LF), ''); + }); + + model.dispose(); + }); + + test('issue #105730: move left behaves differently for multiple cursors', () => { + const model = createTextModel('asdfghjkl, asdfghjkl, asdfghjkl, '); + + withTestCodeEditor( + null, + { + model: model, + wordWrap: 'wordWrapColumn', + wordWrapColumn: 24 + }, + (editor, viewModel) => { + viewModel.setSelections('test', [ + new Selection(1, 10, 1, 12), + new Selection(1, 21, 1, 23), + new Selection(1, 32, 1, 34) + ]); + moveLeft(editor, viewModel, false); + assertCursor(viewModel, [ + new Selection(1, 10, 1, 10), + new Selection(1, 21, 1, 21), + new Selection(1, 32, 1, 32) + ]); + + viewModel.setSelections('test', [ + new Selection(1, 10, 1, 12), + new Selection(1, 21, 1, 23), + new Selection(1, 32, 1, 34) + ]); + moveLeft(editor, viewModel, true); + assertCursor(viewModel, [ + new Selection(1, 10, 1, 11), + new Selection(1, 21, 1, 22), + new Selection(1, 32, 1, 33) + ]); + }); + }); + + test('issue #105730: move right should always skip wrap point', () => { + const model = createTextModel('asdfghjkl, asdfghjkl, asdfghjkl, \nasdfghjkl,'); + + withTestCodeEditor( + null, + { + model: model, + wordWrap: 'wordWrapColumn', + wordWrapColumn: 24 + }, + (editor, viewModel) => { + viewModel.setSelections('test', [ + new Selection(1, 22, 1, 22) + ]); + moveRight(editor, viewModel, false); + moveRight(editor, viewModel, false); + assertCursor(viewModel, [ + new Selection(1, 24, 1, 24), + ]); + + viewModel.setSelections('test', [ + new Selection(1, 22, 1, 22) + ]); + moveRight(editor, viewModel, true); + moveRight(editor, viewModel, true); + assertCursor(viewModel, [ + new Selection(1, 22, 1, 24), + ]); + } + ); + }); + + test('issue #123178: sticky tab in consecutive wrapped lines', () => { + const model = createTextModel(' aaaa aaaa', { tabSize: 4 }); + + withTestCodeEditor( + null, + { + model: model, + wordWrap: 'wordWrapColumn', + wordWrapColumn: 8, + stickyTabStops: true, + }, + (editor, viewModel) => { + viewModel.setSelections('test', [ + new Selection(1, 9, 1, 9) + ]); + moveRight(editor, viewModel, false); + assertCursor(viewModel, [ + new Selection(1, 10, 1, 10), + ]); + + moveLeft(editor, viewModel, false); + assertCursor(viewModel, [ + new Selection(1, 9, 1, 9), + ]); + } + ); + }); }); suite('Editor Controller - Cursor Configuration', () => { @@ -6103,4 +6283,62 @@ suite('Undo stops', () => { assert.strictEqual(model.getValue(), 'hello world\nhello world'); }); }); + + test('there is a single undo stop for consecutive whitespaces', () => { + let model = createTextModel( + [ + '' + ].join('\n'), + { + insertSpaces: false, + } + ); + + withTestCodeEditor(null, { model: model }, (editor, viewModel) => { + viewModel.type('a', 'keyboard'); + viewModel.type('b', 'keyboard'); + viewModel.type(' ', 'keyboard'); + viewModel.type(' ', 'keyboard'); + viewModel.type('c', 'keyboard'); + viewModel.type('d', 'keyboard'); + + assert.strictEqual(model.getValue(EndOfLinePreference.LF), 'ab cd', 'assert1'); + + CoreEditingCommands.Undo.runEditorCommand(null, editor, null); + assert.strictEqual(model.getValue(EndOfLinePreference.LF), 'ab ', 'assert2'); + + CoreEditingCommands.Undo.runEditorCommand(null, editor, null); + assert.strictEqual(model.getValue(EndOfLinePreference.LF), 'ab', 'assert3'); + + CoreEditingCommands.Undo.runEditorCommand(null, editor, null); + assert.strictEqual(model.getValue(EndOfLinePreference.LF), '', 'assert4'); + }); + }); + + test('there is no undo stop after a single whitespace', () => { + let model = createTextModel( + [ + '' + ].join('\n'), + { + insertSpaces: false, + } + ); + + withTestCodeEditor(null, { model: model }, (editor, viewModel) => { + viewModel.type('a', 'keyboard'); + viewModel.type('b', 'keyboard'); + viewModel.type(' ', 'keyboard'); + viewModel.type('c', 'keyboard'); + viewModel.type('d', 'keyboard'); + + assert.strictEqual(model.getValue(EndOfLinePreference.LF), 'ab cd', 'assert1'); + + CoreEditingCommands.Undo.runEditorCommand(null, editor, null); + assert.strictEqual(model.getValue(EndOfLinePreference.LF), 'ab', 'assert3'); + + CoreEditingCommands.Undo.runEditorCommand(null, editor, null); + assert.strictEqual(model.getValue(EndOfLinePreference.LF), '', 'assert4'); + }); + }); }); diff --git a/lib/vscode/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts b/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts rename to src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts diff --git a/lib/vscode/src/vs/editor/test/browser/controller/imeTester.html b/src/vs/editor/test/browser/controller/imeTester.html similarity index 100% rename from lib/vscode/src/vs/editor/test/browser/controller/imeTester.html rename to src/vs/editor/test/browser/controller/imeTester.html diff --git a/lib/vscode/src/vs/editor/test/browser/controller/imeTester.ts b/src/vs/editor/test/browser/controller/imeTester.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/browser/controller/imeTester.ts rename to src/vs/editor/test/browser/controller/imeTester.ts diff --git a/lib/vscode/src/vs/editor/test/browser/controller/inputRecorder.html b/src/vs/editor/test/browser/controller/inputRecorder.html similarity index 100% rename from lib/vscode/src/vs/editor/test/browser/controller/inputRecorder.html rename to src/vs/editor/test/browser/controller/inputRecorder.html diff --git a/lib/vscode/src/vs/editor/test/browser/controller/textAreaState.test.ts b/src/vs/editor/test/browser/controller/textAreaState.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/browser/controller/textAreaState.test.ts rename to src/vs/editor/test/browser/controller/textAreaState.test.ts diff --git a/lib/vscode/src/vs/editor/test/browser/core/editorState.test.ts b/src/vs/editor/test/browser/core/editorState.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/browser/core/editorState.test.ts rename to src/vs/editor/test/browser/core/editorState.test.ts diff --git a/lib/vscode/src/vs/editor/test/browser/editorTestServices.ts b/src/vs/editor/test/browser/editorTestServices.ts similarity index 92% rename from lib/vscode/src/vs/editor/test/browser/editorTestServices.ts rename to src/vs/editor/test/browser/editorTestServices.ts index 55ceb3734a21..f69b4a613161 100644 --- a/lib/vscode/src/vs/editor/test/browser/editorTestServices.ts +++ b/src/vs/editor/test/browser/editorTestServices.ts @@ -19,9 +19,9 @@ export class TestCodeEditorService extends AbstractCodeEditorService { this.lastInput = input; return Promise.resolve(null); } - public registerDecorationType(key: string, options: IDecorationRenderOptions, parentTypeKey?: string): void { } + public registerDecorationType(description: string, key: string, options: IDecorationRenderOptions, parentTypeKey?: string): void { } public removeDecorationType(key: string): void { } - public resolveDecorationOptions(decorationTypeKey: string, writable: boolean): IModelDecorationOptions { return {}; } + public resolveDecorationOptions(decorationTypeKey: string, writable: boolean): IModelDecorationOptions { return { description: 'test' }; } public resolveDecorationCSSRules(decorationTypeKey: string): CSSRuleList | null { return null; } } diff --git a/lib/vscode/src/vs/editor/test/browser/services/decorationRenderOptions.test.ts b/src/vs/editor/test/browser/services/decorationRenderOptions.test.ts similarity index 87% rename from lib/vscode/src/vs/editor/test/browser/services/decorationRenderOptions.test.ts rename to src/vs/editor/test/browser/services/decorationRenderOptions.test.ts index 55be31487cea..e995b8de89c0 100644 --- a/lib/vscode/src/vs/editor/test/browser/services/decorationRenderOptions.test.ts +++ b/src/vs/editor/test/browser/services/decorationRenderOptions.test.ts @@ -59,12 +59,12 @@ suite('Decoration Render Options', () => { }; test('register and resolve decoration type', () => { let s = new TestCodeEditorServiceImpl(null, themeServiceMock); - s.registerDecorationType('example', options); + s.registerDecorationType('test', 'example', options); assert.notStrictEqual(s.resolveDecorationOptions('example', false), undefined); }); test('remove decoration type', () => { let s = new TestCodeEditorServiceImpl(null, themeServiceMock); - s.registerDecorationType('example', options); + s.registerDecorationType('test', 'example', options); assert.notStrictEqual(s.resolveDecorationOptions('example', false), undefined); s.removeDecorationType('example'); assert.throws(() => s.resolveDecorationOptions('example', false)); @@ -77,7 +77,7 @@ suite('Decoration Render Options', () => { test('css properties', () => { const styleSheet = new TestGlobalStyleSheet(); const s = new TestCodeEditorServiceImpl(styleSheet, themeServiceMock); - s.registerDecorationType('example', options); + s.registerDecorationType('test', 'example', options); const sheet = readStyleSheet(styleSheet); assert(sheet.indexOf(`{background:url('https://github.com/microsoft/vscode/blob/main/resources/linux/code.png') center center no-repeat;background-size:contain;}`) >= 0); assert(sheet.indexOf(`{background-color:red;border-color:yellow;box-sizing: border-box;}`) >= 0); @@ -94,7 +94,7 @@ suite('Decoration Render Options', () => { editorBackground: '#FF0000' })); const s = new TestCodeEditorServiceImpl(styleSheet, themeService); - s.registerDecorationType('example', options); + s.registerDecorationType('test', 'example', options); assert.strictEqual(readStyleSheet(styleSheet), '.monaco-editor .ced-example-0 {background-color:#ff0000;border-color:transparent;box-sizing: border-box;}'); themeService.setTheme(new TestColorTheme({ @@ -127,7 +127,7 @@ suite('Decoration Render Options', () => { infoForeground: '#444444' })); const s = new TestCodeEditorServiceImpl(styleSheet, themeService); - s.registerDecorationType('example', options); + s.registerDecorationType('test', 'example', options); const expected = [ '.vs-dark.monaco-editor .ced-example-4::after, .hc-black.monaco-editor .ced-example-4::after {color:#444444 !important;}', '.vs-dark.monaco-editor .ced-example-1, .hc-black.monaco-editor .ced-example-1 {color:#000000 !important;}', @@ -145,7 +145,7 @@ suite('Decoration Render Options', () => { const s = new TestCodeEditorServiceImpl(styleSheet, themeServiceMock); // URI, only minimal encoding - s.registerDecorationType('example', { gutterIconPath: URI.parse('data:image/svg+xml;base64,PHN2ZyB4b+') }); + s.registerDecorationType('test', 'example', { gutterIconPath: URI.parse('data:image/svg+xml;base64,PHN2ZyB4b+') }); assert(readStyleSheet(styleSheet).indexOf(`{background:url('data:image/svg+xml;base64,PHN2ZyB4b+') center center no-repeat;}`) > 0); s.removeDecorationType('example'); @@ -159,27 +159,27 @@ suite('Decoration Render Options', () => { if (platform.isWindows) { // windows file path (used as string) - s.registerDecorationType('example', { gutterIconPath: URI.file('c:\\files\\miles\\more.png') }); + s.registerDecorationType('test', 'example', { gutterIconPath: URI.file('c:\\files\\miles\\more.png') }); assertBackground('file:///c:/files/miles/more.png', 'vscode-file://vscode-app/c:/files/miles/more.png'); s.removeDecorationType('example'); // single quote must always be escaped/encoded - s.registerDecorationType('example', { gutterIconPath: URI.file('c:\\files\\foo\\b\'ar.png') }); + s.registerDecorationType('test', 'example', { gutterIconPath: URI.file('c:\\files\\foo\\b\'ar.png') }); assertBackground('file:///c:/files/foo/b%27ar.png', 'vscode-file://vscode-app/c:/files/foo/b%27ar.png'); s.removeDecorationType('example'); } else { // unix file path (used as string) - s.registerDecorationType('example', { gutterIconPath: URI.file('/Users/foo/bar.png') }); + s.registerDecorationType('test', 'example', { gutterIconPath: URI.file('/Users/foo/bar.png') }); assertBackground('file:///Users/foo/bar.png', 'vscode-file://vscode-app/Users/foo/bar.png'); s.removeDecorationType('example'); // single quote must always be escaped/encoded - s.registerDecorationType('example', { gutterIconPath: URI.file('/Users/foo/b\'ar.png') }); + s.registerDecorationType('test', 'example', { gutterIconPath: URI.file('/Users/foo/b\'ar.png') }); assertBackground('file:///Users/foo/b%27ar.png', 'vscode-file://vscode-app/Users/foo/b%27ar.png'); s.removeDecorationType('example'); } - s.registerDecorationType('example', { gutterIconPath: URI.parse('http://test/pa\'th') }); + s.registerDecorationType('test', 'example', { gutterIconPath: URI.parse('http://test/pa\'th') }); assert(readStyleSheet(styleSheet).indexOf(`{background:url('http://test/pa%27th') center center no-repeat;}`) > 0); s.removeDecorationType('example'); }); diff --git a/lib/vscode/src/vs/editor/test/browser/services/openerService.test.ts b/src/vs/editor/test/browser/services/openerService.test.ts similarity index 74% rename from lib/vscode/src/vs/editor/test/browser/services/openerService.test.ts rename to src/vs/editor/test/browser/services/openerService.test.ts index 08c904f07649..fe11e4745096 100644 --- a/lib/vscode/src/vs/editor/test/browser/services/openerService.test.ts +++ b/src/vs/editor/test/browser/services/openerService.test.ts @@ -8,6 +8,7 @@ import { URI } from 'vs/base/common/uri'; import { OpenerService } from 'vs/editor/browser/services/openerService'; import { TestCodeEditorService } from 'vs/editor/test/browser/editorTestServices'; import { CommandsRegistry, ICommandService, NullCommandService } from 'vs/platform/commands/common/commands'; +import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { matchesScheme } from 'vs/platform/opener/common/opener'; suite('OpenerService', function () { @@ -32,28 +33,28 @@ suite('OpenerService', function () { test('delegate to editorService, scheme:///fff', async function () { const openerService = new OpenerService(editorService, NullCommandService); await openerService.open(URI.parse('another:///somepath')); - assert.strictEqual(editorService.lastInput!.options!.selection, undefined); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection, undefined); }); test('delegate to editorService, scheme:///fff#L123', async function () { const openerService = new OpenerService(editorService, NullCommandService); await openerService.open(URI.parse('file:///somepath#L23')); - assert.strictEqual(editorService.lastInput!.options!.selection!.startLineNumber, 23); - assert.strictEqual(editorService.lastInput!.options!.selection!.startColumn, 1); - assert.strictEqual(editorService.lastInput!.options!.selection!.endLineNumber, undefined); - assert.strictEqual(editorService.lastInput!.options!.selection!.endColumn, undefined); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.startLineNumber, 23); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.startColumn, 1); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.endLineNumber, undefined); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.endColumn, undefined); assert.strictEqual(editorService.lastInput!.resource.fragment, ''); await openerService.open(URI.parse('another:///somepath#L23')); - assert.strictEqual(editorService.lastInput!.options!.selection!.startLineNumber, 23); - assert.strictEqual(editorService.lastInput!.options!.selection!.startColumn, 1); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.startLineNumber, 23); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.startColumn, 1); await openerService.open(URI.parse('another:///somepath#L23,45')); - assert.strictEqual(editorService.lastInput!.options!.selection!.startLineNumber, 23); - assert.strictEqual(editorService.lastInput!.options!.selection!.startColumn, 45); - assert.strictEqual(editorService.lastInput!.options!.selection!.endLineNumber, undefined); - assert.strictEqual(editorService.lastInput!.options!.selection!.endColumn, undefined); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.startLineNumber, 23); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.startColumn, 45); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.endLineNumber, undefined); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.endColumn, undefined); assert.strictEqual(editorService.lastInput!.resource.fragment, ''); }); @@ -61,17 +62,17 @@ suite('OpenerService', function () { const openerService = new OpenerService(editorService, NullCommandService); await openerService.open(URI.parse('file:///somepath#23')); - assert.strictEqual(editorService.lastInput!.options!.selection!.startLineNumber, 23); - assert.strictEqual(editorService.lastInput!.options!.selection!.startColumn, 1); - assert.strictEqual(editorService.lastInput!.options!.selection!.endLineNumber, undefined); - assert.strictEqual(editorService.lastInput!.options!.selection!.endColumn, undefined); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.startLineNumber, 23); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.startColumn, 1); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.endLineNumber, undefined); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.endColumn, undefined); assert.strictEqual(editorService.lastInput!.resource.fragment, ''); await openerService.open(URI.parse('file:///somepath#23,45')); - assert.strictEqual(editorService.lastInput!.options!.selection!.startLineNumber, 23); - assert.strictEqual(editorService.lastInput!.options!.selection!.startColumn, 45); - assert.strictEqual(editorService.lastInput!.options!.selection!.endLineNumber, undefined); - assert.strictEqual(editorService.lastInput!.options!.selection!.endColumn, undefined); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.startLineNumber, 23); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.startColumn, 45); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.endLineNumber, undefined); + assert.strictEqual((editorService.lastInput!.options as ITextEditorOptions)!.selection!.endColumn, undefined); assert.strictEqual(editorService.lastInput!.resource.fragment, ''); }); @@ -245,4 +246,25 @@ suite('OpenerService', function () { assert.ok(!matchesScheme(URI.parse('htt://microsoft.com'), 'http')); assert.ok(!matchesScheme(URI.parse('z://microsoft.com'), 'http')); }); + + test('resolveExternalUri', async function () { + const openerService = new OpenerService(editorService, NullCommandService); + + try { + await openerService.resolveExternalUri(URI.parse('file:///Users/user/folder')); + assert.fail('Should not reach here'); + } catch { + // OK + } + + const disposable = openerService.registerExternalUriResolver({ + async resolveExternalUri(uri) { + return { resolved: uri, dispose() { } }; + } + }); + + const result = await openerService.resolveExternalUri(URI.parse('file:///Users/user/folder')); + assert.deepStrictEqual(result.resolved.toString(), 'file:///Users/user/folder'); + disposable.dispose(); + }); }); diff --git a/lib/vscode/src/vs/editor/test/browser/testCodeEditor.ts b/src/vs/editor/test/browser/testCodeEditor.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/browser/testCodeEditor.ts rename to src/vs/editor/test/browser/testCodeEditor.ts diff --git a/lib/vscode/src/vs/editor/test/browser/testCommand.ts b/src/vs/editor/test/browser/testCommand.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/browser/testCommand.ts rename to src/vs/editor/test/browser/testCommand.ts diff --git a/lib/vscode/src/vs/editor/test/browser/view/minimapCharRenderer.test.ts b/src/vs/editor/test/browser/view/minimapCharRenderer.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/browser/view/minimapCharRenderer.test.ts rename to src/vs/editor/test/browser/view/minimapCharRenderer.test.ts diff --git a/lib/vscode/src/vs/editor/test/browser/view/viewLayer.test.ts b/src/vs/editor/test/browser/view/viewLayer.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/browser/view/viewLayer.test.ts rename to src/vs/editor/test/browser/view/viewLayer.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/commentMode.ts b/src/vs/editor/test/common/commentMode.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/commentMode.ts rename to src/vs/editor/test/common/commentMode.ts diff --git a/lib/vscode/src/vs/editor/test/common/config/commonEditorConfig.test.ts b/src/vs/editor/test/common/config/commonEditorConfig.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/config/commonEditorConfig.test.ts rename to src/vs/editor/test/common/config/commonEditorConfig.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/controller/cursorAtomicMoveOperations.test.ts b/src/vs/editor/test/common/controller/cursorAtomicMoveOperations.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/controller/cursorAtomicMoveOperations.test.ts rename to src/vs/editor/test/common/controller/cursorAtomicMoveOperations.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/controller/cursorMoveHelper.test.ts b/src/vs/editor/test/common/controller/cursorMoveHelper.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/controller/cursorMoveHelper.test.ts rename to src/vs/editor/test/common/controller/cursorMoveHelper.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/core/characterClassifier.test.ts b/src/vs/editor/test/common/core/characterClassifier.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/core/characterClassifier.test.ts rename to src/vs/editor/test/common/core/characterClassifier.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/core/lineTokens.test.ts b/src/vs/editor/test/common/core/lineTokens.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/core/lineTokens.test.ts rename to src/vs/editor/test/common/core/lineTokens.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/core/range.test.ts b/src/vs/editor/test/common/core/range.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/core/range.test.ts rename to src/vs/editor/test/common/core/range.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/core/stringBuilder.test.ts b/src/vs/editor/test/common/core/stringBuilder.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/core/stringBuilder.test.ts rename to src/vs/editor/test/common/core/stringBuilder.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/core/viewLineToken.ts b/src/vs/editor/test/common/core/viewLineToken.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/core/viewLineToken.ts rename to src/vs/editor/test/common/core/viewLineToken.ts diff --git a/lib/vscode/src/vs/editor/test/common/diff/diffComputer.test.ts b/src/vs/editor/test/common/diff/diffComputer.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/diff/diffComputer.test.ts rename to src/vs/editor/test/common/diff/diffComputer.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/editorTestUtils.ts b/src/vs/editor/test/common/editorTestUtils.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/editorTestUtils.ts rename to src/vs/editor/test/common/editorTestUtils.ts diff --git a/lib/vscode/src/vs/editor/test/common/mocks/mockMode.ts b/src/vs/editor/test/common/mocks/mockMode.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/mocks/mockMode.ts rename to src/vs/editor/test/common/mocks/mockMode.ts diff --git a/lib/vscode/src/vs/editor/test/common/mocks/testConfiguration.ts b/src/vs/editor/test/common/mocks/testConfiguration.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/mocks/testConfiguration.ts rename to src/vs/editor/test/common/mocks/testConfiguration.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/benchmark/benchmarkUtils.ts b/src/vs/editor/test/common/model/benchmark/benchmarkUtils.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/benchmark/benchmarkUtils.ts rename to src/vs/editor/test/common/model/benchmark/benchmarkUtils.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/benchmark/bootstrap.js b/src/vs/editor/test/common/model/benchmark/bootstrap.js similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/benchmark/bootstrap.js rename to src/vs/editor/test/common/model/benchmark/bootstrap.js diff --git a/lib/vscode/src/vs/editor/test/common/model/benchmark/entry.ts b/src/vs/editor/test/common/model/benchmark/entry.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/benchmark/entry.ts rename to src/vs/editor/test/common/model/benchmark/entry.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/benchmark/modelbuilder.benchmark.ts b/src/vs/editor/test/common/model/benchmark/modelbuilder.benchmark.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/benchmark/modelbuilder.benchmark.ts rename to src/vs/editor/test/common/model/benchmark/modelbuilder.benchmark.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/benchmark/operations.benchmark.ts b/src/vs/editor/test/common/model/benchmark/operations.benchmark.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/benchmark/operations.benchmark.ts rename to src/vs/editor/test/common/model/benchmark/operations.benchmark.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/benchmark/searchNReplace.benchmark.ts b/src/vs/editor/test/common/model/benchmark/searchNReplace.benchmark.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/benchmark/searchNReplace.benchmark.ts rename to src/vs/editor/test/common/model/benchmark/searchNReplace.benchmark.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/editStack.test.ts b/src/vs/editor/test/common/model/editStack.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/editStack.test.ts rename to src/vs/editor/test/common/model/editStack.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/editableTextModel.test.ts b/src/vs/editor/test/common/model/editableTextModel.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/editableTextModel.test.ts rename to src/vs/editor/test/common/model/editableTextModel.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/editableTextModelAuto.test.ts b/src/vs/editor/test/common/model/editableTextModelAuto.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/editableTextModelAuto.test.ts rename to src/vs/editor/test/common/model/editableTextModelAuto.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/editableTextModelTestUtils.ts b/src/vs/editor/test/common/model/editableTextModelTestUtils.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/editableTextModelTestUtils.ts rename to src/vs/editor/test/common/model/editableTextModelTestUtils.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/intervalTree.test.ts b/src/vs/editor/test/common/model/intervalTree.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/intervalTree.test.ts rename to src/vs/editor/test/common/model/intervalTree.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/linesTextBuffer/linesTextBuffer.test.ts b/src/vs/editor/test/common/model/linesTextBuffer/linesTextBuffer.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/linesTextBuffer/linesTextBuffer.test.ts rename to src/vs/editor/test/common/model/linesTextBuffer/linesTextBuffer.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/linesTextBuffer/linesTextBufferBuilder.test.ts b/src/vs/editor/test/common/model/linesTextBuffer/linesTextBufferBuilder.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/linesTextBuffer/linesTextBufferBuilder.test.ts rename to src/vs/editor/test/common/model/linesTextBuffer/linesTextBufferBuilder.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/linesTextBuffer/textBufferAutoTestUtils.ts b/src/vs/editor/test/common/model/linesTextBuffer/textBufferAutoTestUtils.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/linesTextBuffer/textBufferAutoTestUtils.ts rename to src/vs/editor/test/common/model/linesTextBuffer/textBufferAutoTestUtils.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/model.line.test.ts b/src/vs/editor/test/common/model/model.line.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/model.line.test.ts rename to src/vs/editor/test/common/model/model.line.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/model.modes.test.ts b/src/vs/editor/test/common/model/model.modes.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/model.modes.test.ts rename to src/vs/editor/test/common/model/model.modes.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/model.test.ts b/src/vs/editor/test/common/model/model.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/model.test.ts rename to src/vs/editor/test/common/model/model.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/modelDecorations.test.ts b/src/vs/editor/test/common/model/modelDecorations.test.ts similarity index 97% rename from lib/vscode/src/vs/editor/test/common/model/modelDecorations.test.ts rename to src/vs/editor/test/common/model/modelDecorations.test.ts index da7b00939101..b38ee055688e 100644 --- a/lib/vscode/src/vs/editor/test/common/model/modelDecorations.test.ts +++ b/src/vs/editor/test/common/model/modelDecorations.test.ts @@ -45,6 +45,7 @@ function modelHasNoDecorations(model: TextModel) { function addDecoration(model: TextModel, startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, className: string): string { return model.changeDecorations((changeAccessor) => { return changeAccessor.addDecoration(new Range(startLineNumber, startColumn, endLineNumber, endColumn), { + description: 'test', className: className }); })!; @@ -407,7 +408,7 @@ suite('Editor Model - Model Decorations', () => { }); test('removeAllDecorationsWithOwnerId works', () => { - thisModel.deltaDecorations([], [{ range: new Range(1, 2, 4, 1), options: { className: 'myType1' } }], 1); + thisModel.deltaDecorations([], [{ range: new Range(1, 2, 4, 1), options: { description: 'test', className: 'myType1' } }], 1); thisModel.removeAllDecorationsWithOwnerId(1); modelHasNoDecorations(thisModel); }); @@ -422,7 +423,7 @@ suite('Decorations and editing', () => { 'Third Line' ].join('\n')); - const id = model.deltaDecorations([], [{ range: decRange, options: { stickiness: stickiness } }])[0]; + const id = model.deltaDecorations([], [{ range: decRange, options: { description: 'test', stickiness: stickiness } }])[0]; model.applyEdits([{ range: editRange, text: editText, @@ -1123,6 +1124,7 @@ suite('deltaDecorations', () => { return { range: dec.range, options: { + description: 'test', className: dec.id } }; @@ -1276,6 +1278,7 @@ suite('deltaDecorations', () => { endColumn: 1 }, options: { + description: 'test', hoverMessage: { value: 'hello1' } } }]); @@ -1288,6 +1291,7 @@ suite('deltaDecorations', () => { endColumn: 1 }, options: { + description: 'test', hoverMessage: { value: 'hello2' } } }]); @@ -1312,9 +1316,11 @@ suite('deltaDecorations', () => { startColumn: 1, endLineNumber: 1, endColumn: 1 - }, { - stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges - } + }, + { + description: 'test', + stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges + } ); }); model.changeDecorations((changeAccessor) => { @@ -1349,16 +1355,16 @@ suite('deltaDecorations', () => { ].join('\n')); model.deltaDecorations([], [ - { range: new Range(1, 1, 1, 1), options: { className: '1' } }, - { range: new Range(1, 13, 1, 13), options: { className: '2' } }, - { range: new Range(2, 1, 2, 1), options: { className: '3' } }, - { range: new Range(2, 1, 2, 4), options: { className: '4' } }, - { range: new Range(2, 8, 2, 13), options: { className: '5' } }, - { range: new Range(3, 1, 4, 6), options: { className: '6' } }, - { range: new Range(1, 1, 3, 6), options: { className: 'x1' } }, - { range: new Range(2, 5, 2, 8), options: { className: 'x2' } }, - { range: new Range(1, 1, 2, 8), options: { className: 'x3' } }, - { range: new Range(2, 5, 3, 1), options: { className: 'x4' } }, + { range: new Range(1, 1, 1, 1), options: { description: 'test', className: '1' } }, + { range: new Range(1, 13, 1, 13), options: { description: 'test', className: '2' } }, + { range: new Range(2, 1, 2, 1), options: { description: 'test', className: '3' } }, + { range: new Range(2, 1, 2, 4), options: { description: 'test', className: '4' } }, + { range: new Range(2, 8, 2, 13), options: { description: 'test', className: '5' } }, + { range: new Range(3, 1, 4, 6), options: { description: 'test', className: '6' } }, + { range: new Range(1, 1, 3, 6), options: { description: 'test', className: 'x1' } }, + { range: new Range(2, 5, 2, 8), options: { description: 'test', className: 'x2' } }, + { range: new Range(1, 1, 2, 8), options: { description: 'test', className: 'x3' } }, + { range: new Range(2, 5, 3, 1), options: { description: 'test', className: 'x4' } }, ]); let inRange = model.getDecorationsInRange(new Range(2, 6, 2, 6)); @@ -1376,7 +1382,7 @@ suite('deltaDecorations', () => { 'My First Line' ].join('\n')); - const id = model.deltaDecorations([], [{ range: new Range(1, 2, 1, 14), options: { stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, collapseOnReplaceEdit: true } }])[0]; + const id = model.deltaDecorations([], [{ range: new Range(1, 2, 1, 14), options: { description: 'test', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, collapseOnReplaceEdit: true } }])[0]; model.applyEdits([{ range: new Range(1, 1, 1, 14), text: 'Some new text that is longer than the previous one', diff --git a/lib/vscode/src/vs/editor/test/common/model/modelEditOperation.test.ts b/src/vs/editor/test/common/model/modelEditOperation.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/modelEditOperation.test.ts rename to src/vs/editor/test/common/model/modelEditOperation.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.test.ts b/src/vs/editor/test/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.test.ts rename to src/vs/editor/test/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/textChange.test.ts b/src/vs/editor/test/common/model/textChange.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/textChange.test.ts rename to src/vs/editor/test/common/model/textChange.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/textModel.test.ts b/src/vs/editor/test/common/model/textModel.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/textModel.test.ts rename to src/vs/editor/test/common/model/textModel.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/textModelSearch.test.ts b/src/vs/editor/test/common/model/textModelSearch.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/textModelSearch.test.ts rename to src/vs/editor/test/common/model/textModelSearch.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/textModelWithTokens.test.ts b/src/vs/editor/test/common/model/textModelWithTokens.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/textModelWithTokens.test.ts rename to src/vs/editor/test/common/model/textModelWithTokens.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/model/tokensStore.test.ts b/src/vs/editor/test/common/model/tokensStore.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/model/tokensStore.test.ts rename to src/vs/editor/test/common/model/tokensStore.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/modes/languageConfiguration.test.ts b/src/vs/editor/test/common/modes/languageConfiguration.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/modes/languageConfiguration.test.ts rename to src/vs/editor/test/common/modes/languageConfiguration.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/modes/languageSelector.test.ts b/src/vs/editor/test/common/modes/languageSelector.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/modes/languageSelector.test.ts rename to src/vs/editor/test/common/modes/languageSelector.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/modes/linkComputer.test.ts b/src/vs/editor/test/common/modes/linkComputer.test.ts similarity index 90% rename from lib/vscode/src/vs/editor/test/common/modes/linkComputer.test.ts rename to src/vs/editor/test/common/modes/linkComputer.test.ts index 5bb34c911212..67e46bd8e629 100644 --- a/lib/vscode/src/vs/editor/test/common/modes/linkComputer.test.ts +++ b/src/vs/editor/test/common/modes/linkComputer.test.ts @@ -230,4 +230,25 @@ suite('Editor Modes - Link Computer', () => { ' http://tree-mark.chips.jp/レーズン&ベリーミックス ' ); }); + + test('issue #121438: Link detection stops at【...】', () => { + assertLink( + 'aa https://zh.wikipedia.org/wiki/【我推的孩子】 aa', + ' https://zh.wikipedia.org/wiki/【我推的孩子】 ' + ); + }); + + test('issue #121438: Link detection stops at《...》', () => { + assertLink( + 'aa https://zh.wikipedia.org/wiki/《新青年》编辑部旧址 aa', + ' https://zh.wikipedia.org/wiki/《新青年》编辑部旧址 ' + ); + }); + + test('issue #121438: Link detection stops at “...”', () => { + assertLink( + 'aa https://zh.wikipedia.org/wiki/“常凯申”误译事件 aa', + ' https://zh.wikipedia.org/wiki/“常凯申”误译事件 ' + ); + }); }); diff --git a/lib/vscode/src/vs/editor/test/common/modes/supports/characterPair.test.ts b/src/vs/editor/test/common/modes/supports/characterPair.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/modes/supports/characterPair.test.ts rename to src/vs/editor/test/common/modes/supports/characterPair.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/modes/supports/electricCharacter.test.ts b/src/vs/editor/test/common/modes/supports/electricCharacter.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/modes/supports/electricCharacter.test.ts rename to src/vs/editor/test/common/modes/supports/electricCharacter.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/modes/supports/javascriptOnEnterRules.ts b/src/vs/editor/test/common/modes/supports/javascriptOnEnterRules.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/modes/supports/javascriptOnEnterRules.ts rename to src/vs/editor/test/common/modes/supports/javascriptOnEnterRules.ts diff --git a/lib/vscode/src/vs/editor/test/common/modes/supports/onEnter.test.ts b/src/vs/editor/test/common/modes/supports/onEnter.test.ts similarity index 84% rename from lib/vscode/src/vs/editor/test/common/modes/supports/onEnter.test.ts rename to src/vs/editor/test/common/modes/supports/onEnter.test.ts index 1af36e9ef898..ea8b81da269a 100644 --- a/lib/vscode/src/vs/editor/test/common/modes/supports/onEnter.test.ts +++ b/src/vs/editor/test/common/modes/supports/onEnter.test.ts @@ -47,6 +47,40 @@ suite('OnEnter', () => { testIndentAction('begin', '', IndentAction.Indent); }); + + test('Issue #121125: onEnterRules with global modifier', () => { + const support = new OnEnterSupport({ + onEnterRules: [ + { + action: { + appendText: '/// ', + indentAction: IndentAction.Outdent + }, + beforeText: /^\s*\/{3}.*$/gm + } + ] + }); + + let testIndentAction = (previousLineText: string, beforeText: string, afterText: string, expectedIndentAction: IndentAction | null, expectedAppendText: string | null, removeText: number = 0) => { + let actual = support.onEnter(EditorAutoIndentStrategy.Advanced, previousLineText, beforeText, afterText); + if (expectedIndentAction === null) { + assert.strictEqual(actual, null, 'isNull:' + beforeText); + } else { + assert.strictEqual(actual !== null, true, 'isNotNull:' + beforeText); + assert.strictEqual(actual!.indentAction, expectedIndentAction, 'indentAction:' + beforeText); + if (expectedAppendText !== null) { + assert.strictEqual(actual!.appendText, expectedAppendText, 'appendText:' + beforeText); + } + if (removeText !== 0) { + assert.strictEqual(actual!.removeText, removeText, 'removeText:' + beforeText); + } + } + }; + + testIndentAction('/// line', '/// line', '', IndentAction.Outdent, '/// '); + testIndentAction('/// line', '/// line', '', IndentAction.Outdent, '/// '); + }); + test('uses regExpRules', () => { let support = new OnEnterSupport({ onEnterRules: javascriptOnEnterRules diff --git a/lib/vscode/src/vs/editor/test/common/modes/supports/richEditBrackets.test.ts b/src/vs/editor/test/common/modes/supports/richEditBrackets.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/modes/supports/richEditBrackets.test.ts rename to src/vs/editor/test/common/modes/supports/richEditBrackets.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/modes/supports/tokenization.test.ts b/src/vs/editor/test/common/modes/supports/tokenization.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/modes/supports/tokenization.test.ts rename to src/vs/editor/test/common/modes/supports/tokenization.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/modes/textToHtmlTokenizer.test.ts b/src/vs/editor/test/common/modes/textToHtmlTokenizer.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/modes/textToHtmlTokenizer.test.ts rename to src/vs/editor/test/common/modes/textToHtmlTokenizer.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/modesTestUtils.ts b/src/vs/editor/test/common/modesTestUtils.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/modesTestUtils.ts rename to src/vs/editor/test/common/modesTestUtils.ts diff --git a/lib/vscode/src/vs/editor/test/common/services/editorSimpleWorker.test.ts b/src/vs/editor/test/common/services/editorSimpleWorker.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/services/editorSimpleWorker.test.ts rename to src/vs/editor/test/common/services/editorSimpleWorker.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/services/languagesRegistry.test.ts b/src/vs/editor/test/common/services/languagesRegistry.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/services/languagesRegistry.test.ts rename to src/vs/editor/test/common/services/languagesRegistry.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/services/modelService.test.ts b/src/vs/editor/test/common/services/modelService.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/services/modelService.test.ts rename to src/vs/editor/test/common/services/modelService.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/services/semanticTokensDto.test.ts b/src/vs/editor/test/common/services/semanticTokensDto.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/services/semanticTokensDto.test.ts rename to src/vs/editor/test/common/services/semanticTokensDto.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/services/testTextResourcePropertiesService.ts b/src/vs/editor/test/common/services/testTextResourcePropertiesService.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/services/testTextResourcePropertiesService.ts rename to src/vs/editor/test/common/services/testTextResourcePropertiesService.ts diff --git a/lib/vscode/src/vs/editor/test/common/services/textResourceConfigurationService.test.ts b/src/vs/editor/test/common/services/textResourceConfigurationService.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/services/textResourceConfigurationService.test.ts rename to src/vs/editor/test/common/services/textResourceConfigurationService.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/view/overviewZoneManager.test.ts b/src/vs/editor/test/common/view/overviewZoneManager.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/view/overviewZoneManager.test.ts rename to src/vs/editor/test/common/view/overviewZoneManager.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts b/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts rename to src/vs/editor/test/common/viewLayout/editorLayoutProvider.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/viewLayout/lineDecorations.test.ts b/src/vs/editor/test/common/viewLayout/lineDecorations.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/viewLayout/lineDecorations.test.ts rename to src/vs/editor/test/common/viewLayout/lineDecorations.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/viewLayout/linesLayout.test.ts b/src/vs/editor/test/common/viewLayout/linesLayout.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/viewLayout/linesLayout.test.ts rename to src/vs/editor/test/common/viewLayout/linesLayout.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts b/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts similarity index 95% rename from lib/vscode/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts rename to src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts index 9f94af260fe9..ed5e03b5bd8d 100644 --- a/lib/vscode/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts +++ b/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts @@ -809,63 +809,63 @@ suite('viewLineRenderer.renderLine', () => { const _expected = decodeCharacterMapping(expected); assert.deepStrictEqual(_actual, _expected); } +}); - function assertCharacterMapping(actual: CharacterMapping, expectedCharPartOffsets: number[][], expectedPartLengths: number[]): void { - - assertCharPartOffsets(actual, expectedCharPartOffsets); +function assertCharacterMapping(actual: CharacterMapping, expectedCharPartOffsets: number[][], expectedPartLengths: number[]): void { - let expectedCharAbsoluteOffset: number[] = [], currentPartAbsoluteOffset = 0; - for (let partIndex = 0; partIndex < expectedCharPartOffsets.length; partIndex++) { - const part = expectedCharPartOffsets[partIndex]; + assertCharPartOffsets(actual, expectedCharPartOffsets); - for (const charIndex of part) { - expectedCharAbsoluteOffset.push(currentPartAbsoluteOffset + charIndex); - } + let expectedCharAbsoluteOffset: number[] = [], currentPartAbsoluteOffset = 0; + for (let partIndex = 0; partIndex < expectedCharPartOffsets.length; partIndex++) { + const part = expectedCharPartOffsets[partIndex]; - currentPartAbsoluteOffset += expectedPartLengths[partIndex]; + for (const charIndex of part) { + expectedCharAbsoluteOffset.push(currentPartAbsoluteOffset + charIndex); } - let actualCharOffset: number[] = []; - let tmp = actual.getAbsoluteOffsets(); - for (let i = 0; i < tmp.length; i++) { - actualCharOffset[i] = tmp[i]; - } - assert.deepStrictEqual(actualCharOffset, expectedCharAbsoluteOffset); + currentPartAbsoluteOffset += expectedPartLengths[partIndex]; } - function assertCharPartOffsets(actual: CharacterMapping, expected: number[][]): void { - - let charOffset = 0; - for (let partIndex = 0; partIndex < expected.length; partIndex++) { - let part = expected[partIndex]; - for (const charIndex of part) { - // here - let _actualPartData = actual.charOffsetToPartData(charOffset); - let actualPartIndex = CharacterMapping.getPartIndex(_actualPartData); - let actualCharIndex = CharacterMapping.getCharIndex(_actualPartData); - - assert.deepStrictEqual( - { partIndex: actualPartIndex, charIndex: actualCharIndex }, - { partIndex: partIndex, charIndex: charIndex }, - `character mapping for offset ${charOffset}` - ); - - // here - let actualOffset = actual.partDataToCharOffset(partIndex, part[part.length - 1] + 1, charIndex); - - assert.strictEqual( - actualOffset, - charOffset, - `character mapping for part ${partIndex}, ${charIndex}` - ); - - charOffset++; - } - } + let actualCharOffset: number[] = []; + let tmp = actual.getAbsoluteOffsets(); + for (let i = 0; i < tmp.length; i++) { + actualCharOffset[i] = tmp[i]; + } + assert.deepStrictEqual(actualCharOffset, expectedCharAbsoluteOffset); +} - assert.strictEqual(actual.length, charOffset); +function assertCharPartOffsets(actual: CharacterMapping, expected: number[][]): void { + + let charOffset = 0; + for (let partIndex = 0; partIndex < expected.length; partIndex++) { + let part = expected[partIndex]; + for (const charIndex of part) { + // here + let _actualPartData = actual.charOffsetToPartData(charOffset); + let actualPartIndex = CharacterMapping.getPartIndex(_actualPartData); + let actualCharIndex = CharacterMapping.getCharIndex(_actualPartData); + + assert.deepStrictEqual( + { partIndex: actualPartIndex, charIndex: actualCharIndex }, + { partIndex: partIndex, charIndex: charIndex }, + `character mapping for offset ${charOffset}` + ); + + // here + let actualOffset = actual.partDataToCharOffset(partIndex, part[part.length - 1] + 1, charIndex); + + assert.strictEqual( + actualOffset, + charOffset, + `character mapping for part ${partIndex}, ${charIndex}` + ); + + charOffset++; + } } -}); + + assert.strictEqual(actual.length, charOffset); +} suite('viewLineRenderer.renderLine 2', () => { @@ -1739,7 +1739,7 @@ suite('viewLineRenderer.renderLine 2', () => { let expected = [ '', '\u00a0\u00a0\u00a0\u00a0}', - '', + '', '' ].join(''); @@ -2138,6 +2138,52 @@ suite('viewLineRenderer.renderLine 2', () => { assert.deepStrictEqual(actual.html, expected); }); + test('issue #124038: Multiple end-of-line text decorations get merged', () => { + const actual = renderViewLine(new RenderLineInput( + true, + false, + ' if', + false, + true, + false, + 0, + createViewLineTokens([createPart(4, 1), createPart(6, 2)]), + [ + new LineDecoration(7, 7, 'ced-1-TextEditorDecorationType2-17c14d98-3 ced-1-TextEditorDecorationType2-3', InlineDecorationType.Before), + new LineDecoration(7, 7, 'ced-1-TextEditorDecorationType2-17c14d98-4 ced-1-TextEditorDecorationType2-4', InlineDecorationType.After), + new LineDecoration(7, 7, 'ced-ghost-text-1-4', InlineDecorationType.After), + ], + 4, + 0, + 10, + 10, + 10, + 10000, + 'all', + false, + false, + null + )); + + const expected = [ + '', + '····if', + '' + ].join(''); + + assert.deepStrictEqual(actual.html, expected); + assertCharacterMapping(actual.characterMapping, + [ + [0, 1, 2, 3], + [0, 1], + [], + [0], + [], + ], + [4, 2, 0, 0] + ); + }); + function createTestGetColumnOfLinePartOffset(lineContent: string, tabSize: number, parts: ViewLineToken[], expectedPartLengths: number[]): (partIndex: number, partLength: number, offset: number, expected: number) => void { let renderLineOutput = renderViewLine(new RenderLineInput( diff --git a/lib/vscode/src/vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test.ts b/src/vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test.ts rename to src/vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/viewModel/prefixSumComputer.test.ts b/src/vs/editor/test/common/viewModel/prefixSumComputer.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/viewModel/prefixSumComputer.test.ts rename to src/vs/editor/test/common/viewModel/prefixSumComputer.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts b/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts rename to src/vs/editor/test/common/viewModel/splitLinesCollection.test.ts diff --git a/lib/vscode/src/vs/editor/test/common/viewModel/testViewModel.ts b/src/vs/editor/test/common/viewModel/testViewModel.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/viewModel/testViewModel.ts rename to src/vs/editor/test/common/viewModel/testViewModel.ts diff --git a/lib/vscode/src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts b/src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts similarity index 99% rename from lib/vscode/src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts rename to src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts index 9b2862773433..f0b0996b5b46 100644 --- a/lib/vscode/src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts +++ b/src/vs/editor/test/common/viewModel/viewModelDecorations.test.ts @@ -28,6 +28,7 @@ suite('ViewModelDecorations', () => { model.changeDecorations((accessor) => { let createOpts = (id: string) => { return { + description: 'test', className: id, inlineClassName: 'i-' + id, beforeContentClassName: 'b-' + id, @@ -165,6 +166,7 @@ suite('ViewModelDecorations', () => { accessor.addDecoration( new Range(1, 50, 1, 51), { + description: 'test', beforeContentClassName: 'dec1' } ); @@ -199,6 +201,7 @@ suite('ViewModelDecorations', () => { accessor.addDecoration( new Range(1, 1, 1, 1), { + description: 'test', beforeContentClassName: 'before1', afterContentClassName: 'after1' } diff --git a/lib/vscode/src/vs/editor/test/common/viewModel/viewModelImpl.test.ts b/src/vs/editor/test/common/viewModel/viewModelImpl.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/common/viewModel/viewModelImpl.test.ts rename to src/vs/editor/test/common/viewModel/viewModelImpl.test.ts diff --git a/lib/vscode/src/vs/editor/test/node/classification/typescript-test.ts b/src/vs/editor/test/node/classification/typescript-test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/node/classification/typescript-test.ts rename to src/vs/editor/test/node/classification/typescript-test.ts diff --git a/lib/vscode/src/vs/editor/test/node/classification/typescript.test.ts b/src/vs/editor/test/node/classification/typescript.test.ts similarity index 100% rename from lib/vscode/src/vs/editor/test/node/classification/typescript.test.ts rename to src/vs/editor/test/node/classification/typescript.test.ts diff --git a/lib/vscode/src/vs/loader.js b/src/vs/loader.js similarity index 100% rename from lib/vscode/src/vs/loader.js rename to src/vs/loader.js diff --git a/lib/vscode/src/vs/monaco.d.ts b/src/vs/monaco.d.ts similarity index 96% rename from lib/vscode/src/vs/monaco.d.ts rename to src/vs/monaco.d.ts index a7b09f897c19..0958d5b1d685 100644 --- a/lib/vscode/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -1983,6 +1983,11 @@ declare namespace monaco.editor { * @event */ onDidChangeLanguageConfiguration(listener: (e: IModelLanguageConfigurationChangedEvent) => void): IDisposable; + /** + * An event emitted when the model has been attached to the first editor or detached from the last editor. + * @event + */ + onDidChangeAttached(listener: () => void): IDisposable; /** * An event emitted right before disposing the model. * @event @@ -1993,6 +1998,10 @@ declare namespace monaco.editor { * and make all necessary clean-up to release this object to the GC. */ dispose(): void; + /** + * Returns if this model is attached to an editor or not. + */ + isAttachedToEditor(): boolean; } /** @@ -2964,8 +2973,9 @@ declare namespace monaco.editor { * Suggest options. */ suggest?: ISuggestOptions; + inlineSuggest?: IInlineSuggestOptions; /** - * Smart select opptions; + * Smart select options. */ smartSelect?: ISmartSelectOptions; /** @@ -3219,7 +3229,11 @@ declare namespace monaco.editor { /** * Control the behavior and rendering of the inline hints. */ - inlineHints?: IEditorInlineHintsOptions; + inlayHints?: IEditorInlayHintsOptions; + /** + * Control if the editor should use shadow DOM. + */ + useShadowDOM?: boolean; } /** @@ -3580,9 +3594,9 @@ declare namespace monaco.editor { export type EditorLightbulbOptions = Readonly>; /** - * Configuration options for editor inlineHints + * Configuration options for editor inlayHints */ - export interface IEditorInlineHintsOptions { + export interface IEditorInlayHintsOptions { /** * Enable the inline hints. * Defaults to true. @@ -3600,7 +3614,7 @@ declare namespace monaco.editor { fontFamily?: string; } - export type EditorInlineHintsOptions = Readonly>; + export type EditorInlayHintsOptions = Readonly>; /** * Configuration options for editor minimap @@ -3799,6 +3813,15 @@ declare namespace monaco.editor { readonly scrollByPage: boolean; } + export interface IInlineSuggestOptions { + /** + * Enable or disable the rendering of automatic inline completions. + */ + enabled?: boolean; + } + + export type InternalInlineSuggestOptions = Readonly>; + /** * Configuration options for editor suggest widget */ @@ -3831,6 +3854,10 @@ declare namespace monaco.editor { * Enable or disable the suggest status bar. */ showStatusBar?: boolean; + /** + * Enable or disable the rendering of the suggestion preview. + */ + preview?: boolean; /** * Show details inline with the label. Defaults to true. */ @@ -3847,6 +3874,10 @@ declare namespace monaco.editor { * Show constructor-suggestions. */ showConstructors?: boolean; + /** + * Show deprecated-suggestions. + */ + showDeprecated?: boolean; /** * Show field-suggestions. */ @@ -4035,82 +4066,84 @@ declare namespace monaco.editor { highlightActiveIndentGuide = 49, hover = 50, inDiffEditor = 51, - letterSpacing = 52, - lightbulb = 53, - lineDecorationsWidth = 54, - lineHeight = 55, - lineNumbers = 56, - lineNumbersMinChars = 57, - linkedEditing = 58, - links = 59, - matchBrackets = 60, - minimap = 61, - mouseStyle = 62, - mouseWheelScrollSensitivity = 63, - mouseWheelZoom = 64, - multiCursorMergeOverlapping = 65, - multiCursorModifier = 66, - multiCursorPaste = 67, - occurrencesHighlight = 68, - overviewRulerBorder = 69, - overviewRulerLanes = 70, - padding = 71, - parameterHints = 72, - peekWidgetDefaultFocus = 73, - definitionLinkOpensInPeek = 74, - quickSuggestions = 75, - quickSuggestionsDelay = 76, - readOnly = 77, - renameOnType = 78, - renderControlCharacters = 79, - renderIndentGuides = 80, - renderFinalNewline = 81, - renderLineHighlight = 82, - renderLineHighlightOnlyWhenFocus = 83, - renderValidationDecorations = 84, - renderWhitespace = 85, - revealHorizontalRightPadding = 86, - roundedSelection = 87, - rulers = 88, - scrollbar = 89, - scrollBeyondLastColumn = 90, - scrollBeyondLastLine = 91, - scrollPredominantAxis = 92, - selectionClipboard = 93, - selectionHighlight = 94, - selectOnLineNumbers = 95, - showFoldingControls = 96, - showUnused = 97, - snippetSuggestions = 98, - smartSelect = 99, - smoothScrolling = 100, - stickyTabStops = 101, - stopRenderingLineAfter = 102, - suggest = 103, - suggestFontSize = 104, - suggestLineHeight = 105, - suggestOnTriggerCharacters = 106, - suggestSelection = 107, - tabCompletion = 108, - tabIndex = 109, - unusualLineTerminators = 110, - useTabStops = 111, - wordSeparators = 112, - wordWrap = 113, - wordWrapBreakAfterCharacters = 114, - wordWrapBreakBeforeCharacters = 115, - wordWrapColumn = 116, - wordWrapOverride1 = 117, - wordWrapOverride2 = 118, - wrappingIndent = 119, - wrappingStrategy = 120, - showDeprecated = 121, - inlineHints = 122, - editorClassName = 123, - pixelRatio = 124, - tabFocusMode = 125, - layoutInfo = 126, - wrappingInfo = 127 + inlineSuggest = 52, + letterSpacing = 53, + lightbulb = 54, + lineDecorationsWidth = 55, + lineHeight = 56, + lineNumbers = 57, + lineNumbersMinChars = 58, + linkedEditing = 59, + links = 60, + matchBrackets = 61, + minimap = 62, + mouseStyle = 63, + mouseWheelScrollSensitivity = 64, + mouseWheelZoom = 65, + multiCursorMergeOverlapping = 66, + multiCursorModifier = 67, + multiCursorPaste = 68, + occurrencesHighlight = 69, + overviewRulerBorder = 70, + overviewRulerLanes = 71, + padding = 72, + parameterHints = 73, + peekWidgetDefaultFocus = 74, + definitionLinkOpensInPeek = 75, + quickSuggestions = 76, + quickSuggestionsDelay = 77, + readOnly = 78, + renameOnType = 79, + renderControlCharacters = 80, + renderIndentGuides = 81, + renderFinalNewline = 82, + renderLineHighlight = 83, + renderLineHighlightOnlyWhenFocus = 84, + renderValidationDecorations = 85, + renderWhitespace = 86, + revealHorizontalRightPadding = 87, + roundedSelection = 88, + rulers = 89, + scrollbar = 90, + scrollBeyondLastColumn = 91, + scrollBeyondLastLine = 92, + scrollPredominantAxis = 93, + selectionClipboard = 94, + selectionHighlight = 95, + selectOnLineNumbers = 96, + showFoldingControls = 97, + showUnused = 98, + snippetSuggestions = 99, + smartSelect = 100, + smoothScrolling = 101, + stickyTabStops = 102, + stopRenderingLineAfter = 103, + suggest = 104, + suggestFontSize = 105, + suggestLineHeight = 106, + suggestOnTriggerCharacters = 107, + suggestSelection = 108, + tabCompletion = 109, + tabIndex = 110, + unusualLineTerminators = 111, + useShadowDOM = 112, + useTabStops = 113, + wordSeparators = 114, + wordWrap = 115, + wordWrapBreakAfterCharacters = 116, + wordWrapBreakBeforeCharacters = 117, + wordWrapColumn = 118, + wordWrapOverride1 = 119, + wordWrapOverride2 = 120, + wrappingIndent = 121, + wrappingStrategy = 122, + showDeprecated = 123, + inlayHints = 124, + editorClassName = 125, + pixelRatio = 126, + tabFocusMode = 127, + layoutInfo = 128, + wrappingInfo = 129 } export const EditorOptions: { acceptSuggestionOnCommitCharacter: IEditorOption; @@ -4213,12 +4246,13 @@ declare namespace monaco.editor { showFoldingControls: IEditorOption; showUnused: IEditorOption; showDeprecated: IEditorOption; - inlineHints: IEditorOption; + inlayHints: IEditorOption; snippetSuggestions: IEditorOption; smartSelect: IEditorOption; smoothScrolling: IEditorOption; stopRenderingLineAfter: IEditorOption; suggest: IEditorOption; + inlineSuggest: IEditorOption; suggestFontSize: IEditorOption; suggestLineHeight: IEditorOption; suggestOnTriggerCharacters: IEditorOption; @@ -4226,6 +4260,7 @@ declare namespace monaco.editor { tabCompletion: IEditorOption; tabIndex: IEditorOption; unusualLineTerminators: IEditorOption; + useShadowDOM: IEditorOption; useTabStops: IEditorOption; wordSeparators: IEditorOption; wordWrap: IEditorOption; @@ -4771,7 +4806,7 @@ declare namespace monaco.editor { getRawOptions(): IEditorOptions; /** * Get value of the current model attached to this editor. - * @see `ITextModel.getValue` + * @see {@link ITextModel.getValue} */ getValue(options?: { preserveBOM: boolean; @@ -4779,7 +4814,7 @@ declare namespace monaco.editor { }): string; /** * Set the value of the current model attached to this editor. - * @see `ITextModel.setValue` + * @see {@link ITextModel.setValue} */ setValue(newValue: string): void; /** @@ -4861,7 +4896,7 @@ declare namespace monaco.editor { getLineDecorations(lineNumber: number): IModelDecoration[] | null; /** * All decorations added through this call will get the ownerId of this editor. - * @see `ITextModel.deltaDecorations` + * @see {@link ITextModel.deltaDecorations} */ deltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[]; /** @@ -4966,7 +5001,7 @@ declare namespace monaco.editor { */ export interface IDiffEditor extends IEditor { /** - * @see ICodeEditor.getDomNode + * @see {@link ICodeEditor.getDomNode} */ getDomNode(): HTMLElement; /** @@ -5298,6 +5333,11 @@ declare namespace monaco.languages { */ export function registerDocumentRangeSemanticTokensProvider(languageId: string, provider: DocumentRangeSemanticTokensProvider): IDisposable; + /** + * Register an inline completions provider. + */ + export function registerInlineCompletionsProvider(languageId: string, provider: InlineCompletionsProvider): IDisposable; + /** * Contains additional diagnostic information about the context in which * a [code action](#CodeActionProvider.provideCodeActions) is run. @@ -5553,7 +5593,7 @@ declare namespace monaco.languages { } /** - * A provider result represents the values a provider, like the [`HoverProvider`](#HoverProvider), + * A provider result represents the values a provider, like the {@link HoverProvider}, * may return. For once this is the actual result type `T`, like `Hover`, or a thenable that resolves * to that type `T`. In addition, `null` and `undefined` can be returned - either directly or from a * thenable. @@ -5688,13 +5728,13 @@ declare namespace monaco.languages { documentation?: string | IMarkdownString; /** * A string that should be used when comparing this item - * with other items. When `falsy` the [label](#CompletionItem.label) + * with other items. When `falsy` the {@link CompletionItem.label label} * is used. */ sortText?: string; /** * A string that should be used when filtering a set of - * completion items. When `falsy` the [label](#CompletionItem.label) + * completion items. When `falsy` the {@link CompletionItem.label label} * is used. */ filterText?: string; @@ -5718,11 +5758,11 @@ declare namespace monaco.languages { /** * A range of text that should be replaced by this completion item. * - * Defaults to a range from the start of the [current word](#TextDocument.getWordRangeAtPosition) to the + * Defaults to a range from the start of the {@link TextDocument.getWordRangeAtPosition current word} to the * current position. * - * *Note:* The range must be a [single line](#Range.isSingleLine) and it must - * [contain](#Range.contains) the position at which completion has been [requested](#CompletionItemProvider.provideCompletionItems). + * *Note:* The range must be a {@link Range.isSingleLine single line} and it must + * {@link Range.contains contain} the position at which completion has been {@link CompletionItemProvider.provideCompletionItems requested}. */ range: IRange | { insert: IRange; @@ -5763,7 +5803,7 @@ declare namespace monaco.languages { /** * Contains additional information about the context in which - * [completion provider](#CompletionItemProvider.provideCompletionItems) is triggered. + * {@link CompletionItemProvider.provideCompletionItems completion provider} is triggered. */ export interface CompletionContext { /** @@ -5784,10 +5824,10 @@ declare namespace monaco.languages { * * When computing *complete* completion items is expensive, providers can optionally implement * the `resolveCompletionItem`-function. In that case it is enough to return completion - * items with a [label](#CompletionItem.label) from the - * [provideCompletionItems](#CompletionItemProvider.provideCompletionItems)-function. Subsequently, + * items with a {@link CompletionItem.label label} from the + * {@link CompletionItemProvider.provideCompletionItems provideCompletionItems}-function. Subsequently, * when a completion item is shown in the UI and gains focus this provider is asked to resolve - * the item, like adding [doc-comment](#CompletionItem.documentation) or [details](#CompletionItem.detail). + * the item, like adding {@link CompletionItem.documentation doc-comment} or {@link CompletionItem.detail details}. */ export interface CompletionItemProvider { triggerCharacters?: string[]; @@ -5796,14 +5836,68 @@ declare namespace monaco.languages { */ provideCompletionItems(model: editor.ITextModel, position: Position, context: CompletionContext, token: CancellationToken): ProviderResult; /** - * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) - * or [details](#CompletionItem.detail). + * Given a completion item fill in more data, like {@link CompletionItem.documentation doc-comment} + * or {@link CompletionItem.detail details}. * * The editor will only resolve a completion item once. */ resolveCompletionItem?(item: CompletionItem, token: CancellationToken): ProviderResult; } + /** + * How an {@link InlineCompletionsProvider inline completion provider} was triggered. + */ + export enum InlineCompletionTriggerKind { + /** + * Completion was triggered automatically while editing. + * It is sufficient to return a single completion item in this case. + */ + Automatic = 0, + /** + * Completion was triggered explicitly by a user gesture. + * Return multiple completion items to enable cycling through them. + */ + Explicit = 1 + } + + export interface InlineCompletionContext { + /** + * How the completion was triggered. + */ + readonly triggerKind: InlineCompletionTriggerKind; + } + + export interface InlineCompletion { + /** + * The text to insert. + * If the text contains a line break, the range must end at the end of a line. + * If existing text should be replaced, the existing text must be a prefix of the text to insert. + */ + readonly text: string; + /** + * The range to replace. + * Must begin and end on the same line. + */ + readonly range?: IRange; + readonly command?: Command; + } + + export interface InlineCompletions { + readonly items: readonly TItem[]; + } + + export interface InlineCompletionsProvider { + provideInlineCompletions(model: editor.ITextModel, position: Position, context: InlineCompletionContext, token: CancellationToken): ProviderResult; + /** + * Will be called when an item is shown. + */ + handleItemDidShow?(completions: T, item: T['items'][number]): void; + /** + * Will be called when a completions list is no longer in use and can be garbage-collected. + */ + freeInlineCompletions(completions: T): void; + } + export interface CodeAction { title: string; command?: Command; @@ -5942,7 +6036,7 @@ declare namespace monaco.languages { */ range: IRange; /** - * The highlight kind, default is [text](#DocumentHighlightKind.Text). + * The highlight kind, default is {@link DocumentHighlightKind.Text text}. */ kind?: DocumentHighlightKind; } @@ -6269,12 +6363,12 @@ declare namespace monaco.languages { */ label: string; /** - * An [edit](#TextEdit) which is applied to a document when selecting + * An {@link TextEdit edit} which is applied to a document when selecting * this presentation for the color. */ textEdit?: TextEdit; /** - * An optional array of additional [text edits](#TextEdit) that are applied when + * An optional array of additional {@link TextEdit text edits} that are applied when * selecting this color presentation. */ additionalTextEdits?: TextEdit[]; @@ -6346,10 +6440,10 @@ declare namespace monaco.languages { */ end: number; /** - * Describes the [Kind](#FoldingRangeKind) of the folding range such as [Comment](#FoldingRangeKind.Comment) or - * [Region](#FoldingRangeKind.Region). The kind is used to categorize folding ranges and used by commands + * Describes the {@link FoldingRangeKind Kind} of the folding range such as {@link FoldingRangeKind.Comment Comment} or + * {@link FoldingRangeKind.Region Region}. The kind is used to categorize folding ranges and used by commands * like 'Fold all comments'. See - * [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds. + * {@link FoldingRangeKind} for an enumeration of standardized kinds. */ kind?: FoldingRangeKind; } @@ -6370,7 +6464,7 @@ declare namespace monaco.languages { */ static readonly Region: FoldingRangeKind; /** - * Creates a new [FoldingRangeKind](#FoldingRangeKind). + * Creates a new {@link FoldingRangeKind}. * * @param value of the kind. */ @@ -6450,24 +6544,23 @@ declare namespace monaco.languages { resolveCodeLens?(model: editor.ITextModel, codeLens: CodeLens, token: CancellationToken): ProviderResult; } - export enum InlineHintKind { + export enum InlayHintKind { Other = 0, Type = 1, Parameter = 2 } - export interface InlineHint { + export interface InlayHint { text: string; - range: IRange; - kind: InlineHintKind; - description?: string | IMarkdownString; + position: IPosition; + kind: InlayHintKind; whitespaceBefore?: boolean; whitespaceAfter?: boolean; } - export interface InlineHintsProvider { - onDidChangeInlineHints?: IEvent | undefined; - provideInlineHints(model: editor.ITextModel, range: Range, token: CancellationToken): ProviderResult; + export interface InlayHintsProvider { + onDidChangeInlayHints?: IEvent | undefined; + provideInlayHints(model: editor.ITextModel, range: Range, token: CancellationToken): ProviderResult; } export interface SemanticTokensLegend { diff --git a/lib/vscode/src/vs/nls.build.js b/src/vs/nls.build.js similarity index 100% rename from lib/vscode/src/vs/nls.build.js rename to src/vs/nls.build.js diff --git a/lib/vscode/src/vs/nls.d.ts b/src/vs/nls.d.ts similarity index 100% rename from lib/vscode/src/vs/nls.d.ts rename to src/vs/nls.d.ts diff --git a/lib/vscode/src/vs/nls.js b/src/vs/nls.js similarity index 100% rename from lib/vscode/src/vs/nls.js rename to src/vs/nls.js diff --git a/lib/vscode/src/vs/nls.mock.ts b/src/vs/nls.mock.ts similarity index 100% rename from lib/vscode/src/vs/nls.mock.ts rename to src/vs/nls.mock.ts diff --git a/lib/vscode/src/vs/platform/accessibility/common/accessibility.ts b/src/vs/platform/accessibility/common/accessibility.ts similarity index 100% rename from lib/vscode/src/vs/platform/accessibility/common/accessibility.ts rename to src/vs/platform/accessibility/common/accessibility.ts diff --git a/lib/vscode/src/vs/platform/accessibility/common/accessibilityService.ts b/src/vs/platform/accessibility/common/accessibilityService.ts similarity index 100% rename from lib/vscode/src/vs/platform/accessibility/common/accessibilityService.ts rename to src/vs/platform/accessibility/common/accessibilityService.ts diff --git a/lib/vscode/src/vs/base/browser/ui/dropdown/dropdownWithPrimaryActionViewItem.ts b/src/vs/platform/actions/browser/dropdownWithPrimaryActionViewItem.ts similarity index 64% rename from lib/vscode/src/vs/base/browser/ui/dropdown/dropdownWithPrimaryActionViewItem.ts rename to src/vs/platform/actions/browser/dropdownWithPrimaryActionViewItem.ts index eef52a5a0eda..3dc33976b985 100644 --- a/lib/vscode/src/vs/base/browser/ui/dropdown/dropdownWithPrimaryActionViewItem.ts +++ b/src/vs/platform/actions/browser/dropdownWithPrimaryActionViewItem.ts @@ -4,37 +4,49 @@ *--------------------------------------------------------------------------------------------*/ import { IContextMenuProvider } from 'vs/base/browser/contextmenu'; +import * as DOM from 'vs/base/browser/dom'; +import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { ActionViewItem, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem'; import { IAction } from 'vs/base/common/actions'; -import * as DOM from 'vs/base/browser/dom'; -import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { Event } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { MenuItemAction } from 'vs/platform/actions/common/actions'; +import { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { INotificationService } from 'vs/platform/notification/common/notification'; export class DropdownWithPrimaryActionViewItem extends BaseActionViewItem { private _primaryAction: ActionViewItem; private _dropdown: DropdownMenuActionViewItem; private _container: HTMLElement | null = null; - private toDispose: IDisposable[]; + private _dropdownContainer: HTMLElement | null = null; + + get onDidChangeDropdownVisibility(): Event { + return this._dropdown.onDidChangeVisibility; + } constructor( - primaryAction: IAction, + primaryAction: MenuItemAction, dropdownAction: IAction, dropdownMenuActions: IAction[], - _className: string, + className: string, private readonly _contextMenuProvider: IContextMenuProvider, - dropdownIcon?: string + _keybindingService: IKeybindingService, + _notificationService: INotificationService ) { super(null, primaryAction); - this._primaryAction = new ActionViewItem(undefined, primaryAction, { - icon: true, - label: false - }); + this._primaryAction = new MenuEntryActionViewItem(primaryAction, _keybindingService, _notificationService); this._dropdown = new DropdownMenuActionViewItem(dropdownAction, dropdownMenuActions, this._contextMenuProvider, { - menuAsChild: true + menuAsChild: true, + classNames: ['codicon', 'codicon-chevron-down'] }); - this.toDispose = []; + } + + override setActionContext(newContext: unknown): void { + super.setActionContext(newContext); + this._primaryAction.setActionContext(newContext); + this._dropdown.setActionContext(newContext); } override render(container: HTMLElement): void { @@ -43,10 +55,9 @@ export class DropdownWithPrimaryActionViewItem extends BaseActionViewItem { this._container.classList.add('monaco-dropdown-with-primary'); const primaryContainer = DOM.$('.action-container'); this._primaryAction.render(DOM.append(this._container, primaryContainer)); - const dropdownContainer = DOM.$('.dropdown-action-container'); - this._dropdown.render(DOM.append(this._container, dropdownContainer)); - - this.toDispose.push(DOM.addDisposableListener(primaryContainer, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { + this._dropdownContainer = DOM.$('.dropdown-action-container'); + this._dropdown.render(DOM.append(this._container, this._dropdownContainer)); + this._register(DOM.addDisposableListener(primaryContainer, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { const event = new StandardKeyboardEvent(e); if (event.equals(KeyCode.RightArrow)) { this._primaryAction.element!.tabIndex = -1; @@ -54,7 +65,7 @@ export class DropdownWithPrimaryActionViewItem extends BaseActionViewItem { event.stopPropagation(); } })); - this.toDispose.push(DOM.addDisposableListener(dropdownContainer, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { + this._register(DOM.addDisposableListener(this._dropdownContainer, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { const event = new StandardKeyboardEvent(e); if (event.equals(KeyCode.LeftArrow)) { this._primaryAction.element!.tabIndex = 0; @@ -89,18 +100,20 @@ export class DropdownWithPrimaryActionViewItem extends BaseActionViewItem { } } - override dispose(): void { - this.toDispose = dispose(this.toDispose); - } - update(dropdownAction: IAction, dropdownMenuActions: IAction[], dropdownIcon?: string): void { - this._dropdown?.dispose(); + this._dropdown.dispose(); this._dropdown = new DropdownMenuActionViewItem(dropdownAction, dropdownMenuActions, this._contextMenuProvider, { menuAsChild: true, classNames: ['codicon', dropdownIcon || 'codicon-chevron-down'] }); - if (this.element) { - this._dropdown.render(this.element); + if (this._dropdownContainer) { + this._dropdown.render(this._dropdownContainer); } } + + override dispose() { + this._primaryAction.dispose(); + this._dropdown.dispose(); + super.dispose(); + } } diff --git a/lib/vscode/src/vs/platform/actions/browser/menuEntryActionViewItem.css b/src/vs/platform/actions/browser/menuEntryActionViewItem.css similarity index 97% rename from lib/vscode/src/vs/platform/actions/browser/menuEntryActionViewItem.css rename to src/vs/platform/actions/browser/menuEntryActionViewItem.css index 6b4cb93f2d98..4451e684ed10 100644 --- a/lib/vscode/src/vs/platform/actions/browser/menuEntryActionViewItem.css +++ b/src/vs/platform/actions/browser/menuEntryActionViewItem.css @@ -8,6 +8,7 @@ height: 16px; background-repeat: no-repeat; background-position: 50%; + background-size: 16px; } .monaco-action-bar .action-item.menu-entry .action-label { diff --git a/lib/vscode/src/vs/platform/actions/browser/menuEntryActionViewItem.ts b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts similarity index 89% rename from lib/vscode/src/vs/platform/actions/browser/menuEntryActionViewItem.ts rename to src/vs/platform/actions/browser/menuEntryActionViewItem.ts index 169aece680c7..581b30f2879b 100644 --- a/lib/vscode/src/vs/platform/actions/browser/menuEntryActionViewItem.ts +++ b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts @@ -24,14 +24,16 @@ export function createAndFillInContextMenuActions(menu: IMenu, options: IMenuAct const groups = menu.getActions(options); const modifierKeyEmitter = ModifierKeyEmitter.getInstance(); const useAlternativeActions = modifierKeyEmitter.keyStatus.altKey || ((isWindows || isLinux) && modifierKeyEmitter.keyStatus.shiftKey); - fillInActions(groups, target, useAlternativeActions, primaryGroup); + fillInActions(groups, target, useAlternativeActions, primaryGroup ? actionGroup => actionGroup === primaryGroup : actionGroup => actionGroup === 'navigation'); return asDisposable(groups); } -export function createAndFillInActionBarActions(menu: IMenu, options: IMenuActionOptions | undefined, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, primaryGroup?: string, primaryMaxCount?: number, shouldInlineSubmenu?: (action: SubmenuAction, group: string, groupSize: number) => boolean): IDisposable { +export function createAndFillInActionBarActions(menu: IMenu, options: IMenuActionOptions | undefined, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, primaryGroup?: string | ((actionGroup: string) => boolean), primaryMaxCount?: number, shouldInlineSubmenu?: (action: SubmenuAction, group: string, groupSize: number) => boolean, useSeparatorsInPrimaryActions?: boolean): IDisposable { const groups = menu.getActions(options); + const isPrimaryAction = typeof primaryGroup === 'string' ? (actionGroup: string) => actionGroup === primaryGroup : primaryGroup; + // Action bars handle alternative actions on their own so the alternative actions should be ignored - fillInActions(groups, target, false, primaryGroup, primaryMaxCount, shouldInlineSubmenu); + fillInActions(groups, target, false, isPrimaryAction, primaryMaxCount, shouldInlineSubmenu, useSeparatorsInPrimaryActions); return asDisposable(groups); } @@ -49,9 +51,10 @@ function asDisposable(groups: ReadonlyArray<[string, ReadonlyArray]>, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, useAlternativeActions: boolean, - primaryGroup = 'navigation', + isPrimaryAction: (actionGroup: string) => boolean = actionGroup => actionGroup === 'navigation', primaryMaxCount: number = Number.MAX_SAFE_INTEGER, - shouldInlineSubmenu: (action: SubmenuAction, group: string, groupSize: number) => boolean = () => false + shouldInlineSubmenu: (action: SubmenuAction, group: string, groupSize: number) => boolean = () => false, + useSeparatorsInPrimaryActions: boolean = false ): void { let primaryBucket: IAction[]; @@ -69,8 +72,11 @@ function fillInActions( for (const [group, actions] of groups) { let target: IAction[]; - if (group === primaryGroup) { + if (isPrimaryAction(group)) { target = primaryBucket; + if (target.length > 0 && useSeparatorsInPrimaryActions) { + target.push(new Separator()); + } } else { target = secondaryBucket; if (target.length > 0) { @@ -93,7 +99,7 @@ function fillInActions( // ask the outside if submenu should be inlined or not. only ask when // there would be enough space for (const { group, action, index } of submenuInfo) { - const target = group === primaryGroup ? primaryBucket : secondaryBucket; + const target = isPrimaryAction(group) ? primaryBucket : secondaryBucket; // inlining submenus with length 0 or 1 is easy, // larger submenus need to be checked with the overall limit @@ -133,13 +139,15 @@ export class MenuEntryActionViewItem extends ActionViewItem { return this._wantsAltCommand && this._menuItemAction.alt || this._menuItemAction; } - override onClick(event: MouseEvent): void { + override async onClick(event: MouseEvent): Promise { event.preventDefault(); event.stopPropagation(); - this.actionRunner - .run(this._commandAction, this._context) - .catch(err => this._notificationService.error(err)); + try { + await this.actionRunner.run(this._commandAction, this._context); + } catch (err) { + this._notificationService.error(err); + } } override render(container: HTMLElement): void { diff --git a/lib/vscode/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts similarity index 93% rename from lib/vscode/src/vs/platform/actions/common/actions.ts rename to src/vs/platform/actions/common/actions.ts index 5f946cf2ea09..f0e548fea19b 100644 --- a/lib/vscode/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -41,6 +41,7 @@ export type Icon = { dark?: URI; light?: URI; } | ThemeIcon; export interface ICommandAction { id: string; title: string | ICommandActionTitle; + shortTitle?: string | ICommandActionTitle; category?: string | ILocalizedString; tooltip?: string; icon?: Icon; @@ -87,6 +88,7 @@ export class MenuId { static readonly DebugWatchContext = new MenuId('DebugWatchContext'); static readonly DebugToolBar = new MenuId('DebugToolBar'); static readonly EditorContext = new MenuId('EditorContext'); + static readonly SimpleEditorContext = new MenuId('SimpleEditorContext'); static readonly EditorContextCopy = new MenuId('EditorContextCopy'); static readonly EditorContextPeek = new MenuId('EditorContextPeek'); static readonly EditorTitle = new MenuId('EditorTitle'); @@ -96,6 +98,7 @@ export class MenuId { static readonly ExplorerContext = new MenuId('ExplorerContext'); static readonly ExtensionContext = new MenuId('ExtensionContext'); static readonly GlobalActivity = new MenuId('GlobalActivity'); + static readonly MenubarMainMenu = new MenuId('MenubarMainMenu'); static readonly MenubarAppearanceMenu = new MenuId('MenubarAppearanceMenu'); static readonly MenubarDebugMenu = new MenuId('MenubarDebugMenu'); static readonly MenubarEditMenu = new MenuId('MenubarEditMenu'); @@ -125,9 +128,12 @@ export class MenuId { static readonly StatusBarWindowIndicatorMenu = new MenuId('StatusBarWindowIndicatorMenu'); static readonly StatusBarRemoteIndicatorMenu = new MenuId('StatusBarRemoteIndicatorMenu'); static readonly TestItem = new MenuId('TestItem'); + static readonly TestPeekElement = new MenuId('TestPeekElement'); + static readonly TestPeekTitle = new MenuId('TestPeekTitle'); static readonly TouchBarContext = new MenuId('TouchBarContext'); static readonly TitleBarContext = new MenuId('TitleBarContext'); static readonly TunnelContext = new MenuId('TunnelContext'); + static readonly TunnelProtocol = new MenuId('TunnelProtocol'); static readonly TunnelPortInline = new MenuId('TunnelInline'); static readonly TunnelTitle = new MenuId('TunnelTitle'); static readonly TunnelLocalAddressInline = new MenuId('TunnelLocalAddressInline'); @@ -142,6 +148,7 @@ export class MenuId { static readonly CommentTitle = new MenuId('CommentTitle'); static readonly CommentActions = new MenuId('CommentActions'); static readonly NotebookToolbar = new MenuId('NotebookToolbar'); + static readonly NotebookRightToolbar = new MenuId('NotebookRightToolbar'); static readonly NotebookCellTitle = new MenuId('NotebookCellTitle'); static readonly NotebookCellInsert = new MenuId('NotebookCellInsert'); static readonly NotebookCellBetween = new MenuId('NotebookCellBetween'); @@ -150,6 +157,7 @@ export class MenuId { static readonly NotebookDiffCellInputTitle = new MenuId('NotebookDiffCellInputTitle'); static readonly NotebookDiffCellMetadataTitle = new MenuId('NotebookDiffCellMetadataTitle'); static readonly NotebookDiffCellOutputsTitle = new MenuId('NotebookDiffCellOutputsTitle'); + static readonly NotebookOutputToolbar = new MenuId('NotebookOutputToolbar'); static readonly BulkEditTitle = new MenuId('BulkEditTitle'); static readonly BulkEditContext = new MenuId('BulkEditContext'); static readonly TimelineItemContext = new MenuId('TimelineItemContext'); @@ -157,11 +165,13 @@ export class MenuId { static readonly TimelineTitleContext = new MenuId('TimelineTitleContext'); static readonly AccountsContext = new MenuId('AccountsContext'); static readonly PanelTitle = new MenuId('PanelTitle'); - static readonly TerminalContainerContext = new MenuId('TerminalContainerContext'); - static readonly TerminalToolbarContext = new MenuId('TerminalToolbarContext'); - static readonly TerminalTabsWidgetContext = new MenuId('TerminalTabsWidgetContext'); - static readonly TerminalTabsWidgetEmptyContext = new MenuId('TerminalTabsWidgetEmptyContext'); - static readonly TerminalSingleTabContext = new MenuId('TerminalSingleTabContext'); + static readonly TerminalInstanceContext = new MenuId('TerminalInstanceContext'); + static readonly TerminalNewDropdownContext = new MenuId('TerminalNewDropdownContext'); + static readonly TerminalTabContext = new MenuId('TerminalTabContext'); + static readonly TerminalTabEmptyAreaContext = new MenuId('TerminalTabEmptyAreaContext'); + static readonly TerminalInlineTabContext = new MenuId('TerminalInlineTabContext'); + static readonly WebviewContext = new MenuId('WebviewContext'); + static readonly InlineCompletionsActions = new MenuId('InlineCompletionsActions'); readonly id: number; readonly _debugName: string; @@ -175,6 +185,7 @@ export class MenuId { export interface IMenuActionOptions { arg?: any; shouldForwardArgs?: boolean; + renderShortTitle?: boolean; } export interface IMenu extends IDisposable { @@ -326,7 +337,7 @@ export class ExecuteCommandAction extends Action { super(id, label); } - override run(...args: any[]): Promise { + override run(...args: any[]): Promise { return this._commandService.executeCommand(this.id, ...args); } } @@ -384,7 +395,9 @@ export class MenuItemAction implements IAction { @ICommandService private _commandService: ICommandService ) { this.id = item.id; - this.label = typeof item.title === 'string' ? item.title : item.title.value; + this.label = options?.renderShortTitle && item.shortTitle + ? (typeof item.shortTitle === 'string' ? item.shortTitle : item.shortTitle.value) + : (typeof item.title === 'string' ? item.title : item.title.value); this.tooltip = item.tooltip ?? ''; this.enabled = !item.precondition || contextKeyService.contextMatchesRules(item.precondition); this.checked = false; @@ -417,7 +430,7 @@ export class MenuItemAction implements IAction { // to bridge into the rendering world. } - run(...args: any[]): Promise { + run(...args: any[]): Promise { let runArgs: any[] = []; if (this._options?.arg) { @@ -525,7 +538,7 @@ export interface IAction2Options extends ICommandAction { export abstract class Action2 { constructor(readonly desc: Readonly) { } - abstract run(accessor: ServicesAccessor, ...args: any[]): any; + abstract run(accessor: ServicesAccessor, ...args: any[]): void; } export function registerAction2(ctor: { new(): Action2 }): IDisposable { diff --git a/lib/vscode/src/vs/platform/actions/common/menuService.ts b/src/vs/platform/actions/common/menuService.ts similarity index 100% rename from lib/vscode/src/vs/platform/actions/common/menuService.ts rename to src/vs/platform/actions/common/menuService.ts diff --git a/lib/vscode/src/vs/platform/actions/test/common/menuService.test.ts b/src/vs/platform/actions/test/common/menuService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/actions/test/common/menuService.test.ts rename to src/vs/platform/actions/test/common/menuService.test.ts diff --git a/lib/vscode/src/vs/platform/backup/electron-main/backup.ts b/src/vs/platform/backup/electron-main/backup.ts similarity index 100% rename from lib/vscode/src/vs/platform/backup/electron-main/backup.ts rename to src/vs/platform/backup/electron-main/backup.ts diff --git a/lib/vscode/src/vs/platform/backup/electron-main/backupMainService.ts b/src/vs/platform/backup/electron-main/backupMainService.ts similarity index 98% rename from lib/vscode/src/vs/platform/backup/electron-main/backupMainService.ts rename to src/vs/platform/backup/electron-main/backupMainService.ts index ac5bb2489278..ac9d7f2a86da 100644 --- a/lib/vscode/src/vs/platform/backup/electron-main/backupMainService.ts +++ b/src/vs/platform/backup/electron-main/backupMainService.ts @@ -7,7 +7,7 @@ import * as fs from 'fs'; import { createHash } from 'crypto'; import { join } from 'vs/base/common/path'; import { isLinux } from 'vs/base/common/platform'; -import { writeFileSync, writeFile, readdir, exists, rimraf, RimRafMode } from 'vs/base/node/pfs'; +import { writeFileSync, writeFile, readdir, exists, rimraf, RimRafMode, Promises } from 'vs/base/node/pfs'; import { IBackupMainService, IWorkspaceBackupInfo, isWorkspaceBackupInfo } from 'vs/platform/backup/electron-main/backup'; import { IBackupWorkspacesFormat, IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup'; import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; @@ -49,7 +49,7 @@ export class BackupMainService implements IBackupMainService { async initialize(): Promise { let backups: IBackupWorkspacesFormat; try { - backups = JSON.parse(await fs.promises.readFile(this.workspacesJsonPath, 'utf8')); // invalid JSON or permission issue can happen here + backups = JSON.parse(await Promises.readFile(this.workspacesJsonPath, 'utf8')); // invalid JSON or permission issue can happen here } catch (error) { backups = Object.create(null); } @@ -328,7 +328,7 @@ export class BackupMainService implements IBackupMainService { // Rename backupPath to new empty window backup path const newEmptyWindowBackupPath = this.getBackupPath(newBackupFolder); try { - await fs.promises.rename(backupPath, newEmptyWindowBackupPath); + await Promises.rename(backupPath, newEmptyWindowBackupPath); } catch (error) { this.logService.error(`Backup: Could not rename backup folder: ${error.toString()}`); return false; diff --git a/lib/vscode/src/vs/platform/backup/node/backup.ts b/src/vs/platform/backup/node/backup.ts similarity index 100% rename from lib/vscode/src/vs/platform/backup/node/backup.ts rename to src/vs/platform/backup/node/backup.ts diff --git a/lib/vscode/src/vs/platform/backup/test/electron-main/backupMainService.test.ts b/src/vs/platform/backup/test/electron-main/backupMainService.test.ts similarity index 96% rename from lib/vscode/src/vs/platform/backup/test/electron-main/backupMainService.test.ts rename to src/vs/platform/backup/test/electron-main/backupMainService.test.ts index 9968de89189f..a2101b983e98 100644 --- a/lib/vscode/src/vs/platform/backup/test/electron-main/backupMainService.test.ts +++ b/src/vs/platform/backup/test/electron-main/backupMainService.test.ts @@ -107,7 +107,7 @@ flakySuite('BackupMainService', () => { environmentService = new EnvironmentMainService(parseArgs(process.argv, OPTIONS), { _serviceBrand: undefined, ...product }); - await fs.promises.mkdir(backupHome, { recursive: true }); + await pfs.Promises.mkdir(backupHome, { recursive: true }); configService = new TestConfigurationService(); service = new class TestBackupMainService extends BackupMainService { @@ -446,7 +446,7 @@ flakySuite('BackupMainService', () => { await pfs.writeFile(backupWorkspacesPath, JSON.stringify(workspacesJson)); await service.initialize(); - const buffer = await fs.promises.readFile(backupWorkspacesPath, 'utf-8'); + const buffer = await pfs.Promises.readFile(backupWorkspacesPath, 'utf-8'); const json = JSON.parse(buffer); assert.deepStrictEqual(json.folderURIWorkspaces, [existingTestFolder1.toString()]); }); @@ -462,7 +462,7 @@ flakySuite('BackupMainService', () => { }; await pfs.writeFile(backupWorkspacesPath, JSON.stringify(workspacesJson)); await service.initialize(); - const buffer = await fs.promises.readFile(backupWorkspacesPath, 'utf-8'); + const buffer = await pfs.Promises.readFile(backupWorkspacesPath, 'utf-8'); const json = JSON.parse(buffer); assert.deepStrictEqual(json.folderURIWorkspaces, [existingTestFolder1.toString()]); }); @@ -484,7 +484,7 @@ flakySuite('BackupMainService', () => { await pfs.writeFile(backupWorkspacesPath, JSON.stringify(workspacesJson)); await service.initialize(); - const buffer = await fs.promises.readFile(backupWorkspacesPath, 'utf-8'); + const buffer = await pfs.Promises.readFile(backupWorkspacesPath, 'utf-8'); const json = JSON.parse(buffer); assert.strictEqual(json.rootURIWorkspaces.length, platform.isLinux ? 3 : 1); if (platform.isLinux) { @@ -500,7 +500,7 @@ flakySuite('BackupMainService', () => { service.registerFolderBackupSync(fooFile); service.registerFolderBackupSync(barFile); assertEqualUris(service.getFolderBackupPaths(), [fooFile, barFile]); - const buffer = await fs.promises.readFile(backupWorkspacesPath, 'utf-8'); + const buffer = await pfs.Promises.readFile(backupWorkspacesPath, 'utf-8'); const json = JSON.parse(buffer); assert.deepStrictEqual(json.folderURIWorkspaces, [fooFile.toString(), barFile.toString()]); }); @@ -515,7 +515,7 @@ flakySuite('BackupMainService', () => { assert.strictEqual(ws1.workspace.id, service.getWorkspaceBackups()[0].workspace.id); assert.strictEqual(ws2.workspace.id, service.getWorkspaceBackups()[1].workspace.id); - const buffer = await fs.promises.readFile(backupWorkspacesPath, 'utf-8'); + const buffer = await pfs.Promises.readFile(backupWorkspacesPath, 'utf-8'); const json = JSON.parse(buffer); assert.deepStrictEqual(json.rootURIWorkspaces.map(b => b.configURIPath), [fooFile.toString(), barFile.toString()]); @@ -528,7 +528,7 @@ flakySuite('BackupMainService', () => { service.registerFolderBackupSync(URI.file(fooFile.fsPath.toUpperCase())); assertEqualUris(service.getFolderBackupPaths(), [URI.file(fooFile.fsPath.toUpperCase())]); - const buffer = await fs.promises.readFile(backupWorkspacesPath, 'utf-8'); + const buffer = await pfs.Promises.readFile(backupWorkspacesPath, 'utf-8'); const json = JSON.parse(buffer); assert.deepStrictEqual(json.folderURIWorkspaces, [URI.file(fooFile.fsPath.toUpperCase()).toString()]); }); @@ -538,7 +538,7 @@ flakySuite('BackupMainService', () => { service.registerWorkspaceBackupSync(toWorkspaceBackupInfo(upperFooPath)); assertEqualUris(service.getWorkspaceBackups().map(b => b.workspace.configPath), [URI.file(upperFooPath)]); - const buffer = await fs.promises.readFile(backupWorkspacesPath, 'utf-8'); + const buffer = await pfs.Promises.readFile(backupWorkspacesPath, 'utf-8'); const json = (JSON.parse(buffer)); assert.deepStrictEqual(json.rootURIWorkspaces.map(b => b.configURIPath), [URI.file(upperFooPath).toString()]); }); @@ -549,12 +549,12 @@ flakySuite('BackupMainService', () => { service.registerFolderBackupSync(barFile); service.unregisterFolderBackupSync(fooFile); - const buffer = await fs.promises.readFile(backupWorkspacesPath, 'utf-8'); + const buffer = await pfs.Promises.readFile(backupWorkspacesPath, 'utf-8'); const json = (JSON.parse(buffer)); assert.deepStrictEqual(json.folderURIWorkspaces, [barFile.toString()]); service.unregisterFolderBackupSync(barFile); - const content = await fs.promises.readFile(backupWorkspacesPath, 'utf-8'); + const content = await pfs.Promises.readFile(backupWorkspacesPath, 'utf-8'); const json2 = (JSON.parse(content)); assert.deepStrictEqual(json2.folderURIWorkspaces, []); }); @@ -566,12 +566,12 @@ flakySuite('BackupMainService', () => { service.registerWorkspaceBackupSync(ws2); service.unregisterWorkspaceBackupSync(ws1.workspace); - const buffer = await fs.promises.readFile(backupWorkspacesPath, 'utf-8'); + const buffer = await pfs.Promises.readFile(backupWorkspacesPath, 'utf-8'); const json = (JSON.parse(buffer)); assert.deepStrictEqual(json.rootURIWorkspaces.map(r => r.configURIPath), [barFile.toString()]); service.unregisterWorkspaceBackupSync(ws2.workspace); - const content = await fs.promises.readFile(backupWorkspacesPath, 'utf-8'); + const content = await pfs.Promises.readFile(backupWorkspacesPath, 'utf-8'); const json2 = (JSON.parse(content)); assert.deepStrictEqual(json2.rootURIWorkspaces, []); }); @@ -581,12 +581,12 @@ flakySuite('BackupMainService', () => { service.registerEmptyWindowBackupSync('bar'); service.unregisterEmptyWindowBackupSync('foo'); - const buffer = await fs.promises.readFile(backupWorkspacesPath, 'utf-8'); + const buffer = await pfs.Promises.readFile(backupWorkspacesPath, 'utf-8'); const json = (JSON.parse(buffer)); assert.deepStrictEqual(json.emptyWorkspaceInfos, [{ backupFolder: 'bar' }]); service.unregisterEmptyWindowBackupSync('bar'); - const content = await fs.promises.readFile(backupWorkspacesPath, 'utf-8'); + const content = await pfs.Promises.readFile(backupWorkspacesPath, 'utf-8'); const json2 = (JSON.parse(content)); assert.deepStrictEqual(json2.emptyWorkspaceInfos, []); }); @@ -600,7 +600,7 @@ flakySuite('BackupMainService', () => { await service.initialize(); service.unregisterFolderBackupSync(barFile); service.unregisterEmptyWindowBackupSync('test'); - const content = await fs.promises.readFile(backupWorkspacesPath, 'utf-8'); + const content = await pfs.Promises.readFile(backupWorkspacesPath, 'utf-8'); const json = (JSON.parse(content)); assert.deepStrictEqual(json.folderURIWorkspaces, [existingTestFolder1.toString()]); }); @@ -670,8 +670,8 @@ flakySuite('BackupMainService', () => { assert.strictEqual(((await service.getDirtyWorkspaces()).length), 0); try { - await fs.promises.mkdir(path.join(folderBackupPath, Schemas.file), { recursive: true }); - await fs.promises.mkdir(path.join(workspaceBackupPath, Schemas.untitled), { recursive: true }); + await pfs.Promises.mkdir(path.join(folderBackupPath, Schemas.file), { recursive: true }); + await pfs.Promises.mkdir(path.join(workspaceBackupPath, Schemas.untitled), { recursive: true }); } catch (error) { // ignore - folder might exist already } diff --git a/lib/vscode/src/vs/platform/browser/contextScopedHistoryWidget.ts b/src/vs/platform/browser/contextScopedHistoryWidget.ts similarity index 100% rename from lib/vscode/src/vs/platform/browser/contextScopedHistoryWidget.ts rename to src/vs/platform/browser/contextScopedHistoryWidget.ts diff --git a/lib/vscode/src/vs/platform/checksum/common/checksumService.ts b/src/vs/platform/checksum/common/checksumService.ts similarity index 100% rename from lib/vscode/src/vs/platform/checksum/common/checksumService.ts rename to src/vs/platform/checksum/common/checksumService.ts diff --git a/lib/vscode/src/vs/platform/checksum/electron-sandbox/checksumService.ts b/src/vs/platform/checksum/electron-sandbox/checksumService.ts similarity index 100% rename from lib/vscode/src/vs/platform/checksum/electron-sandbox/checksumService.ts rename to src/vs/platform/checksum/electron-sandbox/checksumService.ts diff --git a/lib/vscode/src/vs/platform/checksum/node/checksumService.ts b/src/vs/platform/checksum/node/checksumService.ts similarity index 100% rename from lib/vscode/src/vs/platform/checksum/node/checksumService.ts rename to src/vs/platform/checksum/node/checksumService.ts diff --git a/lib/vscode/src/vs/platform/checksum/test/node/checksumService.test.ts b/src/vs/platform/checksum/test/node/checksumService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/checksum/test/node/checksumService.test.ts rename to src/vs/platform/checksum/test/node/checksumService.test.ts diff --git a/lib/vscode/src/vs/platform/checksum/test/node/fixtures/lorem.txt b/src/vs/platform/checksum/test/node/fixtures/lorem.txt similarity index 100% rename from lib/vscode/src/vs/platform/checksum/test/node/fixtures/lorem.txt rename to src/vs/platform/checksum/test/node/fixtures/lorem.txt diff --git a/lib/vscode/src/vs/platform/clipboard/browser/clipboardService.ts b/src/vs/platform/clipboard/browser/clipboardService.ts similarity index 100% rename from lib/vscode/src/vs/platform/clipboard/browser/clipboardService.ts rename to src/vs/platform/clipboard/browser/clipboardService.ts diff --git a/lib/vscode/src/vs/platform/clipboard/common/clipboardService.ts b/src/vs/platform/clipboard/common/clipboardService.ts similarity index 100% rename from lib/vscode/src/vs/platform/clipboard/common/clipboardService.ts rename to src/vs/platform/clipboard/common/clipboardService.ts diff --git a/lib/vscode/src/vs/platform/commands/common/commands.ts b/src/vs/platform/commands/common/commands.ts similarity index 100% rename from lib/vscode/src/vs/platform/commands/common/commands.ts rename to src/vs/platform/commands/common/commands.ts diff --git a/lib/vscode/src/vs/platform/commands/test/common/commands.test.ts b/src/vs/platform/commands/test/common/commands.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/commands/test/common/commands.test.ts rename to src/vs/platform/commands/test/common/commands.test.ts diff --git a/lib/vscode/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts similarity index 100% rename from lib/vscode/src/vs/platform/configuration/common/configuration.ts rename to src/vs/platform/configuration/common/configuration.ts diff --git a/lib/vscode/src/vs/platform/configuration/common/configurationModels.ts b/src/vs/platform/configuration/common/configurationModels.ts similarity index 100% rename from lib/vscode/src/vs/platform/configuration/common/configurationModels.ts rename to src/vs/platform/configuration/common/configurationModels.ts diff --git a/lib/vscode/src/vs/platform/configuration/common/configurationRegistry.ts b/src/vs/platform/configuration/common/configurationRegistry.ts similarity index 100% rename from lib/vscode/src/vs/platform/configuration/common/configurationRegistry.ts rename to src/vs/platform/configuration/common/configurationRegistry.ts diff --git a/lib/vscode/src/vs/platform/configuration/common/configurationService.ts b/src/vs/platform/configuration/common/configurationService.ts similarity index 100% rename from lib/vscode/src/vs/platform/configuration/common/configurationService.ts rename to src/vs/platform/configuration/common/configurationService.ts diff --git a/lib/vscode/src/vs/platform/configuration/test/common/configuration.test.ts b/src/vs/platform/configuration/test/common/configuration.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/configuration/test/common/configuration.test.ts rename to src/vs/platform/configuration/test/common/configuration.test.ts diff --git a/lib/vscode/src/vs/platform/configuration/test/common/configurationModels.test.ts b/src/vs/platform/configuration/test/common/configurationModels.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/configuration/test/common/configurationModels.test.ts rename to src/vs/platform/configuration/test/common/configurationModels.test.ts diff --git a/lib/vscode/src/vs/platform/configuration/test/common/configurationRegistry.test.ts b/src/vs/platform/configuration/test/common/configurationRegistry.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/configuration/test/common/configurationRegistry.test.ts rename to src/vs/platform/configuration/test/common/configurationRegistry.test.ts diff --git a/lib/vscode/src/vs/platform/configuration/test/common/configurationService.test.ts b/src/vs/platform/configuration/test/common/configurationService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/configuration/test/common/configurationService.test.ts rename to src/vs/platform/configuration/test/common/configurationService.test.ts diff --git a/lib/vscode/src/vs/platform/configuration/test/common/testConfigurationService.ts b/src/vs/platform/configuration/test/common/testConfigurationService.ts similarity index 100% rename from lib/vscode/src/vs/platform/configuration/test/common/testConfigurationService.ts rename to src/vs/platform/configuration/test/common/testConfigurationService.ts diff --git a/lib/vscode/src/vs/platform/contextkey/browser/contextKeyService.ts b/src/vs/platform/contextkey/browser/contextKeyService.ts similarity index 100% rename from lib/vscode/src/vs/platform/contextkey/browser/contextKeyService.ts rename to src/vs/platform/contextkey/browser/contextKeyService.ts diff --git a/lib/vscode/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts similarity index 99% rename from lib/vscode/src/vs/platform/contextkey/common/contextkey.ts rename to src/vs/platform/contextkey/common/contextkey.ts index 749573dc451d..66e4c24e8674 100644 --- a/lib/vscode/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -21,7 +21,6 @@ STATIC_VALUES.set('isEdge', _userAgent.indexOf('Edg/') >= 0); STATIC_VALUES.set('isFirefox', _userAgent.indexOf('Firefox') >= 0); STATIC_VALUES.set('isChrome', _userAgent.indexOf('Chrome') >= 0); STATIC_VALUES.set('isSafari', _userAgent.indexOf('Safari') >= 0); -STATIC_VALUES.set('isIPad', _userAgent.indexOf('iPad') >= 0); const hasOwnProperty = Object.prototype.hasOwnProperty; diff --git a/lib/vscode/src/vs/platform/contextkey/common/contextkeys.ts b/src/vs/platform/contextkey/common/contextkeys.ts similarity index 87% rename from lib/vscode/src/vs/platform/contextkey/common/contextkeys.ts rename to src/vs/platform/contextkey/common/contextkeys.ts index d98aa5ee62c3..4b40ea1d517f 100644 --- a/lib/vscode/src/vs/platform/contextkey/common/contextkeys.ts +++ b/src/vs/platform/contextkey/common/contextkeys.ts @@ -5,7 +5,7 @@ import { localize } from 'vs/nls'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { isMacintosh, isLinux, isWindows, isWeb } from 'vs/base/common/platform'; +import { isMacintosh, isLinux, isWindows, isWeb, isIOS } from 'vs/base/common/platform'; export const IsMacContext = new RawContextKey('isMac', isMacintosh, localize('isMac', "Whether the operating system is macOS")); export const IsLinuxContext = new RawContextKey('isLinux', isLinux, localize('isLinux', "Whether the operating system is Linux")); @@ -13,6 +13,7 @@ export const IsWindowsContext = new RawContextKey('isWindows', isWindow export const IsWebContext = new RawContextKey('isWeb', isWeb, localize('isWeb', "Whether the platform is a web browser")); export const IsMacNativeContext = new RawContextKey('isMacNative', isMacintosh && !isWeb, localize('isMacNative', "Whether the operating system is macOS on a non-browser platform")); +export const IsIOSContext = new RawContextKey('isIOS', isIOS, localize('isIOS', "Whether the operating system is IOS")); export const IsDevelopmentContext = new RawContextKey('isDevelopment', false, true); diff --git a/lib/vscode/src/vs/platform/contextkey/test/browser/contextkey.test.ts b/src/vs/platform/contextkey/test/browser/contextkey.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/contextkey/test/browser/contextkey.test.ts rename to src/vs/platform/contextkey/test/browser/contextkey.test.ts diff --git a/lib/vscode/src/vs/platform/contextkey/test/common/contextkey.test.ts b/src/vs/platform/contextkey/test/common/contextkey.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/contextkey/test/common/contextkey.test.ts rename to src/vs/platform/contextkey/test/common/contextkey.test.ts diff --git a/lib/vscode/src/vs/platform/contextview/browser/contextMenuHandler.css b/src/vs/platform/contextview/browser/contextMenuHandler.css similarity index 100% rename from lib/vscode/src/vs/platform/contextview/browser/contextMenuHandler.css rename to src/vs/platform/contextview/browser/contextMenuHandler.css diff --git a/lib/vscode/src/vs/platform/contextview/browser/contextMenuHandler.ts b/src/vs/platform/contextview/browser/contextMenuHandler.ts similarity index 100% rename from lib/vscode/src/vs/platform/contextview/browser/contextMenuHandler.ts rename to src/vs/platform/contextview/browser/contextMenuHandler.ts diff --git a/lib/vscode/src/vs/platform/contextview/browser/contextMenuService.ts b/src/vs/platform/contextview/browser/contextMenuService.ts similarity index 94% rename from lib/vscode/src/vs/platform/contextview/browser/contextMenuService.ts rename to src/vs/platform/contextview/browser/contextMenuService.ts index 77c92d6dd26b..afc0b1c930c0 100644 --- a/lib/vscode/src/vs/platform/contextview/browser/contextMenuService.ts +++ b/src/vs/platform/contextview/browser/contextMenuService.ts @@ -12,12 +12,15 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { Disposable } from 'vs/base/common/lifecycle'; import { ModifierKeyEmitter } from 'vs/base/browser/dom'; +import { Emitter } from 'vs/base/common/event'; export class ContextMenuService extends Disposable implements IContextMenuService { declare readonly _serviceBrand: undefined; private contextMenuHandler: ContextMenuHandler; + readonly onDidShowContextMenu = new Emitter().event; + constructor( @ITelemetryService telemetryService: ITelemetryService, @INotificationService notificationService: INotificationService, diff --git a/lib/vscode/src/vs/platform/contextview/browser/contextView.ts b/src/vs/platform/contextview/browser/contextView.ts similarity index 95% rename from lib/vscode/src/vs/platform/contextview/browser/contextView.ts rename to src/vs/platform/contextview/browser/contextView.ts index b33d652cf120..9a37ae690384 100644 --- a/lib/vscode/src/vs/platform/contextview/browser/contextView.ts +++ b/src/vs/platform/contextview/browser/contextView.ts @@ -7,6 +7,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IContextMenuDelegate } from 'vs/base/browser/contextmenu'; import { AnchorAlignment, AnchorAxisAlignment, IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; +import { Event } from 'vs/base/common/event'; export const IContextViewService = createDecorator('contextViewService'); @@ -40,5 +41,7 @@ export interface IContextMenuService { readonly _serviceBrand: undefined; + readonly onDidShowContextMenu: Event; + showContextMenu(delegate: IContextMenuDelegate): void; } diff --git a/lib/vscode/src/vs/platform/contextview/browser/contextViewService.ts b/src/vs/platform/contextview/browser/contextViewService.ts similarity index 100% rename from lib/vscode/src/vs/platform/contextview/browser/contextViewService.ts rename to src/vs/platform/contextview/browser/contextViewService.ts diff --git a/lib/vscode/src/vs/platform/debug/common/extensionHostDebug.ts b/src/vs/platform/debug/common/extensionHostDebug.ts similarity index 100% rename from lib/vscode/src/vs/platform/debug/common/extensionHostDebug.ts rename to src/vs/platform/debug/common/extensionHostDebug.ts diff --git a/lib/vscode/src/vs/platform/debug/common/extensionHostDebugIpc.ts b/src/vs/platform/debug/common/extensionHostDebugIpc.ts similarity index 100% rename from lib/vscode/src/vs/platform/debug/common/extensionHostDebugIpc.ts rename to src/vs/platform/debug/common/extensionHostDebugIpc.ts diff --git a/lib/vscode/src/vs/platform/debug/electron-main/extensionHostDebugIpc.ts b/src/vs/platform/debug/electron-main/extensionHostDebugIpc.ts similarity index 100% rename from lib/vscode/src/vs/platform/debug/electron-main/extensionHostDebugIpc.ts rename to src/vs/platform/debug/electron-main/extensionHostDebugIpc.ts diff --git a/lib/vscode/src/vs/platform/diagnostics/common/diagnostics.ts b/src/vs/platform/diagnostics/common/diagnostics.ts similarity index 100% rename from lib/vscode/src/vs/platform/diagnostics/common/diagnostics.ts rename to src/vs/platform/diagnostics/common/diagnostics.ts diff --git a/lib/vscode/src/vs/platform/diagnostics/electron-sandbox/diagnosticsService.ts b/src/vs/platform/diagnostics/electron-sandbox/diagnosticsService.ts similarity index 100% rename from lib/vscode/src/vs/platform/diagnostics/electron-sandbox/diagnosticsService.ts rename to src/vs/platform/diagnostics/electron-sandbox/diagnosticsService.ts diff --git a/lib/vscode/src/vs/platform/diagnostics/node/diagnosticsService.ts b/src/vs/platform/diagnostics/node/diagnosticsService.ts similarity index 100% rename from lib/vscode/src/vs/platform/diagnostics/node/diagnosticsService.ts rename to src/vs/platform/diagnostics/node/diagnosticsService.ts diff --git a/lib/vscode/src/vs/platform/dialogs/common/dialogs.ts b/src/vs/platform/dialogs/common/dialogs.ts similarity index 100% rename from lib/vscode/src/vs/platform/dialogs/common/dialogs.ts rename to src/vs/platform/dialogs/common/dialogs.ts diff --git a/lib/vscode/src/vs/platform/dialogs/electron-main/dialogMainService.ts b/src/vs/platform/dialogs/electron-main/dialogMainService.ts similarity index 96% rename from lib/vscode/src/vs/platform/dialogs/electron-main/dialogMainService.ts rename to src/vs/platform/dialogs/electron-main/dialogMainService.ts index 164e8d7694c5..b06fa6789eb9 100644 --- a/lib/vscode/src/vs/platform/dialogs/electron-main/dialogMainService.ts +++ b/src/vs/platform/dialogs/electron-main/dialogMainService.ts @@ -6,7 +6,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { MessageBoxOptions, MessageBoxReturnValue, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, dialog, FileFilter, BrowserWindow } from 'electron'; import { Queue } from 'vs/base/common/async'; -import { IStateService } from 'vs/platform/state/node/state'; +import { IStateMainService } from 'vs/platform/state/electron-main/state'; import { isMacintosh } from 'vs/base/common/platform'; import { dirname } from 'vs/base/common/path'; import { normalizeNFC } from 'vs/base/common/normalization'; @@ -55,7 +55,7 @@ export class DialogMainService implements IDialogMainService { private readonly noWindowDialogueQueue = new Queue(); constructor( - @IStateService private readonly stateService: IStateService + @IStateMainService private readonly stateMainService: IStateMainService ) { } @@ -89,8 +89,7 @@ export class DialogMainService implements IDialogMainService { }; // Ensure defaultPath - dialogOptions.defaultPath = options.defaultPath || this.stateService.getItem(DialogMainService.workingDirPickerStorageKey); - + dialogOptions.defaultPath = options.defaultPath || this.stateMainService.getItem(DialogMainService.workingDirPickerStorageKey); // Ensure properties if (typeof options.pickFiles === 'boolean' || typeof options.pickFolders === 'boolean') { @@ -116,7 +115,7 @@ export class DialogMainService implements IDialogMainService { if (result && result.filePaths && result.filePaths.length > 0) { // Remember path in storage for next time - this.stateService.setItem(DialogMainService.workingDirPickerStorageKey, dirname(result.filePaths[0])); + this.stateMainService.setItem(DialogMainService.workingDirPickerStorageKey, dirname(result.filePaths[0])); return result.filePaths; } diff --git a/src/vs/platform/dialogs/test/common/testDialogService.ts b/src/vs/platform/dialogs/test/common/testDialogService.ts new file mode 100644 index 000000000000..1d2b2f08f71b --- /dev/null +++ b/src/vs/platform/dialogs/test/common/testDialogService.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 Severity from 'vs/base/common/severity'; +import { IConfirmation, IConfirmationResult, IDialogService, IDialogOptions, IShowResult, IInputResult } from 'vs/platform/dialogs/common/dialogs'; + +export class TestDialogService implements IDialogService { + + declare readonly _serviceBrand: undefined; + + private confirmResult: IConfirmationResult | undefined = undefined; + setConfirmResult(result: IConfirmationResult) { + this.confirmResult = result; + } + + async confirm(confirmation: IConfirmation): Promise { + if (this.confirmResult) { + const confirmResult = this.confirmResult; + this.confirmResult = undefined; + + return confirmResult; + } + + return { confirmed: false }; + } + + async show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions): Promise { return { choice: 0 }; } + async input(): Promise { { return { choice: 0, values: [] }; } } + async about(): Promise { } +} diff --git a/lib/vscode/src/vs/platform/download/common/download.ts b/src/vs/platform/download/common/download.ts similarity index 100% rename from lib/vscode/src/vs/platform/download/common/download.ts rename to src/vs/platform/download/common/download.ts diff --git a/lib/vscode/src/vs/platform/download/common/downloadIpc.ts b/src/vs/platform/download/common/downloadIpc.ts similarity index 100% rename from lib/vscode/src/vs/platform/download/common/downloadIpc.ts rename to src/vs/platform/download/common/downloadIpc.ts diff --git a/lib/vscode/src/vs/platform/download/common/downloadService.ts b/src/vs/platform/download/common/downloadService.ts similarity index 100% rename from lib/vscode/src/vs/platform/download/common/downloadService.ts rename to src/vs/platform/download/common/downloadService.ts diff --git a/lib/vscode/src/vs/platform/driver/browser/baseDriver.ts b/src/vs/platform/driver/browser/baseDriver.ts similarity index 100% rename from lib/vscode/src/vs/platform/driver/browser/baseDriver.ts rename to src/vs/platform/driver/browser/baseDriver.ts diff --git a/lib/vscode/src/vs/platform/driver/browser/driver.ts b/src/vs/platform/driver/browser/driver.ts similarity index 100% rename from lib/vscode/src/vs/platform/driver/browser/driver.ts rename to src/vs/platform/driver/browser/driver.ts diff --git a/lib/vscode/src/vs/platform/driver/common/driver.ts b/src/vs/platform/driver/common/driver.ts similarity index 100% rename from lib/vscode/src/vs/platform/driver/common/driver.ts rename to src/vs/platform/driver/common/driver.ts diff --git a/lib/vscode/src/vs/platform/driver/common/driverIpc.ts b/src/vs/platform/driver/common/driverIpc.ts similarity index 100% rename from lib/vscode/src/vs/platform/driver/common/driverIpc.ts rename to src/vs/platform/driver/common/driverIpc.ts diff --git a/lib/vscode/src/vs/platform/driver/electron-main/driver.ts b/src/vs/platform/driver/electron-main/driver.ts similarity index 100% rename from lib/vscode/src/vs/platform/driver/electron-main/driver.ts rename to src/vs/platform/driver/electron-main/driver.ts diff --git a/lib/vscode/src/vs/platform/driver/electron-sandbox/driver.ts b/src/vs/platform/driver/electron-sandbox/driver.ts similarity index 100% rename from lib/vscode/src/vs/platform/driver/electron-sandbox/driver.ts rename to src/vs/platform/driver/electron-sandbox/driver.ts diff --git a/lib/vscode/src/vs/platform/driver/node/driver.ts b/src/vs/platform/driver/node/driver.ts similarity index 100% rename from lib/vscode/src/vs/platform/driver/node/driver.ts rename to src/vs/platform/driver/node/driver.ts diff --git a/lib/vscode/src/vs/platform/editor/common/editor.ts b/src/vs/platform/editor/common/editor.ts similarity index 87% rename from lib/vscode/src/vs/platform/editor/common/editor.ts rename to src/vs/platform/editor/common/editor.ts index c5611b87ae40..f4e2cffb7614 100644 --- a/lib/vscode/src/vs/platform/editor/common/editor.ts +++ b/src/vs/platform/editor/common/editor.ts @@ -37,17 +37,17 @@ export interface IEditorModel { export interface IBaseResourceEditorInput { /** - * Optional options to use when opening the text input. + * Optional options to use when opening the input. */ - options?: ITextEditorOptions; + options?: IEditorOptions; /** - * Label to show for the diff editor + * Label to show for the input. */ readonly label?: string; /** - * Description to show for the diff editor + * Description to show for the input. */ readonly description?: string; @@ -70,21 +70,30 @@ export interface IBaseResourceEditorInput { readonly forceUntitled?: boolean; } -/** - * This identifier allows to uniquely identify an editor with a - * resource and type identifier. - */ -export interface IResourceEditorInputIdentifier { +export interface IBaseTextResourceEditorInput extends IBaseResourceEditorInput { /** - * The resource URI of the editor. + * Optional options to use when opening the text input. */ - readonly resource: URI; + options?: ITextEditorOptions; /** - * The type of the editor. + * The contents of the text input if known. If provided, + * the input will not attempt to load the contents from + * disk and may appear dirty. */ - readonly typeId: string; + contents?: string; + + /** + * The encoding of the text input if known. + */ + encoding?: string; + + /** + * The identifier of the language mode of the text input + * if known to use when displaying the contents. + */ + mode?: string; } export interface IResourceEditorInput extends IBaseResourceEditorInput { @@ -93,17 +102,31 @@ export interface IResourceEditorInput extends IBaseResourceEditorInput { * The resource URI of the resource to open. */ readonly resource: URI; +} + +export interface ITextResourceEditorInput extends IResourceEditorInput, IBaseTextResourceEditorInput { /** - * The encoding of the text input if known. + * Optional options to use when opening the text input. */ - readonly encoding?: string; + options?: ITextEditorOptions; +} + +/** + * This identifier allows to uniquely identify an editor with a + * resource and type identifier. + */ +export interface IResourceEditorInputIdentifier { /** - * The identifier of the language mode of the text input - * if known to use when displaying the contents. + * The resource URI of the editor. */ - readonly mode?: string; + readonly resource: URI; + + /** + * The type of the editor. + */ + readonly typeId: string; } export enum EditorActivation { @@ -169,7 +192,7 @@ export interface IEditorOptions { * Will also not activate the group the editor opens in unless the group is already * the active one. This behaviour can be overridden via the `activation` option. */ - readonly preserveFocus?: boolean; + preserveFocus?: boolean; /** * This option is only relevant if an editor is opened into a group that is not active @@ -179,14 +202,14 @@ export interface IEditorOptions { * By default, the editor group will become active unless `preserveFocus` or `inactive` * is specified. */ - readonly activation?: EditorActivation; + activation?: EditorActivation; /** * Tells the editor to reload the editor input in the editor even if it is identical to the one * already showing. By default, the editor will not reload the input if it is identical to the * one showing. */ - readonly forceReload?: boolean; + forceReload?: boolean; /** * Will reveal the editor if it is already opened and visible in any of the opened editor groups. @@ -194,7 +217,7 @@ export interface IEditorOptions { * Note that this option is just a hint that might be ignored if the user wants to open an editor explicitly * to the side of another one or into a specific editor group. */ - readonly revealIfVisible?: boolean; + revealIfVisible?: boolean; /** * Will reveal the editor if it is already opened (even when not visible) in any of the opened editor groups. @@ -202,24 +225,24 @@ export interface IEditorOptions { * Note that this option is just a hint that might be ignored if the user wants to open an editor explicitly * to the side of another one or into a specific editor group. */ - readonly revealIfOpened?: boolean; + revealIfOpened?: boolean; /** * An editor that is pinned remains in the editor stack even when another editor is being opened. * An editor that is not pinned will always get replaced by another editor that is not pinned. */ - readonly pinned?: boolean; + pinned?: boolean; /** * An editor that is sticky moves to the beginning of the editors list within the group and will remain * there unless explicitly closed. Operations such as "Close All" will not close sticky editors. */ - readonly sticky?: boolean; + sticky?: boolean; /** * The index in the document stack where to insert the editor into when opening. */ - readonly index?: number; + index?: number; /** * An active editor that is opened will show its contents directly. Set to true to open an editor @@ -228,13 +251,13 @@ export interface IEditorOptions { * Will also not activate the group the editor opens in unless the group is already * the active one. This behaviour can be overridden via the `activation` option. */ - readonly inactive?: boolean; + inactive?: boolean; /** * Will not show an error in case opening the editor fails and thus allows to show a custom error * message as needed. By default, an error will be presented as notification if opening was not possible. */ - readonly ignoreError?: boolean; + ignoreError?: boolean; /** * Allows to override the editor that should be used to display the input: @@ -242,7 +265,7 @@ export interface IEditorOptions { * - `string`: specific override by id * - `EditorOverride`: specific override handling */ - readonly override?: string | EditorOverride; + override?: string | EditorOverride; /** * A optional hint to signal in which context the editor opens. @@ -254,7 +277,7 @@ export interface IEditorOptions { * some background task, the notification would show in the background, * not as a modal dialog. */ - readonly context?: EditorOpenContext; + context?: EditorOpenContext; } export interface ITextEditorSelection { @@ -269,14 +292,17 @@ export const enum TextEditorSelectionRevealType { * Option to scroll vertically or horizontally as necessary and reveal a range centered vertically. */ Center = 0, + /** * Option to scroll vertically or horizontally as necessary and reveal a range centered vertically only if it lies outside the viewport. */ CenterIfOutsideViewport = 1, + /** * Option to scroll vertically or horizontally as necessary and reveal a range close to the top of the viewport, but not quite at the top. */ NearTop = 2, + /** * Option to scroll vertically or horizontally as necessary and reveal a range close to the top of the viewport, but not quite at the top. * Only if it lies outside the viewport @@ -289,16 +315,16 @@ export interface ITextEditorOptions extends IEditorOptions { /** * Text editor selection. */ - readonly selection?: ITextEditorSelection; + selection?: ITextEditorSelection; /** * Text editor view state. */ - readonly viewState?: object; + viewState?: object; /** * Option to control the text editor selection reveal type. * Defaults to TextEditorSelectionRevealType.Center */ - readonly selectionRevealType?: TextEditorSelectionRevealType; + selectionRevealType?: TextEditorSelectionRevealType; } diff --git a/lib/vscode/src/vs/platform/encryption/common/encryptionService.ts b/src/vs/platform/encryption/common/encryptionService.ts similarity index 100% rename from lib/vscode/src/vs/platform/encryption/common/encryptionService.ts rename to src/vs/platform/encryption/common/encryptionService.ts diff --git a/lib/vscode/src/vs/platform/encryption/electron-main/encryptionMainService.ts b/src/vs/platform/encryption/electron-main/encryptionMainService.ts similarity index 100% rename from lib/vscode/src/vs/platform/encryption/electron-main/encryptionMainService.ts rename to src/vs/platform/encryption/electron-main/encryptionMainService.ts diff --git a/lib/vscode/src/vs/platform/environment/common/argv.ts b/src/vs/platform/environment/common/argv.ts similarity index 97% rename from lib/vscode/src/vs/platform/environment/common/argv.ts rename to src/vs/platform/environment/common/argv.ts index 07cd8868338c..ded07ffcd9e5 100644 --- a/lib/vscode/src/vs/platform/environment/common/argv.ts +++ b/src/vs/platform/environment/common/argv.ts @@ -7,8 +7,6 @@ * A list of command line arguments we support natively. */ export interface NativeParsedArgs { - 'extra-extensions-dir'?: string[]; - 'extra-builtin-extensions-dir'?: string[]; _: string[]; 'folder-uri'?: string[]; // undefined or array of 1 or more 'file-uri'?: string[]; // undefined or array of 1 or more @@ -67,6 +65,7 @@ export interface NativeParsedArgs { 'install-source'?: string; 'disable-updates'?: boolean; 'disable-keytar'?: boolean; + 'disable-workspace-trust'?: boolean; 'disable-crash-reporter'?: boolean; 'crash-reporter-directory'?: string; 'crash-reporter-id'?: string; diff --git a/lib/vscode/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts similarity index 98% rename from lib/vscode/src/vs/platform/environment/common/environment.ts rename to src/vs/platform/environment/common/environment.ts index 3161ff354cab..77efaac3fbaf 100644 --- a/lib/vscode/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -66,6 +66,9 @@ export interface IEnvironmentService { extensionDevelopmentKind?: ExtensionKind[]; extensionTestsLocationURI?: URI; + // --- workspace trust + disableWorkspaceTrust: boolean; + // --- logging logsPath: string; logLevel?: string; @@ -121,8 +124,6 @@ export interface INativeEnvironmentService extends IEnvironmentService { extensionsPath: string; extensionsDownloadPath: string; builtinExtensionsPath: string; - extraExtensionPaths: string[] - extraBuiltinExtensionPaths: string[] // --- smoke test support driverHandle?: string; diff --git a/lib/vscode/src/vs/platform/environment/common/environmentService.ts b/src/vs/platform/environment/common/environmentService.ts similarity index 91% rename from lib/vscode/src/vs/platform/environment/common/environmentService.ts rename to src/vs/platform/environment/common/environmentService.ts index cee37bfe3390..70e06765c697 100644 --- a/lib/vscode/src/vs/platform/environment/common/environmentService.ts +++ b/src/vs/platform/environment/common/environmentService.ts @@ -15,23 +15,6 @@ import { URI } from 'vs/base/common/uri'; import { ExtensionKind } from 'vs/platform/extensions/common/extensions'; import { env } from 'vs/base/common/process'; - -function parsePathArg(arg: string | undefined, process: NodeJS.Process): string | undefined { - if (!arg) { - return undefined; - } - - // Determine if the arg is relative or absolute, if relative use the original CWD - // (VSCODE_CWD), not the potentially overridden one (process.cwd()). - const resolved = resolve(arg); - - if (normalize(arg) === resolved) { - return resolved; - } - - return resolve(process.env['VSCODE_CWD'] || process.cwd(), arg); -} - export interface INativeEnvironmentPaths { /** @@ -190,19 +173,6 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron return undefined; } - /** - * NOTE@coder: add extraExtensionPaths and extraBuiltinExtensionPaths - */ - @memoize - get extraExtensionPaths(): string[] { - return (this._args['extra-extensions-dir'] || []).map((p) => parsePathArg(p, process)); - } - - @memoize - get extraBuiltinExtensionPaths(): string[] { - return (this._args['extra-builtin-extensions-dir'] || []).map((p) => parsePathArg(p, process)); - } - @memoize get extensionDevelopmentKind(): ExtensionKind[] | undefined { return this.args.extensionDevelopmentKind?.map(kind => kind === 'ui' || kind === 'workspace' || kind === 'web' ? kind : 'workspace'); @@ -261,6 +231,9 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron get telemetryLogResource(): URI { return URI.file(join(this.logsPath, 'telemetry.log')); } get disableTelemetry(): boolean { return !!this.args['disable-telemetry']; } + @memoize + get disableWorkspaceTrust(): boolean { return !!this.args['disable-workspace-trust']; } + get args(): NativeParsedArgs { return this._args; } constructor( diff --git a/lib/vscode/src/vs/platform/environment/electron-main/environmentMainService.ts b/src/vs/platform/environment/electron-main/environmentMainService.ts similarity index 100% rename from lib/vscode/src/vs/platform/environment/electron-main/environmentMainService.ts rename to src/vs/platform/environment/electron-main/environmentMainService.ts diff --git a/lib/vscode/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts similarity index 96% rename from lib/vscode/src/vs/platform/environment/node/argv.ts rename to src/vs/platform/environment/node/argv.ts index faf8cfa00cbd..238098af3a06 100644 --- a/lib/vscode/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -52,11 +52,9 @@ export const OPTIONS: OptionDescriptions> = { 'extensions-dir': { type: 'string', deprecates: 'extensionHomePath', cat: 'e', args: 'dir', description: localize('extensionHomePath', "Set the root path for extensions.") }, 'extensions-download-dir': { type: 'string' }, 'builtin-extensions-dir': { type: 'string' }, - 'extra-builtin-extensions-dir': { type: 'string[]', cat: 'o', description: 'Path to an extra builtin extension directory.' }, - 'extra-extensions-dir': { type: 'string[]', cat: 'o', description: 'Path to an extra user extension directory.' }, 'list-extensions': { type: 'boolean', cat: 'e', description: localize('listExtensions', "List the installed extensions.") }, 'show-versions': { type: 'boolean', cat: 'e', description: localize('showVersions', "Show versions of installed extensions, when using --list-extensions.") }, - 'category': { type: 'string', cat: 'e', description: localize('category', "Filters installed extensions by provided category, when using --list-extensions.") }, + 'category': { type: 'string', cat: 'e', description: localize('category', "Filters installed extensions by provided category, when using --list-extensions."), args: 'category' }, 'install-extension': { type: 'string[]', cat: 'e', args: 'extension-id[@version] | path-to-vsix', description: localize('installExtension', "Installs or updates the extension. The identifier of an extension is always `${publisher}.${name}`. Use `--force` argument to update to latest version. To install a specific version provide `@${version}`. For example: 'vscode.csharp@1.2.3'.") }, 'uninstall-extension': { type: 'string[]', cat: 'e', args: 'extension-id', description: localize('uninstallExtension', "Uninstalls an extension.") }, 'enable-proposed-api': { type: 'string[]', cat: 'e', args: 'extension-id', description: localize('experimentalApis', "Enables proposed API features for extensions. Can receive one or more extension IDs to enable individually.") }, @@ -65,18 +63,18 @@ export const OPTIONS: OptionDescriptions> = { 'verbose': { type: 'boolean', cat: 't', description: localize('verbose', "Print verbose output (implies --wait).") }, 'log': { type: 'string', cat: 't', args: 'level', description: localize('log', "Log level to use. Default is 'info'. Allowed values are 'critical', 'error', 'warn', 'info', 'debug', 'trace', 'off'.") }, 'status': { type: 'boolean', alias: 's', cat: 't', description: localize('status', "Print process usage and diagnostics information.") }, - 'prof-startup': { type: 'boolean', cat: 't', description: localize('prof-startup', "Run CPU profiler during startup") }, + 'prof-startup': { type: 'boolean', cat: 't', description: localize('prof-startup', "Run CPU profiler during startup.") }, 'prof-append-timers': { type: 'string' }, 'prof-startup-prefix': { type: 'string' }, 'prof-v8-extensions': { type: 'boolean' }, 'disable-extensions': { type: 'boolean', deprecates: 'disableExtensions', cat: 't', description: localize('disableExtensions', "Disable all installed extensions.") }, 'disable-extension': { type: 'string[]', cat: 't', args: 'extension-id', description: localize('disableExtension', "Disable an extension.") }, - 'sync': { type: 'string', cat: 't', description: localize('turn sync', "Turn sync on or off"), args: ['on', 'off'] }, + 'sync': { type: 'string', cat: 't', description: localize('turn sync', "Turn sync on or off."), args: ['on', 'off'] }, 'inspect-extensions': { type: 'string', deprecates: 'debugPluginHost', args: 'port', cat: 't', description: localize('inspect-extensions', "Allow debugging and profiling of extensions. Check the developer tools for the connection URI.") }, 'inspect-brk-extensions': { type: 'string', deprecates: 'debugBrkPluginHost', args: 'port', cat: 't', description: localize('inspect-brk-extensions', "Allow debugging and profiling of extensions with the extension host being paused after start. Check the developer tools for the connection URI.") }, 'disable-gpu': { type: 'boolean', cat: 't', description: localize('disableGPU', "Disable GPU hardware acceleration.") }, - 'max-memory': { type: 'string', cat: 't', description: localize('maxMemory', "Max memory size for a window (in Mbytes).") }, + 'max-memory': { type: 'string', cat: 't', description: localize('maxMemory', "Max memory size for a window (in Mbytes)."), args: 'memory' }, 'telemetry': { type: 'boolean', cat: 't', description: localize('telemetry', "Shows all telemetry events which VS code collects.") }, 'remote': { type: 'string' }, @@ -99,6 +97,7 @@ export const OPTIONS: OptionDescriptions> = { 'disable-telemetry': { type: 'boolean' }, 'disable-updates': { type: 'boolean' }, 'disable-keytar': { type: 'boolean' }, + 'disable-workspace-trust': { type: 'boolean' }, 'disable-crash-reporter': { type: 'boolean' }, 'crash-reporter-directory': { type: 'string' }, 'crash-reporter-id': { type: 'string' }, diff --git a/lib/vscode/src/vs/platform/environment/node/argvHelper.ts b/src/vs/platform/environment/node/argvHelper.ts similarity index 100% rename from lib/vscode/src/vs/platform/environment/node/argvHelper.ts rename to src/vs/platform/environment/node/argvHelper.ts diff --git a/lib/vscode/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts similarity index 100% rename from lib/vscode/src/vs/platform/environment/node/environmentService.ts rename to src/vs/platform/environment/node/environmentService.ts diff --git a/lib/vscode/src/vs/platform/environment/node/shellEnv.ts b/src/vs/platform/environment/node/shellEnv.ts similarity index 100% rename from lib/vscode/src/vs/platform/environment/node/shellEnv.ts rename to src/vs/platform/environment/node/shellEnv.ts diff --git a/lib/vscode/src/vs/platform/environment/node/stdin.ts b/src/vs/platform/environment/node/stdin.ts similarity index 100% rename from lib/vscode/src/vs/platform/environment/node/stdin.ts rename to src/vs/platform/environment/node/stdin.ts diff --git a/lib/vscode/src/vs/platform/environment/node/userDataPath.d.ts b/src/vs/platform/environment/node/userDataPath.d.ts similarity index 100% rename from lib/vscode/src/vs/platform/environment/node/userDataPath.d.ts rename to src/vs/platform/environment/node/userDataPath.d.ts diff --git a/lib/vscode/src/vs/platform/environment/node/userDataPath.js b/src/vs/platform/environment/node/userDataPath.js similarity index 100% rename from lib/vscode/src/vs/platform/environment/node/userDataPath.js rename to src/vs/platform/environment/node/userDataPath.js diff --git a/lib/vscode/src/vs/platform/environment/node/wait.ts b/src/vs/platform/environment/node/wait.ts similarity index 100% rename from lib/vscode/src/vs/platform/environment/node/wait.ts rename to src/vs/platform/environment/node/wait.ts diff --git a/lib/vscode/src/vs/platform/environment/test/node/argv.test.ts b/src/vs/platform/environment/test/node/argv.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/environment/test/node/argv.test.ts rename to src/vs/platform/environment/test/node/argv.test.ts diff --git a/lib/vscode/src/vs/platform/environment/test/node/environmentService.test.ts b/src/vs/platform/environment/test/node/environmentService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/environment/test/node/environmentService.test.ts rename to src/vs/platform/environment/test/node/environmentService.test.ts diff --git a/lib/vscode/src/vs/platform/environment/test/node/nativeModules.test.ts b/src/vs/platform/environment/test/node/nativeModules.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/environment/test/node/nativeModules.test.ts rename to src/vs/platform/environment/test/node/nativeModules.test.ts diff --git a/lib/vscode/src/vs/platform/environment/test/node/userDataPath.test.ts b/src/vs/platform/environment/test/node/userDataPath.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/environment/test/node/userDataPath.test.ts rename to src/vs/platform/environment/test/node/userDataPath.test.ts diff --git a/lib/vscode/src/vs/platform/extensionManagement/common/configRemotes.ts b/src/vs/platform/extensionManagement/common/configRemotes.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionManagement/common/configRemotes.ts rename to src/vs/platform/extensionManagement/common/configRemotes.ts diff --git a/lib/vscode/src/vs/platform/extensionManagement/common/extensionEnablementService.ts b/src/vs/platform/extensionManagement/common/extensionEnablementService.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionManagement/common/extensionEnablementService.ts rename to src/vs/platform/extensionManagement/common/extensionEnablementService.ts diff --git a/lib/vscode/src/vs/platform/extensionManagement/common/extensionGalleryService.ts b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts similarity index 91% rename from lib/vscode/src/vs/platform/extensionManagement/common/extensionGalleryService.ts rename to src/vs/platform/extensionManagement/common/extensionGalleryService.ts index 45d3b68c4836..068a23e52dbe 100644 --- a/lib/vscode/src/vs/platform/extensionManagement/common/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts @@ -25,48 +25,48 @@ import { optional } from 'vs/platform/instantiation/common/instantiation'; import { joinPath } from 'vs/base/common/resources'; interface IRawGalleryExtensionFile { - assetType: string; - source: string; + readonly assetType: string; + readonly source: string; } interface IRawGalleryExtensionProperty { - key: string; - value: string; + readonly key: string; + readonly value: string; } interface IRawGalleryExtensionVersion { - version: string; - lastUpdated: string; - assetUri: string; - fallbackAssetUri: string; - files: IRawGalleryExtensionFile[]; - properties?: IRawGalleryExtensionProperty[]; + readonly version: string; + readonly lastUpdated: string; + readonly assetUri: string; + readonly fallbackAssetUri: string; + readonly files: IRawGalleryExtensionFile[]; + readonly properties?: IRawGalleryExtensionProperty[]; } interface IRawGalleryExtensionStatistics { - statisticName: string; - value: number; + readonly statisticName: string; + readonly value: number; } interface IRawGalleryExtension { - extensionId: string; - extensionName: string; - displayName: string; - shortDescription: string; - publisher: { displayName: string, publisherId: string, publisherName: string; }; - versions: IRawGalleryExtensionVersion[]; - statistics: IRawGalleryExtensionStatistics[]; - flags: string; + readonly extensionId: string; + readonly extensionName: string; + readonly displayName: string; + readonly shortDescription: string; + readonly publisher: { displayName: string, publisherId: string, publisherName: string; }; + readonly versions: IRawGalleryExtensionVersion[]; + readonly statistics: IRawGalleryExtensionStatistics[]; + readonly flags: string; } interface IRawGalleryQueryResult { - results: { - extensions: IRawGalleryExtension[]; - resultMetadata: { - metadataType: string; - metadataItems: { - name: string; - count: number; + readonly results: { + readonly extensions: IRawGalleryExtension[]; + readonly resultMetadata: { + readonly metadataType: string; + readonly metadataItems: { + readonly name: string; + readonly count: number; }[]; }[] }[]; @@ -121,20 +121,20 @@ const PropertyType = { }; interface ICriterium { - filterType: FilterType; - value?: string; + readonly filterType: FilterType; + readonly value?: string; } const DefaultPageSize = 10; interface IQueryState { - pageNumber: number; - pageSize: number; - sortBy: SortBy; - sortOrder: SortOrder; - flags: Flags; - criteria: ICriterium[]; - assetTypes: string[]; + readonly pageNumber: number; + readonly pageSize: number; + readonly sortBy: SortBy; + readonly sortOrder: SortOrder; + readonly flags: Flags; + readonly criteria: ICriterium[]; + readonly assetTypes: string[]; } const DefaultQueryState: IQueryState = { @@ -148,32 +148,32 @@ const DefaultQueryState: IQueryState = { }; type GalleryServiceQueryClassification = { - filterTypes: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - sortBy: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - sortOrder: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - duration: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', 'isMeasurement': true }; - success: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - requestBodySize: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - responseBodySize?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - statusCode?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - errorCode?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; - count?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + readonly filterTypes: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + readonly sortBy: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + readonly sortOrder: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + readonly duration: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', 'isMeasurement': true }; + readonly success: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + readonly requestBodySize: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + readonly responseBodySize?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + readonly statusCode?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + readonly errorCode?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + readonly count?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; }; type QueryTelemetryData = { - filterTypes: string[]; - sortBy: string; - sortOrder: string; + readonly filterTypes: string[]; + readonly sortBy: string; + readonly sortOrder: string; }; type GalleryServiceQueryEvent = QueryTelemetryData & { - duration: number; - success: boolean; - requestBodySize: string; - responseBodySize?: string; - statusCode?: string; - errorCode?: string; - count?: string; + readonly duration: number; + readonly success: boolean; + readonly requestBodySize: string; + readonly responseBodySize?: string; + readonly statusCode?: string; + readonly errorCode?: string; + readonly count?: string; }; class Query { @@ -358,13 +358,11 @@ function toExtension(galleryExtension: IRawGalleryExtension, version: IRawGaller /* __GDPR__FRAGMENT__ "GalleryExtensionTelemetryData2" : { "index" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "searchText": { "classification": "CustomerContent", "purpose": "FeatureInsight" }, "querySource": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ telemetryData: { index: ((query.pageNumber - 1) * query.pageSize) + index, - searchText: query.searchText, querySource }, preview: getIsPreview(galleryExtension.flags) @@ -435,7 +433,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { private async getCompatibleExtensionByEngine(arg1: IExtensionIdentifier | IGalleryExtension, version?: string): Promise { const extension: IGalleryExtension | null = isIExtensionIdentifier(arg1) ? null : arg1; - if (extension && extension.properties.engine && isEngineValid(extension.properties.engine, this.productService.version)) { + if (extension && extension.properties.engine && isEngineValid(extension.properties.engine, this.productService.version, this.productService.date)) { return extension; } const { id, uuid } = extension ? extension.identifier : arg1; @@ -460,7 +458,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { const versionAsset = rawExtension.versions.filter(v => v.version === version)[0]; if (versionAsset) { const extension = toExtension(rawExtension, versionAsset, 0, query); - if (extension.properties.engine && isEngineValid(extension.properties.engine, this.productService.version)) { + if (extension.properties.engine && isEngineValid(extension.properties.engine, this.productService.version, this.productService.date)) { return extension; } } @@ -713,7 +711,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { try { engine = await this.getEngine(v); } catch (error) { /* Ignore error and skip version */ } - if (engine && isEngineValid(engine, this.productService.version)) { + if (engine && isEngineValid(engine, this.productService.version, this.productService.date)) { result.push({ version: v!.version, date: v!.lastUpdated }); } })); @@ -776,7 +774,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { if (!engine) { return null; } - if (isEngineValid(engine, this.productService.version)) { + if (isEngineValid(engine, this.productService.version, this.productService.date)) { return version; } } @@ -811,13 +809,14 @@ export class ExtensionGalleryService implements IExtensionGalleryService { const version = versions[0]; const engine = await this.getEngine(version); - if (!isEngineValid(engine, this.productService.version)) { + if (!isEngineValid(engine, this.productService.version, this.productService.date)) { return this.getLastValidExtensionVersionRecursively(extension, versions.slice(1)); } - version.properties = version.properties || []; - version.properties.push({ key: PropertyType.Engine, value: engine }); - return version; + return { + ...version, + properties: [...(version.properties || []), { key: PropertyType.Engine, value: engine }] + }; } async getExtensionsReport(): Promise { diff --git a/lib/vscode/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts similarity index 98% rename from lib/vscode/src/vs/platform/extensionManagement/common/extensionManagement.ts rename to src/vs/platform/extensionManagement/common/extensionManagement.ts index e8c40c65d8e0..79b96e3434c7 100644 --- a/lib/vscode/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -203,6 +203,7 @@ export class ExtensionManagementError extends Error { } export type InstallOptions = { isBuiltin?: boolean, isMachineScoped?: boolean, donotIncludePackAndDependencies?: boolean }; +export type InstallVSIXOptions = InstallOptions & { installOnlyNewlyAddedFromExtensionPack?: boolean }; export type UninstallOptions = { donotIncludePack?: boolean, donotCheckDependents?: boolean }; export const IExtensionManagementService = createDecorator('extensionManagementService'); @@ -217,7 +218,7 @@ export interface IExtensionManagementService { zip(extension: ILocalExtension): Promise; unzip(zipLocation: URI): Promise; getManifest(vsix: URI): Promise; - install(vsix: URI, options?: InstallOptions): Promise; + install(vsix: URI, options?: InstallVSIXOptions): Promise; canInstall(extension: IGalleryExtension): Promise; installFromGallery(extension: IGalleryExtension, options?: InstallOptions): Promise; uninstall(extension: ILocalExtension, options?: UninstallOptions): Promise; diff --git a/lib/vscode/src/vs/platform/extensionManagement/common/extensionManagementCLIService.ts b/src/vs/platform/extensionManagement/common/extensionManagementCLIService.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionManagement/common/extensionManagementCLIService.ts rename to src/vs/platform/extensionManagement/common/extensionManagementCLIService.ts diff --git a/lib/vscode/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts similarity index 96% rename from lib/vscode/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts rename to src/vs/platform/extensionManagement/common/extensionManagementIpc.ts index 75422f963b26..1c18ea2121d6 100644 --- a/lib/vscode/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension, IExtensionTipsService, InstallOptions, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension, IExtensionTipsService, InstallOptions, UninstallOptions, InstallVSIXOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { Emitter, Event } from 'vs/base/common/event'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IURITransformer, DefaultURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc'; @@ -62,7 +62,7 @@ export class ExtensionManagementChannel implements IServerChannel { switch (command) { case 'zip': return this.service.zip(transformIncomingExtension(args[0], uriTransformer)).then(uri => transformOutgoingURI(uri, uriTransformer)); case 'unzip': return this.service.unzip(transformIncomingURI(args[0], uriTransformer)); - case 'install': return this.service.install(transformIncomingURI(args[0], uriTransformer)); + case 'install': return this.service.install(transformIncomingURI(args[0], uriTransformer), args[1]); case 'getManifest': return this.service.getManifest(transformIncomingURI(args[0], uriTransformer)); case 'canInstall': return this.service.canInstall(args[0]); case 'installFromGallery': return this.service.installFromGallery(args[0], args[1]); @@ -112,8 +112,8 @@ export class ExtensionManagementChannelClient extends Disposable implements IExt return Promise.resolve(this.channel.call('unzip', [zipLocation])); } - install(vsix: URI): Promise { - return Promise.resolve(this.channel.call('install', [vsix])).then(local => transformIncomingExtension(local, null)); + install(vsix: URI, options?: InstallVSIXOptions): Promise { + return Promise.resolve(this.channel.call('install', [vsix, options])).then(local => transformIncomingExtension(local, null)); } getManifest(vsix: URI): Promise { diff --git a/lib/vscode/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts b/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts rename to src/vs/platform/extensionManagement/common/extensionManagementUtil.ts diff --git a/lib/vscode/src/vs/platform/extensionManagement/common/extensionNls.ts b/src/vs/platform/extensionManagement/common/extensionNls.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionManagement/common/extensionNls.ts rename to src/vs/platform/extensionManagement/common/extensionNls.ts diff --git a/lib/vscode/src/vs/platform/extensionManagement/common/extensionTipsService.ts b/src/vs/platform/extensionManagement/common/extensionTipsService.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionManagement/common/extensionTipsService.ts rename to src/vs/platform/extensionManagement/common/extensionTipsService.ts diff --git a/lib/vscode/src/vs/platform/extensionManagement/common/extensionUrlTrust.ts b/src/vs/platform/extensionManagement/common/extensionUrlTrust.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionManagement/common/extensionUrlTrust.ts rename to src/vs/platform/extensionManagement/common/extensionUrlTrust.ts diff --git a/lib/vscode/src/vs/platform/extensionManagement/common/media/defaultIcon.png b/src/vs/platform/extensionManagement/common/media/defaultIcon.png similarity index 100% rename from lib/vscode/src/vs/platform/extensionManagement/common/media/defaultIcon.png rename to src/vs/platform/extensionManagement/common/media/defaultIcon.png diff --git a/lib/vscode/src/vs/platform/extensionManagement/electron-sandbox/extensionTipsService.ts b/src/vs/platform/extensionManagement/electron-sandbox/extensionTipsService.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionManagement/electron-sandbox/extensionTipsService.ts rename to src/vs/platform/extensionManagement/electron-sandbox/extensionTipsService.ts diff --git a/lib/vscode/src/vs/platform/extensionManagement/node/extensionDownloader.ts b/src/vs/platform/extensionManagement/node/extensionDownloader.ts similarity index 96% rename from lib/vscode/src/vs/platform/extensionManagement/node/extensionDownloader.ts rename to src/vs/platform/extensionManagement/node/extensionDownloader.ts index 53b5f311e54b..97fcf5cc46d6 100644 --- a/lib/vscode/src/vs/platform/extensionManagement/node/extensionDownloader.ts +++ b/src/vs/platform/extensionManagement/node/extensionDownloader.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { promises } from 'fs'; +import { Promises as FSPromises } from 'vs/base/node/pfs'; import { Disposable } from 'vs/base/common/lifecycle'; import { IFileService, IFileStatWithMetadata } from 'vs/platform/files/common/files'; import { IExtensionGalleryService, IGalleryExtension, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; @@ -77,7 +77,7 @@ export class ExtensionsDownloader extends Disposable { private async rename(from: URI, to: URI, retryUntil: number): Promise { try { - await promises.rename(from.fsPath, to.fsPath); + await FSPromises.rename(from.fsPath, to.fsPath); } catch (error) { if (isWindows && error && error.code === 'EPERM' && Date.now() < retryUntil) { this.logService.info(`Failed renaming ${from} to ${to} with 'EPERM' error. Trying again...`); @@ -90,7 +90,7 @@ export class ExtensionsDownloader extends Disposable { private async cleanUp(): Promise { try { if (!(await this.fileService.exists(this.extensionsDownloadDir))) { - this.logService.trace('Extension VSIX downloads cache dir does not exist'); + this.logService.trace('Extension VSIX downlads cache dir does not exist'); return; } const folderStat = await this.fileService.resolve(this.extensionsDownloadDir, { resolveMetadata: true }); diff --git a/lib/vscode/src/vs/platform/extensionManagement/node/extensionLifecycle.ts b/src/vs/platform/extensionManagement/node/extensionLifecycle.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionManagement/node/extensionLifecycle.ts rename to src/vs/platform/extensionManagement/node/extensionLifecycle.ts diff --git a/lib/vscode/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts similarity index 98% rename from lib/vscode/src/vs/platform/extensionManagement/node/extensionManagementService.ts rename to src/vs/platform/extensionManagement/node/extensionManagementService.ts index ed907661490f..7410e3572fc9 100644 --- a/lib/vscode/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as fs from 'fs'; import * as nls from 'vs/nls'; import * as path from 'vs/base/common/path'; import * as pfs from 'vs/base/node/pfs'; @@ -22,7 +21,8 @@ import { INSTALL_ERROR_INCOMPATIBLE, ExtensionManagementError, InstallOptions, - UninstallOptions + UninstallOptions, + InstallVSIXOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { areSameExtensions, getGalleryExtensionId, getMaliciousExtensionsSet, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, ExtensionIdentifierWithVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -140,7 +140,7 @@ export class ExtensionManagementService extends Disposable implements IExtension const collectFilesFromDirectory = async (dir: string): Promise => { let entries = await pfs.readdir(dir); entries = entries.map(e => path.join(dir, e)); - const stats = await Promise.all(entries.map(e => fs.promises.stat(e))); + const stats = await Promise.all(entries.map(e => pfs.Promises.stat(e))); let promise: Promise = Promise.resolve([]); stats.forEach((stat, index) => { const entry = entries[index]; @@ -160,7 +160,7 @@ export class ExtensionManagementService extends Disposable implements IExtension return files.map(f => ({ path: `extension/${path.relative(extension.location.fsPath, f)}`, localPath: f })); } - async install(vsix: URI, options: InstallOptions = {}): Promise { + async install(vsix: URI, options: InstallVSIXOptions = {}): Promise { this.logService.trace('ExtensionManagementService#install', vsix.toString()); return createCancelablePromise(async token => { @@ -170,7 +170,7 @@ export class ExtensionManagementService extends Disposable implements IExtension const manifest = await getManifest(zipPath); const identifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) }; let operation: InstallOperation = InstallOperation.Install; - if (manifest.engines && manifest.engines.vscode && !isEngineValid(manifest.engines.vscode, product.version)) { + if (manifest.engines && manifest.engines.vscode && !isEngineValid(manifest.engines.vscode, product.version, product.date)) { throw new Error(nls.localize('incompatible', "Unable to install extension '{0}' as it is not compatible with VS Code '{1}'.", identifier.id, product.version)); } @@ -212,7 +212,7 @@ export class ExtensionManagementService extends Disposable implements IExtension } catch (e) { /* Ignore */ } try { - const local = await this.installFromZipPath(identifierWithVersion, zipPath, { ...(metadata || {}), ...options }, options, operation, token); + const local = await this.installFromZipPath(identifierWithVersion, zipPath, options.installOnlyNewlyAddedFromExtensionPack ? existing : undefined, { ...(metadata || {}), ...options }, options, operation, token); this.logService.info('Successfully installed the extension:', identifier.id); return local; } catch (e) { @@ -235,11 +235,13 @@ export class ExtensionManagementService extends Disposable implements IExtension return downloadedLocation; } - private async installFromZipPath(identifierWithVersion: ExtensionIdentifierWithVersion, zipPath: string, metadata: IMetadata | undefined, options: InstallOptions, operation: InstallOperation, token: CancellationToken): Promise { + private async installFromZipPath(identifierWithVersion: ExtensionIdentifierWithVersion, zipPath: string, existing: ILocalExtension | undefined, metadata: IMetadata | undefined, options: InstallOptions, operation: InstallOperation, token: CancellationToken): Promise { try { const local = await this.installExtension({ zipPath, identifierWithVersion, metadata }, token); try { - await this.installDependenciesAndPackExtensions(local, undefined, options); + if (!options.donotIncludePackAndDependencies) { + await this.installDependenciesAndPackExtensions(local, existing, options); + } } catch (error) { if (isNonEmptyArray(local.manifest.extensionDependencies)) { this.logService.warn(`Cannot install dependencies of extension:`, local.identifier.id, error.message); diff --git a/lib/vscode/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts b/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts rename to src/vs/platform/extensionManagement/node/extensionManagementUtil.ts diff --git a/lib/vscode/src/vs/platform/extensionManagement/node/extensionUrlTrustService.ts b/src/vs/platform/extensionManagement/node/extensionUrlTrustService.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionManagement/node/extensionUrlTrustService.ts rename to src/vs/platform/extensionManagement/node/extensionUrlTrustService.ts diff --git a/lib/vscode/src/vs/platform/extensionManagement/node/extensionsManifestCache.ts b/src/vs/platform/extensionManagement/node/extensionsManifestCache.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionManagement/node/extensionsManifestCache.ts rename to src/vs/platform/extensionManagement/node/extensionsManifestCache.ts diff --git a/lib/vscode/src/vs/platform/extensionManagement/node/extensionsScanner.ts b/src/vs/platform/extensionManagement/node/extensionsScanner.ts similarity index 92% rename from lib/vscode/src/vs/platform/extensionManagement/node/extensionsScanner.ts rename to src/vs/platform/extensionManagement/node/extensionsScanner.ts index b59301aa06c1..f489f82362ba 100644 --- a/lib/vscode/src/vs/platform/extensionManagement/node/extensionsScanner.ts +++ b/src/vs/platform/extensionManagement/node/extensionsScanner.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as fs from 'fs'; import * as semver from 'vs/base/common/semver/semver'; import { Disposable } from 'vs/base/common/lifecycle'; import * as pfs from 'vs/base/node/pfs'; @@ -24,7 +23,7 @@ import { isWindows } from 'vs/base/common/platform'; import { flatten } from 'vs/base/common/arrays'; import { IStringDictionary } from 'vs/base/common/collections'; import { FileAccess } from 'vs/base/common/network'; -import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files'; +import { IFileService } from 'vs/platform/files/common/files'; import { basename } from 'vs/base/common/resources'; import { generateUuid } from 'vs/base/common/uuid'; import { getErrorMessage } from 'vs/base/common/errors'; @@ -98,7 +97,7 @@ export class ExtensionsScanner extends Disposable { } async scanAllUserExtensions(): Promise { - return this.scanExtensionsInDirs(this.extensionsPath, this.environmentService.extraExtensionPaths, ExtensionType.User); + return this.scanExtensionsInDir(this.extensionsPath, ExtensionType.User); } async extractUserExtension(identifierWithVersion: ExtensionIdentifierWithVersion, zipPath: string, token: CancellationToken): Promise { @@ -159,7 +158,7 @@ export class ExtensionsScanner extends Disposable { storedMetadata.isBuiltin = storedMetadata.isBuiltin || undefined; storedMetadata.installedTimestamp = storedMetadata.installedTimestamp || undefined; const manifestPath = path.join(local.location.fsPath, 'package.json'); - const raw = await fs.promises.readFile(manifestPath, 'utf8'); + const raw = await pfs.Promises.readFile(manifestPath, 'utf8'); const { manifest } = await this.parseManifest(raw); (manifest as ILocalExtensionManifest).__metadata = storedMetadata; await pfs.writeFile(manifestPath, JSON.stringify(manifest, null, '\t')); @@ -192,7 +191,7 @@ export class ExtensionsScanner extends Disposable { return this.uninstalledFileLimiter.queue(async () => { let raw: string | undefined; try { - raw = await fs.promises.readFile(this.uninstalledPath, 'utf8'); + raw = await pfs.Promises.readFile(this.uninstalledPath, 'utf8'); } catch (err) { if (err.code !== 'ENOENT') { throw err; @@ -251,7 +250,7 @@ export class ExtensionsScanner extends Disposable { private async rename(identifier: IExtensionIdentifier, extractPath: string, renamePath: string, retryUntil: number): Promise { try { - await fs.promises.rename(extractPath, renamePath); + await pfs.Promises.rename(extractPath, renamePath); } catch (error) { if (isWindows && error && error.code === 'EPERM' && Date.now() < retryUntil) { this.logService.info(`Failed renaming ${extractPath} to ${renamePath} with 'EPERM' error. Trying again...`, identifier.id); @@ -276,20 +275,8 @@ export class ExtensionsScanner extends Disposable { private async scanExtensionsInDir(dir: string, type: ExtensionType): Promise { const limiter = new Limiter(10); - /* - * NOTE@coder: use fileService.resolve() like upstream does, - * but simply ignore directories that do not exist. (upstream does not) - * - * Used to (<1.54) use pfs.readdir. - */ - const stat = await this.fileService.resolve(URI.file(dir)) - .catch((error) => { - if (!(error instanceof FileOperationError && error.fileOperationResult === FileOperationResult.FILE_NOT_FOUND)) { - throw error; - } - return undefined; - }); - if (stat && stat.children) { + const stat = await this.fileService.resolve(URI.file(dir)); + if (stat.children) { const extensions = await Promise.all(stat.children.filter(c => c.isDirectory) .map(c => limiter.queue(async () => { if (type === ExtensionType.User && basename(c.resource).indexOf('.') === 0) { // Do not consider user extension folder starting with `.` @@ -326,7 +313,7 @@ export class ExtensionsScanner extends Disposable { } private async scanDefaultSystemExtensions(): Promise { - const result = await this.scanExtensionsInDirs(this.systemExtensionsPath, this.environmentService.extraBuiltinExtensionPaths, ExtensionType.System); + const result = await this.scanExtensionsInDir(this.systemExtensionsPath, ExtensionType.System); this.logService.trace('Scanned system extensions:', result.length); return result; } @@ -405,9 +392,9 @@ export class ExtensionsScanner extends Disposable { private async readManifest(extensionPath: string): Promise<{ manifest: IExtensionManifest; metadata: IStoredMetadata | null; }> { const promises = [ - fs.promises.readFile(path.join(extensionPath, 'package.json'), 'utf8') + pfs.Promises.readFile(path.join(extensionPath, 'package.json'), 'utf8') .then(raw => this.parseManifest(raw)), - fs.promises.readFile(path.join(extensionPath, 'package.nls.json'), 'utf8') + pfs.Promises.readFile(path.join(extensionPath, 'package.nls.json'), 'utf8') .then(undefined, err => err.code !== 'ENOENT' ? Promise.reject(err) : '{}') .then(raw => JSON.parse(raw)) ]; @@ -430,9 +417,4 @@ export class ExtensionsScanner extends Disposable { } }); } - - private async scanExtensionsInDirs(dir: string, dirs: string[], type: ExtensionType): Promise{ - const results = await Promise.all([dir, ...dirs].map((path) => this.scanExtensionsInDir(path, type))); - return results.reduce((flat, current) => flat.concat(current), []); - } } diff --git a/lib/vscode/src/vs/platform/extensionManagement/node/extensionsWatcher.ts b/src/vs/platform/extensionManagement/node/extensionsWatcher.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionManagement/node/extensionsWatcher.ts rename to src/vs/platform/extensionManagement/node/extensionsWatcher.ts diff --git a/lib/vscode/src/vs/platform/extensionManagement/test/common/configRemotes.test.ts b/src/vs/platform/extensionManagement/test/common/configRemotes.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionManagement/test/common/configRemotes.test.ts rename to src/vs/platform/extensionManagement/test/common/configRemotes.test.ts diff --git a/lib/vscode/src/vs/platform/extensionManagement/test/common/extensionGalleryService.test.ts b/src/vs/platform/extensionManagement/test/common/extensionGalleryService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionManagement/test/common/extensionGalleryService.test.ts rename to src/vs/platform/extensionManagement/test/common/extensionGalleryService.test.ts diff --git a/lib/vscode/src/vs/platform/extensionManagement/test/common/extensionManagement.test.ts b/src/vs/platform/extensionManagement/test/common/extensionManagement.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionManagement/test/common/extensionManagement.test.ts rename to src/vs/platform/extensionManagement/test/common/extensionManagement.test.ts diff --git a/lib/vscode/src/vs/platform/extensionRecommendations/common/extensionRecommendations.ts b/src/vs/platform/extensionRecommendations/common/extensionRecommendations.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionRecommendations/common/extensionRecommendations.ts rename to src/vs/platform/extensionRecommendations/common/extensionRecommendations.ts diff --git a/lib/vscode/src/vs/platform/extensionRecommendations/electron-sandbox/extensionRecommendationsIpc.ts b/src/vs/platform/extensionRecommendations/electron-sandbox/extensionRecommendationsIpc.ts similarity index 100% rename from lib/vscode/src/vs/platform/extensionRecommendations/electron-sandbox/extensionRecommendationsIpc.ts rename to src/vs/platform/extensionRecommendations/electron-sandbox/extensionRecommendationsIpc.ts diff --git a/lib/vscode/src/vs/platform/extensions/common/extensionValidator.ts b/src/vs/platform/extensions/common/extensionValidator.ts similarity index 79% rename from lib/vscode/src/vs/platform/extensions/common/extensionValidator.ts rename to src/vs/platform/extensions/common/extensionValidator.ts index 77f125ff2201..89d668cbac07 100644 --- a/lib/vscode/src/vs/platform/extensions/common/extensionValidator.ts +++ b/src/vs/platform/extensions/common/extensionValidator.ts @@ -24,10 +24,12 @@ export interface INormalizedVersion { minorMustEqual: boolean; patchBase: number; patchMustEqual: boolean; + notBefore: number; /* milliseconds timestamp, or 0 */ isMinimum: boolean; } const VERSION_REGEXP = /^(\^|>=)?((\d+)|x)\.((\d+)|x)\.((\d+)|x)(\-.*)?$/; +const NOT_BEFORE_REGEXP = /^-(\d{4})(\d{2})(\d{2})$/; export function isValidVersionStr(version: string): boolean { version = version.trim(); @@ -93,6 +95,15 @@ export function normalizeVersion(version: IParsedVersion | null): INormalizedVer } } + let notBefore = 0; + if (version.preRelease) { + const match = NOT_BEFORE_REGEXP.exec(version.preRelease); + if (match) { + const [, year, month, day] = match; + notBefore = Date.UTC(Number(year), Number(month) - 1, Number(day)); + } + } + return { majorBase: majorBase, majorMustEqual: majorMustEqual, @@ -100,16 +111,24 @@ export function normalizeVersion(version: IParsedVersion | null): INormalizedVer minorMustEqual: minorMustEqual, patchBase: patchBase, patchMustEqual: patchMustEqual, - isMinimum: version.hasGreaterEquals + isMinimum: version.hasGreaterEquals, + notBefore, }; } -export function isValidVersion(_version: string | INormalizedVersion, _desiredVersion: string | INormalizedVersion): boolean { +export function isValidVersion(_inputVersion: string | INormalizedVersion, _inputDate: ProductDate, _desiredVersion: string | INormalizedVersion): boolean { let version: INormalizedVersion | null; - if (typeof _version === 'string') { - version = normalizeVersion(parseVersion(_version)); + if (typeof _inputVersion === 'string') { + version = normalizeVersion(parseVersion(_inputVersion)); } else { - version = _version; + version = _inputVersion; + } + + let productTs: number | undefined; + if (_inputDate instanceof Date) { + productTs = _inputDate.getTime(); + } else if (typeof _inputDate === 'string') { + productTs = new Date(_inputDate).getTime(); } let desiredVersion: INormalizedVersion | null; @@ -130,6 +149,7 @@ export function isValidVersion(_version: string | INormalizedVersion, _desiredVe let desiredMajorBase = desiredVersion.majorBase; let desiredMinorBase = desiredVersion.minorBase; let desiredPatchBase = desiredVersion.patchBase; + let desiredNotBefore = desiredVersion.notBefore; let majorMustEqual = desiredVersion.majorMustEqual; let minorMustEqual = desiredVersion.minorMustEqual; @@ -152,6 +172,10 @@ export function isValidVersion(_version: string | INormalizedVersion, _desiredVe return false; } + if (productTs && productTs < desiredNotBefore) { + return false; + } + return patchBase >= desiredPatchBase; } @@ -200,6 +224,11 @@ export function isValidVersion(_version: string | INormalizedVersion, _desiredVe } // at this point, patchBase are equal + + if (productTs && productTs < desiredNotBefore) { + return false; + } + return true; } @@ -211,22 +240,24 @@ export interface IReducedExtensionDescription { main?: string; } -export function isValidExtensionVersion(version: string, extensionDesc: IReducedExtensionDescription, notices: string[]): boolean { +type ProductDate = string | Date | undefined; + +export function isValidExtensionVersion(version: string, date: ProductDate, extensionDesc: IReducedExtensionDescription, notices: string[]): boolean { if (extensionDesc.isBuiltin || typeof extensionDesc.main === 'undefined') { // No version check for builtin or declarative extensions return true; } - return isVersionValid(version, extensionDesc.engines.vscode, notices); + return isVersionValid(version, date, extensionDesc.engines.vscode, notices); } -export function isEngineValid(engine: string, version: string): boolean { +export function isEngineValid(engine: string, version: string, date: ProductDate): boolean { // TODO@joao: discuss with alex '*' doesn't seem to be a valid engine version - return engine === '*' || isVersionValid(version, engine); + return engine === '*' || isVersionValid(version, date, engine); } -export function isVersionValid(currentVersion: string, requestedVersion: string, notices: string[] = []): boolean { +function isVersionValid(currentVersion: string, date: ProductDate, requestedVersion: string, notices: string[] = []): boolean { let desiredVersion = normalizeVersion(parseVersion(requestedVersion)); if (!desiredVersion) { @@ -251,7 +282,7 @@ export function isVersionValid(currentVersion: string, requestedVersion: string, } } - if (!isValidVersion(currentVersion, desiredVersion)) { + if (!isValidVersion(currentVersion, date, desiredVersion)) { notices.push(nls.localize('versionMismatch', "Extension is not compatible with Code {0}. Extension requires: {1}.", currentVersion, requestedVersion)); return false; } diff --git a/lib/vscode/src/vs/platform/extensions/common/extensions.ts b/src/vs/platform/extensions/common/extensions.ts similarity index 89% rename from lib/vscode/src/vs/platform/extensions/common/extensions.ts rename to src/vs/platform/extensions/common/extensions.ts index dde7a4c4b00d..663d8934e4c6 100644 --- a/lib/vscode/src/vs/platform/extensions/common/extensions.ts +++ b/src/vs/platform/extensions/common/extensions.ts @@ -116,10 +116,12 @@ export interface IAuthenticationContribution { export interface IWalkthroughStep { readonly id: string; readonly title: string; - readonly description: string; + readonly description: string | undefined; readonly media: - | { path: string | { dark: string, light: string, hc: string }, altText: string } - | { path: string, }, + | { image: string | { dark: string, light: string, hc: string }, altText: string, markdown?: never } + | { markdown: string, image?: never } + readonly completionEvents?: string[]; + /** @deprecated use `completionEvents: 'onCommand:...'` */ readonly doneOn?: { command: string }; readonly when?: string; } @@ -129,7 +131,6 @@ export interface IWalkthrough { readonly title: string; readonly description: string; readonly steps: IWalkthroughStep[]; - readonly primary?: boolean; readonly when?: string; } @@ -166,13 +167,30 @@ export interface IExtensionContributions { } export interface IExtensionCapabilities { - readonly virtualWorkspaces?: boolean; + readonly virtualWorkspaces?: ExtensionVirtualWorkpaceSupport; readonly untrustedWorkspaces?: ExtensionUntrustedWorkspaceSupport; } + + export type ExtensionKind = 'ui' | 'workspace' | 'web'; -export type ExtensionUntrustedWorkpaceSupportType = boolean | 'limited'; -export type ExtensionUntrustedWorkspaceSupport = { supported: true; } | { supported: false, description: string } | { supported: 'limited', description: string, restrictedConfigurations?: string[] }; + +export type LimitedWorkpaceSupportType = 'limited'; +export type ExtensionUntrustedWorkpaceSupportType = boolean | LimitedWorkpaceSupportType; +export type ExtensionUntrustedWorkspaceSupport = { supported: true; } | { supported: false, description: string } | { supported: LimitedWorkpaceSupportType, description: string, restrictedConfigurations?: string[] }; + +export type ExtensionVirtualWorkpaceSupportType = boolean | LimitedWorkpaceSupportType; +export type ExtensionVirtualWorkpaceSupport = boolean | { supported: true; } | { supported: false | LimitedWorkpaceSupportType, description: string }; + +export function getWorkpaceSupportTypeMessage(supportType: ExtensionUntrustedWorkspaceSupport | ExtensionVirtualWorkpaceSupport | undefined): string | undefined { + if (typeof supportType === 'object' && supportType !== null) { + if (supportType.supported !== true) { + return supportType.description; + } + } + return undefined; +} + export function isIExtensionIdentifier(thing: any): thing is IExtensionIdentifier { return thing diff --git a/lib/vscode/src/vs/platform/extensions/test/common/extensionValidator.test.ts b/src/vs/platform/extensions/test/common/extensionValidator.test.ts similarity index 95% rename from lib/vscode/src/vs/platform/extensions/test/common/extensionValidator.test.ts rename to src/vs/platform/extensions/test/common/extensionValidator.test.ts index 999789c85a61..5fd309aac0f8 100644 --- a/lib/vscode/src/vs/platform/extensions/test/common/extensionValidator.test.ts +++ b/src/vs/platform/extensions/test/common/extensionValidator.test.ts @@ -6,6 +6,7 @@ import * as assert from 'assert'; import { INormalizedVersion, IParsedVersion, IReducedExtensionDescription, isValidExtensionVersion, isValidVersion, isValidVersionStr, normalizeVersion, parseVersion } from 'vs/platform/extensions/common/extensionValidator'; suite('Extension Version Validator', () => { + const productVersion = '2021-05-11T21:54:30.577Z'; test('isValidVersionStr', () => { assert.strictEqual(isValidVersionStr('0.10.0-dev'), true); @@ -53,13 +54,16 @@ suite('Extension Version Validator', () => { }); test('normalizeVersion', () => { - function assertNormalizeVersion(version: string, majorBase: number, majorMustEqual: boolean, minorBase: number, minorMustEqual: boolean, patchBase: number, patchMustEqual: boolean, isMinimum: boolean): void { + function assertNormalizeVersion(version: string, majorBase: number, majorMustEqual: boolean, minorBase: number, minorMustEqual: boolean, patchBase: number, patchMustEqual: boolean, isMinimum: boolean, notBefore = 0): void { const actual = normalizeVersion(parseVersion(version)); - const expected: INormalizedVersion = { majorBase, majorMustEqual, minorBase, minorMustEqual, patchBase, patchMustEqual, isMinimum }; + const expected: INormalizedVersion = { majorBase, majorMustEqual, minorBase, minorMustEqual, patchBase, patchMustEqual, isMinimum, notBefore }; assert.deepStrictEqual(actual, expected, 'parseVersion for ' + version); } - assertNormalizeVersion('0.10.0-dev', 0, true, 10, true, 0, true, false); + assertNormalizeVersion('0.10.0-dev', 0, true, 10, true, 0, true, false, 0); + assertNormalizeVersion('0.10.0-222222222', 0, true, 10, true, 0, true, false, 0); + assertNormalizeVersion('0.10.0-20210511', 0, true, 10, true, 0, true, false, new Date('2021-05-11T00:00:00Z').getTime()); + assertNormalizeVersion('0.10.0', 0, true, 10, true, 0, true, false); assertNormalizeVersion('0.10.1', 0, true, 10, true, 1, true, false); assertNormalizeVersion('0.10.100', 0, true, 10, true, 100, true, false); @@ -75,11 +79,12 @@ suite('Extension Version Validator', () => { assertNormalizeVersion('>=0.0.1', 0, true, 0, true, 1, true, true); assertNormalizeVersion('>=2.4.3', 2, true, 4, true, 3, true, true); + assertNormalizeVersion('>=2.4.3', 2, true, 4, true, 3, true, true); }); test('isValidVersion', () => { function testIsValidVersion(version: string, desiredVersion: string, expectedResult: boolean): void { - let actual = isValidVersion(version, desiredVersion); + let actual = isValidVersion(version, productVersion, desiredVersion); assert.strictEqual(actual, expectedResult, 'extension - vscode: ' + version + ', desiredVersion: ' + desiredVersion + ' should be ' + expectedResult); } @@ -211,7 +216,7 @@ suite('Extension Version Validator', () => { main: hasMain ? 'something' : undefined }; let reasons: string[] = []; - let actual = isValidExtensionVersion(version, desc, reasons); + let actual = isValidExtensionVersion(version, productVersion, desc, reasons); assert.strictEqual(actual, expectedResult, 'version: ' + version + ', desiredVersion: ' + desiredVersion + ', desc: ' + JSON.stringify(desc) + ', reasons: ' + JSON.stringify(reasons)); } @@ -390,5 +395,12 @@ suite('Extension Version Validator', () => { testIsValidVersion('2.0.0', '^1.100.0', false); testIsValidVersion('2.0.0', '^2.0.0', true); testIsValidVersion('2.0.0', '*', false); // fails due to lack of specificity + + // date tags + testIsValidVersion('1.10.0', '^1.10.0-20210511', true); // current date + testIsValidVersion('1.10.0', '^1.10.0-20210510', true); // before date + testIsValidVersion('1.10.0', '^1.10.0-20210512', false); // future date + testIsValidVersion('1.10.1', '^1.10.0-20200101', true); // before date, but ahead version + testIsValidVersion('1.11.0', '^1.10.0-20200101', true); }); }); diff --git a/lib/vscode/src/vs/workbench/contrib/externalTerminal/common/externalTerminal.ts b/src/vs/platform/externalTerminal/common/externalTerminal.ts similarity index 67% rename from lib/vscode/src/vs/workbench/contrib/externalTerminal/common/externalTerminal.ts rename to src/vs/platform/externalTerminal/common/externalTerminal.ts index 3aab081a27a2..72d71f88520b 100644 --- a/lib/vscode/src/vs/workbench/contrib/externalTerminal/common/externalTerminal.ts +++ b/src/vs/platform/externalTerminal/common/externalTerminal.ts @@ -6,7 +6,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ITerminalEnvironment } from 'vs/platform/terminal/common/terminal'; -export const IExternalTerminalService = createDecorator('nativeTerminalService'); +export const IExternalTerminalService = createDecorator('externalTerminal'); export interface IExternalTerminalSettings { linuxExec?: string; @@ -14,10 +14,17 @@ export interface IExternalTerminalSettings { windowsExec?: string; } +export interface ITerminalForPlatform { + windows: string, + linux: string, + osx: string +} + export interface IExternalTerminalService { readonly _serviceBrand: undefined; - openTerminal(path: string): void; + openTerminal(path: string): Promise; runInTerminal(title: string, cwd: string, args: string[], env: ITerminalEnvironment, settings: IExternalTerminalSettings): Promise; + getDefaultTerminalForPlatforms(): Promise; } export interface IExternalTerminalConfiguration { @@ -26,3 +33,11 @@ export interface IExternalTerminalConfiguration { external: IExternalTerminalSettings; }; } + +export const DEFAULT_TERMINAL_OSX = 'Terminal.app'; + +export const IExternalTerminalMainService = createDecorator('externalTerminal'); + +export interface IExternalTerminalMainService extends IExternalTerminalService { + readonly _serviceBrand: undefined; +} diff --git a/lib/vscode/src/vs/workbench/contrib/externalTerminal/node/externalTerminalService.test.ts b/src/vs/platform/externalTerminal/electron-main/externalTerminalService.test.ts similarity index 95% rename from lib/vscode/src/vs/workbench/contrib/externalTerminal/node/externalTerminalService.test.ts rename to src/vs/platform/externalTerminal/electron-main/externalTerminalService.test.ts index 264e8a93275f..a3acac5ce135 100644 --- a/lib/vscode/src/vs/workbench/contrib/externalTerminal/node/externalTerminalService.test.ts +++ b/src/vs/platform/externalTerminal/electron-main/externalTerminalService.test.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { deepEqual, equal } from 'assert'; -import { WindowsExternalTerminalService, LinuxExternalTerminalService, MacExternalTerminalService } from 'vs/workbench/contrib/externalTerminal/node/externalTerminalService'; -import { DEFAULT_TERMINAL_OSX } from 'vs/workbench/contrib/externalTerminal/node/externalTerminal'; +import { DEFAULT_TERMINAL_OSX } from 'vs/platform/externalTerminal/common/externalTerminal'; +import { WindowsExternalTerminalService, MacExternalTerminalService, LinuxExternalTerminalService } from 'vs/platform/externalTerminal/node/externalTerminalService'; suite('ExternalTerminalService', () => { let mockOnExit: Function; diff --git a/src/vs/platform/externalTerminal/electron-sandbox/externalTerminalMainService.ts b/src/vs/platform/externalTerminal/electron-sandbox/externalTerminalMainService.ts new file mode 100644 index 000000000000..3b1ce4c60c7b --- /dev/null +++ b/src/vs/platform/externalTerminal/electron-sandbox/externalTerminalMainService.ts @@ -0,0 +1,16 @@ +/*--------------------------------------------------------------------------------------------- + * 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'; +import { registerMainProcessRemoteService } from 'vs/platform/ipc/electron-sandbox/services'; +import { IExternalTerminalService } from 'vs/platform/externalTerminal/common/externalTerminal'; + +export const IExternalTerminalMainService = createDecorator('externalTerminal'); + +export interface IExternalTerminalMainService extends IExternalTerminalService { + readonly _serviceBrand: undefined; +} + +registerMainProcessRemoteService(IExternalTerminalMainService, 'externalTerminal', { supportsDelayedInstantiation: true }); diff --git a/lib/vscode/src/vs/workbench/contrib/externalTerminal/node/externalTerminalService.ts b/src/vs/platform/externalTerminal/node/externalTerminalService.ts similarity index 75% rename from lib/vscode/src/vs/workbench/contrib/externalTerminal/node/externalTerminalService.ts rename to src/vs/platform/externalTerminal/node/externalTerminalService.ts index eb3b37ab5697..a7ae827eee1c 100644 --- a/lib/vscode/src/vs/workbench/contrib/externalTerminal/node/externalTerminalService.ts +++ b/src/vs/platform/externalTerminal/node/externalTerminalService.ts @@ -9,72 +9,42 @@ import * as processes from 'vs/base/node/processes'; import * as nls from 'vs/nls'; import * as pfs from 'vs/base/node/pfs'; import * as env from 'vs/base/common/platform'; -import { IExternalTerminalService, IExternalTerminalConfiguration, IExternalTerminalSettings } from 'vs/workbench/contrib/externalTerminal/common/externalTerminal'; +import { IExternalTerminalConfiguration, IExternalTerminalSettings, DEFAULT_TERMINAL_OSX, ITerminalForPlatform, IExternalTerminalMainService } from 'vs/platform/externalTerminal/common/externalTerminal'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { optional } from 'vs/platform/instantiation/common/instantiation'; -import { DEFAULT_TERMINAL_OSX } from 'vs/workbench/contrib/externalTerminal/node/externalTerminal'; import { FileAccess } from 'vs/base/common/network'; import { ITerminalEnvironment } from 'vs/platform/terminal/common/terminal'; +import { sanitizeProcessEnvironment } from 'vs/base/common/processes'; const TERMINAL_TITLE = nls.localize('console.title', "VS Code Console"); -export class WindowsExternalTerminalService implements IExternalTerminalService { +abstract class ExternalTerminalService { public _serviceBrand: undefined; - private static readonly CMD = 'cmd.exe'; + async getDefaultTerminalForPlatforms(): Promise { + const linuxTerminal = await LinuxExternalTerminalService.getDefaultTerminalLinuxReady(); + return { windows: WindowsExternalTerminalService.getDefaultTerminalWindows(), linux: linuxTerminal, osx: 'xterm' }; + } +} - private readonly _configurationService?: IConfigurationService; +export class WindowsExternalTerminalService extends ExternalTerminalService implements IExternalTerminalMainService { + private static readonly CMD = 'cmd.exe'; + private static _DEFAULT_TERMINAL_WINDOWS: string; constructor( - @optional(IConfigurationService) configurationService: IConfigurationService + @optional(IConfigurationService) private readonly _configurationService: IConfigurationService ) { - this._configurationService = configurationService; + super(); } - public openTerminal(cwd?: string): void { - if (this._configurationService) { - const configuration = this._configurationService.getValue(); - this.spawnTerminal(cp, configuration, processes.getWindowsShell(), cwd); - } + public openTerminal(cwd?: string): Promise { + const configuration = this._configurationService.getValue(); + return this.spawnTerminal(cp, configuration, processes.getWindowsShell(), cwd); } - public runInTerminal(title: string, dir: string, args: string[], envVars: ITerminalEnvironment, settings: IExternalTerminalSettings): Promise { - - const exec = settings.windowsExec || WindowsExternalTerminalService.getDefaultTerminalWindows(); - - return new Promise((resolve, reject) => { - - const title = `"${dir} - ${TERMINAL_TITLE}"`; - const command = `""${args.join('" "')}" & pause"`; // use '|' to only pause on non-zero exit code - - const cmdArgs = [ - '/c', 'start', title, '/wait', exec, '/c', command - ]; - - // merge environment variables into a copy of the process.env - const env = Object.assign({}, process.env, envVars); - - // delete environment variables that have a null value - Object.keys(env).filter(v => env[v] === null).forEach(key => delete env[key]); - - const options: any = { - cwd: dir, - env: env, - windowsVerbatimArguments: true - }; - - const cmd = cp.spawn(WindowsExternalTerminalService.CMD, cmdArgs, options); - cmd.on('error', err => { - reject(improveError(err)); - }); - - resolve(undefined); - }); - } - - private spawnTerminal(spawner: typeof cp, configuration: IExternalTerminalConfiguration, command: string, cwd?: string): Promise { + public spawnTerminal(spawner: typeof cp, configuration: IExternalTerminalConfiguration, command: string, cwd?: string): Promise { const terminalConfig = configuration.terminal.external; - const exec = terminalConfig.windowsExec || WindowsExternalTerminalService.getDefaultTerminalWindows(); + const exec = terminalConfig?.windowsExec || WindowsExternalTerminalService.getDefaultTerminalWindows(); // Make the drive letter uppercase on Windows (see #9448) if (cwd && cwd[1] === ':') { @@ -102,14 +72,45 @@ export class WindowsExternalTerminalService implements IExternalTerminalService } return new Promise((c, e) => { - const env = cwd ? { cwd: cwd } : undefined; - const child = spawner.spawn(command, cmdArgs, env); + const env = getSanitizedEnvironment(process); + const child = spawner.spawn(command, cmdArgs, { cwd, env }); child.on('error', e); child.on('exit', () => c()); }); } - private static _DEFAULT_TERMINAL_WINDOWS: string; + public runInTerminal(title: string, dir: string, args: string[], envVars: ITerminalEnvironment, settings: IExternalTerminalSettings): Promise { + const exec = 'windowsExec' in settings && settings.windowsExec ? settings.windowsExec : WindowsExternalTerminalService.getDefaultTerminalWindows(); + + return new Promise((resolve, reject) => { + + const title = `"${dir} - ${TERMINAL_TITLE}"`; + const command = `""${args.join('" "')}" & pause"`; // use '|' to only pause on non-zero exit code + + const cmdArgs = [ + '/c', 'start', title, '/wait', exec, '/c', command + ]; + + // merge environment variables into a copy of the process.env + const env = Object.assign({}, getSanitizedEnvironment(process), envVars); + + // delete environment variables that have a null value + Object.keys(env).filter(v => env[v] === null).forEach(key => delete env[key]); + + const options: any = { + cwd: dir, + env: env, + windowsVerbatimArguments: true + }; + + const cmd = cp.spawn(WindowsExternalTerminalService.CMD, cmdArgs, options); + cmd.on('error', err => { + reject(improveError(err)); + }); + + resolve(undefined); + }); + } public static getDefaultTerminalWindows(): string { if (!WindowsExternalTerminalService._DEFAULT_TERMINAL_WINDOWS) { @@ -120,24 +121,18 @@ export class WindowsExternalTerminalService implements IExternalTerminalService } } -export class MacExternalTerminalService implements IExternalTerminalService { - public _serviceBrand: undefined; - +export class MacExternalTerminalService extends ExternalTerminalService implements IExternalTerminalMainService { private static readonly OSASCRIPT = '/usr/bin/osascript'; // osascript is the AppleScript interpreter on OS X - private readonly _configurationService?: IConfigurationService; - constructor( - @optional(IConfigurationService) configurationService: IConfigurationService + @optional(IConfigurationService) private readonly _configurationService: IConfigurationService ) { - this._configurationService = configurationService; + super(); } - public openTerminal(cwd?: string): void { - if (this._configurationService) { - const configuration = this._configurationService.getValue(); - this.spawnTerminal(cp, configuration, cwd); - } + public openTerminal(cwd?: string): Promise { + const configuration = this._configurationService.getValue(); + return this.spawnTerminal(cp, configuration, cwd); } public runInTerminal(title: string, dir: string, args: string[], envVars: ITerminalEnvironment, settings: IExternalTerminalSettings): Promise { @@ -204,9 +199,9 @@ export class MacExternalTerminalService implements IExternalTerminalService { }); } - private spawnTerminal(spawner: typeof cp, configuration: IExternalTerminalConfiguration, cwd?: string): Promise { + spawnTerminal(spawner: typeof cp, configuration: IExternalTerminalConfiguration, cwd?: string): Promise { const terminalConfig = configuration.terminal.external; - const terminalApp = terminalConfig.osxExec || DEFAULT_TERMINAL_OSX; + const terminalApp = terminalConfig?.osxExec || DEFAULT_TERMINAL_OSX; return new Promise((c, e) => { const args = ['-a', terminalApp]; @@ -220,24 +215,19 @@ export class MacExternalTerminalService implements IExternalTerminalService { } } -export class LinuxExternalTerminalService implements IExternalTerminalService { - public _serviceBrand: undefined; +export class LinuxExternalTerminalService extends ExternalTerminalService implements IExternalTerminalMainService { private static readonly WAIT_MESSAGE = nls.localize('press.any.key', "Press any key to continue..."); - private readonly _configurationService?: IConfigurationService; - constructor( - @optional(IConfigurationService) configurationService: IConfigurationService + @optional(IConfigurationService) private readonly _configurationService: IConfigurationService ) { - this._configurationService = configurationService; + super(); } - public openTerminal(cwd?: string): void { - if (this._configurationService) { - const configuration = this._configurationService.getValue(); - this.spawnTerminal(cp, configuration, cwd); - } + public openTerminal(cwd?: string): Promise { + const configuration = this._configurationService.getValue(); + return this.spawnTerminal(cp, configuration, cwd); } public runInTerminal(title: string, dir: string, args: string[], envVars: ITerminalEnvironment, settings: IExternalTerminalSettings): Promise { @@ -296,20 +286,6 @@ export class LinuxExternalTerminalService implements IExternalTerminalService { }); } - private spawnTerminal(spawner: typeof cp, configuration: IExternalTerminalConfiguration, cwd?: string): Promise { - const terminalConfig = configuration.terminal.external; - const execPromise = terminalConfig.linuxExec ? Promise.resolve(terminalConfig.linuxExec) : LinuxExternalTerminalService.getDefaultTerminalLinuxReady(); - - return new Promise((c, e) => { - execPromise.then(exec => { - const env = cwd ? { cwd } : undefined; - const child = spawner.spawn(exec, [], env); - child.on('error', e); - child.on('exit', () => c()); - }); - }); - } - private static _DEFAULT_TERMINAL_LINUX_READY: Promise; public static async getDefaultTerminalLinuxReady(): Promise { @@ -337,6 +313,26 @@ export class LinuxExternalTerminalService implements IExternalTerminalService { } return LinuxExternalTerminalService._DEFAULT_TERMINAL_LINUX_READY; } + + spawnTerminal(spawner: typeof cp, configuration: IExternalTerminalConfiguration, cwd?: string): Promise { + const terminalConfig = configuration.terminal.external; + const execPromise = terminalConfig?.linuxExec ? Promise.resolve(terminalConfig.linuxExec) : LinuxExternalTerminalService.getDefaultTerminalLinuxReady(); + + return new Promise((c, e) => { + execPromise.then(exec => { + const env = getSanitizedEnvironment(process); + const child = spawner.spawn(exec, [], { cwd, env }); + child.on('error', e); + child.on('exit', () => c()); + }); + }); + } +} + +function getSanitizedEnvironment(process: NodeJS.Process) { + const env = process.env; + sanitizeProcessEnvironment(env); + return env; } /** diff --git a/lib/vscode/src/vs/platform/files/browser/htmlFileSystemProvider.ts b/src/vs/platform/files/browser/htmlFileSystemProvider.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/browser/htmlFileSystemProvider.ts rename to src/vs/platform/files/browser/htmlFileSystemProvider.ts diff --git a/lib/vscode/src/vs/platform/files/browser/indexedDBFileSystemProvider.ts b/src/vs/platform/files/browser/indexedDBFileSystemProvider.ts similarity index 98% rename from lib/vscode/src/vs/platform/files/browser/indexedDBFileSystemProvider.ts rename to src/vs/platform/files/browser/indexedDBFileSystemProvider.ts index cd2c43ebbaca..a2c59739067e 100644 --- a/lib/vscode/src/vs/platform/files/browser/indexedDBFileSystemProvider.ts +++ b/src/vs/platform/files/browser/indexedDBFileSystemProvider.ts @@ -23,7 +23,7 @@ const ERR_FILE_NOT_DIR = createFileSystemProviderError(localize('fileNotDirector const ERR_DIR_NOT_EMPTY = createFileSystemProviderError(localize('dirIsNotEmpty', "Directory is not empty"), FileSystemProviderErrorCode.Unknown); // Arbitrary Internal Errors (should never be thrown in production) -const ERR_UNKNOWN_INTERNAL = (message: string) => createFileSystemProviderError(localize('internal', "Internal error occured in IndexedDB File System Provider. ({0})", message), FileSystemProviderErrorCode.Unknown); +const ERR_UNKNOWN_INTERNAL = (message: string) => createFileSystemProviderError(localize('internal', "Internal error occurred in IndexedDB File System Provider. ({0})", message), FileSystemProviderErrorCode.Unknown); export class IndexedDB { @@ -99,7 +99,7 @@ class IndexedDBFileSystemNode { } - read(path: string) { + read(path: string): IndexedDBFileSystemEntry | undefined { return this.doRead(path.split('/').filter(p => p.length)); } diff --git a/lib/vscode/src/vs/platform/files/common/fileService.ts b/src/vs/platform/files/common/fileService.ts similarity index 97% rename from lib/vscode/src/vs/platform/files/common/fileService.ts rename to src/vs/platform/files/common/fileService.ts index 0453e6f4c60d..5cfc79d94ef5 100644 --- a/lib/vscode/src/vs/platform/files/common/fileService.ts +++ b/src/vs/platform/files/common/fileService.ts @@ -6,7 +6,7 @@ import { localize } from 'vs/nls'; import { mark } from 'vs/base/common/performance'; import { Disposable, IDisposable, toDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; -import { IFileService, IResolveFileOptions, FileChangesEvent, FileOperationEvent, IFileSystemProviderRegistrationEvent, IFileSystemProvider, IFileStat, IResolveFileResult, ICreateFileOptions, IFileSystemProviderActivationEvent, FileOperationError, FileOperationResult, FileOperation, FileSystemProviderCapabilities, FileType, toFileSystemProviderErrorCode, FileSystemProviderErrorCode, IStat, IFileStatWithMetadata, IResolveMetadataFileOptions, etag, hasReadWriteCapability, hasFileFolderCopyCapability, hasOpenReadWriteCloseCapability, toFileOperationResult, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IResolveFileResultWithMetadata, IWatchOptions, IWriteFileOptions, IReadFileOptions, IFileStreamContent, IFileContent, ETAG_DISABLED, hasFileReadStreamCapability, IFileSystemProviderWithFileReadStreamCapability, ensureFileSystemProviderError, IFileSystemProviderCapabilitiesChangeEvent, IReadFileStreamOptions, FileDeleteOptions } from 'vs/platform/files/common/files'; +import { IFileService, IResolveFileOptions, FileChangesEvent, FileOperationEvent, IFileSystemProviderRegistrationEvent, IFileSystemProvider, IFileStat, IResolveFileResult, ICreateFileOptions, IFileSystemProviderActivationEvent, FileOperationError, FileOperationResult, FileOperation, FileSystemProviderCapabilities, FileType, toFileSystemProviderErrorCode, FileSystemProviderErrorCode, IStat, IFileStatWithMetadata, IResolveMetadataFileOptions, etag, hasReadWriteCapability, hasFileFolderCopyCapability, hasOpenReadWriteCloseCapability, toFileOperationResult, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IResolveFileResultWithMetadata, IWatchOptions, IWriteFileOptions, IReadFileOptions, IFileStreamContent, IFileContent, ETAG_DISABLED, hasFileReadStreamCapability, IFileSystemProviderWithFileReadStreamCapability, ensureFileSystemProviderError, IFileSystemProviderCapabilitiesChangeEvent, IReadFileStreamOptions, FileDeleteOptions, FilePermission, NotModifiedSinceFileOperationError } from 'vs/platform/files/common/files'; import { URI } from 'vs/base/common/uri'; import { Emitter } from 'vs/base/common/event'; import { IExtUri, extUri, extUriIgnorePathCase, isAbsolutePath } from 'vs/base/common/resources'; @@ -234,6 +234,7 @@ export class FileService extends Disposable implements IFileService { mtime: stat.mtime, ctime: stat.ctime, size: stat.size, + readonly: Boolean((stat.permissions ?? 0) & FilePermission.Readonly) || Boolean(provider.capabilities & FileSystemProviderCapabilities.Readonly), etag: etag({ mtime: stat.mtime, size: stat.size }) }; @@ -401,6 +402,9 @@ export class FileService extends Disposable implements IFileService { throw new FileOperationError(localize('fileIsDirectoryWriteError', "Unable to write file '{0}' that is actually a directory", this.resourceForError(resource)), FileOperationResult.FILE_IS_DIRECTORY, options); } + // File cannot be readonly + this.throwIfFileIsReadonly(resource, stat); + // Dirty write prevention: if the file on disk has been changed and does not match our expected // mtime and etag, we bail out to prevent dirty writing. // @@ -526,7 +530,14 @@ export class FileService extends Disposable implements IFileService { await consumeStream(fileStream); } - throw new FileOperationError(localize('err.read', "Unable to read file '{0}' ({1})", this.resourceForError(resource), ensureFileSystemProviderError(error).toString()), toFileOperationResult(error), options); + // Re-throw errors as file operation errors but preserve + // specific errors (such as not modified since) + const message = localize('err.read', "Unable to read file '{0}' ({1})", this.resourceForError(resource), ensureFileSystemProviderError(error).toString()); + if (error instanceof NotModifiedSinceFileOperationError) { + throw new NotModifiedSinceFileOperationError(message, error.stat, options); + } else { + throw new FileOperationError(message, toFileOperationResult(error), options); + } } } @@ -594,7 +605,7 @@ export class FileService extends Disposable implements IFileService { // Throw if file not modified since (unless disabled) if (options && typeof options.etag === 'string' && options.etag !== ETAG_DISABLED && options.etag === stat.etag) { - throw new FileOperationError(localize('fileNotModifiedError', "File not modified since"), FileOperationResult.FILE_NOT_MODIFIED_SINCE, options); + throw new NotModifiedSinceFileOperationError(localize('fileNotModifiedError', "File not modified since"), stat, options); } // Throw if file is too large to load @@ -912,14 +923,22 @@ export class FileService extends Disposable implements IFileService { } // Validate delete - const exists = await this.exists(resource); - if (!exists) { + let stat: IStat | undefined = undefined; + try { + stat = await provider.stat(resource); + } catch (error) { + // Handled later + } + + if (stat) { + this.throwIfFileIsReadonly(resource, stat); + } else { throw new FileOperationError(localize('deleteFailedNotFound', "Unable to delete non-existing file '{0}'", this.resourceForError(resource)), FileOperationResult.FILE_NOT_FOUND); } // Validate recursive const recursive = !!options?.recursive; - if (!recursive && exists) { + if (!recursive) { const stat = await this.resolve(resource); if (stat.isDirectory && Array.isArray(stat.children) && stat.children.length > 0) { throw new Error(localize('deleteFailedNonEmptyFolder', "Unable to delete non-empty folder '{0}'.", this.resourceForError(resource))); @@ -1227,6 +1246,12 @@ export class FileService extends Disposable implements IFileService { return provider; } + private throwIfFileIsReadonly(resource: URI, stat: IStat): void { + if ((stat.permissions ?? 0) & FilePermission.Readonly) { + throw new FileOperationError(localize('err.readonly', "Unable to modify readonly file '{0}'", this.resourceForError(resource)), FileOperationResult.FILE_PERMISSION_DENIED); + } + } + private resourceForError(resource: URI): string { if (resource.scheme === Schemas.file) { return resource.fsPath; diff --git a/lib/vscode/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts similarity index 97% rename from lib/vscode/src/vs/platform/files/common/files.ts rename to src/vs/platform/files/common/files.ts index f2543a85c6f7..774f4e22c000 100644 --- a/lib/vscode/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -11,7 +11,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { Event } from 'vs/base/common/event'; import { startsWithIgnoreCase } from 'vs/base/common/strings'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { isNumber, isUndefinedOrNull } from 'vs/base/common/types'; +import { isNumber } from 'vs/base/common/types'; import { VSBuffer, VSBufferReadable, VSBufferReadableStream } from 'vs/base/common/buffer'; import { ReadableStreamEvents } from 'vs/base/common/stream'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -315,6 +315,14 @@ export enum FileType { SymbolicLink = 64 } +export enum FilePermission { + + /** + * File is readonly. + */ + Readonly = 1 +} + export interface IStat { /** @@ -335,7 +343,12 @@ export interface IStat { /** * The size of the file in bytes. */ - size: number; + readonly size: number; + + /** + * The file permissions. + */ + readonly permissions?: FilePermission; } export interface IWatchOptions { @@ -400,7 +413,7 @@ export interface IFileSystemProvider { readonly capabilities: FileSystemProviderCapabilities; readonly onDidChangeCapabilities: Event; - readonly onDidErrorOccur?: Event; // TODO@bpasero remove once file watchers are solid + readonly onDidErrorOccur?: Event; readonly onDidChangeFile: Event; watch(resource: URI, opts: IWatchOptions): IDisposable; @@ -475,7 +488,7 @@ export enum FileSystemProviderErrorCode { export class FileSystemProviderError extends Error { - constructor(message: string, public readonly code: FileSystemProviderErrorCode) { + constructor(message: string, readonly code: FileSystemProviderErrorCode) { super(message); } } @@ -592,7 +605,7 @@ export class FileOperationEvent { constructor(resource: URI, operation: FileOperation.DELETE); constructor(resource: URI, operation: FileOperation.CREATE | FileOperation.MOVE | FileOperation.COPY, target: IFileStatWithMetadata); - constructor(public readonly resource: URI, public readonly operation: FileOperation, public readonly target?: IFileStatWithMetadata) { } + constructor(readonly resource: URI, readonly operation: FileOperation, readonly target?: IFileStatWithMetadata) { } isOperation(operation: FileOperation.DELETE): boolean; isOperation(operation: FileOperation.MOVE | FileOperation.COPY | FileOperation.CREATE): this is { readonly target: IFileStatWithMetadata }; @@ -868,6 +881,11 @@ interface IBaseStat { * it is optional. */ readonly etag?: string; + + /** + * The file is read-only. + */ + readonly readonly?: boolean; } export interface IBaseStatWithMetadata extends Required { } @@ -906,6 +924,7 @@ export interface IFileStatWithMetadata extends IFileStat, IBaseStatWithMetadata readonly ctime: number; readonly etag: string; readonly size: number; + readonly readonly: boolean; readonly children?: IFileStatWithMetadata[]; } @@ -956,7 +975,7 @@ export interface IReadFileOptions extends IBaseReadFileOptions { * * Typically you should not need to use this flag but if * for example you are quickly reading a file right after - * a file event occured and the file changes a lot, there + * a file event occurred and the file changes a lot, there * is a chance that a read returns an empty or partial file * because a pending write has not finished yet. * @@ -1019,12 +1038,23 @@ export interface ICreateFileOptions { } export class FileOperationError extends Error { - constructor(message: string, public fileOperationResult: FileOperationResult, public options?: IReadFileOptions & IWriteFileOptions & ICreateFileOptions) { + constructor( + message: string, + readonly fileOperationResult: FileOperationResult, + readonly options?: IReadFileOptions & IWriteFileOptions & ICreateFileOptions + ) { super(message); } +} + +export class NotModifiedSinceFileOperationError extends FileOperationError { - static isFileOperationError(obj: unknown): obj is FileOperationError { - return obj instanceof Error && !isUndefinedOrNull((obj as FileOperationError).fileOperationResult); + constructor( + message: string, + readonly stat: IFileStatWithMetadata, + options?: IReadFileOptions + ) { + super(message, FileOperationResult.FILE_NOT_MODIFIED_SINCE, options); } } diff --git a/lib/vscode/src/vs/platform/files/common/inMemoryFilesystemProvider.ts b/src/vs/platform/files/common/inMemoryFilesystemProvider.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/common/inMemoryFilesystemProvider.ts rename to src/vs/platform/files/common/inMemoryFilesystemProvider.ts diff --git a/lib/vscode/src/vs/platform/files/common/io.ts b/src/vs/platform/files/common/io.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/common/io.ts rename to src/vs/platform/files/common/io.ts diff --git a/lib/vscode/src/vs/platform/files/common/ipcFileSystemProvider.ts b/src/vs/platform/files/common/ipcFileSystemProvider.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/common/ipcFileSystemProvider.ts rename to src/vs/platform/files/common/ipcFileSystemProvider.ts diff --git a/lib/vscode/src/vs/platform/files/electron-browser/diskFileSystemProvider.ts b/src/vs/platform/files/electron-browser/diskFileSystemProvider.ts similarity index 93% rename from lib/vscode/src/vs/platform/files/electron-browser/diskFileSystemProvider.ts rename to src/vs/platform/files/electron-browser/diskFileSystemProvider.ts index 9cdde03ee714..635d995865ce 100644 --- a/lib/vscode/src/vs/platform/files/electron-browser/diskFileSystemProvider.ts +++ b/src/vs/platform/files/electron-browser/diskFileSystemProvider.ts @@ -3,11 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { DiskFileSystemProvider as NodeDiskFileSystemProvider, IDiskFileSystemProviderOptions } from 'vs/platform/files/node/diskFileSystemProvider'; -import { FileDeleteOptions, FileSystemProviderCapabilities } from 'vs/platform/files/common/files'; -import { isWindows } from 'vs/base/common/platform'; import { localize } from 'vs/nls'; +import { isWindows } from 'vs/base/common/platform'; import { basename } from 'vs/base/common/path'; +import { DiskFileSystemProvider as NodeDiskFileSystemProvider, IDiskFileSystemProviderOptions } from 'vs/platform/files/node/diskFileSystemProvider'; +import { FileDeleteOptions, FileSystemProviderCapabilities } from 'vs/platform/files/common/files'; import { ILogService } from 'vs/platform/log/common/log'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; @@ -34,8 +34,11 @@ export class DiskFileSystemProvider extends NodeDiskFileSystemProvider { return super.doDelete(filePath, opts); } - const result = await this.nativeHostService.moveItemToTrash(filePath); - if (!result) { + try { + await this.nativeHostService.moveItemToTrash(filePath); + } catch (error) { + this.logService.error(error); + throw new Error(isWindows ? localize('binFailed', "Failed to move '{0}' to the recycle bin", basename(filePath)) : localize('trashFailed', "Failed to move '{0}' to the trash", basename(filePath))); } } diff --git a/lib/vscode/src/vs/platform/files/node/diskFileSystemProvider.ts b/src/vs/platform/files/node/diskFileSystemProvider.ts similarity index 96% rename from lib/vscode/src/vs/platform/files/node/diskFileSystemProvider.ts rename to src/vs/platform/files/node/diskFileSystemProvider.ts index ff111367d43e..c950ddc09d45 100644 --- a/lib/vscode/src/vs/platform/files/node/diskFileSystemProvider.ts +++ b/src/vs/platform/files/node/diskFileSystemProvider.ts @@ -3,14 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { open, close, read, write, fdatasync, Stats, promises } from 'fs'; -import { promisify } from 'util'; +import { Stats } from 'fs'; import { IDisposable, Disposable, toDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; import { FileSystemProviderCapabilities, IFileChange, IWatchOptions, IStat, FileType, FileDeleteOptions, FileOverwriteOptions, FileWriteOptions, FileOpenOptions, FileSystemProviderErrorCode, createFileSystemProviderError, FileSystemProviderError, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithFileReadStreamCapability, IFileSystemProviderWithOpenReadWriteCloseCapability, FileReadStreamOptions, IFileSystemProviderWithFileFolderCopyCapability, isFileOpenForWriteOptions } from 'vs/platform/files/common/files'; import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { isLinux, isWindows } from 'vs/base/common/platform'; -import { SymlinkSupport, move, copy, rimraf, RimRafMode, exists, readdir, IDirent } from 'vs/base/node/pfs'; +import { SymlinkSupport, move, copy, rimraf, RimRafMode, exists, readdir, IDirent, Promises } from 'vs/base/node/pfs'; import { normalize, basename, dirname } from 'vs/base/common/path'; import { joinPath } from 'vs/base/common/resources'; import { isEqual } from 'vs/base/common/extpath'; @@ -47,7 +46,7 @@ export class DiskFileSystemProvider extends Disposable implements private readonly BUFFER_SIZE = this.options?.bufferSize || 64 * 1024; constructor( - private readonly logService: ILogService, + protected readonly logService: ILogService, private readonly options?: IDiskFileSystemProviderOptions ) { super(); @@ -152,7 +151,7 @@ export class DiskFileSystemProvider extends Disposable implements try { const filePath = this.toFilePath(resource); - return await promises.readFile(filePath); + return await Promises.readFile(filePath); } catch (error) { throw this.toFileSystemProviderError(error); } @@ -216,7 +215,7 @@ export class DiskFileSystemProvider extends Disposable implements try { const { stat } = await SymlinkSupport.stat(filePath); if (!(stat.mode & 0o200 /* File mode indicating writable by owner */)) { - await promises.chmod(filePath, stat.mode | 0o200); + await Promises.chmod(filePath, stat.mode | 0o200); } } catch (error) { this.logService.trace(error); // ignore any errors here and try to just write @@ -232,7 +231,7 @@ export class DiskFileSystemProvider extends Disposable implements // by first truncating the file and then writing with r+ flag. This helps to save hidden files on Windows // (see https://github.com/microsoft/vscode/issues/931) and prevent removing alternate data streams // (see https://github.com/microsoft/vscode/issues/6363) - await promises.truncate(filePath, 0); + await Promises.truncate(filePath, 0); // After a successful truncate() the flag can be set to 'r+' which will not truncate. flags = 'r+'; @@ -256,7 +255,7 @@ export class DiskFileSystemProvider extends Disposable implements flags = 'r'; } - const handle = await promisify(open)(filePath, flags); + const handle = await Promises.open(filePath, flags); // remember this handle to track file position of the handle // we init the position to 0 since the file descriptor was @@ -290,7 +289,7 @@ export class DiskFileSystemProvider extends Disposable implements // to flush the contents to disk if possible. if (this.writeHandles.delete(fd) && this.canFlush) { try { - await promisify(fdatasync)(fd); + await Promises.fdatasync(fd); } catch (error) { // In some exotic setups it is well possible that node fails to sync // In that case we disable flushing and log the error to our logger @@ -299,7 +298,7 @@ export class DiskFileSystemProvider extends Disposable implements } } - return await promisify(close)(fd); + return await Promises.close(fd); } catch (error) { throw this.toFileSystemProviderError(error); } @@ -310,7 +309,7 @@ export class DiskFileSystemProvider extends Disposable implements let bytesRead: number | null = null; try { - const result = await promisify(read)(fd, data, offset, length, normalizedPos); + const result = await Promises.read(fd, data, offset, length, normalizedPos); if (typeof result === 'number') { bytesRead = result; // node.d.ts fail @@ -396,7 +395,7 @@ export class DiskFileSystemProvider extends Disposable implements let bytesWritten: number | null = null; try { - const result = await promisify(write)(fd, data, offset, length, normalizedPos); + const result = await Promises.write(fd, data, offset, length, normalizedPos); if (typeof result === 'number') { bytesWritten = result; // node.d.ts fail @@ -418,7 +417,7 @@ export class DiskFileSystemProvider extends Disposable implements async mkdir(resource: URI): Promise { try { - await promises.mkdir(this.toFilePath(resource)); + await Promises.mkdir(this.toFilePath(resource)); } catch (error) { throw this.toFileSystemProviderError(error); } @@ -438,7 +437,7 @@ export class DiskFileSystemProvider extends Disposable implements if (opts.recursive) { await rimraf(filePath, RimRafMode.MOVE); } else { - await promises.unlink(filePath); + await Promises.unlink(filePath); } } @@ -542,7 +541,7 @@ export class DiskFileSystemProvider extends Disposable implements return this.watchRecursive(resource, opts.excludes); } - return this.watchNonRecursive(resource); // TODO@bpasero ideally the same watcher can be used in both cases + return this.watchNonRecursive(resource); } private watchRecursive(resource: URI, excludes: string[]): IDisposable { diff --git a/lib/vscode/src/vs/platform/files/node/watcher/nodejs/watcherService.ts b/src/vs/platform/files/node/watcher/nodejs/watcherService.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/node/watcher/nodejs/watcherService.ts rename to src/vs/platform/files/node/watcher/nodejs/watcherService.ts diff --git a/lib/vscode/src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts b/src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts rename to src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts diff --git a/lib/vscode/src/vs/platform/files/node/watcher/nsfw/test/nsfwWatcherService.test.ts b/src/vs/platform/files/node/watcher/nsfw/test/nsfwWatcherService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/node/watcher/nsfw/test/nsfwWatcherService.test.ts rename to src/vs/platform/files/node/watcher/nsfw/test/nsfwWatcherService.test.ts diff --git a/lib/vscode/src/vs/platform/files/node/watcher/nsfw/watcher.ts b/src/vs/platform/files/node/watcher/nsfw/watcher.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/node/watcher/nsfw/watcher.ts rename to src/vs/platform/files/node/watcher/nsfw/watcher.ts diff --git a/lib/vscode/src/vs/platform/files/node/watcher/nsfw/watcherApp.ts b/src/vs/platform/files/node/watcher/nsfw/watcherApp.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/node/watcher/nsfw/watcherApp.ts rename to src/vs/platform/files/node/watcher/nsfw/watcherApp.ts diff --git a/lib/vscode/src/vs/platform/files/node/watcher/nsfw/watcherService.ts b/src/vs/platform/files/node/watcher/nsfw/watcherService.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/node/watcher/nsfw/watcherService.ts rename to src/vs/platform/files/node/watcher/nsfw/watcherService.ts diff --git a/lib/vscode/src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts b/src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts rename to src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts diff --git a/lib/vscode/src/vs/platform/files/node/watcher/unix/test/chockidarWatcherService.test.ts b/src/vs/platform/files/node/watcher/unix/test/chockidarWatcherService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/node/watcher/unix/test/chockidarWatcherService.test.ts rename to src/vs/platform/files/node/watcher/unix/test/chockidarWatcherService.test.ts diff --git a/lib/vscode/src/vs/platform/files/node/watcher/unix/watcher.ts b/src/vs/platform/files/node/watcher/unix/watcher.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/node/watcher/unix/watcher.ts rename to src/vs/platform/files/node/watcher/unix/watcher.ts diff --git a/lib/vscode/src/vs/platform/files/node/watcher/unix/watcherApp.ts b/src/vs/platform/files/node/watcher/unix/watcherApp.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/node/watcher/unix/watcherApp.ts rename to src/vs/platform/files/node/watcher/unix/watcherApp.ts diff --git a/lib/vscode/src/vs/platform/files/node/watcher/unix/watcherService.ts b/src/vs/platform/files/node/watcher/unix/watcherService.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/node/watcher/unix/watcherService.ts rename to src/vs/platform/files/node/watcher/unix/watcherService.ts diff --git a/lib/vscode/src/vs/platform/files/node/watcher/watcher.ts b/src/vs/platform/files/node/watcher/watcher.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/node/watcher/watcher.ts rename to src/vs/platform/files/node/watcher/watcher.ts diff --git a/lib/vscode/src/vs/platform/files/node/watcher/win32/CodeHelper.exe b/src/vs/platform/files/node/watcher/win32/CodeHelper.exe similarity index 100% rename from lib/vscode/src/vs/platform/files/node/watcher/win32/CodeHelper.exe rename to src/vs/platform/files/node/watcher/win32/CodeHelper.exe diff --git a/lib/vscode/src/vs/platform/files/node/watcher/win32/CodeHelper.md b/src/vs/platform/files/node/watcher/win32/CodeHelper.md similarity index 100% rename from lib/vscode/src/vs/platform/files/node/watcher/win32/CodeHelper.md rename to src/vs/platform/files/node/watcher/win32/CodeHelper.md diff --git a/lib/vscode/src/vs/platform/files/node/watcher/win32/csharpWatcherService.ts b/src/vs/platform/files/node/watcher/win32/csharpWatcherService.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/node/watcher/win32/csharpWatcherService.ts rename to src/vs/platform/files/node/watcher/win32/csharpWatcherService.ts diff --git a/lib/vscode/src/vs/platform/files/node/watcher/win32/watcherService.ts b/src/vs/platform/files/node/watcher/win32/watcherService.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/node/watcher/win32/watcherService.ts rename to src/vs/platform/files/node/watcher/win32/watcherService.ts diff --git a/lib/vscode/src/vs/platform/files/test/browser/fileService.test.ts b/src/vs/platform/files/test/browser/fileService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/test/browser/fileService.test.ts rename to src/vs/platform/files/test/browser/fileService.test.ts diff --git a/lib/vscode/src/vs/platform/files/test/browser/indexedDBFileService.test.ts b/src/vs/platform/files/test/browser/indexedDBFileService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/test/browser/indexedDBFileService.test.ts rename to src/vs/platform/files/test/browser/indexedDBFileService.test.ts diff --git a/lib/vscode/src/vs/platform/files/test/common/files.test.ts b/src/vs/platform/files/test/common/files.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/test/common/files.test.ts rename to src/vs/platform/files/test/common/files.test.ts diff --git a/lib/vscode/src/vs/platform/files/test/common/nullFileSystemProvider.ts b/src/vs/platform/files/test/common/nullFileSystemProvider.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/test/common/nullFileSystemProvider.ts rename to src/vs/platform/files/test/common/nullFileSystemProvider.ts diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/diskFileService.test.ts b/src/vs/platform/files/test/electron-browser/diskFileService.test.ts similarity index 97% rename from lib/vscode/src/vs/platform/files/test/electron-browser/diskFileService.test.ts rename to src/vs/platform/files/test/electron-browser/diskFileService.test.ts index ebdd45d8622f..00c4d13a547b 100644 --- a/lib/vscode/src/vs/platform/files/test/electron-browser/diskFileService.test.ts +++ b/src/vs/platform/files/test/electron-browser/diskFileService.test.ts @@ -10,10 +10,10 @@ import { Schemas } from 'vs/base/common/network'; import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { flakySuite, getRandomTestPath, getPathFromAmdModule } from 'vs/base/test/node/testUtils'; import { join, basename, dirname, posix } from 'vs/base/common/path'; -import { copy, rimraf, rimrafSync } from 'vs/base/node/pfs'; +import { copy, Promises, rimraf, rimrafSync } from 'vs/base/node/pfs'; import { URI } from 'vs/base/common/uri'; -import { existsSync, statSync, readdirSync, readFileSync, writeFileSync, renameSync, unlinkSync, mkdirSync, createReadStream, promises } from 'fs'; -import { FileOperation, FileOperationEvent, IFileStat, FileOperationResult, FileSystemProviderCapabilities, FileChangeType, IFileChange, FileChangesEvent, FileOperationError, etag, IStat, IFileStatWithMetadata, IReadFileOptions } from 'vs/platform/files/common/files'; +import { existsSync, statSync, readdirSync, readFileSync, writeFileSync, renameSync, unlinkSync, mkdirSync, createReadStream } from 'fs'; +import { FileOperation, FileOperationEvent, IFileStat, FileOperationResult, FileSystemProviderCapabilities, FileChangeType, IFileChange, FileChangesEvent, FileOperationError, etag, IStat, IFileStatWithMetadata, IReadFileOptions, FilePermission, NotModifiedSinceFileOperationError } from 'vs/platform/files/common/files'; import { NullLogService } from 'vs/platform/log/common/log'; import { isLinux, isWindows } from 'vs/base/common/platform'; import { DisposableStore } from 'vs/base/common/lifecycle'; @@ -56,6 +56,7 @@ export class TestDiskFileSystemProvider extends DiskFileSystemProvider { private invalidStatSize: boolean = false; private smallStatSize: boolean = false; + private readonly: boolean = false; private _testCapabilities!: FileSystemProviderCapabilities; override get capabilities(): FileSystemProviderCapabilities { @@ -88,13 +89,19 @@ export class TestDiskFileSystemProvider extends DiskFileSystemProvider { this.smallStatSize = enabled; } + setReadonly(readonly: boolean): void { + this.readonly = readonly; + } + override async stat(resource: URI): Promise { const res = await super.stat(resource); if (this.invalidStatSize) { - res.size = String(res.size) as any; // for https://github.com/microsoft/vscode/issues/72909 + (res as any).size = String(res.size) as any; // for https://github.com/microsoft/vscode/issues/72909 } else if (this.smallStatSize) { - res.size = 1; + (res as any).size = 1; + } else if (this.readonly) { + (res as any).permissions = FilePermission.Readonly; } return res; @@ -213,6 +220,7 @@ flakySuite('Disk File Service', function () { assert.strictEqual(resolved.name, 'index.html'); assert.strictEqual(resolved.isFile, true); assert.strictEqual(resolved.isDirectory, false); + assert.strictEqual(resolved.readonly, false); assert.strictEqual(resolved.isSymbolicLink, false); assert.strictEqual(resolved.resource.toString(), resource.toString()); assert.strictEqual(resolved.children, undefined); @@ -233,6 +241,7 @@ flakySuite('Disk File Service', function () { assert.ok(result.children); assert.ok(result.children!.length > 0); assert.ok(result!.isDirectory); + assert.strictEqual(result.readonly, false); assert.ok(result.mtime! > 0); assert.ok(result.ctime! > 0); assert.strictEqual(result.children!.length, testsElements.length); @@ -408,7 +417,7 @@ flakySuite('Disk File Service', function () { test('resolve - folder symbolic link', async () => { const link = URI.file(join(testDir, 'deep-link')); - await promises.symlink(join(testDir, 'deep'), link.fsPath, 'junction'); + await Promises.symlink(join(testDir, 'deep'), link.fsPath, 'junction'); const resolved = await service.resolve(link); assert.strictEqual(resolved.children!.length, 4); @@ -418,7 +427,7 @@ flakySuite('Disk File Service', function () { (isWindows ? test.skip /* windows: cannot create file symbolic link without elevated context */ : test)('resolve - file symbolic link', async () => { const link = URI.file(join(testDir, 'lorem.txt-linked')); - await promises.symlink(join(testDir, 'lorem.txt'), link.fsPath); + await Promises.symlink(join(testDir, 'lorem.txt'), link.fsPath); const resolved = await service.resolve(link); assert.strictEqual(resolved.isDirectory, false); @@ -426,7 +435,7 @@ flakySuite('Disk File Service', function () { }); test('resolve - symbolic link pointing to non-existing file does not break', async () => { - await promises.symlink(join(testDir, 'foo'), join(testDir, 'bar'), 'junction'); + await Promises.symlink(join(testDir, 'foo'), join(testDir, 'bar'), 'junction'); const resolved = await service.resolve(URI.file(testDir)); assert.strictEqual(resolved.isDirectory, true); @@ -477,7 +486,7 @@ flakySuite('Disk File Service', function () { (isWindows ? test.skip /* windows: cannot create file symbolic link without elevated context */ : test)('deleteFile - symbolic link (exists)', async () => { const target = URI.file(join(testDir, 'lorem.txt')); const link = URI.file(join(testDir, 'lorem.txt-linked')); - await promises.symlink(target.fsPath, link.fsPath); + await Promises.symlink(target.fsPath, link.fsPath); const source = await service.resolve(link); @@ -499,7 +508,7 @@ flakySuite('Disk File Service', function () { (isWindows ? test.skip /* windows: cannot create file symbolic link without elevated context */ : test)('deleteFile - symbolic link (pointing to non-existing file)', async () => { const target = URI.file(join(testDir, 'foo')); const link = URI.file(join(testDir, 'bar')); - await promises.symlink(target.fsPath, link.fsPath); + await Promises.symlink(target.fsPath, link.fsPath); let event: FileOperationEvent; disposables.add(service.onDidRunOperation(e => event = e)); @@ -1482,6 +1491,7 @@ flakySuite('Disk File Service', function () { assert.ok(error); assert.strictEqual(error!.fileOperationResult, FileOperationResult.FILE_NOT_MODIFIED_SINCE); + assert.ok(error instanceof NotModifiedSinceFileOperationError && error.stat); assert.strictEqual(fileProvider.totalBytesRead, 0); } @@ -1592,7 +1602,7 @@ flakySuite('Disk File Service', function () { (isWindows ? test.skip /* windows: cannot create file symbolic link without elevated context */ : test)('readFile - dangling symbolic link - https://github.com/microsoft/vscode/issues/116049', async () => { const link = URI.file(join(testDir, 'small.js-link')); - await promises.symlink(join(testDir, 'small.js'), link.fsPath); + await Promises.symlink(join(testDir, 'small.js'), link.fsPath); let error: FileOperationError | undefined = undefined; try { @@ -1928,8 +1938,8 @@ flakySuite('Disk File Service', function () { await service.writeFile(lockedFile, VSBuffer.fromString('Locked File')); - const stats = await promises.stat(lockedFile.fsPath); - await promises.chmod(lockedFile.fsPath, stats.mode & ~0o200); + const stats = await Promises.stat(lockedFile.fsPath); + await Promises.chmod(lockedFile.fsPath, stats.mode & ~0o200); let error; const newContent = 'Updates to locked file'; @@ -2091,7 +2101,7 @@ flakySuite('Disk File Service', function () { (runWatchTests && !isWindows /* windows: cannot create file symbolic link without elevated context */ ? test : test.skip)('watch - file symbolic link', async () => { const toWatch = URI.file(join(testDir, 'lorem.txt-linked')); - await promises.symlink(join(testDir, 'lorem.txt'), toWatch.fsPath); + await Promises.symlink(join(testDir, 'lorem.txt'), toWatch.fsPath); const promise = assertWatch(toWatch, [[FileChangeType.UPDATED, toWatch]]); setTimeout(() => writeFileSync(toWatch.fsPath, 'Changes'), 50); @@ -2219,7 +2229,7 @@ flakySuite('Disk File Service', function () { (runWatchTests ? test : test.skip)('watch - folder (non recursive) - symbolic link - change file', async () => { const watchDir = URI.file(join(testDir, 'deep-link')); - await promises.symlink(join(testDir, 'deep'), watchDir.fsPath, 'junction'); + await Promises.symlink(join(testDir, 'deep'), watchDir.fsPath, 'junction'); const file = URI.file(join(watchDir.fsPath, 'index.html')); writeFileSync(file.fsPath, 'Init'); @@ -2390,4 +2400,32 @@ flakySuite('Disk File Service', function () { await fileProvider.close(fdWrite); await fileProvider.close(fdRead); }); + + test('readonly - is handled properly for a single resource', async () => { + fileProvider.setReadonly(true); + + const resource = URI.file(join(testDir, 'index.html')); + + const resolveResult = await service.resolve(resource); + assert.strictEqual(resolveResult.readonly, true); + + const readResult = await service.readFile(resource); + assert.strictEqual(readResult.readonly, true); + + let writeFileError: Error | undefined = undefined; + try { + await service.writeFile(resource, VSBuffer.fromString('Hello Test')); + } catch (error) { + writeFileError = error; + } + assert.ok(writeFileError); + + let deleteFileError: Error | undefined = undefined; + try { + await service.del(resource); + } catch (error) { + deleteFileError = error; + } + assert.ok(deleteFileError); + }); }); diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/company.js b/src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/company.js similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/company.js rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/company.js diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/conway.js b/src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/conway.js similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/conway.js rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/conway.js diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/employee.js b/src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/employee.js similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/employee.js rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/employee.js diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/small.js b/src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/small.js similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/small.js rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/examples/small.js diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/index.html b/src/vs/platform/files/test/electron-browser/fixtures/resolver/index.html similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/index.html rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/index.html diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/company.js b/src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/company.js similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/company.js rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/company.js diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/conway.js b/src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/conway.js similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/conway.js rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/conway.js diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/employee.js b/src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/employee.js similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/employee.js rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/employee.js diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/small.js b/src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/small.js similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/small.js rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/other/deep/small.js diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/site.css b/src/vs/platform/files/test/electron-browser/fixtures/resolver/site.css similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/resolver/site.css rename to src/vs/platform/files/test/electron-browser/fixtures/resolver/site.css diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/binary.txt b/src/vs/platform/files/test/electron-browser/fixtures/service/binary.txt similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/binary.txt rename to src/vs/platform/files/test/electron-browser/fixtures/service/binary.txt diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/deep/company.js b/src/vs/platform/files/test/electron-browser/fixtures/service/deep/company.js similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/deep/company.js rename to src/vs/platform/files/test/electron-browser/fixtures/service/deep/company.js diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/deep/conway.js b/src/vs/platform/files/test/electron-browser/fixtures/service/deep/conway.js similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/deep/conway.js rename to src/vs/platform/files/test/electron-browser/fixtures/service/deep/conway.js diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/deep/employee.js b/src/vs/platform/files/test/electron-browser/fixtures/service/deep/employee.js similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/deep/employee.js rename to src/vs/platform/files/test/electron-browser/fixtures/service/deep/employee.js diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/deep/small.js b/src/vs/platform/files/test/electron-browser/fixtures/service/deep/small.js similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/deep/small.js rename to src/vs/platform/files/test/electron-browser/fixtures/service/deep/small.js diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/index.html b/src/vs/platform/files/test/electron-browser/fixtures/service/index.html similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/index.html rename to src/vs/platform/files/test/electron-browser/fixtures/service/index.html diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/lorem.txt b/src/vs/platform/files/test/electron-browser/fixtures/service/lorem.txt similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/lorem.txt rename to src/vs/platform/files/test/electron-browser/fixtures/service/lorem.txt diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/small.txt b/src/vs/platform/files/test/electron-browser/fixtures/service/small.txt similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/small.txt rename to src/vs/platform/files/test/electron-browser/fixtures/service/small.txt diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/small_umlaut.txt b/src/vs/platform/files/test/electron-browser/fixtures/service/small_umlaut.txt similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/small_umlaut.txt rename to src/vs/platform/files/test/electron-browser/fixtures/service/small_umlaut.txt diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/some_utf16le.css b/src/vs/platform/files/test/electron-browser/fixtures/service/some_utf16le.css similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/some_utf16le.css rename to src/vs/platform/files/test/electron-browser/fixtures/service/some_utf16le.css diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/some_utf8_bom.txt b/src/vs/platform/files/test/electron-browser/fixtures/service/some_utf8_bom.txt similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/fixtures/service/some_utf8_bom.txt rename to src/vs/platform/files/test/electron-browser/fixtures/service/some_utf8_bom.txt diff --git a/lib/vscode/src/vs/platform/files/test/electron-browser/normalizer.test.ts b/src/vs/platform/files/test/electron-browser/normalizer.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/files/test/electron-browser/normalizer.test.ts rename to src/vs/platform/files/test/electron-browser/normalizer.test.ts diff --git a/lib/vscode/src/vs/platform/instantiation/common/descriptors.ts b/src/vs/platform/instantiation/common/descriptors.ts similarity index 100% rename from lib/vscode/src/vs/platform/instantiation/common/descriptors.ts rename to src/vs/platform/instantiation/common/descriptors.ts diff --git a/lib/vscode/src/vs/platform/instantiation/common/extensions.ts b/src/vs/platform/instantiation/common/extensions.ts similarity index 100% rename from lib/vscode/src/vs/platform/instantiation/common/extensions.ts rename to src/vs/platform/instantiation/common/extensions.ts diff --git a/lib/vscode/src/vs/platform/instantiation/common/graph.ts b/src/vs/platform/instantiation/common/graph.ts similarity index 100% rename from lib/vscode/src/vs/platform/instantiation/common/graph.ts rename to src/vs/platform/instantiation/common/graph.ts diff --git a/lib/vscode/src/vs/platform/instantiation/common/instantiation.ts b/src/vs/platform/instantiation/common/instantiation.ts similarity index 100% rename from lib/vscode/src/vs/platform/instantiation/common/instantiation.ts rename to src/vs/platform/instantiation/common/instantiation.ts diff --git a/lib/vscode/src/vs/platform/instantiation/common/instantiationService.ts b/src/vs/platform/instantiation/common/instantiationService.ts similarity index 100% rename from lib/vscode/src/vs/platform/instantiation/common/instantiationService.ts rename to src/vs/platform/instantiation/common/instantiationService.ts diff --git a/lib/vscode/src/vs/platform/instantiation/common/serviceCollection.ts b/src/vs/platform/instantiation/common/serviceCollection.ts similarity index 100% rename from lib/vscode/src/vs/platform/instantiation/common/serviceCollection.ts rename to src/vs/platform/instantiation/common/serviceCollection.ts diff --git a/lib/vscode/src/vs/platform/instantiation/test/common/graph.test.ts b/src/vs/platform/instantiation/test/common/graph.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/instantiation/test/common/graph.test.ts rename to src/vs/platform/instantiation/test/common/graph.test.ts diff --git a/lib/vscode/src/vs/platform/instantiation/test/common/instantiationService.test.ts b/src/vs/platform/instantiation/test/common/instantiationService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/instantiation/test/common/instantiationService.test.ts rename to src/vs/platform/instantiation/test/common/instantiationService.test.ts diff --git a/lib/vscode/src/vs/platform/instantiation/test/common/instantiationServiceMock.ts b/src/vs/platform/instantiation/test/common/instantiationServiceMock.ts similarity index 100% rename from lib/vscode/src/vs/platform/instantiation/test/common/instantiationServiceMock.ts rename to src/vs/platform/instantiation/test/common/instantiationServiceMock.ts diff --git a/lib/vscode/src/vs/platform/ipc/electron-browser/mainProcessService.ts b/src/vs/platform/ipc/electron-browser/mainProcessService.ts similarity index 100% rename from lib/vscode/src/vs/platform/ipc/electron-browser/mainProcessService.ts rename to src/vs/platform/ipc/electron-browser/mainProcessService.ts diff --git a/lib/vscode/src/vs/platform/ipc/electron-sandbox/mainProcessService.ts b/src/vs/platform/ipc/electron-sandbox/mainProcessService.ts similarity index 100% rename from lib/vscode/src/vs/platform/ipc/electron-sandbox/mainProcessService.ts rename to src/vs/platform/ipc/electron-sandbox/mainProcessService.ts diff --git a/lib/vscode/src/vs/platform/ipc/electron-sandbox/services.ts b/src/vs/platform/ipc/electron-sandbox/services.ts similarity index 100% rename from lib/vscode/src/vs/platform/ipc/electron-sandbox/services.ts rename to src/vs/platform/ipc/electron-sandbox/services.ts diff --git a/lib/vscode/src/vs/platform/issue/common/issue.ts b/src/vs/platform/issue/common/issue.ts similarity index 90% rename from lib/vscode/src/vs/platform/issue/common/issue.ts rename to src/vs/platform/issue/common/issue.ts index 58e1883dcf34..0f398932e6d8 100644 --- a/lib/vscode/src/vs/platform/issue/common/issue.ts +++ b/src/vs/platform/issue/common/issue.ts @@ -58,6 +58,7 @@ export interface IssueReporterData extends WindowData { issueType?: IssueType; extensionId?: string; experiments?: string; + restrictedMode: boolean; githubAccessToken: string; readonly issueTitle?: string; readonly issueBody?: string; @@ -70,8 +71,14 @@ export interface ISettingSearchResult { } export interface ProcessExplorerStyles extends WindowStyles { - hoverBackground?: string; - hoverForeground?: string; + listHoverBackground?: string; + listHoverForeground?: string; + listFocusBackground?: string; + listFocusForeground?: string; + listFocusOutline?: string; + listActiveSelectionBackground?: string; + listActiveSelectionForeground?: string; + listHoverOutline?: string; } export interface ProcessExplorerData extends WindowData { diff --git a/lib/vscode/src/vs/platform/issue/common/issueReporterUtil.ts b/src/vs/platform/issue/common/issueReporterUtil.ts similarity index 100% rename from lib/vscode/src/vs/platform/issue/common/issueReporterUtil.ts rename to src/vs/platform/issue/common/issueReporterUtil.ts diff --git a/lib/vscode/src/vs/platform/issue/electron-main/issueMainService.ts b/src/vs/platform/issue/electron-main/issueMainService.ts similarity index 94% rename from lib/vscode/src/vs/platform/issue/electron-main/issueMainService.ts rename to src/vs/platform/issue/electron-main/issueMainService.ts index e6be46456109..1eb0ac224bc6 100644 --- a/lib/vscode/src/vs/platform/issue/electron-main/issueMainService.ts +++ b/src/vs/platform/issue/electron-main/issueMainService.ts @@ -25,6 +25,13 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; export const IIssueMainService = createDecorator('issueMainService'); +interface IBrowserWindowOptions { + backgroundColor: string | undefined; + title: string; + zoomLevel: number; + alwaysOnTop: boolean; +} + export interface IIssueMainService extends ICommonIssueService { } export class IssueMainService implements ICommonIssueService { @@ -189,7 +196,12 @@ export class IssueMainService implements ICommonIssueService { const issueReporterWindowConfigUrl = issueReporterDisposables.add(this.protocolMainService.createIPCObjectUrl()); const position = this.getWindowPosition(this.issueReporterParentWindow, 700, 800); - this.issueReporterWindow = this.createBrowserWindow(position, issueReporterWindowConfigUrl, data.styles.backgroundColor, localize('issueReporter', "Issue Reporter"), data.zoomLevel); + this.issueReporterWindow = this.createBrowserWindow(position, issueReporterWindowConfigUrl, { + backgroundColor: data.styles.backgroundColor, + title: localize('issueReporter', "Issue Reporter"), + zoomLevel: data.zoomLevel, + alwaysOnTop: false + }); // Store into config object URL issueReporterWindowConfigUrl.update({ @@ -239,7 +251,12 @@ export class IssueMainService implements ICommonIssueService { const processExplorerWindowConfigUrl = processExplorerDisposables.add(this.protocolMainService.createIPCObjectUrl()); const position = this.getWindowPosition(this.processExplorerParentWindow, 800, 500); - this.processExplorerWindow = this.createBrowserWindow(position, processExplorerWindowConfigUrl, data.styles.backgroundColor, localize('processExplorer', "Process Explorer"), data.zoomLevel); + this.processExplorerWindow = this.createBrowserWindow(position, processExplorerWindowConfigUrl, { + backgroundColor: data.styles.backgroundColor, + title: localize('processExplorer', "Process Explorer"), + zoomLevel: data.zoomLevel, + alwaysOnTop: true + }); // Store into config object URL processExplorerWindowConfigUrl.update({ @@ -273,7 +290,7 @@ export class IssueMainService implements ICommonIssueService { this.processExplorerWindow?.focus(); } - private createBrowserWindow(position: IWindowState, ipcObjectUrl: IIPCObjectUrl, backgroundColor: string | undefined, title: string, zoomLevel: number): BrowserWindow { + private createBrowserWindow(position: IWindowState, ipcObjectUrl: IIPCObjectUrl, options: IBrowserWindowOptions): BrowserWindow { const window = new BrowserWindow({ fullscreen: false, skipTaskbar: true, @@ -284,8 +301,8 @@ export class IssueMainService implements ICommonIssueService { minHeight: 200, x: position.x, y: position.y, - title, - backgroundColor: backgroundColor || IssueMainService.DEFAULT_BACKGROUND_COLOR, + title: options.title, + backgroundColor: options.backgroundColor || IssueMainService.DEFAULT_BACKGROUND_COLOR, webPreferences: { preload: FileAccess.asFileUri('vs/base/parts/sandbox/electron-browser/preload.js', require).fsPath, additionalArguments: [`--vscode-window-config=${ipcObjectUrl.resource.toString()}`, '--context-isolation' /* TODO@bpasero: Use process.contextIsolateed when 13-x-y is adopted (https://github.com/electron/electron/pull/28030) */], @@ -294,10 +311,11 @@ export class IssueMainService implements ICommonIssueService { enableRemoteModule: false, spellcheck: false, nativeWindowOpen: true, - zoomFactor: zoomLevelToZoomFactor(zoomLevel), + zoomFactor: zoomLevelToZoomFactor(options.zoomLevel), sandbox: true, - contextIsolation: true - } + contextIsolation: true, + }, + alwaysOnTop: options.alwaysOnTop }); window.setMenuBarVisibility(false); diff --git a/lib/vscode/src/vs/platform/issue/electron-sandbox/issue.ts b/src/vs/platform/issue/electron-sandbox/issue.ts similarity index 100% rename from lib/vscode/src/vs/platform/issue/electron-sandbox/issue.ts rename to src/vs/platform/issue/electron-sandbox/issue.ts diff --git a/lib/vscode/src/vs/platform/jsonschemas/common/jsonContributionRegistry.ts b/src/vs/platform/jsonschemas/common/jsonContributionRegistry.ts similarity index 100% rename from lib/vscode/src/vs/platform/jsonschemas/common/jsonContributionRegistry.ts rename to src/vs/platform/jsonschemas/common/jsonContributionRegistry.ts diff --git a/lib/vscode/src/vs/platform/keybinding/common/abstractKeybindingService.ts b/src/vs/platform/keybinding/common/abstractKeybindingService.ts similarity index 98% rename from lib/vscode/src/vs/platform/keybinding/common/abstractKeybindingService.ts rename to src/vs/platform/keybinding/common/abstractKeybindingService.ts index 689431ec33e9..6de8a0e61e58 100644 --- a/lib/vscode/src/vs/platform/keybinding/common/abstractKeybindingService.ts +++ b/src/vs/platform/keybinding/common/abstractKeybindingService.ts @@ -107,8 +107,8 @@ export abstract class AbstractKeybindingService extends Disposable implements IK ); } - public lookupKeybinding(commandId: string): ResolvedKeybinding | undefined { - const result = this._getResolver().lookupPrimaryKeybinding(commandId); + public lookupKeybinding(commandId: string, context?: IContextKeyService): ResolvedKeybinding | undefined { + const result = this._getResolver().lookupPrimaryKeybinding(commandId, context); if (!result) { return undefined; } diff --git a/lib/vscode/src/vs/platform/keybinding/common/baseResolvedKeybinding.ts b/src/vs/platform/keybinding/common/baseResolvedKeybinding.ts similarity index 100% rename from lib/vscode/src/vs/platform/keybinding/common/baseResolvedKeybinding.ts rename to src/vs/platform/keybinding/common/baseResolvedKeybinding.ts diff --git a/lib/vscode/src/vs/platform/keybinding/common/keybinding.ts b/src/vs/platform/keybinding/common/keybinding.ts similarity index 94% rename from lib/vscode/src/vs/platform/keybinding/common/keybinding.ts rename to src/vs/platform/keybinding/common/keybinding.ts index a88b35753de5..7c7b4b2bb1ab 100644 --- a/lib/vscode/src/vs/platform/keybinding/common/keybinding.ts +++ b/src/vs/platform/keybinding/common/keybinding.ts @@ -6,7 +6,7 @@ import { Event } from 'vs/base/common/event'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { Keybinding, KeyCode, ResolvedKeybinding } from 'vs/base/common/keyCodes'; -import { IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IResolveResult } from 'vs/platform/keybinding/common/keybindingResolver'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; @@ -85,7 +85,7 @@ export interface IKeybindingService { * Look up the preferred (last defined) keybinding for a command. * @returns The preferred keybinding or null if the command is not bound. */ - lookupKeybinding(commandId: string): ResolvedKeybinding | undefined; + lookupKeybinding(commandId: string, context?: IContextKeyService): ResolvedKeybinding | undefined; getDefaultKeybindingsContent(): string; diff --git a/lib/vscode/src/vs/platform/keybinding/common/keybindingResolver.ts b/src/vs/platform/keybinding/common/keybindingResolver.ts similarity index 95% rename from lib/vscode/src/vs/platform/keybinding/common/keybindingResolver.ts rename to src/vs/platform/keybinding/common/keybindingResolver.ts index ca31e62e54e0..753e607ef07a 100644 --- a/lib/vscode/src/vs/platform/keybinding/common/keybindingResolver.ts +++ b/src/vs/platform/keybinding/common/keybindingResolver.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IContext, ContextKeyExpression, ContextKeyExprType } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpression, ContextKeyExprType, IContext, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; export interface IResolveResult { @@ -247,13 +247,15 @@ export class KeybindingResolver { return result; } - public lookupPrimaryKeybinding(commandId: string): ResolvedKeybindingItem | null { + public lookupPrimaryKeybinding(commandId: string, context?: IContextKeyService): ResolvedKeybindingItem | null { let items = this._lookupMap.get(commandId); if (typeof items === 'undefined' || items.length === 0) { return null; } - return items[items.length - 1]; + const itemMatchingContext = context && + Array.from(items).reverse().find(item => context.contextMatchesRules(item.when)); + return itemMatchingContext ?? items[items.length - 1]; } public resolve(context: IContext, currentChord: string | null, keypress: string): IResolveResult | null { diff --git a/lib/vscode/src/vs/platform/keybinding/common/keybindingsRegistry.ts b/src/vs/platform/keybinding/common/keybindingsRegistry.ts similarity index 100% rename from lib/vscode/src/vs/platform/keybinding/common/keybindingsRegistry.ts rename to src/vs/platform/keybinding/common/keybindingsRegistry.ts diff --git a/lib/vscode/src/vs/platform/keybinding/common/resolvedKeybindingItem.ts b/src/vs/platform/keybinding/common/resolvedKeybindingItem.ts similarity index 100% rename from lib/vscode/src/vs/platform/keybinding/common/resolvedKeybindingItem.ts rename to src/vs/platform/keybinding/common/resolvedKeybindingItem.ts diff --git a/lib/vscode/src/vs/platform/keybinding/common/usLayoutResolvedKeybinding.ts b/src/vs/platform/keybinding/common/usLayoutResolvedKeybinding.ts similarity index 100% rename from lib/vscode/src/vs/platform/keybinding/common/usLayoutResolvedKeybinding.ts rename to src/vs/platform/keybinding/common/usLayoutResolvedKeybinding.ts diff --git a/lib/vscode/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts rename to src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts diff --git a/lib/vscode/src/vs/platform/keybinding/test/common/keybindingLabels.test.ts b/src/vs/platform/keybinding/test/common/keybindingLabels.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/keybinding/test/common/keybindingLabels.test.ts rename to src/vs/platform/keybinding/test/common/keybindingLabels.test.ts diff --git a/lib/vscode/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts b/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts rename to src/vs/platform/keybinding/test/common/keybindingResolver.test.ts diff --git a/lib/vscode/src/vs/platform/keybinding/test/common/mockKeybindingService.ts b/src/vs/platform/keybinding/test/common/mockKeybindingService.ts similarity index 100% rename from lib/vscode/src/vs/platform/keybinding/test/common/mockKeybindingService.ts rename to src/vs/platform/keybinding/test/common/mockKeybindingService.ts diff --git a/lib/vscode/src/vs/platform/keyboardLayout/common/dispatchConfig.ts b/src/vs/platform/keyboardLayout/common/dispatchConfig.ts similarity index 100% rename from lib/vscode/src/vs/platform/keyboardLayout/common/dispatchConfig.ts rename to src/vs/platform/keyboardLayout/common/dispatchConfig.ts diff --git a/lib/vscode/src/vs/platform/keyboardLayout/common/keyboardLayout.ts b/src/vs/platform/keyboardLayout/common/keyboardLayout.ts similarity index 100% rename from lib/vscode/src/vs/platform/keyboardLayout/common/keyboardLayout.ts rename to src/vs/platform/keyboardLayout/common/keyboardLayout.ts diff --git a/lib/vscode/src/vs/platform/keyboardLayout/common/keyboardLayoutService.ts b/src/vs/platform/keyboardLayout/common/keyboardLayoutService.ts similarity index 100% rename from lib/vscode/src/vs/platform/keyboardLayout/common/keyboardLayoutService.ts rename to src/vs/platform/keyboardLayout/common/keyboardLayoutService.ts diff --git a/lib/vscode/src/vs/platform/keyboardLayout/common/keyboardMapper.ts b/src/vs/platform/keyboardLayout/common/keyboardMapper.ts similarity index 100% rename from lib/vscode/src/vs/platform/keyboardLayout/common/keyboardMapper.ts rename to src/vs/platform/keyboardLayout/common/keyboardMapper.ts diff --git a/lib/vscode/src/vs/platform/keyboardLayout/electron-main/keyboardLayoutMainService.ts b/src/vs/platform/keyboardLayout/electron-main/keyboardLayoutMainService.ts similarity index 100% rename from lib/vscode/src/vs/platform/keyboardLayout/electron-main/keyboardLayoutMainService.ts rename to src/vs/platform/keyboardLayout/electron-main/keyboardLayoutMainService.ts diff --git a/lib/vscode/src/vs/platform/label/common/label.ts b/src/vs/platform/label/common/label.ts similarity index 100% rename from lib/vscode/src/vs/platform/label/common/label.ts rename to src/vs/platform/label/common/label.ts diff --git a/lib/vscode/src/vs/platform/launch/common/launch.ts b/src/vs/platform/launch/common/launch.ts similarity index 100% rename from lib/vscode/src/vs/platform/launch/common/launch.ts rename to src/vs/platform/launch/common/launch.ts diff --git a/lib/vscode/src/vs/platform/launch/electron-main/launchMainService.ts b/src/vs/platform/launch/electron-main/launchMainService.ts similarity index 100% rename from lib/vscode/src/vs/platform/launch/electron-main/launchMainService.ts rename to src/vs/platform/launch/electron-main/launchMainService.ts diff --git a/lib/vscode/src/vs/platform/layout/browser/layoutService.ts b/src/vs/platform/layout/browser/layoutService.ts similarity index 100% rename from lib/vscode/src/vs/platform/layout/browser/layoutService.ts rename to src/vs/platform/layout/browser/layoutService.ts diff --git a/lib/vscode/src/vs/platform/lifecycle/common/lifecycle.ts b/src/vs/platform/lifecycle/common/lifecycle.ts similarity index 100% rename from lib/vscode/src/vs/platform/lifecycle/common/lifecycle.ts rename to src/vs/platform/lifecycle/common/lifecycle.ts diff --git a/lib/vscode/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts b/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts similarity index 87% rename from lib/vscode/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts rename to src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts index c5d69ba4f5fa..2d18175d2658 100644 --- a/lib/vscode/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts +++ b/src/vs/platform/lifecycle/electron-main/lifecycleMainService.ts @@ -5,7 +5,7 @@ import { ipcMain, app, BrowserWindow } from 'electron'; import { ILogService } from 'vs/platform/log/common/log'; -import { IStateService } from 'vs/platform/state/node/state'; +import { IStateMainService } from 'vs/platform/state/electron-main/state'; import { Event, Emitter } from 'vs/base/common/event'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ICodeWindow } from 'vs/platform/windows/electron-main/windows'; @@ -115,12 +115,12 @@ export interface ILifecycleMainService { /** * Restart the application with optional arguments (CLI). All lifecycle event handlers are triggered. */ - relaunch(options?: { addArgs?: string[], removeArgs?: string[] }): void; + relaunch(options?: { addArgs?: string[], removeArgs?: string[] }): Promise; /** * Shutdown the application normally. All lifecycle event handlers are triggered. */ - quit(fromUpdate?: boolean): Promise; + quit(willRestart?: boolean): Promise; /** * Forcefully shutdown the application. No livecycle event handlers are triggered. @@ -158,7 +158,7 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe declare readonly _serviceBrand: undefined; - private static readonly QUIT_FROM_RESTART_MARKER = 'quit.from.restart'; // use a marker to find out if the session was restarted + private static readonly QUIT_AND_RESTART_KEY = 'lifecycle.quitAndRestart'; private readonly _onBeforeShutdown = this._register(new Emitter()); readonly onBeforeShutdown = this._onBeforeShutdown.event; @@ -188,28 +188,29 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe private oneTimeListenerTokenGenerator = 0; private windowCounter = 0; - private pendingQuitPromise: Promise | null = null; - private pendingQuitPromiseResolve: { (veto: boolean): void } | null = null; + private pendingQuitPromise: Promise | undefined = undefined; + private pendingQuitPromiseResolve: { (veto: boolean): void } | undefined = undefined; - private pendingWillShutdownPromise: Promise | null = null; + private pendingWillShutdownPromise: Promise | undefined = undefined; private readonly phaseWhen = new Map(); constructor( @ILogService private readonly logService: ILogService, - @IStateService private readonly stateService: IStateService + @IStateMainService private readonly stateMainService: IStateMainService ) { super(); - this.handleRestarted(); + this.resolveRestarted(); this.when(LifecycleMainPhase.Ready).then(() => this.registerListeners()); } - private handleRestarted(): void { - this._wasRestarted = !!this.stateService.getItem(LifecycleMainService.QUIT_FROM_RESTART_MARKER); + private resolveRestarted(): void { + this._wasRestarted = !!this.stateMainService.getItem(LifecycleMainService.QUIT_AND_RESTART_KEY); if (this._wasRestarted) { - this.stateService.removeItem(LifecycleMainService.QUIT_FROM_RESTART_MARKER); // remove the marker right after if found + // remove the marker right after if found + this.stateMainService.removeItem(LifecycleMainService.QUIT_AND_RESTART_KEY); } } @@ -294,7 +295,23 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe } }); - this.pendingWillShutdownPromise = Promises.settled(joiners).then(() => undefined, err => this.logService.error(err)); + this.pendingWillShutdownPromise = (async () => { + + // Settle all shutdown event joiners + try { + await Promises.settled(joiners); + } catch (error) { + this.logService.error(error); + } + + // Then, always make sure at the end + // the state service is flushed. + try { + await this.stateMainService.close(); + } catch (error) { + this.logService.error(error); + } + })(); return this.pendingWillShutdownPromise; } @@ -454,8 +471,8 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe private resolvePendingQuitPromise(veto: boolean): void { if (this.pendingQuitPromiseResolve) { this.pendingQuitPromiseResolve(veto); - this.pendingQuitPromiseResolve = null; - this.pendingQuitPromise = null; + this.pendingQuitPromiseResolve = undefined; + this.pendingQuitPromise = undefined; } } @@ -502,16 +519,16 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe }); } - quit(fromUpdate?: boolean): Promise { + quit(willRestart?: boolean): Promise { if (this.pendingQuitPromise) { return this.pendingQuitPromise; } - this.logService.trace(`Lifecycle#quit() - from update: ${fromUpdate}`); + this.logService.trace(`Lifecycle#quit() - will restart: ${willRestart}`); - // Remember the reason for quit was to restart - if (fromUpdate) { - this.stateService.setItem(LifecycleMainService.QUIT_FROM_RESTART_MARKER, true); + // Remember if we are about to restart + if (willRestart) { + this.stateMainService.setItem(LifecycleMainService.QUIT_AND_RESTART_KEY, true); } this.pendingQuitPromise = new Promise(resolve => { @@ -528,7 +545,7 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe return this.pendingQuitPromise; } - relaunch(options?: { addArgs?: string[], removeArgs?: string[] }): void { + async relaunch(options?: { addArgs?: string[], removeArgs?: string[] }): Promise { this.logService.trace('Lifecycle#relaunch()'); const args = process.argv.slice(1); @@ -545,37 +562,34 @@ export class LifecycleMainService extends Disposable implements ILifecycleMainSe } } - let quitVetoed = false; - app.once('quit', () => { - if (!quitVetoed) { - - // Remember the reason for quit was to restart - 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 - // behaviour. As such, we briefly change back to that directory and then when - // Code starts it will set it back to the installation directory again. - try { - if (isWindows) { - const currentWorkingDir = cwd(); - if (currentWorkingDir !== process.cwd()) { - process.chdir(currentWorkingDir); - } + const quitListener = () => { + // 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 + // behaviour. As such, we briefly change back to that directory and then when + // Code starts it will set it back to the installation directory again. + try { + if (isWindows) { + const currentWorkingDir = cwd(); + if (currentWorkingDir !== process.cwd()) { + process.chdir(currentWorkingDir); } - } catch (err) { - this.logService.error(err); } - - // relaunch after we are sure there is no veto - this.logService.trace('Lifecycle#relaunch() - calling app.relaunch()'); - app.relaunch({ args }); + } catch (err) { + this.logService.error(err); } - }); + + // relaunch after we are sure there is no veto + this.logService.trace('Lifecycle#relaunch() - calling app.relaunch()'); + app.relaunch({ args }); + }; + app.once('quit', quitListener); // app.relaunch() does not quit automatically, so we quit first, // check for vetoes and then relaunch from the app.on('quit') event - this.quit().then(veto => quitVetoed = veto); + const veto = await this.quit(true /* will restart */); + if (veto) { + app.removeListener('quit', quitListener); + } } async kill(code?: number): Promise { diff --git a/lib/vscode/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts similarity index 94% rename from lib/vscode/src/vs/platform/list/browser/listService.ts rename to src/vs/platform/list/browser/listService.ts index 6b2f6b35019e..648e319d7d63 100644 --- a/lib/vscode/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -183,7 +183,7 @@ function toWorkbenchListOptions(options: IListOptions, configurationServic } }; - result.smoothScrolling = configurationService.getValue(listSmoothScrolling); + result.smoothScrolling = Boolean(configurationService.getValue(listSmoothScrolling)); return [result, disposables]; } @@ -221,7 +221,7 @@ export class WorkbenchList extends List { @IConfigurationService configurationService: IConfigurationService, @IKeybindingService keybindingService: IKeybindingService ) { - const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : configurationService.getValue(horizontalScrollingKey); + const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : Boolean(configurationService.getValue(horizontalScrollingKey)); const [workbenchListOptions, workbenchListOptionsDisposable] = toWorkbenchListOptions(options, configurationService, keybindingService); super(user, container, delegate, renderers, @@ -282,11 +282,11 @@ export class WorkbenchList extends List { let options: IListOptionsUpdate = {}; if (e.affectsConfiguration(horizontalScrollingKey) && this.horizontalScrolling === undefined) { - const horizontalScrolling = configurationService.getValue(horizontalScrollingKey); + const horizontalScrolling = Boolean(configurationService.getValue(horizontalScrollingKey)); options = { ...options, horizontalScrolling }; } if (e.affectsConfiguration(listSmoothScrolling)) { - const smoothScrolling = configurationService.getValue(listSmoothScrolling); + const smoothScrolling = Boolean(configurationService.getValue(listSmoothScrolling)); options = { ...options, smoothScrolling }; } if (Object.keys(options).length > 0) { @@ -348,7 +348,7 @@ export class WorkbenchPagedList extends PagedList { @IConfigurationService configurationService: IConfigurationService, @IKeybindingService keybindingService: IKeybindingService ) { - const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : configurationService.getValue(horizontalScrollingKey); + const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : Boolean(configurationService.getValue(horizontalScrollingKey)); const [workbenchListOptions, workbenchListOptionsDisposable] = toWorkbenchListOptions(options, configurationService, keybindingService); super(user, container, delegate, renderers, { @@ -394,11 +394,11 @@ export class WorkbenchPagedList extends PagedList { let options: IListOptionsUpdate = {}; if (e.affectsConfiguration(horizontalScrollingKey) && this.horizontalScrolling === undefined) { - const horizontalScrolling = configurationService.getValue(horizontalScrollingKey); + const horizontalScrolling = Boolean(configurationService.getValue(horizontalScrollingKey)); options = { ...options, horizontalScrolling }; } if (e.affectsConfiguration(listSmoothScrolling)) { - const smoothScrolling = configurationService.getValue(listSmoothScrolling); + const smoothScrolling = Boolean(configurationService.getValue(listSmoothScrolling)); options = { ...options, smoothScrolling }; } if (Object.keys(options).length > 0) { @@ -469,7 +469,7 @@ export class WorkbenchTable extends Table { @IConfigurationService configurationService: IConfigurationService, @IKeybindingService keybindingService: IKeybindingService ) { - const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : configurationService.getValue(horizontalScrollingKey); + const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : Boolean(configurationService.getValue(horizontalScrollingKey)); const [workbenchListOptions, workbenchListOptionsDisposable] = toWorkbenchListOptions(options, configurationService, keybindingService); super(user, container, delegate, columns, renderers, @@ -531,11 +531,11 @@ export class WorkbenchTable extends Table { let options: IListOptionsUpdate = {}; if (e.affectsConfiguration(horizontalScrollingKey) && this.horizontalScrolling === undefined) { - const horizontalScrolling = configurationService.getValue(horizontalScrollingKey); + const horizontalScrolling = Boolean(configurationService.getValue(horizontalScrollingKey)); options = { ...options, horizontalScrolling }; } if (e.affectsConfiguration(listSmoothScrolling)) { - const smoothScrolling = configurationService.getValue(listSmoothScrolling); + const smoothScrolling = Boolean(configurationService.getValue(listSmoothScrolling)); options = { ...options, smoothScrolling }; } if (Object.keys(options).length > 0) { @@ -999,10 +999,10 @@ function workbenchTreeDataPreamble { // give priority to the context key value to disable this completely - let automaticKeyboardNavigation = contextKeyService.getContextKeyValue(WorkbenchListAutomaticKeyboardNavigationKey); + let automaticKeyboardNavigation = Boolean(contextKeyService.getContextKeyValue(WorkbenchListAutomaticKeyboardNavigationKey)); if (automaticKeyboardNavigation) { - automaticKeyboardNavigation = configurationService.getValue(automaticKeyboardNavigationSettingKey); + automaticKeyboardNavigation = Boolean(configurationService.getValue(automaticKeyboardNavigationSettingKey)); } return automaticKeyboardNavigation; @@ -1010,7 +1010,7 @@ function workbenchTreeDataPreamble(keyboardNavigationSettingKey); - const horizontalScrolling = options.horizontalScrolling !== undefined ? options.horizontalScrolling : configurationService.getValue(horizontalScrollingKey); + const horizontalScrolling = options.horizontalScrolling !== undefined ? options.horizontalScrolling : Boolean(configurationService.getValue(horizontalScrollingKey)); const [workbenchListOptions, disposable] = toWorkbenchListOptions(options, configurationService, keybindingService); const additionalScrollHeight = options.additionalScrollHeight; @@ -1023,7 +1023,7 @@ function workbenchTreeDataPreamble(treeIndentKey), renderIndentGuides: configurationService.getValue(treeRenderIndentGuidesKey), - smoothScrolling: configurationService.getValue(listSmoothScrolling), + smoothScrolling: Boolean(configurationService.getValue(listSmoothScrolling)), automaticKeyboardNavigation: getAutomaticKeyboardNavigation(), simpleKeyboardNavigation: keyboardNavigation === 'simple', filterOnType: keyboardNavigation === 'filter', @@ -1120,7 +1120,7 @@ class WorkbenchTreeInternals { newOptions = { ...newOptions, renderIndentGuides }; } if (e.affectsConfiguration(listSmoothScrolling)) { - const smoothScrolling = configurationService.getValue(listSmoothScrolling); + const smoothScrolling = Boolean(configurationService.getValue(listSmoothScrolling)); newOptions = { ...newOptions, smoothScrolling }; } if (e.affectsConfiguration(keyboardNavigationSettingKey)) { @@ -1130,7 +1130,7 @@ class WorkbenchTreeInternals { newOptions = { ...newOptions, automaticKeyboardNavigation: getAutomaticKeyboardNavigation() }; } if (e.affectsConfiguration(horizontalScrollingKey) && options.horizontalScrolling === undefined) { - const horizontalScrolling = configurationService.getValue(horizontalScrollingKey); + const horizontalScrolling = Boolean(configurationService.getValue(horizontalScrollingKey)); newOptions = { ...newOptions, horizontalScrolling }; } if (e.affectsConfiguration(treeExpandMode) && options.expandOnlyOnTwistieClick === undefined) { @@ -1171,20 +1171,20 @@ class WorkbenchTreeInternals { const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); configurationRegistry.registerConfiguration({ - 'id': 'workbench', - 'order': 7, - 'title': localize('workbenchConfigurationTitle', "Workbench"), - 'type': 'object', - 'properties': { + id: 'workbench', + order: 7, + title: localize('workbenchConfigurationTitle', "Workbench"), + type: 'object', + properties: { [multiSelectModifierSettingKey]: { - 'type': 'string', - 'enum': ['ctrlCmd', 'alt'], - 'enumDescriptions': [ + type: 'string', + enum: ['ctrlCmd', 'alt'], + enumDescriptions: [ localize('multiSelectModifier.ctrlCmd', "Maps to `Control` on Windows and Linux and to `Command` on macOS."), localize('multiSelectModifier.alt', "Maps to `Alt` on Windows and Linux and to `Option` on macOS.") ], - 'default': 'ctrlCmd', - 'description': localize({ + default: 'ctrlCmd', + description: localize({ key: 'multiSelectModifier', comment: [ '- `ctrlCmd` refers to a value the setting can take and should not be localized.', @@ -1193,25 +1193,25 @@ configurationRegistry.registerConfiguration({ }, "The modifier to be used to add an item in trees and lists to a multi-selection with the mouse (for example in the explorer, open editors and scm view). The 'Open to Side' mouse gestures - if supported - will adapt such that they do not conflict with the multiselect modifier.") }, [openModeSettingKey]: { - 'type': 'string', - 'enum': ['singleClick', 'doubleClick'], - 'default': 'singleClick', - 'description': localize({ + type: 'string', + enum: ['singleClick', 'doubleClick'], + default: 'singleClick', + description: localize({ key: 'openModeModifier', comment: ['`singleClick` and `doubleClick` refers to a value the setting can take and should not be localized.'] }, "Controls how to open items in trees and lists using the mouse (if supported). Note that some trees and lists might choose to ignore this setting if it is not applicable.") }, [horizontalScrollingKey]: { - 'type': 'boolean', - 'default': false, - 'description': localize('horizontalScrolling setting', "Controls whether lists and trees support horizontal scrolling in the workbench. Warning: turning on this setting has a performance implication.") + type: 'boolean', + default: false, + description: localize('horizontalScrolling setting', "Controls whether lists and trees support horizontal scrolling in the workbench. Warning: turning on this setting has a performance implication.") }, [treeIndentKey]: { - 'type': 'number', - 'default': 8, + type: 'number', + default: 8, minimum: 0, maximum: 40, - 'description': localize('tree indent setting', "Controls tree indentation in pixels.") + description: localize('tree indent setting', "Controls tree indentation in pixels.") }, [treeRenderIndentGuidesKey]: { type: 'string', @@ -1225,19 +1225,19 @@ configurationRegistry.registerConfiguration({ description: localize('list smoothScrolling setting', "Controls whether lists and trees have smooth scrolling."), }, [keyboardNavigationSettingKey]: { - 'type': 'string', - 'enum': ['simple', 'highlight', 'filter'], - 'enumDescriptions': [ + type: 'string', + enum: ['simple', 'highlight', 'filter'], + enumDescriptions: [ localize('keyboardNavigationSettingKey.simple', "Simple keyboard navigation focuses elements which match the keyboard input. Matching is done only on prefixes."), localize('keyboardNavigationSettingKey.highlight', "Highlight keyboard navigation highlights elements which match the keyboard input. Further up and down navigation will traverse only the highlighted elements."), localize('keyboardNavigationSettingKey.filter', "Filter keyboard navigation will filter out and hide all the elements which do not match the keyboard input.") ], - 'default': 'highlight', - 'description': localize('keyboardNavigationSettingKey', "Controls the keyboard navigation style for lists and trees in the workbench. Can be simple, highlight and filter.") + default: 'highlight', + description: localize('keyboardNavigationSettingKey', "Controls the keyboard navigation style for lists and trees in the workbench. Can be simple, highlight and filter.") }, [automaticKeyboardNavigationSettingKey]: { - 'type': 'boolean', - 'default': true, + type: 'boolean', + default: true, markdownDescription: localize('automatic keyboard navigation setting', "Controls whether keyboard navigation in lists and trees is automatically triggered simply by typing. If set to `false`, keyboard navigation is only triggered when executing the `list.toggleKeyboardNavigation` command, for which you can assign a keyboard shortcut.") }, [treeExpandMode]: { diff --git a/lib/vscode/src/vs/platform/localizations/common/localizations.ts b/src/vs/platform/localizations/common/localizations.ts similarity index 100% rename from lib/vscode/src/vs/platform/localizations/common/localizations.ts rename to src/vs/platform/localizations/common/localizations.ts diff --git a/lib/vscode/src/vs/platform/localizations/node/localizations.ts b/src/vs/platform/localizations/node/localizations.ts similarity index 98% rename from lib/vscode/src/vs/platform/localizations/node/localizations.ts rename to src/vs/platform/localizations/node/localizations.ts index 02f3df5a9111..e1ef23c7b367 100644 --- a/lib/vscode/src/vs/platform/localizations/node/localizations.ts +++ b/src/vs/platform/localizations/node/localizations.ts @@ -3,8 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { writeFile } from 'vs/base/node/pfs'; -import { promises } from 'fs'; +import { Promises, writeFile } from 'vs/base/node/pfs'; import { createHash } from 'crypto'; import { IExtensionManagementService, ILocalExtension, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -158,7 +157,7 @@ class LanguagePacksCache extends Disposable { private withLanguagePacks(fn: (languagePacks: { [language: string]: ILanguagePack }) => T | null = () => null): Promise { return this.languagePacksFileLimiter.queue(() => { let result: T | null = null; - return promises.readFile(this.languagePacksFilePath, 'utf8') + return Promises.readFile(this.languagePacksFilePath, 'utf8') .then(undefined, err => err.code === 'ENOENT' ? Promise.resolve('{}') : Promise.reject(err)) .then<{ [language: string]: ILanguagePack }>(raw => { try { return JSON.parse(raw); } catch (e) { return {}; } }) .then(languagePacks => { result = fn(languagePacks); return languagePacks; }) diff --git a/lib/vscode/src/vs/platform/log/browser/log.ts b/src/vs/platform/log/browser/log.ts similarity index 100% rename from lib/vscode/src/vs/platform/log/browser/log.ts rename to src/vs/platform/log/browser/log.ts diff --git a/lib/vscode/src/vs/platform/log/common/bufferLog.ts b/src/vs/platform/log/common/bufferLog.ts similarity index 100% rename from lib/vscode/src/vs/platform/log/common/bufferLog.ts rename to src/vs/platform/log/common/bufferLog.ts diff --git a/lib/vscode/src/vs/platform/log/common/fileLog.ts b/src/vs/platform/log/common/fileLog.ts similarity index 100% rename from lib/vscode/src/vs/platform/log/common/fileLog.ts rename to src/vs/platform/log/common/fileLog.ts diff --git a/lib/vscode/src/vs/platform/log/common/log.ts b/src/vs/platform/log/common/log.ts similarity index 100% rename from lib/vscode/src/vs/platform/log/common/log.ts rename to src/vs/platform/log/common/log.ts diff --git a/lib/vscode/src/vs/platform/log/common/logIpc.ts b/src/vs/platform/log/common/logIpc.ts similarity index 100% rename from lib/vscode/src/vs/platform/log/common/logIpc.ts rename to src/vs/platform/log/common/logIpc.ts diff --git a/lib/vscode/src/vs/platform/log/node/loggerService.ts b/src/vs/platform/log/node/loggerService.ts similarity index 100% rename from lib/vscode/src/vs/platform/log/node/loggerService.ts rename to src/vs/platform/log/node/loggerService.ts diff --git a/lib/vscode/src/vs/platform/log/node/spdlogLog.ts b/src/vs/platform/log/node/spdlogLog.ts similarity index 88% rename from lib/vscode/src/vs/platform/log/node/spdlogLog.ts rename to src/vs/platform/log/node/spdlogLog.ts index b97064e29f74..a57db48bc31d 100644 --- a/lib/vscode/src/vs/platform/log/node/spdlogLog.ts +++ b/src/vs/platform/log/node/spdlogLog.ts @@ -7,20 +7,21 @@ import { LogLevel, ILogger, AbstractMessageLogger } from 'vs/platform/log/common import * as spdlog from 'spdlog'; import { ByteSize } from 'vs/platform/files/common/files'; -async function createSpdLogLogger(name: string, logfilePath: string, filesize: number, filecount: number): Promise { +async function createSpdLogLogger(name: string, logfilePath: string, filesize: number, filecount: number): Promise { // Do not crash if spdlog cannot be loaded try { const _spdlog = await import('spdlog'); - _spdlog.setAsyncMode(8192, 500); - return _spdlog.createRotatingLoggerAsync(name, logfilePath, filesize, filecount); + _spdlog.setFlushOn(LogLevel.Trace); + return _spdlog.createAsyncRotatingLogger(name, logfilePath, filesize, filecount); } catch (e) { console.error(e); } return null; } -export function createRotatingLogger(name: string, filename: string, filesize: number, filecount: number): spdlog.RotatingLogger { +export function createRotatingLogger(name: string, filename: string, filesize: number, filecount: number): Promise { const _spdlog: typeof spdlog = require.__$__nodeRequire('spdlog'); + _spdlog.setFlushOn(LogLevel.Trace); return _spdlog.createRotatingLogger(name, filename, filesize, filecount); } @@ -29,7 +30,7 @@ interface ILog { message: string; } -function log(logger: spdlog.RotatingLogger, level: LogLevel, message: string): void { +function log(logger: spdlog.Logger, level: LogLevel, message: string): void { switch (level) { case LogLevel.Trace: logger.trace(message); break; case LogLevel.Debug: logger.debug(message); break; @@ -45,7 +46,7 @@ export class SpdLogLogger extends AbstractMessageLogger implements ILogger { private buffer: ILog[] = []; private readonly _loggerCreationPromise: Promise; - private _logger: spdlog.RotatingLogger | undefined; + private _logger: spdlog.Logger | undefined; constructor( private readonly name: string, diff --git a/lib/vscode/src/vs/platform/markers/common/markerService.ts b/src/vs/platform/markers/common/markerService.ts similarity index 100% rename from lib/vscode/src/vs/platform/markers/common/markerService.ts rename to src/vs/platform/markers/common/markerService.ts diff --git a/lib/vscode/src/vs/platform/markers/common/markers.ts b/src/vs/platform/markers/common/markers.ts similarity index 100% rename from lib/vscode/src/vs/platform/markers/common/markers.ts rename to src/vs/platform/markers/common/markers.ts diff --git a/lib/vscode/src/vs/platform/markers/test/common/markerService.test.ts b/src/vs/platform/markers/test/common/markerService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/markers/test/common/markerService.test.ts rename to src/vs/platform/markers/test/common/markerService.test.ts diff --git a/lib/vscode/src/vs/platform/menubar/common/menubar.ts b/src/vs/platform/menubar/common/menubar.ts similarity index 100% rename from lib/vscode/src/vs/platform/menubar/common/menubar.ts rename to src/vs/platform/menubar/common/menubar.ts diff --git a/lib/vscode/src/vs/platform/menubar/electron-main/menubar.ts b/src/vs/platform/menubar/electron-main/menubar.ts similarity index 91% rename from lib/vscode/src/vs/platform/menubar/electron-main/menubar.ts rename to src/vs/platform/menubar/electron-main/menubar.ts index f9ab5a1e3e56..7f8f5b76d601 100644 --- a/lib/vscode/src/vs/platform/menubar/electron-main/menubar.ts +++ b/src/vs/platform/menubar/electron-main/menubar.ts @@ -19,7 +19,7 @@ import { IWindowsMainService, IWindowsCountChangedEvent, OpenContext } from 'vs/ import { IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService'; import { IMenubarData, IMenubarKeybinding, MenubarMenuItem, isMenubarMenuItemSeparator, isMenubarMenuItemSubmenu, isMenubarMenuItemAction, IMenubarMenu, isMenubarMenuItemRecentAction, IMenubarMenuRecentItemAction } from 'vs/platform/menubar/common/menubar'; import { URI } from 'vs/base/common/uri'; -import { IStateService } from 'vs/platform/state/node/state'; +import { IStateMainService } from 'vs/platform/state/electron-main/state'; import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; import { INativeHostMainService } from 'vs/platform/native/electron-main/nativeHostMainService'; @@ -70,7 +70,7 @@ export class Menubar { @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IWorkspacesHistoryMainService private readonly workspacesHistoryMainService: IWorkspacesHistoryMainService, - @IStateService private readonly stateService: IStateService, + @IStateMainService private readonly stateMainService: IStateMainService, @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @ILogService private readonly logService: ILogService, @INativeHostMainService private readonly nativeHostMainService: INativeHostMainService, @@ -100,7 +100,7 @@ export class Menubar { } private restoreCachedMenubarData() { - const menubarData = this.stateService.getItem(Menubar.lastKnownMenubarStorageKey); + const menubarData = this.stateMainService.getItem(Menubar.lastKnownMenubarStorageKey); if (menubarData) { if (menubarData.menus) { this.menubarMenus = menubarData.menus; @@ -200,7 +200,7 @@ export class Menubar { this.keybindings = menubarData.keybindings; // Save off new menu and keybindings - this.stateService.setItem(Menubar.lastKnownMenubarStorageKey, menubarData); + this.stateMainService.setItem(Menubar.lastKnownMenubarStorageKey, menubarData); this.scheduleUpdateMenu(); } @@ -285,53 +285,60 @@ export class Menubar { } // File - const fileMenu = new Menu(); - const fileMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mFile', comment: ['&& denotes a mnemonic'] }, "&&File")), submenu: fileMenu }); - - this.setMenuById(fileMenu, 'File'); - menubar.append(fileMenuItem); + if (this.shouldDrawMenu('File')) { + const fileMenu = new Menu(); + const fileMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mFile', comment: ['&& denotes a mnemonic'] }, "&&File")), submenu: fileMenu }); + this.setMenuById(fileMenu, 'File'); + menubar.append(fileMenuItem); + } // Edit - const editMenu = new Menu(); - const editMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mEdit', comment: ['&& denotes a mnemonic'] }, "&&Edit")), submenu: editMenu }); - - this.setMenuById(editMenu, 'Edit'); - menubar.append(editMenuItem); + if (this.shouldDrawMenu('Edit')) { + const editMenu = new Menu(); + const editMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mEdit', comment: ['&& denotes a mnemonic'] }, "&&Edit")), submenu: editMenu }); + this.setMenuById(editMenu, 'Edit'); + menubar.append(editMenuItem); + } // Selection - const selectionMenu = new Menu(); - const selectionMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mSelection', comment: ['&& denotes a mnemonic'] }, "&&Selection")), submenu: selectionMenu }); - - this.setMenuById(selectionMenu, 'Selection'); - menubar.append(selectionMenuItem); + if (this.shouldDrawMenu('Selection')) { + const selectionMenu = new Menu(); + const selectionMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mSelection', comment: ['&& denotes a mnemonic'] }, "&&Selection")), submenu: selectionMenu }); + this.setMenuById(selectionMenu, 'Selection'); + menubar.append(selectionMenuItem); + } // View - const viewMenu = new Menu(); - const viewMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mView', comment: ['&& denotes a mnemonic'] }, "&&View")), submenu: viewMenu }); - - this.setMenuById(viewMenu, 'View'); - menubar.append(viewMenuItem); + if (this.shouldDrawMenu('View')) { + const viewMenu = new Menu(); + const viewMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mView', comment: ['&& denotes a mnemonic'] }, "&&View")), submenu: viewMenu }); + this.setMenuById(viewMenu, 'View'); + menubar.append(viewMenuItem); + } // Go - const gotoMenu = new Menu(); - const gotoMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mGoto', comment: ['&& denotes a mnemonic'] }, "&&Go")), submenu: gotoMenu }); - - this.setMenuById(gotoMenu, 'Go'); - menubar.append(gotoMenuItem); + if (this.shouldDrawMenu('Go')) { + const gotoMenu = new Menu(); + const gotoMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mGoto', comment: ['&& denotes a mnemonic'] }, "&&Go")), submenu: gotoMenu }); + this.setMenuById(gotoMenu, 'Go'); + menubar.append(gotoMenuItem); + } // Debug - const debugMenu = new Menu(); - const debugMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mRun', comment: ['&& denotes a mnemonic'] }, "&&Run")), submenu: debugMenu }); - - this.setMenuById(debugMenu, 'Run'); - menubar.append(debugMenuItem); + if (this.shouldDrawMenu('Run')) { + const debugMenu = new Menu(); + const debugMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mRun', comment: ['&& denotes a mnemonic'] }, "&&Run")), submenu: debugMenu }); + this.setMenuById(debugMenu, 'Run'); + menubar.append(debugMenuItem); + } // Terminal - const terminalMenu = new Menu(); - const terminalMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mTerminal', comment: ['&& denotes a mnemonic'] }, "&&Terminal")), submenu: terminalMenu }); - - this.setMenuById(terminalMenu, 'Terminal'); - menubar.append(terminalMenuItem); + if (this.shouldDrawMenu('Terminal')) { + const terminalMenu = new Menu(); + const terminalMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mTerminal', comment: ['&& denotes a mnemonic'] }, "&&Terminal")), submenu: terminalMenu }); + this.setMenuById(terminalMenu, 'Terminal'); + menubar.append(terminalMenuItem); + } // Mac: Window let macWindowMenuItem: MenuItem | undefined; @@ -346,11 +353,12 @@ export class Menubar { } // Help - const helpMenu = new Menu(); - const helpMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mHelp', comment: ['&& denotes a mnemonic'] }, "&&Help")), submenu: helpMenu, role: 'help' }); - - this.setMenuById(helpMenu, 'Help'); - menubar.append(helpMenuItem); + if (this.shouldDrawMenu('Help')) { + const helpMenu = new Menu(); + const helpMenuItem = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'mHelp', comment: ['&& denotes a mnemonic'] }, "&&Help")), submenu: helpMenu, role: 'help' }); + this.setMenuById(helpMenu, 'Help'); + menubar.append(helpMenuItem); + } if (menubar.items && menubar.items.length > 0) { Menu.setApplicationMenu(menubar); diff --git a/lib/vscode/src/vs/platform/menubar/electron-main/menubarMainService.ts b/src/vs/platform/menubar/electron-main/menubarMainService.ts similarity index 100% rename from lib/vscode/src/vs/platform/menubar/electron-main/menubarMainService.ts rename to src/vs/platform/menubar/electron-main/menubarMainService.ts diff --git a/lib/vscode/src/vs/platform/menubar/electron-sandbox/menubar.ts b/src/vs/platform/menubar/electron-sandbox/menubar.ts similarity index 100% rename from lib/vscode/src/vs/platform/menubar/electron-sandbox/menubar.ts rename to src/vs/platform/menubar/electron-sandbox/menubar.ts diff --git a/lib/vscode/src/vs/platform/native/common/native.ts b/src/vs/platform/native/common/native.ts similarity index 95% rename from lib/vscode/src/vs/platform/native/common/native.ts rename to src/vs/platform/native/common/native.ts index dfe4994a11aa..a4133673c0ee 100644 --- a/lib/vscode/src/vs/platform/native/common/native.ts +++ b/src/vs/platform/native/common/native.ts @@ -5,7 +5,7 @@ import { Event } from 'vs/base/common/event'; import { MessageBoxOptions, MessageBoxReturnValue, OpenDevToolsOptions, SaveDialogOptions, OpenDialogOptions, OpenDialogReturnValue, SaveDialogReturnValue, MouseInputEvent } from 'vs/base/parts/sandbox/common/electronTypes'; -import { IOpenedWindow, IWindowOpenable, IOpenEmptyWindowOptions, IOpenWindowOptions, IColorScheme } from 'vs/platform/windows/common/windows'; +import { IOpenedWindow, IWindowOpenable, IOpenEmptyWindowOptions, IOpenWindowOptions, IColorScheme, IPartsSplash } from 'vs/platform/windows/common/windows'; import { INativeOpenDialogOptions } from 'vs/platform/dialogs/common/dialogs'; import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; import { URI } from 'vs/base/common/uri'; @@ -72,6 +72,8 @@ export interface ICommonNativeHostService { setMinimumSize(width: number | undefined, height: number | undefined): Promise; + saveWindowSplash(splash: IPartsSplash): Promise; + /** * Make the window focused. * @@ -97,7 +99,7 @@ export interface ICommonNativeHostService { setRepresentedFilename(path: string): Promise; setDocumentEdited(edited: boolean): Promise; openExternal(url: string): Promise; - moveItemToTrash(fullPath: string, deleteOnFail?: boolean): Promise; + moveItemToTrash(fullPath: string): Promise; isAdmin(): Promise; writeElevated(source: URI, target: URI, options?: { unlock?: boolean }): Promise; @@ -127,6 +129,10 @@ export interface ICommonNativeHostService { toggleWindowTabsBar(): Promise; updateTouchBar(items: ISerializableCommandAction[][]): Promise; + // macOS Shell command + installShellCommand(): Promise; + uninstallShellCommand(): Promise; + // Lifecycle notifyReady(): Promise relaunch(options?: { addArgs?: string[], removeArgs?: string[] }): Promise; diff --git a/lib/vscode/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts similarity index 84% rename from lib/vscode/src/vs/platform/native/electron-main/nativeHostMainService.ts rename to src/vs/platform/native/electron-main/nativeHostMainService.ts index a0b1a3bd86fd..692db1dbaa90 100644 --- a/lib/vscode/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -3,11 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { exec } from 'child_process'; +import { promisify } from 'util'; +import { localize } from 'vs/nls'; +import { realpath } from 'vs/base/node/extpath'; import { Emitter, Event } from 'vs/base/common/event'; import { IWindowsMainService, ICodeWindow, OpenContext } from 'vs/platform/windows/electron-main/windows'; import { MessageBoxOptions, MessageBoxReturnValue, shell, OpenDevToolsOptions, SaveDialogOptions, SaveDialogReturnValue, OpenDialogOptions, OpenDialogReturnValue, Menu, BrowserWindow, app, clipboard, powerMonitor, nativeTheme, screen, Display } from 'electron'; import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; -import { IOpenedWindow, IOpenWindowOptions, IWindowOpenable, IOpenEmptyWindowOptions, IColorScheme } from 'vs/platform/windows/common/windows'; +import { IOpenedWindow, IOpenWindowOptions, IWindowOpenable, IOpenEmptyWindowOptions, IColorScheme, IPartsSplash } from 'vs/platform/windows/common/windows'; import { INativeOpenDialogOptions } from 'vs/platform/dialogs/common/dialogs'; import { isMacintosh, isWindows, isLinux, isLinuxSnap } from 'vs/base/common/platform'; import { ICommonNativeHostService, IOSProperties, IOSStatistics } from 'vs/platform/native/common/native'; @@ -15,7 +19,7 @@ import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; import { AddFirstParameterToFunctions } from 'vs/base/common/types'; import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogMainService'; -import { SymlinkSupport } from 'vs/base/node/pfs'; +import { exists, Promises, SymlinkSupport } from 'vs/base/node/pfs'; import { URI } from 'vs/base/common/uri'; import { ITelemetryData, ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -23,11 +27,12 @@ import { MouseInputEvent } from 'vs/base/parts/sandbox/common/electronTypes'; import { arch, totalmem, release, platform, type, loadavg, freemem, cpus } from 'os'; import { virtualMachineHint } from 'vs/base/node/id'; import { ILogService } from 'vs/platform/log/common/log'; -import { dirname, join } from 'vs/base/common/path'; +import { dirname, join, resolve } from 'vs/base/common/path'; import { IProductService } from 'vs/platform/product/common/productService'; import { memoize } from 'vs/base/common/decorators'; import { Disposable } from 'vs/base/common/lifecycle'; import { ISharedProcess } from 'vs/platform/sharedProcess/node/sharedProcess'; +import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService'; export interface INativeHostMainService extends AddFirstParameterToFunctions /* only methods, not events */, number | undefined /* window ID */> { } @@ -50,7 +55,8 @@ export class NativeHostMainService extends Disposable implements INativeHostMain @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService, @ITelemetryService private readonly telemetryService: ITelemetryService, @ILogService private readonly logService: ILogService, - @IProductService private readonly productService: IProductService + @IProductService private readonly productService: IProductService, + @IThemeMainService private readonly themeMainService: IThemeMainService ) { super(); @@ -247,9 +253,106 @@ export class NativeHostMainService extends Disposable implements INativeHostMain } } + async saveWindowSplash(windowId: number | undefined, splash: IPartsSplash): Promise { + this.themeMainService.saveWindowSplash(windowId, splash); + } + //#endregion + //#region macOS Shell Command + + async installShellCommand(windowId: number | undefined): Promise { + const { source, target } = await this.getShellCommandLink(); + + // Only install unless already existing + try { + const { symbolicLink } = await SymlinkSupport.stat(source); + if (symbolicLink && !symbolicLink.dangling) { + const linkTargetRealPath = await realpath(source); + if (target === linkTargetRealPath) { + return; + } + } + + // Different source, delete it first + await Promises.unlink(source); + } catch (error) { + if (error.code !== 'ENOENT') { + throw error; // throw on any error but file not found + } + } + + try { + await Promises.symlink(target, source); + } catch (error) { + if (error.code !== 'EACCES' && error.code !== 'ENOENT') { + throw error; + } + + const { response } = await this.showMessageBox(windowId, { + type: 'info', + message: localize('warnEscalation', "{0} will now prompt with 'osascript' for Administrator privileges to install the shell command.", this.productService.nameShort), + buttons: [localize('ok', "OK"), localize('cancel', "Cancel")], + cancelId: 1 + }); + + if (response === 0 /* OK */) { + try { + const command = `osascript -e "do shell script \\"mkdir -p /usr/local/bin && ln -sf \'${target}\' \'${source}\'\\" with administrator privileges"`; + await promisify(exec)(command); + } catch (error) { + throw new Error(localize('cantCreateBinFolder', "Unable to install the shell command '{0}'.", source)); + } + } + } + } + + async uninstallShellCommand(windowId: number | undefined): Promise { + const { source } = await this.getShellCommandLink(); + + try { + await Promises.unlink(source); + } catch (error) { + switch (error.code) { + case 'EACCES': + const { response } = await this.showMessageBox(windowId, { + type: 'info', + message: localize('warnEscalationUninstall', "{0} will now prompt with 'osascript' for Administrator privileges to uninstall the shell command.", this.productService.nameShort), + buttons: [localize('ok', "OK"), localize('cancel', "Cancel")], + cancelId: 1 + }); + + if (response === 0 /* OK */) { + try { + const command = `osascript -e "do shell script \\"rm \'${source}\'\\" with administrator privileges"`; + await promisify(exec)(command); + } catch (error) { + throw new Error(localize('cantUninstall', "Unable to uninstall the shell command '{0}'.", source)); + } + } + break; + case 'ENOENT': + break; // ignore file not found + default: + throw error; + } + } + } + + private async getShellCommandLink(): Promise<{ readonly source: string, readonly target: string }> { + const target = resolve(this.environmentMainService.appRoot, 'bin', 'code'); + const source = `/usr/local/bin/${this.productService.applicationName}`; + + // Ensure source exists + const sourceExists = await exists(target); + if (!sourceExists) { + throw new Error(localize('sourceMissing', "Unable to find shell script in '{0}'", target)); + } + + return { source, target }; + } + //#region Dialog async showMessageBox(windowId: number | undefined, options: MessageBoxOptions): Promise { @@ -376,8 +479,8 @@ export class NativeHostMainService extends Disposable implements INativeHostMain process.env['GDK_PIXBUF_MODULEDIR'] = gdkPixbufModuleDir; } - async moveItemToTrash(windowId: number | undefined, fullPath: string): Promise { - return shell.moveItemToTrash(fullPath); + moveItemToTrash(windowId: number | undefined, fullPath: string): Promise { + return shell.trashItem(fullPath); } async isAdmin(): Promise { @@ -599,9 +702,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain // Otherwise: normal quit else { - setTimeout(() => { - this.lifecycleMainService.quit(); - }, 10 /* delay to unwind callback stack (IPC) */); + this.lifecycleMainService.quit(); } } @@ -711,6 +812,27 @@ export class NativeHostMainService extends Disposable implements INativeHostMain async setPassword(windowId: number | undefined, service: string, account: string, password: string): Promise { const keytar = await this.withKeytar(); + const MAX_SET_ATTEMPTS = 3; + + // Sometimes Keytar has a problem talking to the keychain on the OS. To be more resilient, we retry a few times. + const setPasswordWithRetry = async (service: string, account: string, password: string) => { + let attempts = 0; + let error: any; + while (attempts < MAX_SET_ATTEMPTS) { + try { + await keytar.setPassword(service, account, password); + return; + } catch (e) { + error = e; + this.logService.warn('Error attempting to set a password: ', e); + attempts++; + await new Promise(resolve => setTimeout(resolve, 200)); + } + } + + // throw last error + throw error; + }; if (isWindows && password.length > NativeHostMainService.MAX_PASSWORD_LENGTH) { let index = 0; @@ -726,12 +848,12 @@ export class NativeHostMainService extends Disposable implements INativeHostMain hasNextChunk: hasNextChunk }; - await keytar.setPassword(service, chunk ? `${account}-${chunk}` : account, JSON.stringify(content)); + await setPasswordWithRetry(service, chunk ? `${account}-${chunk}` : account, JSON.stringify(content)); chunk++; } } else { - await keytar.setPassword(service, account, password); + await setPasswordWithRetry(service, account, password); } this._onDidChangePassword.fire({ service, account }); diff --git a/lib/vscode/src/vs/platform/native/electron-sandbox/native.ts b/src/vs/platform/native/electron-sandbox/native.ts similarity index 91% rename from lib/vscode/src/vs/platform/native/electron-sandbox/native.ts rename to src/vs/platform/native/electron-sandbox/native.ts index bb3f6bc715ce..01f1f94aaef3 100644 --- a/lib/vscode/src/vs/platform/native/electron-sandbox/native.ts +++ b/src/vs/platform/native/electron-sandbox/native.ts @@ -12,7 +12,7 @@ export const INativeHostService = createDecorator('nativeHos * A set of methods specific to a native host, i.e. unsupported in web * environments. * - * @see `IHostService` for methods that can be used in native and web + * @see {@link IHostService} for methods that can be used in native and web * hosts. */ export interface INativeHostService extends ICommonNativeHostService { } diff --git a/lib/vscode/src/vs/platform/native/electron-sandbox/nativeHostService.ts b/src/vs/platform/native/electron-sandbox/nativeHostService.ts similarity index 100% rename from lib/vscode/src/vs/platform/native/electron-sandbox/nativeHostService.ts rename to src/vs/platform/native/electron-sandbox/nativeHostService.ts diff --git a/lib/vscode/src/vs/platform/notification/common/notification.ts b/src/vs/platform/notification/common/notification.ts similarity index 100% rename from lib/vscode/src/vs/platform/notification/common/notification.ts rename to src/vs/platform/notification/common/notification.ts diff --git a/lib/vscode/src/vs/platform/notification/test/common/testNotificationService.ts b/src/vs/platform/notification/test/common/testNotificationService.ts similarity index 100% rename from lib/vscode/src/vs/platform/notification/test/common/testNotificationService.ts rename to src/vs/platform/notification/test/common/testNotificationService.ts diff --git a/src/vs/platform/opener/browser/link.ts b/src/vs/platform/opener/browser/link.ts new file mode 100644 index 000000000000..86a95a1cec47 --- /dev/null +++ b/src/vs/platform/opener/browser/link.ts @@ -0,0 +1,104 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { IOpenerService } from 'vs/platform/opener/common/opener'; +import { $, EventHelper, EventLike } from 'vs/base/browser/dom'; +import { DomEmitter, domEvent } from 'vs/base/browser/event'; +import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { textLinkActiveForeground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry'; + +export interface ILinkDescriptor { + readonly label: string; + readonly href: string; + readonly title?: string; +} + +export interface ILinkOptions { + readonly opener?: (href: string) => void; + readonly textLinkForeground?: string; +} + +export class Link extends Disposable { + + readonly el: HTMLAnchorElement; + private _enabled: boolean = true; + + get enabled(): boolean { + return this._enabled; + } + + set enabled(enabled: boolean) { + if (enabled) { + this.el.setAttribute('aria-disabled', 'false'); + this.el.tabIndex = 0; + this.el.style.pointerEvents = 'auto'; + this.el.style.opacity = '1'; + this.el.style.cursor = 'pointer'; + this._enabled = false; + } else { + this.el.setAttribute('aria-disabled', 'true'); + this.el.tabIndex = -1; + this.el.style.pointerEvents = 'none'; + this.el.style.opacity = '0.4'; + this.el.style.cursor = 'default'; + this._enabled = true; + } + + this._enabled = enabled; + } + + constructor( + link: ILinkDescriptor, + options: ILinkOptions | undefined = undefined, + @IOpenerService openerService: IOpenerService + ) { + super(); + + this.el = $('a.monaco-link', { + tabIndex: 0, + href: link.href, + title: link.title + }, link.label); + + const onClickEmitter = this._register(new DomEmitter(this.el, 'click')); + const onEnterPress = Event.chain(domEvent(this.el, 'keypress')) + .map(e => new StandardKeyboardEvent(e)) + .filter(e => e.keyCode === KeyCode.Enter) + .event; + const onOpen = Event.any(onClickEmitter.event, onEnterPress); + + this._register(onOpen(e => { + if (!this.enabled) { + return; + } + + EventHelper.stop(e, true); + + if (options?.opener) { + options.opener(link.href); + } else { + openerService.open(link.href, { allowCommands: true }); + } + })); + + this.enabled = true; + } +} + +registerThemingParticipant((theme, collector) => { + const textLinkForegroundColor = theme.getColor(textLinkForeground); + if (textLinkForegroundColor) { + collector.addRule(`.monaco-link { color: ${textLinkForegroundColor}; }`); + } + + const textLinkActiveForegroundColor = theme.getColor(textLinkActiveForeground); + if (textLinkActiveForegroundColor) { + collector.addRule(`.monaco-link:hover { color: ${textLinkActiveForegroundColor}; }`); + } +}); diff --git a/lib/vscode/src/vs/platform/opener/common/opener.ts b/src/vs/platform/opener/common/opener.ts similarity index 98% rename from lib/vscode/src/vs/platform/opener/common/opener.ts rename to src/vs/platform/opener/common/opener.ts index 33c465736b78..fad7d23c761e 100644 --- a/lib/vscode/src/vs/platform/opener/common/opener.ts +++ b/src/vs/platform/opener/common/opener.ts @@ -109,6 +109,7 @@ export interface IOpenerService { /** * Resolve a resource to its external form. + * @throws whenever resolvers couldn't resolve this resource externally. */ resolveExternalUri(resource: URI, options?: ResolveExternalUriOptions): Promise; } diff --git a/lib/vscode/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts similarity index 84% rename from lib/vscode/src/vs/platform/product/common/product.ts rename to src/vs/platform/product/common/product.ts index a0e1e4c15ace..4a0b94187d63 100644 --- a/lib/vscode/src/vs/platform/product/common/product.ts +++ b/src/vs/platform/product/common/product.ts @@ -13,7 +13,7 @@ import { ISandboxConfiguration } from 'vs/base/parts/sandbox/common/sandboxTypes let product: IProductConfiguration; // Native sandbox environment -if (typeof globals.vscode !== 'undefined') { +if (typeof globals.vscode !== 'undefined' && typeof globals.vscode.context !== 'undefined') { const configuration: ISandboxConfiguration | undefined = globals.vscode.context.configuration(); if (configuration) { product = configuration.product; @@ -54,7 +54,7 @@ else { // Running out of sources if (Object.keys(product).length === 0) { Object.assign(product, { - version: '1.56.0-dev', + version: '1.57.0-dev', nameShort: isWeb ? 'Code Web - OSS Dev' : 'Code - OSS Dev', nameLong: isWeb ? 'Code Web - OSS Dev' : 'Code - OSS Dev', applicationName: 'code-oss', @@ -66,19 +66,13 @@ else { extensionAllowedProposedApi: [ 'ms-vscode.vscode-js-profile-flame', 'ms-vscode.vscode-js-profile-table', - 'ms-vscode.github-browser', - 'ms-vscode.github-richnav', 'ms-vscode.remotehub', - 'ms-vscode.remotehub-insiders' + 'ms-vscode.remotehub-insiders', + 'GitHub.remotehub', + 'GitHub.remotehub-insiders' ], }); } - // NOTE@coder: Add the ability to inject settings from the server. - const el = document.getElementById('vscode-remote-product-configuration'); - const rawProductConfiguration = el && el.getAttribute('data-settings'); - if (rawProductConfiguration) { - Object.assign(product, JSON.parse(rawProductConfiguration)); - } } export default product; diff --git a/lib/vscode/src/vs/platform/product/common/productService.ts b/src/vs/platform/product/common/productService.ts similarity index 100% rename from lib/vscode/src/vs/platform/product/common/productService.ts rename to src/vs/platform/product/common/productService.ts diff --git a/lib/vscode/src/vs/platform/progress/common/progress.ts b/src/vs/platform/progress/common/progress.ts similarity index 93% rename from lib/vscode/src/vs/platform/progress/common/progress.ts rename to src/vs/platform/progress/common/progress.ts index 9c784f36c567..4603828430e8 100644 --- a/lib/vscode/src/vs/platform/progress/common/progress.ts +++ b/src/vs/platform/progress/common/progress.ts @@ -19,7 +19,7 @@ export interface IProgressService { readonly _serviceBrand: undefined; withProgress( - options: IProgressOptions | IProgressNotificationOptions | IProgressWindowOptions | IProgressCompositeOptions, + options: IProgressOptions | IProgressDialogOptions | IProgressNotificationOptions | IProgressWindowOptions | IProgressCompositeOptions, task: (progress: IProgress) => Promise, onDidCancel?: (choice?: number) => void ): Promise; @@ -66,6 +66,11 @@ export interface IProgressNotificationOptions extends IProgressOptions { readonly silent?: boolean; } +export interface IProgressDialogOptions extends IProgressOptions { + readonly delay?: number; + readonly detail?: string; +} + export interface IProgressWindowOptions extends IProgressOptions { readonly location: ProgressLocation.Window; readonly command?: string; @@ -134,7 +139,7 @@ export class UnmanagedProgress extends Disposable { private lastStep?: IProgressStep; constructor( - options: IProgressOptions | IProgressNotificationOptions | IProgressWindowOptions | IProgressCompositeOptions, + options: IProgressOptions | IProgressDialogOptions | IProgressNotificationOptions | IProgressWindowOptions | IProgressCompositeOptions, @IProgressService progressService: IProgressService, ) { super(); @@ -159,7 +164,6 @@ export class UnmanagedProgress extends Disposable { } } - export class LongRunningOperation extends Disposable { private currentOperationId = 0; private readonly currentOperationDisposables = this._register(new DisposableStore()); diff --git a/lib/vscode/src/vs/platform/protocol/electron-main/protocol.ts b/src/vs/platform/protocol/electron-main/protocol.ts similarity index 87% rename from lib/vscode/src/vs/platform/protocol/electron-main/protocol.ts rename to src/vs/platform/protocol/electron-main/protocol.ts index e224973ab708..85a213cfa075 100644 --- a/lib/vscode/src/vs/platform/protocol/electron-main/protocol.ts +++ b/src/vs/platform/protocol/electron-main/protocol.ts @@ -34,12 +34,8 @@ export interface IProtocolMainService { /** * Allows to make an object accessible to a renderer * via `ipcRenderer.invoke(resource.toString())`. - * - * @param obj the (optional) object to make accessible to the - * renderer. Can be updated later via the `IObjectUrl#update` - * method too. */ - createIPCObjectUrl(obj?: T): IIPCObjectUrl; + createIPCObjectUrl(): IIPCObjectUrl; /** * Adds a `URI` as root to the list of allowed diff --git a/lib/vscode/src/vs/platform/protocol/electron-main/protocolMainService.ts b/src/vs/platform/protocol/electron-main/protocolMainService.ts similarity index 93% rename from lib/vscode/src/vs/platform/protocol/electron-main/protocolMainService.ts rename to src/vs/platform/protocol/electron-main/protocolMainService.ts index 9f93a6b7755a..798aa745d4d1 100644 --- a/lib/vscode/src/vs/platform/protocol/electron-main/protocolMainService.ts +++ b/src/vs/platform/protocol/electron-main/protocolMainService.ts @@ -22,7 +22,7 @@ export class ProtocolMainService extends Disposable implements IProtocolMainServ declare readonly _serviceBrand: undefined; private readonly validRoots = TernarySearchTree.forUris(() => !isLinux); - private readonly validExtensions = new Set(['.png', '.jpg', '.jpeg', '.gif', '.bmp']); // https://github.com/microsoft/vscode/issues/119384 + private readonly validExtensions = new Set(['.svg', '.png', '.jpg', '.jpeg', '.gif', '.bmp']); // https://github.com/microsoft/vscode/issues/119384 constructor( @INativeEnvironmentService environmentService: INativeEnvironmentService, @@ -47,10 +47,10 @@ export class ProtocolMainService extends Disposable implements IProtocolMainServ const { defaultSession } = session; // Register vscode-file:// handler - defaultSession.protocol.registerFileProtocol(Schemas.vscodeFileResource, (request, callback) => this.handleResourceRequest(request, callback as unknown as ProtocolCallback)); + defaultSession.protocol.registerFileProtocol(Schemas.vscodeFileResource, (request, callback) => this.handleResourceRequest(request, callback)); // Intercept any file:// access - defaultSession.protocol.interceptFileProtocol(Schemas.file, (request, callback) => this.handleFileRequest(request, callback as unknown as ProtocolCallback)); + defaultSession.protocol.interceptFileProtocol(Schemas.file, (request, callback) => this.handleFileRequest(request, callback)); // Cleanup this._register(toDisposable(() => { @@ -142,7 +142,8 @@ export class ProtocolMainService extends Disposable implements IProtocolMainServ //#region IPC Object URLs - createIPCObjectUrl(obj: T): IIPCObjectUrl { + createIPCObjectUrl(): IIPCObjectUrl { + let obj: T | undefined = undefined; // Create unique URI const resource = URI.from({ @@ -152,7 +153,7 @@ export class ProtocolMainService extends Disposable implements IProtocolMainServ // Install IPC handler const channel = resource.toString(); - const handler = async (): Promise => obj; + const handler = async (): Promise => obj; ipcMain.handle(channel, handler); this.logService.trace(`IPC Object URL: Registered new channel ${channel}.`); diff --git a/lib/vscode/src/vs/platform/quickinput/browser/commandsQuickAccess.ts b/src/vs/platform/quickinput/browser/commandsQuickAccess.ts similarity index 95% rename from lib/vscode/src/vs/platform/quickinput/browser/commandsQuickAccess.ts rename to src/vs/platform/quickinput/browser/commandsQuickAccess.ts index 96210a56e382..e84a282762a2 100644 --- a/lib/vscode/src/vs/platform/quickinput/browser/commandsQuickAccess.ts +++ b/src/vs/platform/quickinput/browser/commandsQuickAccess.ts @@ -19,7 +19,8 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import { WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { isPromiseCanceledError } from 'vs/base/common/errors'; -import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import Severity from 'vs/base/common/severity'; import { toErrorMessage } from 'vs/base/common/errorMessage'; export interface ICommandQuickPick extends IPickerQuickAccessItem { @@ -47,14 +48,14 @@ export abstract class AbstractCommandsQuickAccessProvider extends PickerQuickAcc @IKeybindingService private readonly keybindingService: IKeybindingService, @ICommandService private readonly commandService: ICommandService, @ITelemetryService private readonly telemetryService: ITelemetryService, - @INotificationService private readonly notificationService: INotificationService + @IDialogService private readonly dialogService: IDialogService ) { super(AbstractCommandsQuickAccessProvider.PREFIX, options); this.options = options; } - protected async getPicks(filter: string, disposables: DisposableStore, token: CancellationToken): Promise> { + protected async _getPicks(filter: string, disposables: DisposableStore, token: CancellationToken): Promise> { // Ask subclass for all command picks const allCommandPicks = await this.getCommandPicks(disposables, token); @@ -162,7 +163,7 @@ export abstract class AbstractCommandsQuickAccessProvider extends PickerQuickAcc await this.commandService.executeCommand(commandPick.commandId); } catch (error) { if (!isPromiseCanceledError(error)) { - this.notificationService.error(localize('canNotRun', "Command '{0}' resulted in an error ({1})", commandPick.label, toErrorMessage(error))); + this.dialogService.show(Severity.Error, localize('canNotRun', "Command '{0}' resulted in an error ({1})", commandPick.label, toErrorMessage(error)), [localize('ok', 'OK')]); } } } diff --git a/lib/vscode/src/vs/platform/quickinput/browser/helpQuickAccess.ts b/src/vs/platform/quickinput/browser/helpQuickAccess.ts similarity index 100% rename from lib/vscode/src/vs/platform/quickinput/browser/helpQuickAccess.ts rename to src/vs/platform/quickinput/browser/helpQuickAccess.ts diff --git a/lib/vscode/src/vs/platform/quickinput/browser/pickerQuickAccess.ts b/src/vs/platform/quickinput/browser/pickerQuickAccess.ts similarity index 96% rename from lib/vscode/src/vs/platform/quickinput/browser/pickerQuickAccess.ts rename to src/vs/platform/quickinput/browser/pickerQuickAccess.ts index 4d8dafdbf0e5..52db4d078817 100644 --- a/lib/vscode/src/vs/platform/quickinput/browser/pickerQuickAccess.ts +++ b/src/vs/platform/quickinput/browser/pickerQuickAccess.ts @@ -5,7 +5,7 @@ import { IQuickPick, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; -import { IQuickPickSeparator, IKeyMods, IQuickPickAcceptEvent } from 'vs/base/parts/quickinput/common/quickInput'; +import { IQuickPickSeparator, IKeyMods, IQuickPickDidAcceptEvent } from 'vs/base/parts/quickinput/common/quickInput'; import { IQuickAccessProvider } from 'vs/platform/quickinput/common/quickAccess'; import { IDisposable, DisposableStore, Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { timeout } from 'vs/base/common/async'; @@ -42,7 +42,7 @@ export interface IPickerQuickAccessItem extends IQuickPickItem { * @param keyMods the state of modifier keys when the item was accepted. * @param event the underlying event that caused the accept to trigger. */ - accept?(keyMods: IKeyMods, event: IQuickPickAcceptEvent): void; + accept?(keyMods: IKeyMods, event: IQuickPickDidAcceptEvent): void; /** * A method that will be executed when a button of the pick item was @@ -122,7 +122,7 @@ export abstract class PickerQuickAccessProvider, skipEmpty?: boolean): boolean => { let items: readonly Pick[]; @@ -330,5 +330,5 @@ export abstract class PickerQuickAccessProvider | Promise> | FastAndSlowPicks | null; + protected abstract _getPicks(filter: string, disposables: DisposableStore, token: CancellationToken): Picks | Promise> | FastAndSlowPicks | null; } diff --git a/lib/vscode/src/vs/platform/quickinput/browser/quickAccess.ts b/src/vs/platform/quickinput/browser/quickAccess.ts similarity index 87% rename from lib/vscode/src/vs/platform/quickinput/browser/quickAccess.ts rename to src/vs/platform/quickinput/browser/quickAccess.ts index 1e580e4ff30e..2054edb38381 100644 --- a/lib/vscode/src/vs/platform/quickinput/browser/quickAccess.ts +++ b/src/vs/platform/quickinput/browser/quickAccess.ts @@ -31,7 +31,17 @@ export class QuickAccessController extends Disposable implements IQuickAccessCon super(); } + pick(value = '', options?: IQuickAccessOptions): Promise { + return this.doShowOrPick(value, true, options); + } + show(value = '', options?: IQuickAccessOptions): void { + this.doShowOrPick(value, false, options); + } + + private doShowOrPick(value: string, pick: true, options?: IQuickAccessOptions): Promise; + private doShowOrPick(value: string, pick: false, options?: IQuickAccessOptions): void; + private doShowOrPick(value: string, pick: boolean, options?: IQuickAccessOptions): Promise | void { // Find provider for the value to show const [provider, descriptor] = this.getOrInstantiateProvider(value); @@ -99,6 +109,18 @@ export class QuickAccessController extends Disposable implements IQuickAccessCon picker.ariaLabel = descriptor?.placeholder; } + // Pick mode: setup a promise that can be resolved + // with the selected items and prevent execution + let pickPromise: Promise | undefined = undefined; + let pickResolve: Function | undefined = undefined; + if (pick) { + pickPromise = new Promise(resolve => pickResolve = resolve); + disposables.add(once(picker.onWillAccept)(e => { + e.veto(); + picker.hide(); + })); + } + // Register listeners disposables.add(this.registerPickerListeners(picker, provider, descriptor, value)); @@ -119,12 +141,20 @@ export class QuickAccessController extends Disposable implements IQuickAccessCon // Start to dispose once picker hides disposables.dispose(); + + // Resolve pick promise with selected items + pickResolve?.(picker.selectedItems); }); // Finally, show the picker. This is important because a provider // may not call this and then our disposables would leak that rely // on the onDidHide event. picker.show(); + + // Pick mode: return with promise + if (pick) { + return pickPromise; + } } private adjustValueSelection(picker: IQuickPick, descriptor?: IQuickAccessProviderDescriptor, options?: IQuickAccessOptions): void { diff --git a/lib/vscode/src/vs/platform/quickinput/browser/quickInput.ts b/src/vs/platform/quickinput/browser/quickInput.ts similarity index 94% rename from lib/vscode/src/vs/platform/quickinput/browser/quickInput.ts rename to src/vs/platform/quickinput/browser/quickInput.ts index e0884b98b1d5..bb05ceea74ec 100644 --- a/lib/vscode/src/vs/platform/quickinput/browser/quickInput.ts +++ b/src/vs/platform/quickinput/browser/quickInput.ts @@ -7,7 +7,7 @@ import { IQuickInputService, IQuickPickItem, IPickOptions, IInputOptions, IQuick import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IThemeService, Themable } from 'vs/platform/theme/common/themeService'; -import { inputBackground, inputForeground, inputBorder, inputValidationInfoBackground, inputValidationInfoForeground, inputValidationInfoBorder, inputValidationWarningBackground, inputValidationWarningForeground, inputValidationWarningBorder, inputValidationErrorBackground, inputValidationErrorForeground, inputValidationErrorBorder, badgeBackground, badgeForeground, contrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, progressBarBackground, widgetShadow, listFocusForeground, activeContrastBorder, pickerGroupBorder, pickerGroupForeground, quickInputForeground, quickInputBackground, quickInputTitleBackground, quickInputListFocusBackground, keybindingLabelBackground, keybindingLabelForeground, keybindingLabelBorder, keybindingLabelBottomBorder } from 'vs/platform/theme/common/colorRegistry'; +import { inputBackground, inputForeground, inputBorder, inputValidationInfoBackground, inputValidationInfoForeground, inputValidationInfoBorder, inputValidationWarningBackground, inputValidationWarningForeground, inputValidationWarningBorder, inputValidationErrorBackground, inputValidationErrorForeground, inputValidationErrorBorder, badgeBackground, badgeForeground, contrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, progressBarBackground, widgetShadow, activeContrastBorder, pickerGroupBorder, pickerGroupForeground, quickInputForeground, quickInputBackground, quickInputTitleBackground, quickInputListFocusBackground, keybindingLabelBackground, keybindingLabelForeground, keybindingLabelBorder, keybindingLabelBottomBorder, quickInputListFocusForeground } from 'vs/platform/theme/common/colorRegistry'; import { CancellationToken } from 'vs/base/common/cancellation'; import { computeStyles } from 'vs/platform/theme/common/styler'; import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -219,7 +219,7 @@ export class QuickInputService extends Themable implements IQuickInputService { list: computeStyles(this.theme, { listBackground: quickInputBackground, // Look like focused when inactive. - listInactiveFocusForeground: listFocusForeground, + listInactiveFocusForeground: quickInputListFocusForeground, listInactiveFocusBackground: quickInputListFocusBackground, listFocusOutline: activeContrastBorder, listInactiveFocusOutline: activeContrastBorder, diff --git a/lib/vscode/src/vs/platform/quickinput/common/quickAccess.ts b/src/vs/platform/quickinput/common/quickAccess.ts similarity index 96% rename from lib/vscode/src/vs/platform/quickinput/common/quickAccess.ts rename to src/vs/platform/quickinput/common/quickAccess.ts index 3b682f00add4..d1e7fd05a85f 100644 --- a/lib/vscode/src/vs/platform/quickinput/common/quickAccess.ts +++ b/src/vs/platform/quickinput/common/quickAccess.ts @@ -36,6 +36,13 @@ export interface IQuickAccessController { * Open the quick access picker with the optional value prefilled. */ show(value?: string, options?: IQuickAccessOptions): void; + + /** + * Same as `show()` but instead of executing the selected pick item, + * it will be returned. May return `undefined` in case no item was + * picked by the user. + */ + pick(value?: string, options?: IQuickAccessOptions): Promise; } export enum DefaultQuickAccessFilterValue { diff --git a/lib/vscode/src/vs/platform/quickinput/common/quickInput.ts b/src/vs/platform/quickinput/common/quickInput.ts similarity index 100% rename from lib/vscode/src/vs/platform/quickinput/common/quickInput.ts rename to src/vs/platform/quickinput/common/quickInput.ts diff --git a/lib/vscode/src/vs/platform/registry/common/platform.ts b/src/vs/platform/registry/common/platform.ts similarity index 100% rename from lib/vscode/src/vs/platform/registry/common/platform.ts rename to src/vs/platform/registry/common/platform.ts diff --git a/lib/vscode/src/vs/platform/registry/test/common/platform.test.ts b/src/vs/platform/registry/test/common/platform.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/registry/test/common/platform.test.ts rename to src/vs/platform/registry/test/common/platform.test.ts diff --git a/lib/vscode/src/vs/platform/remote/browser/browserSocketFactory.ts b/src/vs/platform/remote/browser/browserSocketFactory.ts similarity index 96% rename from lib/vscode/src/vs/platform/remote/browser/browserSocketFactory.ts rename to src/vs/platform/remote/browser/browserSocketFactory.ts index c65de8ad37e7..2f343e841ab9 100644 --- a/lib/vscode/src/vs/platform/remote/browser/browserSocketFactory.ts +++ b/src/vs/platform/remote/browser/browserSocketFactory.ts @@ -208,8 +208,7 @@ export class BrowserSocketFactory implements ISocketFactory { } connect(host: string, port: number, query: string, callback: IConnectCallback): void { - // NOTE@coder: Modified to work against the current path. - const socket = this._webSocketFactory.create(`${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${window.location.host}${window.location.pathname}?${query}&skipWebSocketFrames=false`); + const socket = this._webSocketFactory.create(`ws://${/:/.test(host) ? `[${host}]` : host}:${port}/?${query}&skipWebSocketFrames=false`); const errorListener = socket.onError((err) => callback(err, undefined)); socket.onOpen(() => { errorListener.dispose(); @@ -217,3 +216,6 @@ export class BrowserSocketFactory implements ISocketFactory { }); } } + + + diff --git a/lib/vscode/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts similarity index 95% rename from lib/vscode/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts rename to src/vs/platform/remote/browser/remoteAuthorityResolverService.ts index 3d5d29b8e007..e7f177ceb17b 100644 --- a/lib/vscode/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts +++ b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts @@ -40,6 +40,10 @@ export class RemoteAuthorityResolverService extends Disposable implements IRemot return this._cache.get(authority)!; } + async getCanonicalURI(uri: URI): Promise { + return uri; + } + getConnectionData(authority: string): IRemoteConnectionData | null { if (!this._cache.has(authority)) { return null; @@ -76,4 +80,7 @@ export class RemoteAuthorityResolverService extends Disposable implements IRemot RemoteAuthorities.setConnectionToken(authority, connectionToken); this._onDidChangeConnectionData.fire(); } + + _setCanonicalURIProvider(provider: (uri: URI) => Promise): void { + } } diff --git a/lib/vscode/src/vs/platform/remote/common/remoteAgentConnection.ts b/src/vs/platform/remote/common/remoteAgentConnection.ts similarity index 100% rename from lib/vscode/src/vs/platform/remote/common/remoteAgentConnection.ts rename to src/vs/platform/remote/common/remoteAgentConnection.ts diff --git a/lib/vscode/src/vs/platform/remote/common/remoteAgentEnvironment.ts b/src/vs/platform/remote/common/remoteAgentEnvironment.ts similarity index 100% rename from lib/vscode/src/vs/platform/remote/common/remoteAgentEnvironment.ts rename to src/vs/platform/remote/common/remoteAgentEnvironment.ts diff --git a/lib/vscode/src/vs/platform/remote/common/remoteAuthorityResolver.ts b/src/vs/platform/remote/common/remoteAuthorityResolver.ts similarity index 89% rename from lib/vscode/src/vs/platform/remote/common/remoteAuthorityResolver.ts rename to src/vs/platform/remote/common/remoteAuthorityResolver.ts index 52902edfcbcd..9a3108779985 100644 --- a/lib/vscode/src/vs/platform/remote/common/remoteAuthorityResolver.ts +++ b/src/vs/platform/remote/common/remoteAuthorityResolver.ts @@ -5,6 +5,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event } from 'vs/base/common/event'; +import { URI } from 'vs/base/common/uri'; export const IRemoteAuthorityResolverService = createDecorator('remoteAuthorityResolverService'); @@ -15,15 +16,9 @@ export interface ResolvedAuthority { readonly connectionToken: string | undefined; } -export enum RemoteTrustOption { - Unknown = 0, - DisableTrust = 1, - MachineTrusted = 2 -} - export interface ResolvedOptions { readonly extensionHostEnv?: { [key: string]: string | null }; - readonly trust?: RemoteTrustOption; + readonly isTrusted?: boolean; } export interface TunnelDescription { @@ -98,9 +93,18 @@ export interface IRemoteAuthorityResolverService { resolveAuthority(authority: string): Promise; getConnectionData(authority: string): IRemoteConnectionData | null; + /** + * Get the canonical URI for a `vscode-remote://` URI. + * + * **NOTE**: This can throw e.g. in cases where there is no resolver installed for the specific remote authority. + * + * @param uri The `vscode-remote://` URI + */ + getCanonicalURI(uri: URI): Promise; _clearResolvedAuthority(authority: string): void; _setResolvedAuthority(resolvedAuthority: ResolvedAuthority, resolvedOptions?: ResolvedOptions): void; _setResolvedAuthorityError(authority: string, err: any): void; _setAuthorityConnectionToken(authority: string, connectionToken: string): void; + _setCanonicalURIProvider(provider: (uri: URI) => Promise): void; } diff --git a/lib/vscode/src/vs/platform/remote/common/remoteHosts.ts b/src/vs/platform/remote/common/remoteHosts.ts similarity index 90% rename from lib/vscode/src/vs/platform/remote/common/remoteHosts.ts rename to src/vs/platform/remote/common/remoteHosts.ts index 6894d782f5d1..e125df902cdf 100644 --- a/lib/vscode/src/vs/platform/remote/common/remoteHosts.ts +++ b/src/vs/platform/remote/common/remoteHosts.ts @@ -26,7 +26,7 @@ export function getRemoteName(authority: string | undefined): string | undefined return authority.substr(0, pos); } -function isVirtualResource(resource: URI) { +export function isVirtualResource(resource: URI) { return resource.scheme !== Schemas.file && resource.scheme !== Schemas.vscodeRemote; } @@ -42,3 +42,7 @@ export function getVirtualWorkspaceLocation(workspace: IWorkspace): { scheme: st export function getVirtualWorkspaceScheme(workspace: IWorkspace): string | undefined { return getVirtualWorkspaceLocation(workspace)?.scheme; } + +export function isVirtualWorkspace(workspace: IWorkspace): boolean { + return getVirtualWorkspaceLocation(workspace) !== undefined; +} diff --git a/lib/vscode/src/vs/platform/remote/common/tunnel.ts b/src/vs/platform/remote/common/tunnel.ts similarity index 99% rename from lib/vscode/src/vs/platform/remote/common/tunnel.ts rename to src/vs/platform/remote/common/tunnel.ts index 06de888d61fe..bd67538ee5f6 100644 --- a/lib/vscode/src/vs/platform/remote/common/tunnel.ts +++ b/src/vs/platform/remote/common/tunnel.ts @@ -86,6 +86,7 @@ export interface ITunnelService { readonly onTunnelOpened: Event; readonly onTunnelClosed: Event<{ host: string, port: number; }>; readonly canElevate: boolean; + readonly hasTunnelProvider: boolean; canTunnel(uri: URI): boolean; openTunnel(addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localPort?: number, elevateIfNeeded?: boolean, isPublic?: boolean): Promise | undefined; @@ -141,6 +142,10 @@ export abstract class AbstractTunnelService implements ITunnelService { @ILogService protected readonly logService: ILogService ) { } + get hasTunnelProvider(): boolean { + return !!this._tunnelProvider; + } + setTunnelProvider(provider: ITunnelProvider | undefined, features: TunnelProviderFeatures): IDisposable { this._tunnelProvider = provider; if (!provider) { diff --git a/lib/vscode/src/vs/platform/remote/electron-sandbox/remoteAuthorityResolverService.ts b/src/vs/platform/remote/electron-sandbox/remoteAuthorityResolverService.ts similarity index 63% rename from lib/vscode/src/vs/platform/remote/electron-sandbox/remoteAuthorityResolverService.ts rename to src/vs/platform/remote/electron-sandbox/remoteAuthorityResolverService.ts index 41529a21aee5..93081c02147d 100644 --- a/lib/vscode/src/vs/platform/remote/electron-sandbox/remoteAuthorityResolverService.ts +++ b/src/vs/platform/remote/electron-sandbox/remoteAuthorityResolverService.ts @@ -8,22 +8,27 @@ import * as errors from 'vs/base/common/errors'; import { RemoteAuthorities } from 'vs/base/common/network'; import { Disposable } from 'vs/base/common/lifecycle'; import { Emitter } from 'vs/base/common/event'; - -class PendingResolveAuthorityRequest { - - public value: ResolverResult | null; - - constructor( - private readonly _resolve: (value: ResolverResult) => void, - private readonly _reject: (err: any) => void, - public readonly promise: Promise, - ) { - this.value = null; +import { URI } from 'vs/base/common/uri'; + +class PendingPromise { + public readonly promise: Promise; + public readonly input: I; + public result: R | null; + private _resolve!: (value: R) => void; + private _reject!: (err: any) => void; + + constructor(request: I) { + this.input = request; + this.promise = new Promise((resolve, reject) => { + this._resolve = resolve; + this._reject = reject; + }); + this.result = null; } - resolve(value: ResolverResult): void { - this.value = value; - this._resolve(this.value); + resolve(result: R): void { + this.result = result; + this._resolve(this.result); } reject(err: any): void { @@ -38,40 +43,50 @@ export class RemoteAuthorityResolverService extends Disposable implements IRemot private readonly _onDidChangeConnectionData = this._register(new Emitter()); public readonly onDidChangeConnectionData = this._onDidChangeConnectionData.event; - private readonly _resolveAuthorityRequests: Map; + private readonly _resolveAuthorityRequests: Map>; private readonly _connectionTokens: Map; + private readonly _canonicalURIRequests: Map>; + private _canonicalURIProvider: ((uri: URI) => Promise) | null; constructor() { super(); - this._resolveAuthorityRequests = new Map(); + this._resolveAuthorityRequests = new Map>(); this._connectionTokens = new Map(); + this._canonicalURIRequests = new Map>(); + this._canonicalURIProvider = null; } resolveAuthority(authority: string): Promise { if (!this._resolveAuthorityRequests.has(authority)) { - let resolve: (value: ResolverResult) => void; - let reject: (err: any) => void; - const promise = new Promise((_resolve, _reject) => { - resolve = _resolve; - reject = _reject; - }); - this._resolveAuthorityRequests.set(authority, new PendingResolveAuthorityRequest(resolve!, reject!, promise)); + this._resolveAuthorityRequests.set(authority, new PendingPromise(authority)); } return this._resolveAuthorityRequests.get(authority)!.promise; } + async getCanonicalURI(uri: URI): Promise { + const key = uri.toString(); + if (!this._canonicalURIRequests.has(key)) { + const request = new PendingPromise(uri); + if (this._canonicalURIProvider) { + this._canonicalURIProvider(request.input).then((uri) => request.resolve(uri), (err) => request.reject(err)); + } + this._canonicalURIRequests.set(key, request); + } + return this._canonicalURIRequests.get(key)!.promise; + } + getConnectionData(authority: string): IRemoteConnectionData | null { if (!this._resolveAuthorityRequests.has(authority)) { return null; } const request = this._resolveAuthorityRequests.get(authority)!; - if (!request.value) { + if (!request.result) { return null; } const connectionToken = this._connectionTokens.get(authority); return { - host: request.value.authority.host, - port: request.value.authority.port, + host: request.result.authority.host, + port: request.result.authority.port, connectionToken: connectionToken }; } @@ -107,4 +122,11 @@ export class RemoteAuthorityResolverService extends Disposable implements IRemot RemoteAuthorities.setConnectionToken(authority, connectionToken); this._onDidChangeConnectionData.fire(); } + + _setCanonicalURIProvider(provider: (uri: URI) => Promise): void { + this._canonicalURIProvider = provider; + this._canonicalURIRequests.forEach((value) => { + this._canonicalURIProvider!(value.input).then((uri) => value.resolve(uri), (err) => value.reject(err)); + }); + } } diff --git a/lib/vscode/src/vs/platform/remote/node/nodeSocketFactory.ts b/src/vs/platform/remote/node/nodeSocketFactory.ts similarity index 100% rename from lib/vscode/src/vs/platform/remote/node/nodeSocketFactory.ts rename to src/vs/platform/remote/node/nodeSocketFactory.ts diff --git a/lib/vscode/src/vs/platform/remote/node/tunnelService.ts b/src/vs/platform/remote/node/tunnelService.ts similarity index 82% rename from lib/vscode/src/vs/platform/remote/node/tunnelService.ts rename to src/vs/platform/remote/node/tunnelService.ts index 6483000c8701..711b80e7e670 100644 --- a/lib/vscode/src/vs/platform/remote/node/tunnelService.ts +++ b/src/vs/platform/remote/node/tunnelService.ts @@ -8,6 +8,7 @@ import { Barrier } from 'vs/base/common/async'; import { Disposable } from 'vs/base/common/lifecycle'; import { findFreePortFaster } from 'vs/base/node/ports'; import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService } from 'vs/platform/log/common/log'; import { IProductService } from 'vs/platform/product/common/productService'; import { connectRemoteAgentTunnel, IConnectionOptions, IAddressProvider, ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; @@ -15,8 +16,8 @@ import { AbstractTunnelService, RemoteTunnel } from 'vs/platform/remote/common/t import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory'; import { ISignService } from 'vs/platform/sign/common/sign'; -async function createRemoteTunnel(options: IConnectionOptions, tunnelRemoteHost: string, tunnelRemotePort: number, tunnelLocalPort?: number): Promise { - const tunnel = new NodeRemoteTunnel(options, tunnelRemoteHost, tunnelRemotePort, tunnelLocalPort); +async function createRemoteTunnel(options: IConnectionOptions, defaultTunnelHost: string, tunnelRemoteHost: string, tunnelRemotePort: number, tunnelLocalPort?: number): Promise { + const tunnel = new NodeRemoteTunnel(options, defaultTunnelHost, tunnelRemoteHost, tunnelRemotePort, tunnelLocalPort); return tunnel.waitForReady(); } @@ -38,7 +39,7 @@ class NodeRemoteTunnel extends Disposable implements RemoteTunnel { private readonly _socketsDispose: Map void> = new Map(); - constructor(options: IConnectionOptions, tunnelRemoteHost: string, tunnelRemotePort: number, private readonly suggestedLocalPort?: number) { + constructor(options: IConnectionOptions, private readonly defaultTunnelHost: string, tunnelRemoteHost: string, tunnelRemotePort: number, private readonly suggestedLocalPort?: number) { super(); this._options = options; this._server = net.createServer(); @@ -76,17 +77,19 @@ class NodeRemoteTunnel extends Disposable implements RemoteTunnel { // if that fails, the method above returns 0, which works out fine below... let address: string | net.AddressInfo | null = null; - address = (this._server.listen(localPort).address()); + this._server.listen(localPort, this.defaultTunnelHost); + await this._barrier.wait(); + address = this._server.address(); // It is possible for findFreePortFaster to return a port that there is already a server listening on. This causes the previous listen call to error out. if (!address) { localPort = 0; - address = (this._server.listen(localPort).address()); + this._server.listen(localPort, this.defaultTunnelHost); + await this._barrier.wait(); + address = this._server.address(); } this.tunnelLocalPort = address.port; - - await this._barrier.wait(); this.localAddress = `${this.tunnelRemoteHost === '127.0.0.1' ? '127.0.0.1' : 'localhost'}:${address.port}`; return this; } @@ -135,11 +138,16 @@ export class BaseTunnelService extends AbstractTunnelService { private readonly socketFactory: ISocketFactory, @ILogService logService: ILogService, @ISignService private readonly signService: ISignService, - @IProductService private readonly productService: IProductService + @IProductService private readonly productService: IProductService, + @IConfigurationService private readonly configurationService: IConfigurationService ) { super(logService); } + private get defaultTunnelHost(): string { + return (this.configurationService.getValue('remote.localPortHost') === 'localhost') ? '127.0.0.1' : '0.0.0.0'; + } + protected retainOrCreateTunnel(addressProvider: IAddressProvider, remoteHost: string, remotePort: number, localPort: number | undefined, elevateIfNeeded: boolean, isPublic: boolean): Promise | undefined { const existing = this.getTunnelFromMap(remoteHost, remotePort); if (existing) { @@ -160,7 +168,7 @@ export class BaseTunnelService extends AbstractTunnelService { ipcLogger: null }; - const tunnel = createRemoteTunnel(options, remoteHost, remotePort, localPort); + const tunnel = createRemoteTunnel(options, this.defaultTunnelHost, remoteHost, remotePort, localPort); this.logService.trace('ForwardedPorts: (TunnelService) Tunnel created without provider.'); this.addTunnelToMap(remoteHost, remotePort, tunnel); return tunnel; @@ -172,8 +180,9 @@ export class TunnelService extends BaseTunnelService { public constructor( @ILogService logService: ILogService, @ISignService signService: ISignService, - @IProductService productService: IProductService + @IProductService productService: IProductService, + @IConfigurationService configurationService: IConfigurationService ) { - super(nodeSocketFactory, logService, signService, productService); + super(nodeSocketFactory, logService, signService, productService, configurationService); } } diff --git a/lib/vscode/src/vs/platform/request/browser/requestService.ts b/src/vs/platform/request/browser/requestService.ts similarity index 100% rename from lib/vscode/src/vs/platform/request/browser/requestService.ts rename to src/vs/platform/request/browser/requestService.ts diff --git a/lib/vscode/src/vs/platform/request/common/request.ts b/src/vs/platform/request/common/request.ts similarity index 100% rename from lib/vscode/src/vs/platform/request/common/request.ts rename to src/vs/platform/request/common/request.ts diff --git a/lib/vscode/src/vs/platform/request/common/requestIpc.ts b/src/vs/platform/request/common/requestIpc.ts similarity index 100% rename from lib/vscode/src/vs/platform/request/common/requestIpc.ts rename to src/vs/platform/request/common/requestIpc.ts diff --git a/lib/vscode/src/vs/platform/request/electron-main/requestMainService.ts b/src/vs/platform/request/electron-main/requestMainService.ts similarity index 100% rename from lib/vscode/src/vs/platform/request/electron-main/requestMainService.ts rename to src/vs/platform/request/electron-main/requestMainService.ts diff --git a/lib/vscode/src/vs/platform/request/node/proxy.ts b/src/vs/platform/request/node/proxy.ts similarity index 100% rename from lib/vscode/src/vs/platform/request/node/proxy.ts rename to src/vs/platform/request/node/proxy.ts diff --git a/lib/vscode/src/vs/platform/request/node/requestService.ts b/src/vs/platform/request/node/requestService.ts similarity index 100% rename from lib/vscode/src/vs/platform/request/node/requestService.ts rename to src/vs/platform/request/node/requestService.ts diff --git a/lib/vscode/src/vs/platform/serviceMachineId/common/serviceMachineId.ts b/src/vs/platform/serviceMachineId/common/serviceMachineId.ts similarity index 100% rename from lib/vscode/src/vs/platform/serviceMachineId/common/serviceMachineId.ts rename to src/vs/platform/serviceMachineId/common/serviceMachineId.ts diff --git a/lib/vscode/src/vs/platform/severityIcon/common/severityIcon.ts b/src/vs/platform/severityIcon/common/severityIcon.ts similarity index 100% rename from lib/vscode/src/vs/platform/severityIcon/common/severityIcon.ts rename to src/vs/platform/severityIcon/common/severityIcon.ts diff --git a/lib/vscode/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts similarity index 97% rename from lib/vscode/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts rename to src/vs/platform/sharedProcess/electron-main/sharedProcess.ts index 64168de41a66..f62912e56d14 100644 --- a/lib/vscode/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts +++ b/src/vs/platform/sharedProcess/electron-main/sharedProcess.ts @@ -18,7 +18,6 @@ import { connect as connectMessagePort } from 'vs/base/parts/ipc/electron-main/i import { assertIsDefined } from 'vs/base/common/types'; import { Emitter, Event } from 'vs/base/common/event'; import { WindowError } from 'vs/platform/windows/electron-main/windows'; -import { resolveShellEnv } from 'vs/platform/environment/node/shellEnv'; import { IProtocolMainService } from 'vs/platform/protocol/electron-main/protocol'; export class SharedProcess extends Disposable implements ISharedProcess { @@ -139,9 +138,6 @@ export class SharedProcess extends Disposable implements ISharedProcess { // Always wait for first window asking for connection await this.firstWindowConnectionBarrier.wait(); - // Resolve shell environment - this.userEnv = { ...this.userEnv, ...(await resolveShellEnv(this.logService, this.environmentMainService.args, process.env)) }; - // Create window for shared process this.createWindow(); diff --git a/lib/vscode/src/vs/platform/sharedProcess/node/sharedProcess.ts b/src/vs/platform/sharedProcess/node/sharedProcess.ts similarity index 100% rename from lib/vscode/src/vs/platform/sharedProcess/node/sharedProcess.ts rename to src/vs/platform/sharedProcess/node/sharedProcess.ts diff --git a/lib/vscode/src/vs/platform/sign/browser/signService.ts b/src/vs/platform/sign/browser/signService.ts similarity index 100% rename from lib/vscode/src/vs/platform/sign/browser/signService.ts rename to src/vs/platform/sign/browser/signService.ts diff --git a/lib/vscode/src/vs/platform/sign/common/sign.ts b/src/vs/platform/sign/common/sign.ts similarity index 100% rename from lib/vscode/src/vs/platform/sign/common/sign.ts rename to src/vs/platform/sign/common/sign.ts diff --git a/lib/vscode/src/vs/platform/sign/node/signService.ts b/src/vs/platform/sign/node/signService.ts similarity index 100% rename from lib/vscode/src/vs/platform/sign/node/signService.ts rename to src/vs/platform/sign/node/signService.ts diff --git a/lib/vscode/src/vs/platform/state/node/state.ts b/src/vs/platform/state/electron-main/state.ts similarity index 72% rename from lib/vscode/src/vs/platform/state/node/state.ts rename to src/vs/platform/state/electron-main/state.ts index 9fd896f914cc..8d498194eb60 100644 --- a/lib/vscode/src/vs/platform/state/node/state.ts +++ b/src/vs/platform/state/electron-main/state.ts @@ -5,15 +5,19 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -export const IStateService = createDecorator('stateService'); +export const IStateMainService = createDecorator('stateMainService'); + +export interface IStateMainService { -export interface IStateService { readonly _serviceBrand: undefined; getItem(key: string, defaultValue: T): T; getItem(key: string, defaultValue?: T): T | undefined; setItem(key: string, data?: object | string | number | boolean | undefined | null): void; + setItems(items: readonly { key: string, data?: object | string | number | boolean | undefined | null }[]): void; removeItem(key: string): void; + + close(): Promise; } diff --git a/src/vs/platform/state/electron-main/stateMainService.ts b/src/vs/platform/state/electron-main/stateMainService.ts new file mode 100644 index 000000000000..08f979251123 --- /dev/null +++ b/src/vs/platform/state/electron-main/stateMainService.ts @@ -0,0 +1,189 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { URI } from 'vs/base/common/uri'; +import { join } from 'vs/base/common/path'; +import { isUndefined, isUndefinedOrNull } from 'vs/base/common/types'; +import { IStateMainService } from 'vs/platform/state/electron-main/state'; +import { ILogService } from 'vs/platform/log/common/log'; +import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; +import { ThrottledDelayer } from 'vs/base/common/async'; +import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files'; +import { VSBuffer } from 'vs/base/common/buffer'; + +type StorageDatabase = { [key: string]: unknown; }; + +export class FileStorage { + + private storage: StorageDatabase = Object.create(null); + private lastSavedStorageContents = ''; + + private readonly flushDelayer = new ThrottledDelayer(100 /* buffer saves over a short time */); + + private initializing: Promise | undefined = undefined; + private closing: Promise | undefined = undefined; + + constructor( + private readonly storagePath: URI, + private readonly logService: ILogService, + private readonly fileService: IFileService + ) { + } + + init(): Promise { + if (!this.initializing) { + this.initializing = this.doInit(); + } + + return this.initializing; + } + + private async doInit(): Promise { + try { + this.lastSavedStorageContents = (await this.fileService.readFile(this.storagePath)).value.toString(); + this.storage = JSON.parse(this.lastSavedStorageContents); + } catch (error) { + if ((error).fileOperationResult !== FileOperationResult.FILE_NOT_FOUND) { + this.logService.error(error); + } + } + } + + getItem(key: string, defaultValue: T): T; + getItem(key: string, defaultValue?: T): T | undefined; + getItem(key: string, defaultValue?: T): T | undefined { + const res = this.storage[key]; + if (isUndefinedOrNull(res)) { + return defaultValue; + } + + return res as T; + } + + setItem(key: string, data?: object | string | number | boolean | undefined | null): void { + this.setItems([{ key, data }]); + } + + setItems(items: readonly { key: string, data?: object | string | number | boolean | undefined | null }[]): void { + let save = false; + + for (const { key, data } of items) { + + // Shortcut for data that did not change + if (this.storage[key] === data) { + continue; + } + + // Remove items when they are undefined or null + if (isUndefinedOrNull(data)) { + if (!isUndefined(this.storage[key])) { + this.storage[key] = undefined; + save = true; + } + } + + // Otherwise add an item + else { + this.storage[key] = data; + save = true; + } + } + + if (save) { + this.save(); + } + } + + removeItem(key: string): void { + + // Only update if the key is actually present (not undefined) + if (!isUndefined(this.storage[key])) { + this.storage[key] = undefined; + this.save(); + } + } + + private async save(delay?: number): Promise { + if (this.closing) { + return; // already about to close + } + + return this.flushDelayer.trigger(() => this.doSave(), delay); + } + + private async doSave(): Promise { + if (!this.initializing) { + return; // if we never initialized, we should not save our state + } + + // Make sure to wait for init to finish first + await this.initializing; + + // Return early if the database has not changed + const serializedDatabase = JSON.stringify(this.storage, null, 4); + if (serializedDatabase === this.lastSavedStorageContents) { + return; + } + + // Write to disk + try { + await this.fileService.writeFile(this.storagePath, VSBuffer.fromString(serializedDatabase)); + this.lastSavedStorageContents = serializedDatabase; + } catch (error) { + this.logService.error(error); + } + } + + async close(): Promise { + if (!this.closing) { + this.closing = this.flushDelayer.trigger(() => this.doSave(), 0 /* as soon as possible */); + } + + return this.closing; + } +} + +export class StateMainService implements IStateMainService { + + declare readonly _serviceBrand: undefined; + + private static readonly STATE_FILE = 'storage.json'; + + private readonly fileStorage: FileStorage; + + constructor( + @IEnvironmentMainService environmentMainService: IEnvironmentMainService, + @ILogService logService: ILogService, + @IFileService fileService: IFileService + ) { + this.fileStorage = new FileStorage(URI.file(join(environmentMainService.userDataPath, StateMainService.STATE_FILE)), logService, fileService); + } + + async init(): Promise { + return this.fileStorage.init(); + } + + getItem(key: string, defaultValue: T): T; + getItem(key: string, defaultValue?: T): T | undefined; + getItem(key: string, defaultValue?: T): T | undefined { + return this.fileStorage.getItem(key, defaultValue); + } + + setItem(key: string, data?: object | string | number | boolean | undefined | null): void { + this.fileStorage.setItem(key, data); + } + + setItems(items: readonly { key: string, data?: object | string | number | boolean | undefined | null }[]): void { + this.fileStorage.setItems(items); + } + + removeItem(key: string): void { + this.fileStorage.removeItem(key); + } + + close(): Promise { + return this.fileStorage.close(); + } +} diff --git a/src/vs/platform/state/test/electron-main/state.test.ts b/src/vs/platform/state/test/electron-main/state.test.ts new file mode 100644 index 000000000000..40b751c6c1e6 --- /dev/null +++ b/src/vs/platform/state/test/electron-main/state.test.ts @@ -0,0 +1,202 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { tmpdir } from 'os'; +import { readFileSync } from 'fs'; +import { join } from 'vs/base/common/path'; +import { flakySuite, getRandomTestPath } from 'vs/base/test/node/testUtils'; +import { FileStorage } from 'vs/platform/state/electron-main/stateMainService'; +import { Promises, rimraf, writeFileSync } from 'vs/base/node/pfs'; +import { ILogService, NullLogService } from 'vs/platform/log/common/log'; +import { IFileService } from 'vs/platform/files/common/files'; +import { FileService } from 'vs/platform/files/common/fileService'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; +import { Schemas } from 'vs/base/common/network'; +import { URI } from 'vs/base/common/uri'; + +flakySuite('StateMainService', () => { + + let testDir: string; + let fileService: IFileService; + let logService: ILogService; + let diskFileSystemProvider: DiskFileSystemProvider; + + setup(() => { + testDir = getRandomTestPath(tmpdir(), 'vsctests', 'statemainservice'); + + logService = new NullLogService(); + + fileService = new FileService(logService); + diskFileSystemProvider = new DiskFileSystemProvider(logService); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); + + return Promises.mkdir(testDir, { recursive: true }); + }); + + teardown(() => { + fileService.dispose(); + diskFileSystemProvider.dispose(); + + return rimraf(testDir); + }); + + test('Basics', async function () { + const storageFile = join(testDir, 'storage.json'); + writeFileSync(storageFile, ''); + + let service = new FileStorage(URI.file(storageFile), logService, fileService); + await service.init(); + + service.setItem('some.key', 'some.value'); + assert.strictEqual(service.getItem('some.key'), 'some.value'); + + service.removeItem('some.key'); + assert.strictEqual(service.getItem('some.key', 'some.default'), 'some.default'); + + assert.ok(!service.getItem('some.unknonw.key')); + + service.setItem('some.other.key', 'some.other.value'); + + await service.close(); + + service = new FileStorage(URI.file(storageFile), logService, fileService); + await service.init(); + + assert.strictEqual(service.getItem('some.other.key'), 'some.other.value'); + + service.setItem('some.other.key', 'some.other.value'); + assert.strictEqual(service.getItem('some.other.key'), 'some.other.value'); + + service.setItem('some.undefined.key', undefined); + assert.strictEqual(service.getItem('some.undefined.key', 'some.default'), 'some.default'); + + service.setItem('some.null.key', null); + assert.strictEqual(service.getItem('some.null.key', 'some.default'), 'some.default'); + + service.setItems([ + { key: 'some.setItems.key1', data: 'some.value' }, + { key: 'some.setItems.key2', data: 0 }, + { key: 'some.setItems.key3', data: true }, + { key: 'some.setItems.key4', data: null }, + { key: 'some.setItems.key5', data: undefined } + ]); + + assert.strictEqual(service.getItem('some.setItems.key1'), 'some.value'); + assert.strictEqual(service.getItem('some.setItems.key2'), 0); + assert.strictEqual(service.getItem('some.setItems.key3'), true); + assert.strictEqual(service.getItem('some.setItems.key4'), undefined); + assert.strictEqual(service.getItem('some.setItems.key5'), undefined); + + service.setItems([ + { key: 'some.setItems.key1', data: undefined }, + { key: 'some.setItems.key2', data: undefined }, + { key: 'some.setItems.key3', data: undefined }, + { key: 'some.setItems.key4', data: null }, + { key: 'some.setItems.key5', data: undefined } + ]); + + assert.strictEqual(service.getItem('some.setItems.key1'), undefined); + assert.strictEqual(service.getItem('some.setItems.key2'), undefined); + assert.strictEqual(service.getItem('some.setItems.key3'), undefined); + assert.strictEqual(service.getItem('some.setItems.key4'), undefined); + assert.strictEqual(service.getItem('some.setItems.key5'), undefined); + }); + + test('Multiple ops are buffered and applied', async function () { + const storageFile = join(testDir, 'storage.json'); + writeFileSync(storageFile, ''); + + let service = new FileStorage(URI.file(storageFile), logService, fileService); + await service.init(); + + service.setItem('some.key1', 'some.value1'); + service.setItem('some.key2', 'some.value2'); + service.setItem('some.key3', 'some.value3'); + service.setItem('some.key4', 'some.value4'); + service.removeItem('some.key4'); + + assert.strictEqual(service.getItem('some.key1'), 'some.value1'); + assert.strictEqual(service.getItem('some.key2'), 'some.value2'); + assert.strictEqual(service.getItem('some.key3'), 'some.value3'); + assert.strictEqual(service.getItem('some.key4'), undefined); + + await service.close(); + + service = new FileStorage(URI.file(storageFile), logService, fileService); + await service.init(); + + assert.strictEqual(service.getItem('some.key1'), 'some.value1'); + assert.strictEqual(service.getItem('some.key2'), 'some.value2'); + assert.strictEqual(service.getItem('some.key3'), 'some.value3'); + assert.strictEqual(service.getItem('some.key4'), undefined); + }); + + test('Used before init', async function () { + const storageFile = join(testDir, 'storage.json'); + writeFileSync(storageFile, ''); + + let service = new FileStorage(URI.file(storageFile), logService, fileService); + + service.setItem('some.key1', 'some.value1'); + service.setItem('some.key2', 'some.value2'); + service.setItem('some.key3', 'some.value3'); + service.setItem('some.key4', 'some.value4'); + service.removeItem('some.key4'); + + assert.strictEqual(service.getItem('some.key1'), 'some.value1'); + assert.strictEqual(service.getItem('some.key2'), 'some.value2'); + assert.strictEqual(service.getItem('some.key3'), 'some.value3'); + assert.strictEqual(service.getItem('some.key4'), undefined); + + await service.init(); + + assert.strictEqual(service.getItem('some.key1'), 'some.value1'); + assert.strictEqual(service.getItem('some.key2'), 'some.value2'); + assert.strictEqual(service.getItem('some.key3'), 'some.value3'); + assert.strictEqual(service.getItem('some.key4'), undefined); + }); + + test('Used after close', async function () { + const storageFile = join(testDir, 'storage.json'); + writeFileSync(storageFile, ''); + + const service = new FileStorage(URI.file(storageFile), logService, fileService); + + await service.init(); + + service.setItem('some.key1', 'some.value1'); + service.setItem('some.key2', 'some.value2'); + service.setItem('some.key3', 'some.value3'); + service.setItem('some.key4', 'some.value4'); + + await service.close(); + + service.setItem('some.key5', 'some.marker'); + + const contents = readFileSync(storageFile).toString(); + assert.ok(contents.includes('some.value1')); + assert.ok(!contents.includes('some.marker')); + + await service.close(); + }); + + test('Closed before init', async function () { + const storageFile = join(testDir, 'storage.json'); + writeFileSync(storageFile, ''); + + const service = new FileStorage(URI.file(storageFile), logService, fileService); + + service.setItem('some.key1', 'some.value1'); + service.setItem('some.key2', 'some.value2'); + service.setItem('some.key3', 'some.value3'); + service.setItem('some.key4', 'some.value4'); + + await service.close(); + + const contents = readFileSync(storageFile).toString(); + assert.strictEqual(contents.length, 0); + }); +}); diff --git a/lib/vscode/src/vs/platform/storage/browser/storageService.ts b/src/vs/platform/storage/browser/storageService.ts similarity index 100% rename from lib/vscode/src/vs/platform/storage/browser/storageService.ts rename to src/vs/platform/storage/browser/storageService.ts diff --git a/lib/vscode/src/vs/platform/storage/common/storage.ts b/src/vs/platform/storage/common/storage.ts similarity index 99% rename from lib/vscode/src/vs/platform/storage/common/storage.ts rename to src/vs/platform/storage/common/storage.ts index 48f3829c9cf9..faecb2618ea5 100644 --- a/lib/vscode/src/vs/platform/storage/common/storage.ts +++ b/src/vs/platform/storage/common/storage.ts @@ -106,7 +106,7 @@ export interface IStorageService { * @param target allows to define the target of the storage operation * to either the current machine or user. */ - store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope, target: StorageTarget): Promise | void; + store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope, target: StorageTarget): void; /** * Delete an element stored under the provided key from storage. diff --git a/lib/vscode/src/vs/platform/storage/common/storageIpc.ts b/src/vs/platform/storage/common/storageIpc.ts similarity index 100% rename from lib/vscode/src/vs/platform/storage/common/storageIpc.ts rename to src/vs/platform/storage/common/storageIpc.ts diff --git a/lib/vscode/src/vs/platform/storage/electron-main/storageIpc.ts b/src/vs/platform/storage/electron-main/storageIpc.ts similarity index 100% rename from lib/vscode/src/vs/platform/storage/electron-main/storageIpc.ts rename to src/vs/platform/storage/electron-main/storageIpc.ts diff --git a/lib/vscode/src/vs/platform/storage/electron-main/storageMain.ts b/src/vs/platform/storage/electron-main/storageMain.ts similarity index 98% rename from lib/vscode/src/vs/platform/storage/electron-main/storageMain.ts rename to src/vs/platform/storage/electron-main/storageMain.ts index 3cd5051587fc..16ca034a8737 100644 --- a/lib/vscode/src/vs/platform/storage/electron-main/storageMain.ts +++ b/src/vs/platform/storage/electron-main/storageMain.ts @@ -3,8 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { promises } from 'fs'; -import { exists, writeFile } from 'vs/base/node/pfs'; +import { exists, Promises, writeFile } from 'vs/base/node/pfs'; import { Event, Emitter } from 'vs/base/common/event'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { ILogService, LogLevel } from 'vs/platform/log/common/log'; @@ -276,7 +275,7 @@ export class WorkspaceStorageMain extends BaseStorageMain implements IStorageMai } // Ensure storage folder exists - await promises.mkdir(workspaceStorageFolderPath, { recursive: true }); + await Promises.mkdir(workspaceStorageFolderPath, { recursive: true }); // Write metadata into folder (but do not await) this.ensureWorkspaceStorageFolderMeta(workspaceStorageFolderPath); diff --git a/lib/vscode/src/vs/platform/storage/electron-main/storageMainService.ts b/src/vs/platform/storage/electron-main/storageMainService.ts similarity index 100% rename from lib/vscode/src/vs/platform/storage/electron-main/storageMainService.ts rename to src/vs/platform/storage/electron-main/storageMainService.ts diff --git a/lib/vscode/src/vs/platform/storage/electron-sandbox/storageService.ts b/src/vs/platform/storage/electron-sandbox/storageService.ts similarity index 100% rename from lib/vscode/src/vs/platform/storage/electron-sandbox/storageService.ts rename to src/vs/platform/storage/electron-sandbox/storageService.ts diff --git a/lib/vscode/src/vs/platform/storage/test/browser/storageService.test.ts b/src/vs/platform/storage/test/browser/storageService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/storage/test/browser/storageService.test.ts rename to src/vs/platform/storage/test/browser/storageService.test.ts diff --git a/lib/vscode/src/vs/platform/storage/test/common/storageService.test.ts b/src/vs/platform/storage/test/common/storageService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/storage/test/common/storageService.test.ts rename to src/vs/platform/storage/test/common/storageService.test.ts diff --git a/lib/vscode/src/vs/platform/storage/test/electron-main/storageMainService.test.ts b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts similarity index 97% rename from lib/vscode/src/vs/platform/storage/test/electron-main/storageMainService.test.ts rename to src/vs/platform/storage/test/electron-main/storageMainService.test.ts index 0f55ca5c3b20..091de0aa8bf4 100644 --- a/lib/vscode/src/vs/platform/storage/test/electron-main/storageMainService.test.ts +++ b/src/vs/platform/storage/test/electron-main/storageMainService.test.ts @@ -66,8 +66,8 @@ suite('StorageMainService', function () { registerWindow(window: ICodeWindow): void { } async reload(window: ICodeWindow, cli?: NativeParsedArgs): Promise { } async unload(window: ICodeWindow, reason: UnloadReason): Promise { return true; } - relaunch(options?: { addArgs?: string[] | undefined; removeArgs?: string[] | undefined; }): void { } - async quit(fromUpdate?: boolean): Promise { return true; } + async relaunch(options?: { addArgs?: string[] | undefined; removeArgs?: string[] | undefined; }): Promise { } + async quit(willRestart?: boolean): Promise { return true; } async kill(code?: number): Promise { } async when(phase: LifecycleMainPhase): Promise { } } diff --git a/lib/vscode/src/vs/platform/telemetry/browser/errorTelemetry.ts b/src/vs/platform/telemetry/browser/errorTelemetry.ts similarity index 100% rename from lib/vscode/src/vs/platform/telemetry/browser/errorTelemetry.ts rename to src/vs/platform/telemetry/browser/errorTelemetry.ts diff --git a/lib/vscode/src/vs/platform/telemetry/common/commonProperties.ts b/src/vs/platform/telemetry/common/commonProperties.ts similarity index 98% rename from lib/vscode/src/vs/platform/telemetry/common/commonProperties.ts rename to src/vs/platform/telemetry/common/commonProperties.ts index 454b873fde13..9bcceeef0654 100644 --- a/lib/vscode/src/vs/platform/telemetry/common/commonProperties.ts +++ b/src/vs/platform/telemetry/common/commonProperties.ts @@ -101,7 +101,7 @@ export async function resolveCommonProperties( return result; } -function verifyMicrosoftInternalDomain(domainList: readonly string[]): boolean { +export function verifyMicrosoftInternalDomain(domainList: readonly string[]): boolean { const userDnsDomain = env['USERDNSDOMAIN']; if (!userDnsDomain) { return false; diff --git a/lib/vscode/src/vs/platform/telemetry/common/errorTelemetry.ts b/src/vs/platform/telemetry/common/errorTelemetry.ts similarity index 100% rename from lib/vscode/src/vs/platform/telemetry/common/errorTelemetry.ts rename to src/vs/platform/telemetry/common/errorTelemetry.ts diff --git a/lib/vscode/src/vs/platform/telemetry/common/gdprTypings.ts b/src/vs/platform/telemetry/common/gdprTypings.ts similarity index 100% rename from lib/vscode/src/vs/platform/telemetry/common/gdprTypings.ts rename to src/vs/platform/telemetry/common/gdprTypings.ts diff --git a/lib/vscode/src/vs/platform/telemetry/common/telemetry.ts b/src/vs/platform/telemetry/common/telemetry.ts similarity index 100% rename from lib/vscode/src/vs/platform/telemetry/common/telemetry.ts rename to src/vs/platform/telemetry/common/telemetry.ts diff --git a/lib/vscode/src/vs/platform/telemetry/common/telemetryIpc.ts b/src/vs/platform/telemetry/common/telemetryIpc.ts similarity index 100% rename from lib/vscode/src/vs/platform/telemetry/common/telemetryIpc.ts rename to src/vs/platform/telemetry/common/telemetryIpc.ts diff --git a/lib/vscode/src/vs/platform/telemetry/common/telemetryLogAppender.ts b/src/vs/platform/telemetry/common/telemetryLogAppender.ts similarity index 100% rename from lib/vscode/src/vs/platform/telemetry/common/telemetryLogAppender.ts rename to src/vs/platform/telemetry/common/telemetryLogAppender.ts diff --git a/lib/vscode/src/vs/platform/telemetry/common/telemetryService.ts b/src/vs/platform/telemetry/common/telemetryService.ts similarity index 100% rename from lib/vscode/src/vs/platform/telemetry/common/telemetryService.ts rename to src/vs/platform/telemetry/common/telemetryService.ts diff --git a/lib/vscode/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts similarity index 100% rename from lib/vscode/src/vs/platform/telemetry/common/telemetryUtils.ts rename to src/vs/platform/telemetry/common/telemetryUtils.ts diff --git a/lib/vscode/src/vs/platform/telemetry/electron-sandbox/customEndpointTelemetryService.ts b/src/vs/platform/telemetry/electron-sandbox/customEndpointTelemetryService.ts similarity index 100% rename from lib/vscode/src/vs/platform/telemetry/electron-sandbox/customEndpointTelemetryService.ts rename to src/vs/platform/telemetry/electron-sandbox/customEndpointTelemetryService.ts diff --git a/lib/vscode/src/vs/platform/telemetry/node/appInsightsAppender.ts b/src/vs/platform/telemetry/node/appInsightsAppender.ts similarity index 100% rename from lib/vscode/src/vs/platform/telemetry/node/appInsightsAppender.ts rename to src/vs/platform/telemetry/node/appInsightsAppender.ts diff --git a/lib/vscode/src/vs/platform/telemetry/node/customEndpointTelemetryService.ts b/src/vs/platform/telemetry/node/customEndpointTelemetryService.ts similarity index 100% rename from lib/vscode/src/vs/platform/telemetry/node/customEndpointTelemetryService.ts rename to src/vs/platform/telemetry/node/customEndpointTelemetryService.ts diff --git a/lib/vscode/src/vs/platform/telemetry/node/errorTelemetry.ts b/src/vs/platform/telemetry/node/errorTelemetry.ts similarity index 100% rename from lib/vscode/src/vs/platform/telemetry/node/errorTelemetry.ts rename to src/vs/platform/telemetry/node/errorTelemetry.ts diff --git a/lib/vscode/src/vs/platform/telemetry/node/telemetry.ts b/src/vs/platform/telemetry/node/telemetry.ts similarity index 100% rename from lib/vscode/src/vs/platform/telemetry/node/telemetry.ts rename to src/vs/platform/telemetry/node/telemetry.ts diff --git a/lib/vscode/src/vs/platform/telemetry/test/browser/telemetryService.test.ts b/src/vs/platform/telemetry/test/browser/telemetryService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/telemetry/test/browser/telemetryService.test.ts rename to src/vs/platform/telemetry/test/browser/telemetryService.test.ts diff --git a/lib/vscode/src/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts b/src/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts rename to src/vs/platform/telemetry/test/common/telemetryLogAppender.test.ts diff --git a/lib/vscode/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts b/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts rename to src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts diff --git a/lib/vscode/src/vs/platform/terminal/common/environmentVariable.ts b/src/vs/platform/terminal/common/environmentVariable.ts similarity index 100% rename from lib/vscode/src/vs/platform/terminal/common/environmentVariable.ts rename to src/vs/platform/terminal/common/environmentVariable.ts diff --git a/lib/vscode/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts similarity index 65% rename from lib/vscode/src/vs/platform/terminal/common/terminal.ts rename to src/vs/platform/terminal/common/terminal.ts index 28a4c9b649f2..6a0a7aa0dd13 100644 --- a/lib/vscode/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -8,6 +8,85 @@ import { Event } from 'vs/base/common/event'; import { IProcessEnvironment, OperatingSystem } from 'vs/base/common/platform'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IGetTerminalLayoutInfoArgs, IProcessDetails, IPtyHostProcessReplayEvent, ISetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess'; +import { ThemeIcon } from 'vs/platform/theme/common/themeService'; + +export const enum TerminalSettingPrefix { + Shell = 'terminal.integrated.shell.', + ShellArgs = 'terminal.integrated.shellArgs.', + DefaultProfile = 'terminal.integrated.defaultProfile.', + Profiles = 'terminal.integrated.profiles.' +} + +export const enum TerminalSettingId { + ShellLinux = 'terminal.integrated.shell.linux', + ShellMacOs = 'terminal.integrated.shell.osx', + ShellWindows = 'terminal.integrated.shell.windows', + SendKeybindingsToShell = 'terminal.integrated.sendKeybindingsToShell', + AutomationShellLinux = 'terminal.integrated.automationShell.linux', + AutomationShellMacOs = 'terminal.integrated.automationShell.osx', + AutomationShellWindows = 'terminal.integrated.automationShell.windows', + ShellArgsLinux = 'terminal.integrated.shellArgs.linux', + ShellArgsMacOs = 'terminal.integrated.shellArgs.osx', + ShellArgsWindows = 'terminal.integrated.shellArgs.windows', + ProfilesWindows = 'terminal.integrated.profiles.windows', + ProfilesMacOs = 'terminal.integrated.profiles.osx', + ProfilesLinux = 'terminal.integrated.profiles.linux', + DefaultProfileLinux = 'terminal.integrated.defaultProfile.linux', + DefaultProfileMacOs = 'terminal.integrated.defaultProfile.osx', + DefaultProfileWindows = 'terminal.integrated.defaultProfile.windows', + UseWslProfiles = 'terminal.integrated.useWslProfiles', + TabsEnabled = 'terminal.integrated.tabs.enabled', + TabsHideCondition = 'terminal.integrated.tabs.hideCondition', + TabsShowActiveTerminal = 'terminal.integrated.tabs.showActiveTerminal', + TabsLocation = 'terminal.integrated.tabs.location', + TabsFocusMode = 'terminal.integrated.tabs.focusMode', + MacOptionIsMeta = 'terminal.integrated.macOptionIsMeta', + MacOptionClickForcesSelection = 'terminal.integrated.macOptionClickForcesSelection', + AltClickMovesCursor = 'terminal.integrated.altClickMovesCursor', + CopyOnSelection = 'terminal.integrated.copyOnSelection', + DrawBoldTextInBrightColors = 'terminal.integrated.drawBoldTextInBrightColors', + FontFamily = 'terminal.integrated.fontFamily', + FontSize = 'terminal.integrated.fontSize', + LetterSpacing = 'terminal.integrated.letterSpacing', + LineHeight = 'terminal.integrated.lineHeight', + MinimumContrastRatio = 'terminal.integrated.minimumContrastRatio', + FastScrollSensitivity = 'terminal.integrated.fastScrollSensitivity', + MouseWheelScrollSensitivity = 'terminal.integrated.mouseWheelScrollSensitivity', + BellDuration = 'terminal.integrated.bellDuration', + FontWeight = 'terminal.integrated.fontWeight', + FontWeightBold = 'terminal.integrated.fontWeightBold', + CursorBlinking = 'terminal.integrated.cursorBlinking', + CursorStyle = 'terminal.integrated.cursorStyle', + CursorWidth = 'terminal.integrated.cursorWidth', + Scrollback = 'terminal.integrated.scrollback', + DetectLocale = 'terminal.integrated.detectLocale', + GpuAcceleration = 'terminal.integrated.gpuAcceleration', + RightClickBehavior = 'terminal.integrated.rightClickBehavior', + Cwd = 'terminal.integrated.cwd', + ConfirmOnExit = 'terminal.integrated.confirmOnExit', + EnableBell = 'terminal.integrated.enableBell', + CommandsToSkipShell = 'terminal.integrated.commandsToSkipShell', + AllowChords = 'terminal.integrated.allowChords', + AllowMnemonics = 'terminal.integrated.allowMnemonics', + EnvMacOs = 'terminal.integrated.env.osx', + EnvLinux = 'terminal.integrated.env.linux', + EnvWindows = 'terminal.integrated.env.windows', + EnvironmentChangesIndicator = 'terminal.integrated.environmentChangesIndicator', + EnvironmentChangesRelaunch = 'terminal.integrated.environmentChangesRelaunch', + ShowExitAlert = 'terminal.integrated.showExitAlert', + SplitCwd = 'terminal.integrated.splitCwd', + WindowsEnableConpty = 'terminal.integrated.windowsEnableConpty', + WordSeparators = 'terminal.integrated.wordSeparators', + TitleMode = 'terminal.integrated.titleMode', + EnableFileLinks = 'terminal.integrated.enableFileLinks', + UnicodeVersion = 'terminal.integrated.unicodeVersion', + ExperimentalLinkProvider = 'terminal.integrated.experimentalLinkProvider', + LocalEchoLatencyThreshold = 'terminal.integrated.localEchoLatencyThreshold', + LocalEchoExcludePrograms = 'terminal.integrated.localEchoExcludePrograms', + LocalEchoStyle = 'terminal.integrated.localEchoStyle', + EnablePersistentSessions = 'terminal.integrated.enablePersistentSessions', + InheritEnv = 'terminal.integrated.inheritEnv' +} export enum WindowsShellType { CommandPrompt = 'cmd', @@ -30,7 +109,6 @@ export interface IRawTerminalTabLayoutInfo { } export type ITerminalTabLayoutInfoById = IRawTerminalTabLayoutInfo; -export type ITerminalTabLayoutInfo = IRawTerminalTabLayoutInfo; export interface IRawTerminalsLayoutInfo { tabs: IRawTerminalTabLayoutInfo[]; @@ -40,11 +118,21 @@ export interface IPtyHostAttachTarget { id: number; pid: number; title: string; + titleSource: TitleEventSource; cwd: string; workspaceId: string; workspaceName: string; isOrphan: boolean; - icon: string | undefined; + icon: TerminalIcon | undefined; +} + +export enum TitleEventSource { + /** From the API or the rename command that overrides any other type */ + Api, + /** From the process name property*/ + Process, + /** From the VT sequence */ + Sequence } export type ITerminalsLayoutInfo = IRawTerminalsLayoutInfo; @@ -96,8 +184,13 @@ export interface IOffProcessTerminalService { attachToProcess(id: number): Promise; listProcesses(): Promise; getDefaultSystemShell(osOverride?: OperatingSystem): Promise; - getShellEnvironment(): Promise; + getProfiles(profiles: unknown, defaultProfile: unknown, includeDetectedProfiles?: boolean): Promise; + getWslPath(original: string): Promise; + getEnvironment(): Promise; + getShellEnvironment(): Promise; setTerminalLayoutInfo(layoutInfo?: ITerminalsLayoutInfoById): Promise; + updateTitle(id: number, title: string, titleSource: TitleEventSource): Promise; + updateIcon(id: number, icon: TerminalIcon, color?: string): Promise; getTerminalLayoutInfo(): Promise; reduceConnectionGraceTime(): Promise; } @@ -115,6 +208,8 @@ export interface IPtyService { readonly onPtyHostStart?: Event; readonly onPtyHostUnresponsive?: Event; readonly onPtyHostResponsive?: Event; + readonly onPtyHostRequestResolveVariables?: Event; + readonly onProcessData: Event<{ id: number, event: IProcessDataEvent | string }>; readonly onProcessExit: Event<{ id: number, event: number | undefined }>; readonly onProcessReady: Event<{ id: number, event: { pid: number, cwd: string } }>; @@ -127,6 +222,7 @@ export interface IPtyService { restartPtyHost?(): Promise; shutdownAll?(): Promise; + acceptPtyHostResolvedVariables?(id: number, resolved: string[]): Promise; createProcess( shellLaunchConfig: IShellLaunchConfig, @@ -159,14 +255,22 @@ export interface IPtyService { processBinary(id: number, data: string): Promise; /** Confirm the process is _not_ an orphan. */ orphanQuestionReply(id: number): Promise; - + updateTitle(id: number, title: string, titleSource: TitleEventSource): Promise; + updateIcon(id: number, icon: TerminalIcon, color?: string): Promise; getDefaultSystemShell(osOverride?: OperatingSystem): Promise; - getShellEnvironment(): Promise; + getProfiles?(profiles: unknown, defaultProfile: unknown, includeDetectedProfiles?: boolean): Promise; + getEnvironment(): Promise; + getWslPath(original: string): Promise; setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): Promise; getTerminalLayoutInfo(args: IGetTerminalLayoutInfoArgs): Promise; reduceConnectionGraceTime(): Promise; } +export interface IRequestResolveVariablesEvent { + id: number; + originalText: string[]; +} + export enum HeartbeatConstants { /** * The duration between heartbeats @@ -260,7 +364,7 @@ export interface IShellLaunchConfig { /** * This is a terminal that attaches to an already running terminal. */ - attachPersistentProcess?: { id: number; pid: number; title: string; cwd: string; icon?: string; }; + attachPersistentProcess?: { id: number; pid: number; title: string; titleSource: TitleEventSource; cwd: string; icon?: TerminalIcon; color?: string }; /** * Whether the terminal process environment should be exactly as provided in @@ -271,6 +375,14 @@ export interface IShellLaunchConfig { */ strictEnv?: boolean; + /** + * Whether the terminal process environment will inherit VS Code's "shell environment" that may + * get sourced from running a login shell depnding on how the application was launched. + * Consumers that rely on development tools being present in the $PATH should set this to true. + * This will overwrite the value of the inheritEnv setting. + */ + useShellEnvironment?: boolean; + /** * When enabled the terminal will run the process as normal but not be surfaced to the user * until `Terminal.show` is called. The typical usage for this is when you need to run @@ -292,18 +404,25 @@ export interface IShellLaunchConfig { isExtensionOwnedTerminal?: boolean; /** - * The codicon ID to use for this terminal. If not specified it will use the default fallback - * icon. + * The icon for the terminal, used primarily in the terminal tab. + */ + icon?: TerminalIcon; + + /** + * The color ID to use for this terminal. If not specified it will use the default fallback */ - icon?: string; + color?: string; } +export type TerminalIcon = ThemeIcon | URI | { light: URI; dark: URI }; + export interface IShellLaunchConfigDto { name?: string; executable?: string; args?: string[] | string; cwd?: string | UriComponents; env?: ITerminalEnvironment; + useShellEnvironment?: boolean; hideFromUser?: boolean; } @@ -316,6 +435,12 @@ export interface ITerminalLaunchError { code?: number; } +export interface IProcessReadyEvent { + pid: number, + cwd: string, + requiresWindowsMode?: boolean +} + /** * An interface representing a raw terminal child process, this contains a subset of the * child_process.ChildProcess node.js interface. @@ -335,7 +460,7 @@ export interface ITerminalChildProcess { onProcessData: Event; onProcessExit: Event; - onProcessReady: Event<{ pid: number, cwd: string }>; + onProcessReady: Event; onProcessTitleChanged: Event; onProcessOverrideDimensions?: Event; onProcessResolvedShellLaunchConfig?: Event; @@ -378,15 +503,20 @@ export interface ITerminalChildProcess { getLatency(): Promise; } +export interface IReconnectConstants { + GraceTime: number, + ShortGraceTime: number +} + export const enum LocalReconnectConstants { /** * If there is no reconnection within this time-frame, consider the connection permanently closed... */ - ReconnectionGraceTime = 60000, // 60 seconds + GraceTime = 60000, // 60 seconds /** * Maximal grace time between the first and the last reconnection... */ - ReconnectionShortGraceTime = 6000, // 6 seconds + ShortGraceTime = 6000, // 6 seconds } export const enum FlowControlConstants { @@ -433,6 +563,18 @@ export interface ITerminalDimensions { rows: number; } +export interface ITerminalProfile { + profileName: string; + path: string; + isDefault: boolean; + isAutoDetected?: boolean; + args?: string | string[] | undefined; + env?: ITerminalEnvironment; + overrideName?: boolean; + color?: string; + icon?: ThemeIcon | URI | { light: URI, dark: URI }; +} + export interface ITerminalDimensionsOverride extends Readonly { /** * indicate that xterm must receive these exact dimensions, even if they overflow the ui! @@ -440,4 +582,26 @@ export interface ITerminalDimensionsOverride extends Readonly(key: string) => T | undefined; +export const enum ProfileSource { + GitBash = 'Git Bash', + Pwsh = 'PowerShell' +} + +export interface IBaseUnresolvedTerminalProfile { + args?: string | string[] | undefined; + isAutoDetected?: boolean; + overrideName?: boolean; + icon?: ThemeIcon | URI | { light: URI, dark: URI }; + color?: string; + env?: ITerminalEnvironment; +} + +export interface ITerminalExecutable extends IBaseUnresolvedTerminalProfile { + path: string | string[]; +} + +export interface ITerminalProfileSource extends IBaseUnresolvedTerminalProfile { + source: ProfileSource; +} + +export type ITerminalProfileObject = ITerminalExecutable | ITerminalProfileSource | null; diff --git a/lib/vscode/src/vs/platform/terminal/common/terminalDataBuffering.ts b/src/vs/platform/terminal/common/terminalDataBuffering.ts similarity index 100% rename from lib/vscode/src/vs/platform/terminal/common/terminalDataBuffering.ts rename to src/vs/platform/terminal/common/terminalDataBuffering.ts diff --git a/src/vs/platform/terminal/common/terminalEnvironment.ts b/src/vs/platform/terminal/common/terminalEnvironment.ts new file mode 100644 index 000000000000..66b5ad31a3f3 --- /dev/null +++ b/src/vs/platform/terminal/common/terminalEnvironment.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. + *--------------------------------------------------------------------------------------------*/ + +export function escapeNonWindowsPath(path: string): string { + let newPath = path; + if (newPath.indexOf('\\') !== 0) { + newPath = newPath.replace(/\\/g, '\\\\'); + } + const bannedChars = /[\`\$\|\&\>\~\#\!\^\*\;\<\"\']/g; + newPath = newPath.replace(bannedChars, ''); + return `'${newPath}'`; +} diff --git a/src/vs/platform/terminal/common/terminalPlatformConfiguration.ts b/src/vs/platform/terminal/common/terminalPlatformConfiguration.ts new file mode 100644 index 000000000000..a5fd0a631f9b --- /dev/null +++ b/src/vs/platform/terminal/common/terminalPlatformConfiguration.ts @@ -0,0 +1,388 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; +import { localize } from 'vs/nls'; +import { ITerminalProfile, TerminalSettingId } from 'vs/platform/terminal/common/terminal'; +import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { Codicon, iconRegistry } from 'vs/base/common/codicons'; +import { OperatingSystem } from 'vs/base/common/platform'; +import { ThemeIcon } from 'vs/platform/theme/common/themeService'; + +const terminalProfileBaseProperties: IJSONSchemaMap = { + args: { + description: localize('terminalProfile.args', 'An optional set of arguments to run the shell executable with.'), + type: 'array', + items: { + type: 'string' + } + }, + overrideName: { + description: localize('terminalProfile.overrideName', 'Controls whether or not the profile name overrides the auto detected one.'), + type: 'boolean' + }, + icon: { + description: localize('terminalProfile.icon', 'A codicon ID to associate with this terminal.'), + type: 'string', + enum: Array.from(iconRegistry.all, icon => icon.id), + markdownEnumDescriptions: Array.from(iconRegistry.all, icon => `$(${icon.id})`), + }, + color: { + description: localize('terminalProfile.color', 'A theme color ID to associate with this terminal.'), + type: ['string', 'null'], + enum: [ + 'terminal.ansiBlack', + 'terminal.ansiRed', + 'terminal.ansiGreen', + 'terminal.ansiYellow', + 'terminal.ansiBlue', + 'terminal.ansiMagenta', + 'terminal.ansiCyan', + 'terminal.ansiWhite' + ], + default: null + }, + env: { + markdownDescription: localize('terminalProfile.env', "An object with environment variables that will be added to the terminal profile process. Set to `null` to delete environment variables from the base environment."), + type: 'object', + additionalProperties: { + type: ['string', 'null'] + }, + default: {} + } +}; + +const terminalProfileSchema: IJSONSchema = { + type: 'object', + required: ['path'], + properties: { + path: { + description: localize('terminalProfile.path', 'A single path to a shell executable or an array of paths that will be used as fallbacks when one fails.'), + type: ['string', 'array'], + items: { + type: 'string' + } + }, + ...terminalProfileBaseProperties + } +}; + +const shellDeprecationMessageLinux = localize('terminal.integrated.shell.linux.deprecation', "This is deprecated, the new recommended way to configure your default shell is by creating a terminal profile in {0} and setting its profile name as the default in {1}. This will currently take priority over the new profiles settings but that will change in the future.", '`#terminal.integrated.profiles.linux#`', '`#terminal.integrated.defaultProfile.linux#`'); +const shellDeprecationMessageOsx = localize('terminal.integrated.shell.osx.deprecation', "This is deprecated, the new recommended way to configure your default shell is by creating a terminal profile in {0} and setting its profile name as the default in {1}. This will currently take priority over the new profiles settings but that will change in the future.", '`#terminal.integrated.profiles.osx#`', '`#terminal.integrated.defaultProfile.osx#`'); +const shellDeprecationMessageWindows = localize('terminal.integrated.shell.windows.deprecation', "This is deprecated, the new recommended way to configure your default shell is by creating a terminal profile in {0} and setting its profile name as the default in {1}. This will currently take priority over the new profiles settings but that will change in the future.", '`#terminal.integrated.profiles.windows#`', '`#terminal.integrated.defaultProfile.windows#`'); + +const terminalPlatformConfiguration: IConfigurationNode = { + id: 'terminal', + order: 100, + title: localize('terminalIntegratedConfigurationTitle', "Integrated Terminal"), + type: 'object', + properties: { + [TerminalSettingId.AutomationShellLinux]: { + restricted: true, + markdownDescription: localize({ + key: 'terminal.integrated.automationShell.linux', + comment: ['{0} and {1} are the `shell` and `shellArgs` settings keys'] + }, "A path that when set will override {0} and ignore {1} values for automation-related terminal usage like tasks and debug.", '`terminal.integrated.shell.linux`', '`shellArgs`'), + type: ['string', 'null'], + default: null + }, + [TerminalSettingId.AutomationShellMacOs]: { + restricted: true, + markdownDescription: localize({ + key: 'terminal.integrated.automationShell.osx', + comment: ['{0} and {1} are the `shell` and `shellArgs` settings keys'] + }, "A path that when set will override {0} and ignore {1} values for automation-related terminal usage like tasks and debug.", '`terminal.integrated.shell.osx`', '`shellArgs`'), + type: ['string', 'null'], + default: null + }, + [TerminalSettingId.AutomationShellWindows]: { + restricted: true, + markdownDescription: localize({ + key: 'terminal.integrated.automationShell.windows', + comment: ['{0} and {1} are the `shell` and `shellArgs` settings keys'] + }, "A path that when set will override {0} and ignore {1} values for automation-related terminal usage like tasks and debug.", '`terminal.integrated.shell.windows`', '`shellArgs`'), + type: ['string', 'null'], + default: null + }, + [TerminalSettingId.ShellLinux]: { + restricted: true, + markdownDescription: localize('terminal.integrated.shell.linux', "The path of the shell that the terminal uses on Linux. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), + type: ['string', 'null'], + default: null, + markdownDeprecationMessage: shellDeprecationMessageLinux + }, + [TerminalSettingId.ShellMacOs]: { + restricted: true, + markdownDescription: localize('terminal.integrated.shell.osx', "The path of the shell that the terminal uses on macOS. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), + type: ['string', 'null'], + default: null, + markdownDeprecationMessage: shellDeprecationMessageOsx + }, + [TerminalSettingId.ShellWindows]: { + restricted: true, + markdownDescription: localize('terminal.integrated.shell.windows', "The path of the shell that the terminal uses on Windows. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), + type: ['string', 'null'], + default: null, + markdownDeprecationMessage: shellDeprecationMessageWindows + }, + [TerminalSettingId.ShellArgsLinux]: { + restricted: true, + markdownDescription: localize('terminal.integrated.shellArgs.linux', "The command line arguments to use when on the Linux terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), + type: 'array', + items: { + type: 'string' + }, + default: [], + markdownDeprecationMessage: shellDeprecationMessageLinux + }, + [TerminalSettingId.ShellArgsMacOs]: { + restricted: true, + markdownDescription: localize('terminal.integrated.shellArgs.osx', "The command line arguments to use when on the macOS terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), + type: 'array', + items: { + type: 'string' + }, + // Unlike on Linux, ~/.profile is not sourced when logging into a macOS session. This + // is the reason terminals on macOS typically run login shells by default which set up + // the environment. See http://unix.stackexchange.com/a/119675/115410 + default: ['-l'], + markdownDeprecationMessage: shellDeprecationMessageOsx + }, + [TerminalSettingId.ShellArgsWindows]: { + restricted: true, + markdownDescription: localize('terminal.integrated.shellArgs.windows', "The command line arguments to use when on the Windows terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), + 'anyOf': [ + { + type: 'array', + items: { + type: 'string', + markdownDescription: localize('terminal.integrated.shellArgs.windows', "The command line arguments to use when on the Windows terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).") + }, + }, + { + type: 'string', + markdownDescription: localize('terminal.integrated.shellArgs.windows.string', "The command line arguments in [command-line format](https://msdn.microsoft.com/en-au/08dfcab2-eb6e-49a4-80eb-87d4076c98c6) to use when on the Windows terminal. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).") + } + ], + default: [], + markdownDeprecationMessage: shellDeprecationMessageWindows + }, + [TerminalSettingId.ProfilesWindows]: { + restricted: true, + markdownDescription: localize( + { + key: 'terminal.integrated.profiles.windows', + comment: ['{0}, {1}, and {2} are the `source`, `path` and optional `args` settings keys'] + }, + "The Windows profiles to present when creating a new terminal via the terminal dropdown. Set to null to exclude them, use the {0} property to use the default detected configuration. Or, set the {1} and optional {2}", '`source`', '`path`', '`args`.' + ), + type: 'object', + default: { + 'PowerShell': { + source: 'PowerShell', + icon: 'terminal-powershell' + }, + 'Command Prompt': { + path: [ + '${env:windir}\\Sysnative\\cmd.exe', + '${env:windir}\\System32\\cmd.exe' + ], + args: [], + icon: 'terminal-cmd' + }, + 'Git Bash': { + source: 'Git Bash' + } + }, + additionalProperties: { + 'anyOf': [ + { + type: 'object', + required: ['source'], + properties: { + source: { + description: localize('terminalProfile.windowsSource', 'A profile source that will auto detect the paths to the shell.'), + enum: ['PowerShell', 'Git Bash'] + }, + ...terminalProfileBaseProperties + } + }, + { type: 'null' }, + terminalProfileSchema + ] + } + }, + [TerminalSettingId.ProfilesMacOs]: { + restricted: true, + markdownDescription: localize( + { + key: 'terminal.integrated.profile.osx', + comment: ['{0} and {1} are the `path` and optional `args` settings keys'] + }, + "The macOS profiles to present when creating a new terminal via the terminal dropdown. When set, these will override the default detected profiles. They are comprised of a {0} and optional {1}", '`path`', '`args`.' + ), + type: 'object', + default: { + 'bash': { + path: 'bash', + args: ['-l'], + icon: 'terminal-bash' + }, + 'zsh': { + path: 'zsh', + args: ['-l'] + }, + 'fish': { + path: 'fish', + args: ['-l'] + }, + 'tmux': { + path: 'tmux', + icon: 'terminal-tmux' + }, + 'pwsh': { + path: 'pwsh', + icon: 'terminal-powershell' + } + }, + additionalProperties: { + 'anyOf': [ + { type: 'null' }, + terminalProfileSchema + ] + } + }, + [TerminalSettingId.ProfilesLinux]: { + restricted: true, + markdownDescription: localize( + { + key: 'terminal.integrated.profile.linux', + comment: ['{0} and {1} are the `path` and optional `args` settings keys'] + }, + "The Linux profiles to present when creating a new terminal via the terminal dropdown. When set, these will override the default detected profiles. They are comprised of a {0} and optional {1}", '`path`', '`args`.' + ), + type: 'object', + default: { + 'bash': { + path: 'bash' + }, + 'zsh': { + path: 'zsh' + }, + 'fish': { + path: 'fish' + }, + 'tmux': { + path: 'tmux', + icon: 'terminal-tmux' + }, + 'pwsh': { + path: 'pwsh', + icon: 'terminal-powershell' + } + }, + additionalProperties: { + 'anyOf': [ + { type: 'null' }, + terminalProfileSchema + ] + } + }, + [TerminalSettingId.UseWslProfiles]: { + description: localize('terminal.integrated.useWslProfiles', 'Controls whether or not WSL distros are shown in the terminal dropdown'), + type: 'boolean', + default: true + }, + [TerminalSettingId.InheritEnv]: { + scope: ConfigurationScope.APPLICATION, + description: localize('terminal.integrated.inheritEnv', "Whether new shells should inherit their environment from VS Code which may source a login shell to ensure $PATH and other development variables are initialized. This has no effect on Windows."), + type: 'boolean', + default: true + }, + } +}; + +/** + * Registers terminal configurations required by shared process and remote server. + */ +export function registerTerminalPlatformConfiguration() { + Registry.as(Extensions.Configuration).registerConfiguration(terminalPlatformConfiguration); + registerTerminalDefaultProfileConfiguration(); +} + +let lastDefaultProfilesConfiguration: IConfigurationNode | undefined; +export function registerTerminalDefaultProfileConfiguration(detectedProfiles?: { os: OperatingSystem, profiles: ITerminalProfile[] }) { + const registry = Registry.as(Extensions.Configuration); + if (lastDefaultProfilesConfiguration) { + registry.deregisterConfigurations([lastDefaultProfilesConfiguration]); + } + let enumValues: string[] | undefined = undefined; + let enumDescriptions: string[] | undefined = undefined; + if (detectedProfiles) { + const result = detectedProfiles.profiles.map(e => { + return { + name: e.profileName, + description: createProfileDescription(e) + }; + }); + enumValues = result.map(e => e.name); + enumDescriptions = result.map(e => e.description); + } + lastDefaultProfilesConfiguration = { + id: 'terminal', + order: 100, + title: localize('terminalIntegratedConfigurationTitle', "Integrated Terminal"), + type: 'object', + properties: { + [TerminalSettingId.DefaultProfileLinux]: { + restricted: true, + markdownDescription: localize('terminal.integrated.defaultProfile.linux', "The default profile used on Linux. This setting will currently be ignored if either {0} or {1} are set.", '`#terminal.integrated.shell.linux#`', '`#terminal.integrated.shellArgs.linux#`'), + type: ['string', 'null'], + default: null, + enum: detectedProfiles?.os === OperatingSystem.Linux ? enumValues : undefined, + markdownEnumDescriptions: detectedProfiles?.os === OperatingSystem.Linux ? enumDescriptions : undefined + }, + [TerminalSettingId.DefaultProfileMacOs]: { + restricted: true, + markdownDescription: localize('terminal.integrated.defaultProfile.osx', "The default profile used on macOS. This setting will currently be ignored if either {0} or {1} are set.", '`#terminal.integrated.shell.osx#`', '`#terminal.integrated.shellArgs.osx#`'), + type: ['string', 'null'], + default: null, + enum: detectedProfiles?.os === OperatingSystem.Macintosh ? enumValues : undefined, + markdownEnumDescriptions: detectedProfiles?.os === OperatingSystem.Macintosh ? enumDescriptions : undefined + }, + [TerminalSettingId.DefaultProfileWindows]: { + restricted: true, + markdownDescription: localize('terminal.integrated.defaultProfile.windows', "The default profile used on Windows. This setting will currently be ignored if either {0} or {1} are set.", '`#terminal.integrated.shell.windows#`', '`#terminal.integrated.shellArgs.windows#`'), + type: ['string', 'null'], + default: null, + enum: detectedProfiles?.os === OperatingSystem.Windows ? enumValues : undefined, + markdownEnumDescriptions: detectedProfiles?.os === OperatingSystem.Windows ? enumDescriptions : undefined + }, + } + }; + registry.registerConfiguration(lastDefaultProfilesConfiguration); +} + +function createProfileDescription(profile: ITerminalProfile): string { + let description = `$(${ThemeIcon.isThemeIcon(profile.icon) ? profile.icon.id : profile.icon ? profile.icon : Codicon.terminal.id}) ${profile.profileName}\n- path: ${profile.path}`; + if (profile.args) { + if (typeof profile.args === 'string') { + description += `\n- args: "${profile.args}"`; + } else { + description += `\n- args: [${profile.args.length === 0 ? '' : profile.args.join(`','`)}]`; + } + } + if (profile.overrideName !== undefined) { + description += `\n- overrideName: ${profile.overrideName}`; + } + if (profile.color) { + description += `\n- color: ${profile.color}`; + } + if (profile.env) { + description += `\n- env: ${JSON.stringify(profile.env)}`; + } + return description; +} diff --git a/lib/vscode/src/vs/platform/terminal/common/terminalProcess.ts b/src/vs/platform/terminal/common/terminalProcess.ts similarity index 93% rename from lib/vscode/src/vs/platform/terminal/common/terminalProcess.ts rename to src/vs/platform/terminal/common/terminalProcess.ts index 6cdf3b88e175..bc51bd66e7d9 100644 --- a/lib/vscode/src/vs/platform/terminal/common/terminalProcess.ts +++ b/src/vs/platform/terminal/common/terminalProcess.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { UriComponents } from 'vs/base/common/uri'; -import { IRawTerminalTabLayoutInfo, ITerminalEnvironment, ITerminalTabLayoutInfoById } from 'vs/platform/terminal/common/terminal'; +import { IRawTerminalTabLayoutInfo, ITerminalEnvironment, ITerminalTabLayoutInfoById, TerminalIcon, TitleEventSource } from 'vs/platform/terminal/common/terminal'; import { ISerializableEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable'; export interface ISingleTerminalConfiguration { @@ -26,7 +26,6 @@ export interface ICompleteTerminalConfiguration { 'terminal.integrated.env.windows': ISingleTerminalConfiguration; 'terminal.integrated.env.osx': ISingleTerminalConfiguration; 'terminal.integrated.env.linux': ISingleTerminalConfiguration; - 'terminal.integrated.inheritEnv': boolean; 'terminal.integrated.cwd': string; 'terminal.integrated.detectLocale': 'auto' | 'off' | 'on'; } @@ -52,11 +51,13 @@ export interface IProcessDetails { id: number; pid: number; title: string; + titleSource: TitleEventSource; cwd: string; workspaceId: string; workspaceName: string; isOrphan: boolean; - icon: string | undefined; + icon: TerminalIcon | undefined; + color: string | undefined; } export type ITerminalTabLayoutInfoDto = IRawTerminalTabLayoutInfo; diff --git a/lib/vscode/src/vs/platform/terminal/common/terminalRecorder.ts b/src/vs/platform/terminal/common/terminalRecorder.ts similarity index 94% rename from lib/vscode/src/vs/platform/terminal/common/terminalRecorder.ts rename to src/vs/platform/terminal/common/terminalRecorder.ts index e8a6e17c3667..68bd0f16fbcf 100644 --- a/lib/vscode/src/vs/platform/terminal/common/terminalRecorder.ts +++ b/src/vs/platform/terminal/common/terminalRecorder.ts @@ -26,7 +26,7 @@ export class TerminalRecorder { this._entries = [{ cols, rows, data: [] }]; } - public recordResize(cols: number, rows: number): void { + recordResize(cols: number, rows: number): void { if (this._entries.length > 0) { const lastEntry = this._entries[this._entries.length - 1]; if (lastEntry.data.length === 0) { @@ -52,7 +52,7 @@ export class TerminalRecorder { this._entries.push({ cols, rows, data: [] }); } - public recordData(data: string): void { + recordData(data: string): void { const lastEntry = this._entries[this._entries.length - 1]; lastEntry.data.push(data); @@ -76,7 +76,7 @@ export class TerminalRecorder { } } - public generateReplayEvent(): IPtyHostProcessReplayEvent { + generateReplayEvent(): IPtyHostProcessReplayEvent { // normalize entries to one element per data array this._entries.forEach((entry) => { if (entry.data.length > 0) { diff --git a/lib/vscode/src/vs/platform/terminal/electron-sandbox/terminal.ts b/src/vs/platform/terminal/electron-sandbox/terminal.ts similarity index 100% rename from lib/vscode/src/vs/platform/terminal/electron-sandbox/terminal.ts rename to src/vs/platform/terminal/electron-sandbox/terminal.ts diff --git a/lib/vscode/src/vs/platform/terminal/node/heartbeatService.ts b/src/vs/platform/terminal/node/heartbeatService.ts similarity index 100% rename from lib/vscode/src/vs/platform/terminal/node/heartbeatService.ts rename to src/vs/platform/terminal/node/heartbeatService.ts diff --git a/lib/vscode/src/vs/platform/terminal/node/ptyHostMain.ts b/src/vs/platform/terminal/node/ptyHostMain.ts similarity index 80% rename from lib/vscode/src/vs/platform/terminal/node/ptyHostMain.ts rename to src/vs/platform/terminal/node/ptyHostMain.ts index d3b08384ec59..2e98f2259c5e 100644 --- a/lib/vscode/src/vs/platform/terminal/node/ptyHostMain.ts +++ b/src/vs/platform/terminal/node/ptyHostMain.ts @@ -23,7 +23,11 @@ server.registerChannel(TerminalIpcChannels.Log, logChannel); const heartbeatService = new HeartbeatService(); server.registerChannel(TerminalIpcChannels.Heartbeat, ProxyChannel.fromService(heartbeatService)); -const ptyService = new PtyService(lastPtyId, logService); +const reconnectConstants = { GraceTime: parseInt(process.env.VSCODE_RECONNECT_GRACE_TIME || '0'), ShortGraceTime: parseInt(process.env.VSCODE_RECONNECT_SHORT_GRACE_TIME || '0') }; +delete process.env.VSCODE_RECONNECT_GRACE_TIME; +delete process.env.VSCODE_RECONNECT_SHORT_GRACE_TIME; + +const ptyService = new PtyService(lastPtyId, logService, reconnectConstants); server.registerChannel(TerminalIpcChannels.PtyHost, ProxyChannel.fromService(ptyService)); process.once('exit', () => { diff --git a/lib/vscode/src/vs/platform/terminal/node/ptyHostService.ts b/src/vs/platform/terminal/node/ptyHostService.ts similarity index 80% rename from lib/vscode/src/vs/platform/terminal/node/ptyHostService.ts rename to src/vs/platform/terminal/node/ptyHostService.ts index fba6308c4efb..9e00f75b5208 100644 --- a/lib/vscode/src/vs/platform/terminal/node/ptyHostService.ts +++ b/src/vs/platform/terminal/node/ptyHostService.ts @@ -5,7 +5,7 @@ import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; -import { IPtyService, IProcessDataEvent, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError, ITerminalsLayoutInfo, TerminalIpcChannels, IHeartbeatService, HeartbeatConstants, TerminalShellType } from 'vs/platform/terminal/common/terminal'; +import { IPtyService, IProcessDataEvent, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError, ITerminalsLayoutInfo, TerminalIpcChannels, IHeartbeatService, HeartbeatConstants, TerminalShellType, ITerminalProfile, IRequestResolveVariablesEvent, TitleEventSource, TerminalIcon, IReconnectConstants } from 'vs/platform/terminal/common/terminal'; import { Client } from 'vs/base/parts/ipc/node/ipc.cp'; import { FileAccess } from 'vs/base/common/network'; import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; @@ -14,6 +14,9 @@ import { Emitter } from 'vs/base/common/event'; import { LogLevelChannelClient } from 'vs/platform/log/common/logIpc'; import { IGetTerminalLayoutInfoArgs, IProcessDetails, IPtyHostProcessReplayEvent, ISetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { detectAvailableProfiles } from 'vs/platform/terminal/node/terminalProfiles'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { registerTerminalPlatformConfiguration } from 'vs/platform/terminal/common/terminalPlatformConfiguration'; enum Constants { MaxRestarts = 5 @@ -25,6 +28,8 @@ enum Constants { */ let lastPtyId = 0; +let lastResolveVariablesRequestId = 0; + /** * This service implements IPtyService by launching a pty host process, forwarding messages to and * from the pty host process and manages the connection. @@ -51,6 +56,9 @@ export class PtyHostService extends Disposable implements IPtyService { readonly onPtyHostUnresponsive = this._onPtyHostUnresponsive.event; private readonly _onPtyHostResponsive = this._register(new Emitter()); readonly onPtyHostResponsive = this._onPtyHostResponsive.event; + private readonly _onPtyHostRequestResolveVariables = this._register(new Emitter()); + readonly onPtyHostRequestResolveVariables = this._onPtyHostRequestResolveVariables.event; + private readonly _onProcessData = this._register(new Emitter<{ id: number, event: IProcessDataEvent | string }>()); readonly onProcessData = this._onProcessData.event; private readonly _onProcessExit = this._register(new Emitter<{ id: number, event: number | undefined }>()); @@ -71,11 +79,17 @@ export class PtyHostService extends Disposable implements IPtyService { readonly onProcessOrphanQuestion = this._onProcessOrphanQuestion.event; constructor( + private readonly _reconnectConstants: IReconnectConstants, + @IConfigurationService private readonly _configurationService: IConfigurationService, @ILogService private readonly _logService: ILogService, @ITelemetryService private readonly _telemetryService: ITelemetryService ) { super(); + // Platform configuration is required on the process running the pty host (shared process or + // remote server). + registerTerminalPlatformConfiguration(); + this._register(toDisposable(() => this._disposePtyHost())); [this._client, this._proxy] = this._startPtyHost(); @@ -91,7 +105,9 @@ export class PtyHostService extends Disposable implements IPtyService { VSCODE_LAST_PTY_ID: lastPtyId, VSCODE_AMD_ENTRYPOINT: 'vs/platform/terminal/node/ptyHostMain', VSCODE_PIPE_LOGGING: 'true', - VSCODE_VERBOSE_LOGGING: 'true' // transmit console logs from server to client + VSCODE_VERBOSE_LOGGING: 'true', // transmit console logs from server to client, + VSCODE_RECONNECT_GRACE_TIME: this._reconnectConstants.GraceTime, + VSCODE_RECONNECT_SHORT_GRACE_TIME: this._reconnectConstants.ShortGraceTime } } ); @@ -122,6 +138,7 @@ export class PtyHostService extends Disposable implements IPtyService { // Setup logging const logChannel = client.getChannel(TerminalIpcChannels.Log); + LogLevelChannelClient.setLevel(logChannel, this._logService.getLevel()); this._register(this._logService.onDidChangeLogLevel(() => { LogLevelChannelClient.setLevel(logChannel, this._logService.getLevel()); })); @@ -153,6 +170,12 @@ export class PtyHostService extends Disposable implements IPtyService { lastPtyId = Math.max(lastPtyId, id); return id; } + updateTitle(id: number, title: string, titleSource: TitleEventSource): Promise { + return this._proxy.updateTitle(id, title, titleSource); + } + updateIcon(id: number, icon: TerminalIcon, color?: string): Promise { + return this._proxy.updateIcon(id, icon, color); + } attachToProcess(id: number): Promise { return this._proxy.attachToProcess(id); } @@ -199,8 +222,14 @@ export class PtyHostService extends Disposable implements IPtyService { getDefaultSystemShell(osOverride?: OperatingSystem): Promise { return this._proxy.getDefaultSystemShell(osOverride); } - getShellEnvironment(): Promise { - return this._proxy.getShellEnvironment(); + async getProfiles(profiles: unknown, defaultProfile: unknown, includeDetectedProfiles: boolean = false): Promise { + return detectAvailableProfiles(profiles, defaultProfile, includeDetectedProfiles, this._configurationService, undefined, this._logService, this._resolveVariables.bind(this)); + } + getEnvironment(): Promise { + return this._proxy.getEnvironment(); + } + getWslPath(original: string): Promise { + return this._proxy.getWslPath(original); } setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): Promise { @@ -279,4 +308,22 @@ export class PtyHostService extends Disposable implements IPtyService { this._heartbeatSecondTimeout = undefined; } } + + private _pendingResolveVariablesRequests: Map void> = new Map(); + private _resolveVariables(text: string[]): Promise { + return new Promise(resolve => { + const id = ++lastResolveVariablesRequestId; + this._pendingResolveVariablesRequests.set(id, resolve); + this._onPtyHostRequestResolveVariables.fire({ id, originalText: text }); + }); + } + async acceptPtyHostResolvedVariables(id: number, resolved: string[]) { + const request = this._pendingResolveVariablesRequests.get(id); + if (request) { + request(resolved); + this._pendingResolveVariablesRequests.delete(id); + } else { + this._logService.warn(`Resolved variables received without matching request ${id}`); + } + } } diff --git a/lib/vscode/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts similarity index 83% rename from lib/vscode/src/vs/platform/terminal/node/ptyService.ts rename to src/vs/platform/terminal/node/ptyService.ts index 6765dfc376e9..d18817bcf0bf 100644 --- a/lib/vscode/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; -import { IProcessEnvironment, OperatingSystem, OS } from 'vs/base/common/platform'; -import { IPtyService, IProcessDataEvent, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError, LocalReconnectConstants, ITerminalsLayoutInfo, IRawTerminalInstanceLayoutInfo, ITerminalTabLayoutInfoById, ITerminalInstanceLayoutInfoById, TerminalShellType } from 'vs/platform/terminal/common/terminal'; +import { IProcessEnvironment, isWindows, OperatingSystem, OS } from 'vs/base/common/platform'; +import { IPtyService, IProcessDataEvent, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError, ITerminalsLayoutInfo, IRawTerminalInstanceLayoutInfo, ITerminalTabLayoutInfoById, ITerminalInstanceLayoutInfoById, TerminalShellType, IProcessReadyEvent, TitleEventSource, TerminalIcon, IReconnectConstants } from 'vs/platform/terminal/common/terminal'; import { AutoOpenBarrier, Queue, RunOnceScheduler } from 'vs/base/common/async'; import { Emitter } from 'vs/base/common/event'; import { TerminalRecorder } from 'vs/platform/terminal/common/terminalRecorder'; @@ -14,6 +14,10 @@ import { ISetTerminalLayoutInfoArgs, ITerminalTabLayoutInfoDto, IProcessDetails, import { ILogService } from 'vs/platform/log/common/log'; import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering'; import { getSystemShell } from 'vs/base/node/shell'; +import { getWindowsBuildNumber } from 'vs/platform/terminal/node/terminalEnvironment'; +import { execFile } from 'child_process'; +import { escapeNonWindowsPath } from 'vs/platform/terminal/common/terminalEnvironment'; +import { URI } from 'vs/base/common/uri'; type WorkspaceId = string; @@ -47,7 +51,8 @@ export class PtyService extends Disposable implements IPtyService { constructor( private _lastPtyId: number, - private readonly _logService: ILogService + private readonly _logService: ILogService, + private readonly _reconnectConstants: IReconnectConstants ) { super(); @@ -79,10 +84,7 @@ export class PtyService extends Disposable implements IPtyService { throw new Error('Attempt to create a process when attach object was provided'); } const id = ++this._lastPtyId; - /** - * NOTE@coder: pass ID into TerminalProcess to fix compile. - */ - const process = new TerminalProcess(id, shellLaunchConfig, cwd, cols, rows, env, executableEnv, windowsEnableConpty, this._logService); + const process = new TerminalProcess(shellLaunchConfig, cwd, cols, rows, env, executableEnv, windowsEnableConpty, this._logService); process.onProcessData(event => this._onProcessData.fire({ id, event })); process.onProcessExit(event => this._onProcessExit.fire({ id, event })); if (process.onProcessOverrideDimensions) { @@ -91,7 +93,7 @@ export class PtyService extends Disposable implements IPtyService { if (process.onProcessResolvedShellLaunchConfig) { process.onProcessResolvedShellLaunchConfig(event => this._onProcessResolvedShellLaunchConfig.fire({ id, event })); } - const persistentProcess = new PersistentTerminalProcess(id, process, workspaceId, workspaceName, shouldPersist, cols, rows, this._logService, shellLaunchConfig.icon); + const persistentProcess = new PersistentTerminalProcess(id, process, workspaceId, workspaceName, shouldPersist, cols, rows, this._reconnectConstants, this._logService, shellLaunchConfig.icon); process.onProcessExit(() => { persistentProcess.dispose(); this._ptys.delete(id); @@ -114,6 +116,14 @@ export class PtyService extends Disposable implements IPtyService { } } + async updateTitle(id: number, title: string, titleSource: TitleEventSource): Promise { + this._throwIfNoPty(id).setTitle(title, titleSource); + } + + async updateIcon(id: number, icon: URI | { light: URI; dark: URI } | { id: string, color?: { id: string } }, color?: string): Promise { + this._throwIfNoPty(id).setIcon(icon, color); + } + async detachFromProcess(id: number): Promise { this._throwIfNoPty(id).detach(); } @@ -169,10 +179,25 @@ export class PtyService extends Disposable implements IPtyService { return getSystemShell(osOverride, process.env); } - async getShellEnvironment(): Promise { + async getEnvironment(): Promise { return { ...process.env }; } + async getWslPath(original: string): Promise { + if (!isWindows) { + return original; + } + if (getWindowsBuildNumber() < 17063) { + return original.replace(/\\/g, '/'); + } + return new Promise(c => { + const proc = execFile('bash.exe', ['-c', `wslpath ${escapeNonWindowsPath(original)}`], {}, (error, stdout, stderr) => { + c(escapeNonWindowsPath(stdout.trim())); + }); + proc.stdin!.end(); + }); + } + async setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): Promise { this._workspaceLayoutInfos.set(args.workspaceId, args); } @@ -181,10 +206,8 @@ export class PtyService extends Disposable implements IPtyService { const layout = this._workspaceLayoutInfos.get(args.workspaceId); if (layout) { const expandedTabs = await Promise.all(layout.tabs.map(async tab => this._expandTerminalTab(tab))); - const filtered = expandedTabs.filter(t => t.terminals.length > 0); - return { - tabs: filtered - }; + const tabs = expandedTabs.filter(t => t.terminals.length > 0); + return { tabs }; } return undefined; } @@ -222,12 +245,14 @@ export class PtyService extends Disposable implements IPtyService { return { id, title: persistentProcess.title, + titleSource: persistentProcess.titleSource, pid: persistentProcess.pid, workspaceId: persistentProcess.workspaceId, workspaceName: persistentProcess.workspaceName, cwd, isOrphan, - icon: persistentProcess.icon + icon: persistentProcess.icon, + color: persistentProcess.color }; } @@ -257,7 +282,7 @@ export class PersistentTerminalProcess extends Disposable { private readonly _onProcessReplay = this._register(new Emitter()); readonly onProcessReplay = this._onProcessReplay.event; - private readonly _onProcessReady = this._register(new Emitter<{ pid: number, cwd: string }>()); + private readonly _onProcessReady = this._register(new Emitter()); readonly onProcessReady = this._onProcessReady.event; private readonly _onProcessTitleChanged = this._register(new Emitter()); readonly onProcessTitleChanged = this._onProcessTitleChanged.event; @@ -274,33 +299,49 @@ export class PersistentTerminalProcess extends Disposable { private _pid = -1; private _cwd = ''; + private _title: string | undefined; + private _titleSource: TitleEventSource = TitleEventSource.Process; get pid(): number { return this._pid; } - get title(): string { return this._terminalProcess.currentTitle; } - get icon(): string | undefined { return this._icon; } + get title(): string { return this._title || this._terminalProcess.currentTitle; } + get titleSource(): TitleEventSource { return this._titleSource; } + get icon(): TerminalIcon | undefined { return this._icon; } + get color(): string | undefined { return this._color; } + + setTitle(title: string, titleSource: TitleEventSource): void { + this._title = title; + this._titleSource = titleSource; + } + + setIcon(icon: TerminalIcon, color?: string): void { + this._icon = icon; + this._color = color; + } constructor( private _persistentProcessId: number, private readonly _terminalProcess: TerminalProcess, - public readonly workspaceId: string, - public readonly workspaceName: string, - public readonly shouldPersistTerminal: boolean, + readonly workspaceId: string, + readonly workspaceName: string, + readonly shouldPersistTerminal: boolean, cols: number, rows: number, + reconnectConstants: IReconnectConstants, private readonly _logService: ILogService, - private readonly _icon?: string + private _icon?: TerminalIcon, + private _color?: string ) { super(); this._recorder = new TerminalRecorder(cols, rows); this._orphanQuestionBarrier = null; this._orphanQuestionReplyTime = 0; this._disconnectRunner1 = this._register(new RunOnceScheduler(() => { - this._logService.info(`Persistent process "${this._persistentProcessId}": The reconnection grace time of ${printTime(LocalReconnectConstants.ReconnectionGraceTime)} has expired, shutting down pid "${this._pid}"`); + this._logService.info(`Persistent process "${this._persistentProcessId}": The reconnection grace time of ${printTime(reconnectConstants.GraceTime)} has expired, shutting down pid "${this._pid}"`); this.shutdown(true); - }, LocalReconnectConstants.ReconnectionGraceTime)); + }, reconnectConstants.GraceTime)); this._disconnectRunner2 = this._register(new RunOnceScheduler(() => { - this._logService.info(`Persistent process "${this._persistentProcessId}": The short reconnection grace time of ${printTime(LocalReconnectConstants.ReconnectionShortGraceTime)} has expired, shutting down pid ${this._pid}`); + this._logService.info(`Persistent process "${this._persistentProcessId}": The short reconnection grace time of ${printTime(reconnectConstants.ShortGraceTime)} has expired, shutting down pid ${this._pid}`); this.shutdown(true); - }, LocalReconnectConstants.ReconnectionShortGraceTime)); + }, reconnectConstants.ShortGraceTime)); this._register(this._terminalProcess.onProcessReady(e => { this._pid = e.pid; @@ -340,7 +381,7 @@ export class PersistentTerminalProcess extends Disposable { } this._isStarted = true; } else { - this._onProcessReady.fire({ pid: this._pid, cwd: this._cwd }); + this._onProcessReady.fire({ pid: this._pid, cwd: this._cwd, requiresWindowsMode: isWindows && getWindowsBuildNumber() < 21376 }); this._onProcessTitleChanged.fire(this._terminalProcess.currentTitle); this._onProcessShellTypeChanged.fire(this._terminalProcess.shellType); this.triggerReplay(); diff --git a/lib/vscode/src/vs/platform/terminal/node/terminalEnvironment.ts b/src/vs/platform/terminal/node/terminalEnvironment.ts similarity index 100% rename from lib/vscode/src/vs/platform/terminal/node/terminalEnvironment.ts rename to src/vs/platform/terminal/node/terminalEnvironment.ts diff --git a/lib/vscode/src/vs/platform/terminal/node/terminalProcess.ts b/src/vs/platform/terminal/node/terminalProcess.ts similarity index 89% rename from lib/vscode/src/vs/platform/terminal/node/terminalProcess.ts rename to src/vs/platform/terminal/node/terminalProcess.ts index a62b73aca55d..b37b6ab2c15d 100644 --- a/lib/vscode/src/vs/platform/terminal/node/terminalProcess.ts +++ b/src/vs/platform/terminal/node/terminalProcess.ts @@ -9,7 +9,7 @@ import * as fs from 'fs'; import * as os from 'os'; import { Event, Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; -import { IShellLaunchConfig, ITerminalLaunchError, FlowControlConstants, ITerminalChildProcess, ITerminalDimensionsOverride, TerminalShellType } from 'vs/platform/terminal/common/terminal'; +import { IShellLaunchConfig, ITerminalLaunchError, FlowControlConstants, ITerminalChildProcess, ITerminalDimensionsOverride, TerminalShellType, IProcessReadyEvent } from 'vs/platform/terminal/common/terminal'; import { exec } from 'child_process'; import { ILogService } from 'vs/platform/log/common/log'; import { findExecutable, getWindowsBuildNumber } from 'vs/platform/terminal/node/terminalEnvironment'; @@ -18,6 +18,7 @@ import { localize } from 'vs/nls'; import { WindowsShellHelper } from 'vs/platform/terminal/node/windowsShellHelper'; import { IProcessEnvironment, isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; import { timeout } from 'vs/base/common/async'; +import { Promises } from 'vs/base/node/pfs'; // Writing large amounts of data can be corrupted for some reason, after looking into this is // appears to be a race condition around writing to the FD which may be based on how powerful the @@ -68,6 +69,7 @@ interface IWriteObject { } export class TerminalProcess extends Disposable implements ITerminalChildProcess { + readonly id = 0; readonly shouldPersist = false; private static _lastKillOrStart = 0; @@ -75,14 +77,8 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess private _exitCode: number | undefined; private _exitMessage: string | undefined; private _closeTimeout: any; - /** - * NOTE@coder: set _ptyProcess and _currentTitle to protected - * to allow access from subclasses. - * - * We subclass it in src/vs/server/channel.ts - */ - protected _ptyProcess: pty.IPty | undefined; - protected _currentTitle: string = ''; + private _ptyProcess: pty.IPty | undefined; + private _currentTitle: string = ''; private _processStartupComplete: Promise | undefined; private _isDisposed: boolean = false; private _windowsShellHelper: WindowsShellHelper | undefined; @@ -95,25 +91,23 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess private _isPtyPaused: boolean = false; private _unacknowledgedCharCount: number = 0; - public get exitMessage(): string | undefined { return this._exitMessage; } + get exitMessage(): string | undefined { return this._exitMessage; } - public get currentTitle(): string { return this._windowsShellHelper?.shellTitle || this._currentTitle; } - public get shellType(): TerminalShellType { return this._windowsShellHelper ? this._windowsShellHelper.shellType : undefined; } + get currentTitle(): string { return this._windowsShellHelper?.shellTitle || this._currentTitle; } + get shellType(): TerminalShellType { return this._windowsShellHelper ? this._windowsShellHelper.shellType : undefined; } private readonly _onProcessData = this._register(new Emitter()); - public get onProcessData(): Event { return this._onProcessData.event; } + get onProcessData(): Event { return this._onProcessData.event; } private readonly _onProcessExit = this._register(new Emitter()); - public get onProcessExit(): Event { return this._onProcessExit.event; } - private readonly _onProcessReady = this._register(new Emitter<{ pid: number, cwd: string }>()); - public get onProcessReady(): Event<{ pid: number, cwd: string }> { return this._onProcessReady.event; } + get onProcessExit(): Event { return this._onProcessExit.event; } + private readonly _onProcessReady = this._register(new Emitter()); + get onProcessReady(): Event { return this._onProcessReady.event; } private readonly _onProcessTitleChanged = this._register(new Emitter()); - public get onProcessTitleChanged(): Event { return this._onProcessTitleChanged.event; } + get onProcessTitleChanged(): Event { return this._onProcessTitleChanged.event; } private readonly _onProcessShellTypeChanged = this._register(new Emitter()); - public readonly onProcessShellTypeChanged = this._onProcessShellTypeChanged.event; + readonly onProcessShellTypeChanged = this._onProcessShellTypeChanged.event; - // NOTE@coder: add id to constructor constructor( - public readonly id: number = 0, private readonly _shellLaunchConfig: IShellLaunchConfig, cwd: string, cols: number, @@ -171,7 +165,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess onProcessOverrideDimensions?: Event | undefined; onProcessResolvedShellLaunchConfig?: Event | undefined; - public async start(): Promise { + async start(): Promise { const results = await Promise.all([this._validateCwd(), this._validateExecutable()]); const firstError = results.find(r => r !== undefined); if (firstError) { @@ -189,7 +183,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess private async _validateCwd(): Promise { try { - const result = await fs.promises.stat(this._initialCwd); + const result = await Promises.stat(this._initialCwd); if (!result.isDirectory()) { return { message: localize('launchFail.cwdNotDirectory', "Starting directory (cwd) \"{0}\" is not a directory", this._initialCwd.toString()) }; } @@ -207,7 +201,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess throw new Error('IShellLaunchConfig.executable not set'); } try { - const result = await fs.promises.stat(slc.executable); + const result = await Promises.stat(slc.executable); if (!result.isFile() && !result.isSymbolicLink()) { return { message: localize('launchFail.executableIsNotFileOrSymlink', "Path to shell executable \"{0}\" is not a file of a symlink", slc.executable) }; } @@ -246,7 +240,6 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess ptyProcess.pause(); } - // Refire the data event this._onProcessData.fire(data); if (this._closeTimeout) { @@ -258,11 +251,11 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess this._exitCode = e.exitCode; this._queueProcessExit(); }); - this._setupTitlePolling(ptyProcess); this._sendProcessId(ptyProcess.pid); + this._setupTitlePolling(ptyProcess); } - public override dispose(): void { + override dispose(): void { this._isDisposed = true; if (this._titleInterval) { clearInterval(this._titleInterval); @@ -273,7 +266,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess private _setupTitlePolling(ptyProcess: pty.IPty) { // Send initial timeout async to give event listeners a chance to init - setTimeout(() => this._sendProcessTitle(ptyProcess), 0); + setTimeout(() => this._sendProcessTitle(ptyProcess)); // Setup polling for non-Windows, for Windows `process` doesn't change if (!isWindows) { this._titleInterval = setInterval(() => { @@ -332,7 +325,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess } private _sendProcessId(pid: number) { - this._onProcessReady.fire({ pid, cwd: this._initialCwd }); + this._onProcessReady.fire({ pid, cwd: this._initialCwd, requiresWindowsMode: isWindows && getWindowsBuildNumber() < 21376 }); } private _sendProcessTitle(ptyProcess: pty.IPty): void { @@ -343,7 +336,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess this._onProcessTitleChanged.fire(this._currentTitle); } - public shutdown(immediate: boolean): void { + shutdown(immediate: boolean): void { // don't force immediate disposal of the terminal processes on Windows as an additional // mitigation for https://github.com/microsoft/vscode/issues/71966 which causes the pty host // to become unresponsive, disconnecting all terminals across all windows. @@ -363,7 +356,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess } } - public input(data: string, isBinary?: boolean): void { + input(data: string, isBinary?: boolean): void { if (this._isDisposed || !this._ptyProcess) { return; } @@ -377,7 +370,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess this._startWrite(); } - public async processBinary(data: string): Promise { + async processBinary(data: string): Promise { this.input(data, true); } @@ -411,7 +404,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess } } - public resize(cols: number, rows: number): void { + resize(cols: number, rows: number): void { if (this._isDisposed) { return; } @@ -444,7 +437,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess } } - public acknowledgeDataEvent(charCount: number): void { + acknowledgeDataEvent(charCount: number): void { // Prevent lower than 0 to heal from errors this._unacknowledgedCharCount = Math.max(this._unacknowledgedCharCount - charCount, 0); this._logService.trace(`Flow control: Ack ${charCount} chars (unacknowledged: ${this._unacknowledgedCharCount})`); @@ -455,7 +448,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess } } - public clearUnacknowledgedChars(): void { + clearUnacknowledgedChars(): void { this._unacknowledgedCharCount = 0; this._logService.trace(`Flow control: Cleared all unacknowledged chars, forcing resume`); if (this._isPtyPaused) { @@ -464,11 +457,11 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess } } - public getInitialCwd(): Promise { + getInitialCwd(): Promise { return Promise.resolve(this._initialCwd); } - public getCwd(): Promise { + getCwd(): Promise { if (isMacintosh) { // Disable cwd lookup on macOS Big Sur due to spawn blocking thread (darwin v20 is macOS // Big Sur) https://github.com/Microsoft/vscode/issues/105446 @@ -513,7 +506,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess }); } - public getLatency(): Promise { + getLatency(): Promise { return Promise.resolve(0); } } @@ -522,12 +515,12 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess * Tracks the latest resize event to be trigger at a later point. */ class DelayedResizer extends Disposable { - public rows: number | undefined; - public cols: number | undefined; + rows: number | undefined; + cols: number | undefined; private _timeout: NodeJS.Timeout; private readonly _onTrigger = this._register(new Emitter<{ rows?: number, cols?: number }>()); - public get onTrigger(): Event<{ rows?: number, cols?: number }> { return this._onTrigger.event; } + get onTrigger(): Event<{ rows?: number, cols?: number }> { return this._onTrigger.event; } constructor() { super(); diff --git a/src/vs/platform/terminal/node/terminalProfiles.ts b/src/vs/platform/terminal/node/terminalProfiles.ts new file mode 100644 index 000000000000..3096641c5ded --- /dev/null +++ b/src/vs/platform/terminal/node/terminalProfiles.ts @@ -0,0 +1,362 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { normalize, basename, delimiter } from 'vs/base/common/path'; +import { enumeratePowerShellInstallations } from 'vs/base/node/powershell'; +import { findExecutable, getWindowsBuildNumber } from 'vs/platform/terminal/node/terminalEnvironment'; +import * as cp from 'child_process'; +import { ILogService } from 'vs/platform/log/common/log'; +import * as pfs from 'vs/base/node/pfs'; +import { ITerminalEnvironment, ITerminalProfile, ITerminalProfileObject, ProfileSource, TerminalSettingId } from 'vs/platform/terminal/common/terminal'; +import { Codicon } from 'vs/base/common/codicons'; +import { isLinux, isWindows } from 'vs/base/common/platform'; +import { ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { URI } from 'vs/base/common/uri'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; + +let profileSources: Map | undefined; + +export function detectAvailableProfiles( + profiles: unknown, + defaultProfile: unknown, + includeDetectedProfiles: boolean, + configurationService: IConfigurationService, + fsProvider?: IFsProvider, + logService?: ILogService, + variableResolver?: (text: string[]) => Promise, + testPaths?: string[] +): Promise { + fsProvider = fsProvider || { + existsFile: pfs.SymlinkSupport.existsFile, + readFile: pfs.Promises.readFile + }; + if (isWindows) { + return detectAvailableWindowsProfiles( + includeDetectedProfiles, + fsProvider, + logService, + configurationService.getValue(TerminalSettingId.UseWslProfiles) !== false, + profiles && typeof profiles === 'object' ? { ...profiles } : configurationService.getValue<{ [key: string]: ITerminalProfileObject }>(TerminalSettingId.ProfilesWindows), + typeof defaultProfile === 'string' ? defaultProfile : configurationService.getValue(TerminalSettingId.DefaultProfileWindows), + testPaths, + variableResolver + ); + } + return detectAvailableUnixProfiles( + fsProvider, + logService, + includeDetectedProfiles, + profiles && typeof profiles === 'object' ? { ...profiles } : configurationService.getValue<{ [key: string]: ITerminalProfileObject }>(isLinux ? TerminalSettingId.ProfilesLinux : TerminalSettingId.ProfilesMacOs), + typeof defaultProfile === 'string' ? defaultProfile : configurationService.getValue(isLinux ? TerminalSettingId.DefaultProfileLinux : TerminalSettingId.DefaultProfileMacOs), + testPaths, + variableResolver + ); +} + +async function detectAvailableWindowsProfiles( + includeDetectedProfiles: boolean, + fsProvider: IFsProvider, + logService?: ILogService, + useWslProfiles?: boolean, + configProfiles?: { [key: string]: ITerminalProfileObject }, + defaultProfileName?: string, + testPaths?: string[], + variableResolver?: (text: string[]) => Promise +): Promise { + // Determine the correct System32 path. We want to point to Sysnative + // when the 32-bit version of VS Code is running on a 64-bit machine. + // The reason for this is because PowerShell's important PSReadline + // module doesn't work if this is not the case. See #27915. + const is32ProcessOn64Windows = process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'); + const system32Path = `${process.env['windir']}\\${is32ProcessOn64Windows ? 'Sysnative' : 'System32'}`; + + let useWSLexe = false; + + if (getWindowsBuildNumber() >= 16299) { + useWSLexe = true; + } + + await initializeWindowsProfiles(testPaths); + + const detectedProfiles: Map = new Map(); + + // Add auto detected profiles + if (includeDetectedProfiles) { + detectedProfiles.set('PowerShell', { + source: ProfileSource.Pwsh, + icon: Codicon.terminalPowershell, + isAutoDetected: true + }); + detectedProfiles.set('Windows PowerShell', { + path: `${system32Path}\\WindowsPowerShell\\v1.0\\powershell.exe`, + icon: Codicon.terminalPowershell, + isAutoDetected: true + }); + detectedProfiles.set('Git Bash', { + source: ProfileSource.GitBash, + isAutoDetected: true + }); + detectedProfiles.set('Cygwin', { + path: [ + `${process.env['HOMEDRIVE']}\\cygwin64\\bin\\bash.exe`, + `${process.env['HOMEDRIVE']}\\cygwin\\bin\\bash.exe` + ], + args: ['--login'], + isAutoDetected: true + }); + detectedProfiles.set('Command Prompt', { + path: `${system32Path}\\cmd.exe`, + icon: Codicon.terminalCmd, + isAutoDetected: true + }); + } + + applyConfigProfilesToMap(configProfiles, detectedProfiles); + + const resultProfiles: ITerminalProfile[] = await transformToTerminalProfiles(detectedProfiles.entries(), defaultProfileName, fsProvider, logService, variableResolver); + + if (includeDetectedProfiles || (!includeDetectedProfiles && useWslProfiles)) { + try { + const result = await getWslProfiles(`${system32Path}\\${useWSLexe ? 'wsl' : 'bash'}.exe`, defaultProfileName); + for (const wslProfile of result) { + if (!configProfiles || !(wslProfile.profileName in configProfiles)) { + resultProfiles.push(wslProfile); + } + } + } catch (e) { + logService?.info('WSL is not installed, so could not detect WSL profiles'); + } + } + + return resultProfiles; +} + +async function transformToTerminalProfiles( + entries: IterableIterator<[string, ITerminalProfileObject]>, + defaultProfileName: string | undefined, + fsProvider: IFsProvider, + logService?: ILogService, + variableResolver?: (text: string[]) => Promise +): Promise { + const resultProfiles: ITerminalProfile[] = []; + for (const [profileName, profile] of entries) { + if (profile === null) { continue; } + let originalPaths: string[]; + let args: string[] | string | undefined; + let icon: ThemeIcon | URI | { light: URI, dark: URI } | undefined = undefined; + if ('source' in profile) { + const source = profileSources?.get(profile.source); + if (!source) { + continue; + } + originalPaths = source.paths; + + // if there are configured args, override the default ones + args = profile.args || source.args; + if (profile.icon) { + icon = profile.icon; + } else if (source.icon) { + icon = source.icon; + } + } else { + originalPaths = Array.isArray(profile.path) ? profile.path : [profile.path]; + args = isWindows ? profile.args : Array.isArray(profile.args) ? profile.args : undefined; + icon = profile.icon || undefined; + } + + const paths = (await variableResolver?.(originalPaths)) || originalPaths.slice(); + const validatedProfile = await validateProfilePaths(profileName, defaultProfileName, paths, fsProvider, args, profile.env, profile.overrideName, profile.isAutoDetected, logService); + if (validatedProfile) { + validatedProfile.isAutoDetected = profile.isAutoDetected; + validatedProfile.icon = icon; + validatedProfile.color = profile.color; + resultProfiles.push(validatedProfile); + } else { + logService?.trace('profile not validated', profileName, originalPaths); + } + } + return resultProfiles; +} + +async function initializeWindowsProfiles(testPaths?: string[]): Promise { + if (profileSources) { + return; + } + + profileSources = new Map(); + profileSources.set( + 'Git Bash', { + profileName: 'Git Bash', + paths: [ + `${process.env['ProgramW6432']}\\Git\\bin\\bash.exe`, + `${process.env['ProgramW6432']}\\Git\\usr\\bin\\bash.exe`, + `${process.env['ProgramFiles']}\\Git\\bin\\bash.exe`, + `${process.env['ProgramFiles']}\\Git\\usr\\bin\\bash.exe`, + `${process.env['LocalAppData']}\\Programs\\Git\\bin\\bash.exe`, + `${process.env['UserProfile']}\\scoop\\apps\\git-with-openssh\\current\\bin\\bash.exe`, + `${process.env['AllUsersProfile']}\\scoop\\apps\\git-with-openssh\\current\\bin\\bash.exe` + ], + args: ['--login'] + }); + profileSources.set('PowerShell', { + profileName: 'PowerShell', + paths: testPaths || await getPowershellPaths(), + icon: ThemeIcon.asThemeIcon(Codicon.terminalPowershell) + }); +} + +async function getPowershellPaths(): Promise { + const paths: string[] = []; + // Add all of the different kinds of PowerShells + for await (const pwshExe of enumeratePowerShellInstallations()) { + paths.push(pwshExe.exePath); + } + return paths; +} + +async function getWslProfiles(wslPath: string, defaultProfileName: string | undefined): Promise { + const profiles: ITerminalProfile[] = []; + const distroOutput = await new Promise((resolve, reject) => { + // wsl.exe output is encoded in utf16le (ie. A -> 0x4100) + cp.exec('wsl.exe -l -q', { encoding: 'utf16le' }, (err, stdout) => { + if (err) { + return reject('Problem occurred when getting wsl distros'); + } + resolve(stdout); + }); + }); + if (!distroOutput) { + return []; + } + const regex = new RegExp(/[\r?\n]/); + const distroNames = distroOutput.split(regex).filter(t => t.trim().length > 0 && t !== ''); + for (const distroName of distroNames) { + // Skip empty lines + if (distroName === '') { + continue; + } + + // docker-desktop and docker-desktop-data are treated as implementation details of + // Docker Desktop for Windows and therefore not exposed + if (distroName.startsWith('docker-desktop')) { + continue; + } + + // Create the profile, adding the icon depending on the distro + const profileName = `${distroName} (WSL)`; + const profile: ITerminalProfile = { + profileName, + path: wslPath, + args: [`-d`, `${distroName}`], + isDefault: profileName === defaultProfileName, + icon: getWslIcon(distroName) + }; + // Add the profile + profiles.push(profile); + } + return profiles; +} + +function getWslIcon(distroName: string): ThemeIcon { + if (distroName.includes('Ubuntu')) { + return ThemeIcon.asThemeIcon(Codicon.terminalUbuntu); + } else if (distroName.includes('Debian')) { + return ThemeIcon.asThemeIcon(Codicon.terminalDebian); + } else { + return ThemeIcon.asThemeIcon(Codicon.terminalLinux); + } +} + +async function detectAvailableUnixProfiles( + fsProvider: IFsProvider, + logService?: ILogService, + includeDetectedProfiles?: boolean, + configProfiles?: { [key: string]: ITerminalProfileObject }, + defaultProfileName?: string, + testPaths?: string[], + variableResolver?: (text: string[]) => Promise +): Promise { + const detectedProfiles: Map = new Map(); + + // Add non-quick launch profiles + if (includeDetectedProfiles) { + const contents = (await fsProvider.readFile('/etc/shells')).toString(); + const profiles = testPaths || contents.split('\n').filter(e => e.trim().indexOf('#') !== 0 && e.trim().length > 0); + const counts: Map = new Map(); + for (const profile of profiles) { + let profileName = basename(profile); + let count = counts.get(profileName) || 0; + count++; + if (count > 1) { + profileName = `${profileName} (${count})`; + } + counts.set(profileName, count); + detectedProfiles.set(profileName, { path: profile, isAutoDetected: true }); + } + } + + applyConfigProfilesToMap(configProfiles, detectedProfiles); + + return await transformToTerminalProfiles(detectedProfiles.entries(), defaultProfileName, fsProvider, logService, variableResolver); +} + +function applyConfigProfilesToMap(configProfiles: { [key: string]: ITerminalProfileObject } | undefined, profilesMap: Map) { + if (!configProfiles) { + return; + } + for (const [profileName, value] of Object.entries(configProfiles)) { + if (value === null || (!('path' in value) && !('source' in value))) { + profilesMap.delete(profileName); + } else { + profilesMap.set(profileName, value); + } + } +} + +async function validateProfilePaths(profileName: string, defaultProfileName: string | undefined, potentialPaths: string[], fsProvider: IFsProvider, args?: string[] | string, env?: ITerminalEnvironment, overrideName?: boolean, isAutoDetected?: boolean, logService?: ILogService): Promise { + if (potentialPaths.length === 0) { + return Promise.resolve(undefined); + } + const path = potentialPaths.shift()!; + if (path === '') { + return validateProfilePaths(profileName, defaultProfileName, potentialPaths, fsProvider, args, env, overrideName, isAutoDetected); + } + + const profile: ITerminalProfile = { profileName, path, args, env, overrideName, isAutoDetected, isDefault: profileName === defaultProfileName }; + + // For non-absolute paths, check if it's available on $PATH + if (basename(path) === path) { + // The executable isn't an absolute path, try find it on the PATH + const envPaths: string[] | undefined = process.env.PATH ? process.env.PATH.split(delimiter) : undefined; + const executable = await findExecutable(path, undefined, envPaths, undefined, fsProvider.existsFile); + if (!executable) { + return validateProfilePaths(profileName, defaultProfileName, potentialPaths, fsProvider, args); + } + return profile; + } + + const result = await fsProvider.existsFile(normalize(path)); + if (result) { + return profile; + } + + return validateProfilePaths(profileName, defaultProfileName, potentialPaths, fsProvider, args, env, overrideName, isAutoDetected); +} + +export interface IFsProvider { + existsFile(path: string): Promise, + readFile(path: string): Promise; +} + +export interface IProfileVariableResolver { + resolve(text: string[]): Promise; +} + +interface IPotentialTerminalProfile { + profileName: string; + paths: string[]; + args?: string[]; + icon?: ThemeIcon | URI | { light: URI, dark: URI }; +} diff --git a/lib/vscode/src/vs/platform/terminal/node/windowsShellHelper.ts b/src/vs/platform/terminal/node/windowsShellHelper.ts similarity index 90% rename from lib/vscode/src/vs/platform/terminal/node/windowsShellHelper.ts rename to src/vs/platform/terminal/node/windowsShellHelper.ts index 64c3d205db2a..efa33b6e5f6f 100644 --- a/lib/vscode/src/vs/platform/terminal/node/windowsShellHelper.ts +++ b/src/vs/platform/terminal/node/windowsShellHelper.ts @@ -38,15 +38,15 @@ export class WindowsShellHelper extends Disposable implements IWindowsShellHelpe private _isDisposed: boolean; private _currentRequest: Promise | undefined; private _shellType: TerminalShellType | undefined; - public get shellType(): TerminalShellType | undefined { return this._shellType; } + get shellType(): TerminalShellType | undefined { return this._shellType; } private _shellTitle: string = ''; - public get shellTitle(): string { return this._shellTitle; } + get shellTitle(): string { return this._shellTitle; } private readonly _onShellNameChanged = new Emitter(); - public get onShellNameChanged(): Event { return this._onShellNameChanged.event; } + get onShellNameChanged(): Event { return this._onShellNameChanged.event; } private readonly _onShellTypeChanged = new Emitter(); - public get onShellTypeChanged(): Event { return this._onShellTypeChanged.event; } + get onShellTypeChanged(): Event { return this._onShellTypeChanged.event; } - public constructor( + constructor( private _rootProcessId: number ) { super(); @@ -112,7 +112,7 @@ export class WindowsShellHelper extends Disposable implements IWindowsShellHelpe return this.traverseTree(tree.children[favouriteChild]); } - public override dispose(): void { + override dispose(): void { this._isDisposed = true; super.dispose(); } @@ -120,7 +120,7 @@ export class WindowsShellHelper extends Disposable implements IWindowsShellHelpe /** * Returns the innermost shell executable running in the terminal */ - public getShellName(): Promise { + getShellName(): Promise { if (this._isDisposed) { return Promise.resolve(''); } @@ -141,7 +141,7 @@ export class WindowsShellHelper extends Disposable implements IWindowsShellHelpe return this._currentRequest; } - public getShellType(executable: string): TerminalShellType { + getShellType(executable: string): TerminalShellType { switch (executable.toLowerCase()) { case 'cmd.exe': return WindowsShellType.CommandPrompt; diff --git a/lib/vscode/src/vs/platform/terminal/test/common/terminalRecorder.test.ts b/src/vs/platform/terminal/test/common/terminalRecorder.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/terminal/test/common/terminalRecorder.test.ts rename to src/vs/platform/terminal/test/common/terminalRecorder.test.ts diff --git a/lib/vscode/src/vs/platform/theme/browser/iconsStyleSheet.ts b/src/vs/platform/theme/browser/iconsStyleSheet.ts similarity index 100% rename from lib/vscode/src/vs/platform/theme/browser/iconsStyleSheet.ts rename to src/vs/platform/theme/browser/iconsStyleSheet.ts diff --git a/lib/vscode/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts similarity index 93% rename from lib/vscode/src/vs/platform/theme/common/colorRegistry.ts rename to src/vs/platform/theme/common/colorRegistry.ts index 0d0f8683aef0..1cea9bb26d81 100644 --- a/lib/vscode/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -11,6 +11,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import * as nls from 'vs/nls'; import { Extensions as JSONExtensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { RunOnceScheduler } from 'vs/base/common/async'; +import { assertNever } from 'vs/base/common/types'; // ------ API types @@ -24,11 +25,21 @@ export interface ColorContribution { readonly deprecationMessage: string | undefined; } - -export interface ColorFunction { - (theme: IColorTheme): Color | undefined; +export const enum ColorTransformType { + Darken, + Lighten, + Transparent, + OneOf, + LessProminent, } +export type ColorTransform = + | { op: ColorTransformType.Darken; value: ColorValue; factor: number } + | { op: ColorTransformType.Lighten; value: ColorValue; factor: number } + | { op: ColorTransformType.Transparent; value: ColorValue; factor: number } + | { op: ColorTransformType.OneOf; values: readonly ColorValue[] } + | { op: ColorTransformType.LessProminent; value: ColorValue; background: ColorValue; factor: number; transparency: number }; + export interface ColorDefaults { light: ColorValue | null; dark: ColorValue | null; @@ -38,7 +49,7 @@ export interface ColorDefaults { /** * A Color Value is either a color literal, a reference to an other color or a derived color */ -export type ColorValue = Color | string | ColorIdentifier | ColorFunction; +export type ColorValue = Color | string | ColorIdentifier | ColorTransform; // color registry export const Extensions = { @@ -344,8 +355,8 @@ export const editorActiveLinkForeground = registerColor('editorLink.activeForegr /** * Inline hints */ -export const editorInlineHintForeground = registerColor('editorInlineHint.foreground', { dark: editorWidgetBackground, light: editorWidgetForeground, hc: editorWidgetBackground }, nls.localize('editorInlineHintForeground', 'Foreground color of inline hints')); -export const editorInlineHintBackground = registerColor('editorInlineHint.background', { dark: editorWidgetForeground, light: editorWidgetBackground, hc: editorWidgetForeground }, nls.localize('editorInlineHintBackground', 'Background color of inline hints')); +export const editorInlayHintForeground = registerColor('editorInlayHint.foreground', { dark: editorWidgetBackground, light: editorWidgetForeground, hc: editorWidgetBackground }, nls.localize('editorInlayHintForeground', 'Foreground color of inline hints')); +export const editorInlayHintBackground = registerColor('editorInlayHint.background', { dark: editorWidgetForeground, light: editorWidgetBackground, hc: editorWidgetForeground }, nls.localize('editorInlayHintBackground', 'Background color of inline hints')); /** * Editor lighbulb icon colors @@ -383,7 +394,8 @@ export const listInactiveFocusOutline = registerColor('list.inactiveFocusOutline export const listHoverBackground = registerColor('list.hoverBackground', { dark: '#2A2D2E', light: '#F0F0F0', hc: null }, nls.localize('listHoverBackground', "List/Tree background when hovering over items using the mouse.")); export const listHoverForeground = registerColor('list.hoverForeground', { dark: null, light: null, hc: null }, nls.localize('listHoverForeground', "List/Tree foreground when hovering over items using the mouse.")); export const listDropBackground = registerColor('list.dropBackground', { dark: '#062F4A', light: '#D6EBFF', hc: null }, nls.localize('listDropBackground', "List/Tree drag and drop background when moving items around using the mouse.")); -export const listHighlightForeground = registerColor('list.highlightForeground', { dark: '#0097fb', light: '#0066BF', hc: focusBorder }, nls.localize('highlight', 'List/Tree foreground color of the match highlights when searching inside the list/tree.')); +export const listHighlightForeground = registerColor('list.highlightForeground', { dark: '#18A3FF', light: '#0066BF', hc: focusBorder }, nls.localize('highlight', 'List/Tree foreground color of the match highlights when searching inside the list/tree.')); +export const listFocusHighlightForeground = registerColor('list.focusHighlightForeground', { dark: listHighlightForeground, light: listHighlightForeground, hc: listHighlightForeground }, nls.localize('listFocusHighlightForeground', 'List/Tree foreground color of the match highlights on actively focused items when searching inside the list/tree.')); export const listInvalidItemForeground = registerColor('list.invalidItemForeground', { dark: '#B89500', light: '#B89500', hc: '#B89500' }, nls.localize('invalidItemForeground', 'List/Tree foreground color for invalid items, for example an unresolved root in explorer.')); export const listErrorForeground = registerColor('list.errorForeground', { dark: '#F88070', light: '#B01011', hc: null }, nls.localize('listErrorForeground', 'Foreground color of list items containing errors.')); export const listWarningForeground = registerColor('list.warningForeground', { dark: '#CCA700', light: '#855F00', hc: null }, nls.localize('listWarningForeground', 'Foreground color of list items containing warnings.')); @@ -400,7 +412,8 @@ export const listDeemphasizedForeground = registerColor('list.deemphasizedForegr * Quick pick widget (dependent on List and tree colors) */ export const _deprecatedQuickInputListFocusBackground = registerColor('quickInput.list.focusBackground', { dark: null, light: null, hc: null }, '', undefined, nls.localize('quickInput.list.focusBackground deprecation', "Please use quickInputList.focusBackground instead")); -export const quickInputListFocusBackground = registerColor('quickInputList.focusBackground', { dark: oneOf(_deprecatedQuickInputListFocusBackground, listFocusBackground, '#062F4A'), light: oneOf(_deprecatedQuickInputListFocusBackground, listFocusBackground, '#D6EBFF'), hc: null }, nls.localize('quickInput.listFocusBackground', "Quick picker background color for the focused item.")); +export const quickInputListFocusForeground = registerColor('quickInputList.focusForeground', { dark: listActiveSelectionForeground, light: listActiveSelectionForeground, hc: listActiveSelectionForeground }, nls.localize('quickInput.listFocusForeground', "Quick picker foreground color for the focused item.")); +export const quickInputListFocusBackground = registerColor('quickInputList.focusBackground', { dark: oneOf(_deprecatedQuickInputListFocusBackground, listActiveSelectionBackground, '#062F4A'), light: oneOf(_deprecatedQuickInputListFocusBackground, listActiveSelectionBackground, '#D6EBFF'), hc: null }, nls.localize('quickInput.listFocusBackground', "Quick picker background color for the focused item.")); /** * Menu colors @@ -493,63 +506,63 @@ export const chartsPurple = registerColor('charts.purple', { dark: '#B180D7', li // ----- color functions -export function darken(colorValue: ColorValue, factor: number): ColorFunction { - return (theme) => { - let color = resolveColorValue(colorValue, theme); - if (color) { - return color.darken(factor); - } - return undefined; - }; +export function executeTransform(transform: ColorTransform, theme: IColorTheme) { + switch (transform.op) { + case ColorTransformType.Darken: + return resolveColorValue(transform.value, theme)?.darken(transform.factor); + + case ColorTransformType.Lighten: + return resolveColorValue(transform.value, theme)?.lighten(transform.factor); + + case ColorTransformType.Transparent: + return resolveColorValue(transform.value, theme)?.transparent(transform.factor); + + case ColorTransformType.OneOf: + for (const candidate of transform.values) { + const color = resolveColorValue(candidate, theme); + if (color) { + return color; + } + } + return undefined; + + case ColorTransformType.LessProminent: + const from = resolveColorValue(transform.value, theme); + if (!from) { + return undefined; + } + + const backgroundColor = resolveColorValue(transform.background, theme); + if (!backgroundColor) { + return from.transparent(transform.factor * transform.transparency); + } + + return from.isDarkerThan(backgroundColor) + ? Color.getLighterColor(from, backgroundColor, transform.factor).transparent(transform.transparency) + : Color.getDarkerColor(from, backgroundColor, transform.factor).transparent(transform.transparency); + default: + throw assertNever(transform); + } } -export function lighten(colorValue: ColorValue, factor: number): ColorFunction { - return (theme) => { - let color = resolveColorValue(colorValue, theme); - if (color) { - return color.lighten(factor); - } - return undefined; - }; +export function darken(colorValue: ColorValue, factor: number): ColorTransform { + return { op: ColorTransformType.Darken, value: colorValue, factor }; } -export function transparent(colorValue: ColorValue, factor: number): ColorFunction { - return (theme) => { - let color = resolveColorValue(colorValue, theme); - if (color) { - return color.transparent(factor); - } - return undefined; - }; +export function lighten(colorValue: ColorValue, factor: number): ColorTransform { + return { op: ColorTransformType.Lighten, value: colorValue, factor }; } -export function oneOf(...colorValues: ColorValue[]): ColorFunction { - return (theme) => { - for (let colorValue of colorValues) { - let color = resolveColorValue(colorValue, theme); - if (color) { - return color; - } - } - return undefined; - }; +export function transparent(colorValue: ColorValue, factor: number): ColorTransform { + return { op: ColorTransformType.Transparent, value: colorValue, factor }; } -function lessProminent(colorValue: ColorValue, backgroundColorValue: ColorValue, factor: number, transparency: number): ColorFunction { - return (theme) => { - let from = resolveColorValue(colorValue, theme); - if (from) { - let backgroundColor = resolveColorValue(backgroundColorValue, theme); - if (backgroundColor) { - if (from.isDarkerThan(backgroundColor)) { - return Color.getLighterColor(from, backgroundColor, factor).transparent(transparency); - } - return Color.getDarkerColor(from, backgroundColor, factor).transparent(transparency); - } - return from.transparent(factor * transparency); - } - return undefined; - }; +export function oneOf(...colorValues: ColorValue[]): ColorTransform { + return { op: ColorTransformType.OneOf, values: colorValues }; +} + +function lessProminent(colorValue: ColorValue, backgroundColorValue: ColorValue, factor: number, transparency: number): ColorTransform { + return { op: ColorTransformType.LessProminent, value: colorValue, background: backgroundColorValue, factor, transparency }; } // ----- implementation @@ -567,8 +580,8 @@ export function resolveColorValue(colorValue: ColorValue | null, theme: IColorTh return theme.getColor(colorValue); } else if (colorValue instanceof Color) { return colorValue; - } else if (typeof colorValue === 'function') { - return colorValue(theme); + } else if (typeof colorValue === 'object') { + return executeTransform(colorValue, theme); } return undefined; } diff --git a/lib/vscode/src/vs/platform/theme/common/iconRegistry.ts b/src/vs/platform/theme/common/iconRegistry.ts similarity index 100% rename from lib/vscode/src/vs/platform/theme/common/iconRegistry.ts rename to src/vs/platform/theme/common/iconRegistry.ts diff --git a/lib/vscode/src/vs/platform/theme/common/styler.ts b/src/vs/platform/theme/common/styler.ts similarity index 90% rename from lib/vscode/src/vs/platform/theme/common/styler.ts rename to src/vs/platform/theme/common/styler.ts index 9827da48c836..6962116082c9 100644 --- a/lib/vscode/src/vs/platform/theme/common/styler.ts +++ b/src/vs/platform/theme/common/styler.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService'; -import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, inputActiveOptionForeground, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listDropBackground, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, ColorFunction, badgeBackground, badgeForeground, progressBarBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionForeground, breadcrumbsBackground, editorWidgetBorder, inputValidationInfoForeground, inputValidationWarningForeground, inputValidationErrorForeground, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuBorder, menuSeparatorBackground, listFilterWidgetOutline, listFilterWidgetNoMatchesOutline, listFilterWidgetBackground, editorWidgetBackground, treeIndentGuidesStroke, editorWidgetForeground, simpleCheckboxBackground, simpleCheckboxBorder, simpleCheckboxForeground, ColorValue, resolveColorValue, textLinkForeground, problemsWarningIconForeground, problemsErrorIconForeground, problemsInfoIconForeground, buttonSecondaryBackground, buttonSecondaryForeground, buttonSecondaryHoverBackground, listFocusOutline, listInactiveFocusOutline, tableColumnsBorder, quickInputListFocusBackground, buttonBorder, keybindingLabelForeground, keybindingLabelBackground, keybindingLabelBorder, keybindingLabelBottomBorder } from 'vs/platform/theme/common/colorRegistry'; +import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, inputActiveOptionForeground, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listDropBackground, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, badgeBackground, badgeForeground, progressBarBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionForeground, breadcrumbsBackground, editorWidgetBorder, inputValidationInfoForeground, inputValidationWarningForeground, inputValidationErrorForeground, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuBorder, menuSeparatorBackground, listFilterWidgetOutline, listFilterWidgetNoMatchesOutline, listFilterWidgetBackground, editorWidgetBackground, treeIndentGuidesStroke, editorWidgetForeground, simpleCheckboxBackground, simpleCheckboxBorder, simpleCheckboxForeground, ColorValue, resolveColorValue, textLinkForeground, problemsWarningIconForeground, problemsErrorIconForeground, problemsInfoIconForeground, buttonSecondaryBackground, buttonSecondaryForeground, buttonSecondaryHoverBackground, listFocusOutline, listInactiveFocusOutline, tableColumnsBorder, quickInputListFocusBackground, buttonBorder, keybindingLabelForeground, keybindingLabelBackground, keybindingLabelBorder, keybindingLabelBottomBorder, quickInputListFocusForeground, ColorTransform } from 'vs/platform/theme/common/colorRegistry'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Color } from 'vs/base/common/color'; import { IThemable, styleFn } from 'vs/base/common/styler'; @@ -35,7 +35,7 @@ export function computeStyles(theme: IColorTheme, styleMap: IColorMapping): ICom } export function attachStyler(themeService: IThemeService, styleMap: T, widgetOrCallback: IThemable | styleFn): IDisposable { - function applyStyles(theme: IColorTheme): void { + function applyStyles(): void { const styles = computeStyles(themeService.getColorTheme(), styleMap); if (typeof widgetOrCallback === 'function') { @@ -45,7 +45,7 @@ export function attachStyler(themeService: IThemeServic } } - applyStyles(themeService.getColorTheme()); + applyStyles(); return themeService.onDidColorThemeChange(applyStyles); } @@ -130,7 +130,7 @@ export function attachSelectBoxStyler(widget: IThemable, themeService: IThemeSer selectBorder: style?.selectBorder || selectBorder, focusBorder: style?.focusBorder || focusBorder, listFocusBackground: style?.listFocusBackground || quickInputListFocusBackground, - listFocusForeground: style?.listFocusForeground || listFocusForeground, + listFocusForeground: style?.listFocusForeground || quickInputListFocusForeground, listFocusOutline: style?.listFocusOutline || ((theme: IColorTheme) => theme.type === ColorScheme.HIGH_CONTRAST ? activeContrastBorder : Color.transparent), listHoverBackground: style?.listHoverBackground || listHoverBackground, listHoverForeground: style?.listHoverForeground || listHoverForeground, @@ -254,16 +254,6 @@ export function attachKeybindingLabelStyler(widget: IThemable, themeService: ITh } as IKeybindingLabelStyleOverrides, widget); } -export interface ILinkStyleOverrides extends IStyleOverrides { - textLinkForeground?: ColorIdentifier; -} - -export function attachLinkStyler(widget: IThemable, themeService: IThemeService, style?: ILinkStyleOverrides): IDisposable { - return attachStyler(themeService, { - textLinkForeground: style?.textLinkForeground || textLinkForeground, - } as ILinkStyleOverrides, widget); -} - export interface IProgressBarStyleOverrides extends IStyleOverrides { progressBarBackground?: ColorIdentifier; } @@ -279,7 +269,7 @@ export function attachStylerCallback(themeService: IThemeService, colors: { [nam } export interface IBreadcrumbsWidgetStyleOverrides extends IColorMapping { - breadcrumbsBackground?: ColorIdentifier | ColorFunction; + breadcrumbsBackground?: ColorIdentifier | ColorTransform; breadcrumbsForeground?: ColorIdentifier; breadcrumbsHoverForeground?: ColorIdentifier; breadcrumbsFocusForeground?: ColorIdentifier; @@ -324,7 +314,7 @@ export function attachMenuStyler(widget: IThemable, themeService: IThemeService, return attachStyler(themeService, { ...defaultMenuStyles, ...style }, widget); } -export interface IDialogStyleOverrides extends IButtonStyleOverrides, ILinkStyleOverrides { +export interface IDialogStyleOverrides extends IButtonStyleOverrides { dialogForeground?: ColorIdentifier; dialogBackground?: ColorIdentifier; dialogShadow?: ColorIdentifier; diff --git a/lib/vscode/src/vs/platform/theme/common/theme.ts b/src/vs/platform/theme/common/theme.ts similarity index 100% rename from lib/vscode/src/vs/platform/theme/common/theme.ts rename to src/vs/platform/theme/common/theme.ts diff --git a/lib/vscode/src/vs/platform/theme/common/themeService.ts b/src/vs/platform/theme/common/themeService.ts similarity index 98% rename from lib/vscode/src/vs/platform/theme/common/themeService.ts rename to src/vs/platform/theme/common/themeService.ts index 4032bab91fc0..9867c464ae36 100644 --- a/lib/vscode/src/vs/platform/theme/common/themeService.ts +++ b/src/vs/platform/theme/common/themeService.ts @@ -67,6 +67,10 @@ export namespace ThemeIcon { return ti1.id === ti2.id && ti1.color?.id === ti2.color?.id; } + export function asThemeIcon(codicon: Codicon): ThemeIcon { + return { id: codicon.id }; + } + export const asClassNameArray: (icon: ThemeIcon) => string[] = CSSIcon.asClassNameArray; export const asClassName: (icon: ThemeIcon) => string = CSSIcon.asClassName; export const asCSSSelector: (icon: ThemeIcon) => string = CSSIcon.asCSSSelector; diff --git a/lib/vscode/src/vs/platform/theme/common/tokenClassificationRegistry.ts b/src/vs/platform/theme/common/tokenClassificationRegistry.ts similarity index 100% rename from lib/vscode/src/vs/platform/theme/common/tokenClassificationRegistry.ts rename to src/vs/platform/theme/common/tokenClassificationRegistry.ts diff --git a/lib/vscode/src/vs/platform/theme/electron-main/themeMainService.ts b/src/vs/platform/theme/electron-main/themeMainService.ts similarity index 53% rename from lib/vscode/src/vs/platform/theme/electron-main/themeMainService.ts rename to src/vs/platform/theme/electron-main/themeMainService.ts index 1d07cf7bfc6b..189811d6fdf6 100644 --- a/lib/vscode/src/vs/platform/theme/electron-main/themeMainService.ts +++ b/src/vs/platform/theme/electron-main/themeMainService.ts @@ -3,10 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { BrowserWindow, nativeTheme } from 'electron'; import { isWindows, isMacintosh } from 'vs/base/common/platform'; -import { ipcMain, nativeTheme } from 'electron'; -import { IStateService } from 'vs/platform/state/node/state'; +import { IStateMainService } from 'vs/platform/state/electron-main/state'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { IPartsSplash } from 'vs/platform/windows/common/windows'; const DEFAULT_BG_LIGHT = '#FFFFFF'; const DEFAULT_BG_DARK = '#1E1E1E'; @@ -14,45 +15,38 @@ const DEFAULT_BG_HC_BLACK = '#000000'; const THEME_STORAGE_KEY = 'theme'; const THEME_BG_STORAGE_KEY = 'themeBackground'; +const THEME_WINDOW_SPLASH = 'windowSplash'; export const IThemeMainService = createDecorator('themeMainService'); export interface IThemeMainService { + readonly _serviceBrand: undefined; getBackgroundColor(): string; + + saveWindowSplash(windowId: number | undefined, splash: IPartsSplash): void; + getWindowSplash(): IPartsSplash | undefined; } export class ThemeMainService implements IThemeMainService { declare readonly _serviceBrand: undefined; - constructor(@IStateService private stateService: IStateService) { - ipcMain.on('vscode:changeColorTheme', (e: Event, windowId: number, broadcast: string) => { - // Theme changes - if (typeof broadcast === 'string') { - this.storeBackgroundColor(JSON.parse(broadcast)); - } - }); - } - - private storeBackgroundColor(data: { baseTheme: string, background: string }): void { - this.stateService.setItem(THEME_STORAGE_KEY, data.baseTheme); - this.stateService.setItem(THEME_BG_STORAGE_KEY, data.background); - } + constructor(@IStateMainService private stateMainService: IStateMainService) { } getBackgroundColor(): string { if ((isWindows || isMacintosh) && nativeTheme.shouldUseInvertedColorScheme) { return DEFAULT_BG_HC_BLACK; } - let background = this.stateService.getItem(THEME_BG_STORAGE_KEY, null); + let background = this.stateMainService.getItem(THEME_BG_STORAGE_KEY, null); if (!background) { let baseTheme: string; if ((isWindows || isMacintosh) && nativeTheme.shouldUseInvertedColorScheme) { baseTheme = 'hc-black'; } else { - baseTheme = this.stateService.getItem(THEME_STORAGE_KEY, 'vs-dark').split(' ')[0]; + baseTheme = this.stateMainService.getItem(THEME_STORAGE_KEY, 'vs-dark').split(' ')[0]; } background = (baseTheme === 'hc-black') ? DEFAULT_BG_HC_BLACK : (baseTheme === 'vs' ? DEFAULT_BG_LIGHT : DEFAULT_BG_DARK); @@ -64,4 +58,32 @@ export class ThemeMainService implements IThemeMainService { return background; } + + saveWindowSplash(windowId: number | undefined, splash: IPartsSplash): void { + + // Update in storage + this.stateMainService.setItems([ + { key: THEME_STORAGE_KEY, data: splash.baseTheme }, + { key: THEME_BG_STORAGE_KEY, data: splash.colorInfo.background }, + { key: THEME_WINDOW_SPLASH, data: splash } + ]); + + // Update in opened windows + if (typeof windowId === 'number') { + this.updateBackgroundColor(windowId, splash); + } + } + + private updateBackgroundColor(windowId: number, splash: IPartsSplash): void { + for (const window of BrowserWindow.getAllWindows()) { + if (window.id === windowId) { + window.setBackgroundColor(splash.colorInfo.background); + break; + } + } + } + + getWindowSplash(): IPartsSplash | undefined { + return this.stateMainService.getItem(THEME_WINDOW_SPLASH); + } } diff --git a/lib/vscode/src/vs/platform/theme/test/common/testThemeService.ts b/src/vs/platform/theme/test/common/testThemeService.ts similarity index 100% rename from lib/vscode/src/vs/platform/theme/test/common/testThemeService.ts rename to src/vs/platform/theme/test/common/testThemeService.ts diff --git a/lib/vscode/src/vs/platform/undoRedo/common/undoRedo.ts b/src/vs/platform/undoRedo/common/undoRedo.ts similarity index 100% rename from lib/vscode/src/vs/platform/undoRedo/common/undoRedo.ts rename to src/vs/platform/undoRedo/common/undoRedo.ts diff --git a/lib/vscode/src/vs/platform/undoRedo/common/undoRedoService.ts b/src/vs/platform/undoRedo/common/undoRedoService.ts similarity index 99% rename from lib/vscode/src/vs/platform/undoRedo/common/undoRedoService.ts rename to src/vs/platform/undoRedo/common/undoRedoService.ts index 7f3d251a52af..5833ce80cc43 100644 --- a/lib/vscode/src/vs/platform/undoRedo/common/undoRedoService.ts +++ b/src/vs/platform/undoRedo/common/undoRedoService.ts @@ -709,7 +709,7 @@ export class UndoRedoService implements IUndoRedoService { private _onError(err: Error, element: StackElement): void { onUnexpectedError(err); - // An error occured while undoing or redoing => drop the undo/redo stack for all affected resources + // An error occurred while undoing or redoing => drop the undo/redo stack for all affected resources for (const strResource of element.strResources) { this.removeElements(strResource); } diff --git a/lib/vscode/src/vs/platform/undoRedo/test/common/undoRedoService.test.ts b/src/vs/platform/undoRedo/test/common/undoRedoService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/undoRedo/test/common/undoRedoService.test.ts rename to src/vs/platform/undoRedo/test/common/undoRedoService.test.ts diff --git a/lib/vscode/src/vs/platform/update/common/update.config.contribution.ts b/src/vs/platform/update/common/update.config.contribution.ts similarity index 100% rename from lib/vscode/src/vs/platform/update/common/update.config.contribution.ts rename to src/vs/platform/update/common/update.config.contribution.ts diff --git a/lib/vscode/src/vs/platform/update/common/update.ts b/src/vs/platform/update/common/update.ts similarity index 100% rename from lib/vscode/src/vs/platform/update/common/update.ts rename to src/vs/platform/update/common/update.ts diff --git a/lib/vscode/src/vs/platform/update/common/updateIpc.ts b/src/vs/platform/update/common/updateIpc.ts similarity index 100% rename from lib/vscode/src/vs/platform/update/common/updateIpc.ts rename to src/vs/platform/update/common/updateIpc.ts diff --git a/lib/vscode/src/vs/platform/update/electron-main/abstractUpdateService.ts b/src/vs/platform/update/electron-main/abstractUpdateService.ts similarity index 98% rename from lib/vscode/src/vs/platform/update/electron-main/abstractUpdateService.ts rename to src/vs/platform/update/electron-main/abstractUpdateService.ts index 289b57cef162..20611427502e 100644 --- a/lib/vscode/src/vs/platform/update/electron-main/abstractUpdateService.ts +++ b/src/vs/platform/update/electron-main/abstractUpdateService.ts @@ -164,7 +164,7 @@ export abstract class AbstractUpdateService implements IUpdateService { this.logService.trace('update#quitAndInstall(): before lifecycle quit()'); - this.lifecycleMainService.quit(true /* from update */).then(vetod => { + this.lifecycleMainService.quit(true /* will restart */).then(vetod => { this.logService.trace(`update#quitAndInstall(): after lifecycle quit() with veto: ${vetod}`); if (vetod) { return; diff --git a/lib/vscode/src/vs/platform/update/electron-main/updateService.darwin.ts b/src/vs/platform/update/electron-main/updateService.darwin.ts similarity index 100% rename from lib/vscode/src/vs/platform/update/electron-main/updateService.darwin.ts rename to src/vs/platform/update/electron-main/updateService.darwin.ts diff --git a/lib/vscode/src/vs/platform/update/electron-main/updateService.linux.ts b/src/vs/platform/update/electron-main/updateService.linux.ts similarity index 100% rename from lib/vscode/src/vs/platform/update/electron-main/updateService.linux.ts rename to src/vs/platform/update/electron-main/updateService.linux.ts diff --git a/lib/vscode/src/vs/platform/update/electron-main/updateService.snap.ts b/src/vs/platform/update/electron-main/updateService.snap.ts similarity index 98% rename from lib/vscode/src/vs/platform/update/electron-main/updateService.snap.ts rename to src/vs/platform/update/electron-main/updateService.snap.ts index d14018a83d71..ac0e652fd862 100644 --- a/lib/vscode/src/vs/platform/update/electron-main/updateService.snap.ts +++ b/src/vs/platform/update/electron-main/updateService.snap.ts @@ -106,7 +106,7 @@ abstract class AbstractUpdateService implements IUpdateService { this.logService.trace('update#quitAndInstall(): before lifecycle quit()'); - this.lifecycleMainService.quit(true /* from update */).then(vetod => { + this.lifecycleMainService.quit(true /* will restart */).then(vetod => { this.logService.trace(`update#quitAndInstall(): after lifecycle quit() with veto: ${vetod}`); if (vetod) { return; diff --git a/lib/vscode/src/vs/platform/update/electron-main/updateService.win32.ts b/src/vs/platform/update/electron-main/updateService.win32.ts similarity index 97% rename from lib/vscode/src/vs/platform/update/electron-main/updateService.win32.ts rename to src/vs/platform/update/electron-main/updateService.win32.ts index eab8c3f18072..93424cad9659 100644 --- a/lib/vscode/src/vs/platform/update/electron-main/updateService.win32.ts +++ b/src/vs/platform/update/electron-main/updateService.win32.ts @@ -54,7 +54,7 @@ export class Win32UpdateService extends AbstractUpdateService { @memoize get cachePath(): Promise { const result = path.join(tmpdir(), `vscode-update-${this.productService.target}-${process.arch}`); - return fs.promises.mkdir(result, { recursive: true }).then(() => result); + return pfs.Promises.mkdir(result, { recursive: true }).then(() => result); } constructor( @@ -145,7 +145,7 @@ export class Win32UpdateService extends AbstractUpdateService { return this.requestService.request({ url }, CancellationToken.None) .then(context => this.fileService.writeFile(URI.file(downloadPath), context.stream)) .then(hash ? () => checksum(downloadPath, update.hash) : () => undefined) - .then(() => fs.promises.rename(downloadPath, updatePackagePath)) + .then(() => pfs.Promises.rename(downloadPath, updatePackagePath)) .then(() => updatePackagePath); }); }).then(packagePath => { @@ -195,7 +195,7 @@ export class Win32UpdateService extends AbstractUpdateService { const promises = versions.filter(filter).map(async one => { try { - await fs.promises.unlink(path.join(cachePath, one)); + await pfs.Promises.unlink(path.join(cachePath, one)); } catch (err) { // ignore } diff --git a/lib/vscode/src/vs/platform/url/common/url.ts b/src/vs/platform/url/common/url.ts similarity index 100% rename from lib/vscode/src/vs/platform/url/common/url.ts rename to src/vs/platform/url/common/url.ts diff --git a/lib/vscode/src/vs/platform/url/common/urlIpc.ts b/src/vs/platform/url/common/urlIpc.ts similarity index 100% rename from lib/vscode/src/vs/platform/url/common/urlIpc.ts rename to src/vs/platform/url/common/urlIpc.ts diff --git a/lib/vscode/src/vs/platform/url/common/urlService.ts b/src/vs/platform/url/common/urlService.ts similarity index 100% rename from lib/vscode/src/vs/platform/url/common/urlService.ts rename to src/vs/platform/url/common/urlService.ts diff --git a/lib/vscode/src/vs/platform/url/electron-main/electronUrlListener.ts b/src/vs/platform/url/electron-main/electronUrlListener.ts similarity index 100% rename from lib/vscode/src/vs/platform/url/electron-main/electronUrlListener.ts rename to src/vs/platform/url/electron-main/electronUrlListener.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/abstractSynchronizer.ts b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/abstractSynchronizer.ts rename to src/vs/platform/userDataSync/common/abstractSynchronizer.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/content.ts b/src/vs/platform/userDataSync/common/content.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/content.ts rename to src/vs/platform/userDataSync/common/content.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/extensionsMerge.ts b/src/vs/platform/userDataSync/common/extensionsMerge.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/extensionsMerge.ts rename to src/vs/platform/userDataSync/common/extensionsMerge.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/extensionsStorageSync.ts b/src/vs/platform/userDataSync/common/extensionsStorageSync.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/extensionsStorageSync.ts rename to src/vs/platform/userDataSync/common/extensionsStorageSync.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/extensionsSync.ts b/src/vs/platform/userDataSync/common/extensionsSync.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/extensionsSync.ts rename to src/vs/platform/userDataSync/common/extensionsSync.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/globalStateMerge.ts b/src/vs/platform/userDataSync/common/globalStateMerge.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/globalStateMerge.ts rename to src/vs/platform/userDataSync/common/globalStateMerge.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/globalStateSync.ts b/src/vs/platform/userDataSync/common/globalStateSync.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/globalStateSync.ts rename to src/vs/platform/userDataSync/common/globalStateSync.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/ignoredExtensions.ts b/src/vs/platform/userDataSync/common/ignoredExtensions.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/ignoredExtensions.ts rename to src/vs/platform/userDataSync/common/ignoredExtensions.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/keybindingsMerge.ts b/src/vs/platform/userDataSync/common/keybindingsMerge.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/keybindingsMerge.ts rename to src/vs/platform/userDataSync/common/keybindingsMerge.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/keybindingsSync.ts b/src/vs/platform/userDataSync/common/keybindingsSync.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/keybindingsSync.ts rename to src/vs/platform/userDataSync/common/keybindingsSync.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/settingsMerge.ts b/src/vs/platform/userDataSync/common/settingsMerge.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/settingsMerge.ts rename to src/vs/platform/userDataSync/common/settingsMerge.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/settingsSync.ts b/src/vs/platform/userDataSync/common/settingsSync.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/settingsSync.ts rename to src/vs/platform/userDataSync/common/settingsSync.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/snippetsMerge.ts b/src/vs/platform/userDataSync/common/snippetsMerge.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/snippetsMerge.ts rename to src/vs/platform/userDataSync/common/snippetsMerge.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/snippetsSync.ts b/src/vs/platform/userDataSync/common/snippetsSync.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/snippetsSync.ts rename to src/vs/platform/userDataSync/common/snippetsSync.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts b/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/userDataAutoSyncService.ts rename to src/vs/platform/userDataSync/common/userDataAutoSyncService.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/userDataSync.ts b/src/vs/platform/userDataSync/common/userDataSync.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/userDataSync.ts rename to src/vs/platform/userDataSync/common/userDataSync.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/userDataSyncAccount.ts b/src/vs/platform/userDataSync/common/userDataSyncAccount.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/userDataSyncAccount.ts rename to src/vs/platform/userDataSync/common/userDataSyncAccount.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/userDataSyncBackupStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncBackupStoreService.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/userDataSyncBackupStoreService.ts rename to src/vs/platform/userDataSync/common/userDataSyncBackupStoreService.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/userDataSyncIpc.ts b/src/vs/platform/userDataSync/common/userDataSyncIpc.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/userDataSyncIpc.ts rename to src/vs/platform/userDataSync/common/userDataSyncIpc.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/userDataSyncLog.ts b/src/vs/platform/userDataSync/common/userDataSyncLog.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/userDataSyncLog.ts rename to src/vs/platform/userDataSync/common/userDataSyncLog.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/userDataSyncMachines.ts b/src/vs/platform/userDataSync/common/userDataSyncMachines.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/userDataSyncMachines.ts rename to src/vs/platform/userDataSync/common/userDataSyncMachines.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/userDataSyncResourceEnablementService.ts b/src/vs/platform/userDataSync/common/userDataSyncResourceEnablementService.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/userDataSyncResourceEnablementService.ts rename to src/vs/platform/userDataSync/common/userDataSyncResourceEnablementService.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/userDataSyncService.ts b/src/vs/platform/userDataSync/common/userDataSyncService.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/userDataSyncService.ts rename to src/vs/platform/userDataSync/common/userDataSyncService.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/userDataSyncServiceIpc.ts b/src/vs/platform/userDataSync/common/userDataSyncServiceIpc.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/userDataSyncServiceIpc.ts rename to src/vs/platform/userDataSync/common/userDataSyncServiceIpc.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts b/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/common/userDataSyncStoreService.ts rename to src/vs/platform/userDataSync/common/userDataSyncStoreService.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/electron-sandbox/userDataAutoSyncService.ts b/src/vs/platform/userDataSync/electron-sandbox/userDataAutoSyncService.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/electron-sandbox/userDataAutoSyncService.ts rename to src/vs/platform/userDataSync/electron-sandbox/userDataAutoSyncService.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/test/common/extensionsMerge.test.ts b/src/vs/platform/userDataSync/test/common/extensionsMerge.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/test/common/extensionsMerge.test.ts rename to src/vs/platform/userDataSync/test/common/extensionsMerge.test.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/test/common/globalStateMerge.test.ts b/src/vs/platform/userDataSync/test/common/globalStateMerge.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/test/common/globalStateMerge.test.ts rename to src/vs/platform/userDataSync/test/common/globalStateMerge.test.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/test/common/globalStateSync.test.ts b/src/vs/platform/userDataSync/test/common/globalStateSync.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/test/common/globalStateSync.test.ts rename to src/vs/platform/userDataSync/test/common/globalStateSync.test.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/test/common/keybindingsMerge.test.ts b/src/vs/platform/userDataSync/test/common/keybindingsMerge.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/test/common/keybindingsMerge.test.ts rename to src/vs/platform/userDataSync/test/common/keybindingsMerge.test.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/test/common/keybindingsSync.test.ts b/src/vs/platform/userDataSync/test/common/keybindingsSync.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/test/common/keybindingsSync.test.ts rename to src/vs/platform/userDataSync/test/common/keybindingsSync.test.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/test/common/settingsMerge.test.ts b/src/vs/platform/userDataSync/test/common/settingsMerge.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/test/common/settingsMerge.test.ts rename to src/vs/platform/userDataSync/test/common/settingsMerge.test.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/test/common/settingsSync.test.ts b/src/vs/platform/userDataSync/test/common/settingsSync.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/test/common/settingsSync.test.ts rename to src/vs/platform/userDataSync/test/common/settingsSync.test.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/test/common/snippetsMerge.test.ts b/src/vs/platform/userDataSync/test/common/snippetsMerge.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/test/common/snippetsMerge.test.ts rename to src/vs/platform/userDataSync/test/common/snippetsMerge.test.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/test/common/snippetsSync.test.ts b/src/vs/platform/userDataSync/test/common/snippetsSync.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/test/common/snippetsSync.test.ts rename to src/vs/platform/userDataSync/test/common/snippetsSync.test.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/test/common/synchronizer.test.ts b/src/vs/platform/userDataSync/test/common/synchronizer.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/test/common/synchronizer.test.ts rename to src/vs/platform/userDataSync/test/common/synchronizer.test.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/test/common/userDataAutoSyncService.test.ts b/src/vs/platform/userDataSync/test/common/userDataAutoSyncService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/test/common/userDataAutoSyncService.test.ts rename to src/vs/platform/userDataSync/test/common/userDataAutoSyncService.test.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/test/common/userDataSyncClient.ts b/src/vs/platform/userDataSync/test/common/userDataSyncClient.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/test/common/userDataSyncClient.ts rename to src/vs/platform/userDataSync/test/common/userDataSyncClient.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/test/common/userDataSyncService.test.ts b/src/vs/platform/userDataSync/test/common/userDataSyncService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/test/common/userDataSyncService.test.ts rename to src/vs/platform/userDataSync/test/common/userDataSyncService.test.ts diff --git a/lib/vscode/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts b/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts rename to src/vs/platform/userDataSync/test/common/userDataSyncStoreService.test.ts diff --git a/lib/vscode/src/vs/platform/webview/common/mimeTypes.ts b/src/vs/platform/webview/common/mimeTypes.ts similarity index 100% rename from lib/vscode/src/vs/platform/webview/common/mimeTypes.ts rename to src/vs/platform/webview/common/mimeTypes.ts diff --git a/lib/vscode/src/vs/platform/webview/common/webviewManagerService.ts b/src/vs/platform/webview/common/webviewManagerService.ts similarity index 100% rename from lib/vscode/src/vs/platform/webview/common/webviewManagerService.ts rename to src/vs/platform/webview/common/webviewManagerService.ts diff --git a/lib/vscode/src/vs/platform/webview/common/webviewPortMapping.ts b/src/vs/platform/webview/common/webviewPortMapping.ts similarity index 100% rename from lib/vscode/src/vs/platform/webview/common/webviewPortMapping.ts rename to src/vs/platform/webview/common/webviewPortMapping.ts diff --git a/lib/vscode/src/vs/platform/webview/electron-main/webviewMainService.ts b/src/vs/platform/webview/electron-main/webviewMainService.ts similarity index 100% rename from lib/vscode/src/vs/platform/webview/electron-main/webviewMainService.ts rename to src/vs/platform/webview/electron-main/webviewMainService.ts diff --git a/lib/vscode/src/vs/platform/webview/electron-main/webviewProtocolProvider.ts b/src/vs/platform/webview/electron-main/webviewProtocolProvider.ts similarity index 100% rename from lib/vscode/src/vs/platform/webview/electron-main/webviewProtocolProvider.ts rename to src/vs/platform/webview/electron-main/webviewProtocolProvider.ts diff --git a/lib/vscode/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts similarity index 91% rename from lib/vscode/src/vs/platform/windows/common/windows.ts rename to src/vs/platform/windows/common/windows.ts index 9fb6e838d522..cc5ac005a9aa 100644 --- a/lib/vscode/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -233,6 +233,31 @@ export interface IOSConfiguration { readonly hostname: string; } +export interface IPartsSplash { + baseTheme: string; + colorInfo: { + background: string; + foreground: string | undefined; + editorBackground: string | undefined; + titleBarBackground: string | undefined; + activityBarBackground: string | undefined; + sideBarBackground: string | undefined; + statusBarBackground: string | undefined; + statusBarNoFolderBackground: string | undefined; + windowBorder: string | undefined; + } + layoutInfo: { + sideBarSide: string; + editorPartMinWidth: number; + titleBarHeight: number; + activityBarWidth: number; + sideBarWidth: number; + statusBarHeight: number; + windowBorder: boolean; + windowBorderRadius: string | undefined; + } | undefined +} + export interface INativeWindowConfiguration extends IWindowConfiguration, NativeParsedArgs, ISandboxConfiguration { mainPid: number; @@ -245,7 +270,7 @@ export interface INativeWindowConfiguration extends IWindowConfiguration, Native tmpDir: string; userDataDir: string; - partsSplashPath: string; + partsSplash?: IPartsSplash; workspace?: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier; diff --git a/lib/vscode/src/vs/platform/windows/electron-main/window.ts b/src/vs/platform/windows/electron-main/window.ts similarity index 97% rename from lib/vscode/src/vs/platform/windows/electron-main/window.ts rename to src/vs/platform/windows/electron-main/window.ts index d4011761837d..c597738aa696 100644 --- a/lib/vscode/src/vs/platform/windows/electron-main/window.ts +++ b/src/vs/platform/windows/electron-main/window.ts @@ -34,7 +34,6 @@ import { IFileService } from 'vs/platform/files/common/files'; import { FileAccess, Schemas } from 'vs/base/common/network'; import { isLaunchedFromCli } from 'vs/platform/environment/node/argvHelper'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { INativeHostMainService } from 'vs/platform/native/electron-main/nativeHostMainService'; import { IProtocolMainService } from 'vs/platform/protocol/electron-main/protocol'; export interface IWindowCreationOptions { @@ -153,7 +152,6 @@ export class CodeWindow extends Disposable implements ICodeWindow { @ITelemetryService private readonly telemetryService: ITelemetryService, @IDialogMainService private readonly dialogMainService: IDialogMainService, @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, - @INativeHostMainService private readonly nativeHostMainService: INativeHostMainService, @IProductService private readonly productService: IProductService, @IProtocolMainService private readonly protocolMainService: IProtocolMainService ) { @@ -441,7 +439,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { }); // Block all SVG requests from unsupported origins - const supportedSvgSchemes = new Set([Schemas.file, Schemas.vscodeFileResource, Schemas.vscodeRemoteResource, 'devtools']); // TODO: handle webview origin + const supportedSvgSchemes = new Set([Schemas.file, Schemas.vscodeFileResource, Schemas.vscodeRemoteResource, 'devtools']); // TODO@mjbvz: handle webview origin // But allow them if the are made from inside an webview const isSafeFrame = (requestFrame: WebFrameMain | undefined): boolean => { @@ -453,13 +451,16 @@ export class CodeWindow extends Disposable implements ICodeWindow { return false; }; + const isRequestFromSafeContext = (details: Electron.OnBeforeRequestListenerDetails | Electron.OnHeadersReceivedListenerDetails): boolean => { + return details.resourceType === 'xhr' || isSafeFrame(details.frame); + }; + this._win.webContents.session.webRequest.onBeforeRequest((details, callback) => { const uri = URI.parse(details.url); if (uri.path.endsWith('.svg')) { const isSafeResourceUrl = supportedSvgSchemes.has(uri.scheme) || uri.path.includes(Schemas.vscodeRemoteResource); if (!isSafeResourceUrl) { - const isSafeContext = isSafeFrame(details.frame); - return callback({ cancel: !isSafeContext }); + return callback({ cancel: !isRequestFromSafeContext(details) }); } } @@ -485,8 +486,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { // remote extension schemes have the following format // http://127.0.0.1:/vscode-remote-resource?path= if (!uri.path.includes(Schemas.vscodeRemoteResource) && contentTypes.some(contentType => contentType.toLowerCase().includes('image/svg'))) { - const isSafeContext = isSafeFrame(details.frame); - return callback({ cancel: !isSafeContext }); + return callback({ cancel: !isRequestFromSafeContext(details) }); } } @@ -510,22 +510,6 @@ export class CodeWindow extends Disposable implements ICodeWindow { this._lastFocusTime = Date.now(); }); - if (isMacintosh) { - this._register(this.nativeHostMainService.onDidChangeDisplay(() => { - if (!this._win) { - return; // disposed - } - - // Simple fullscreen doesn't resize automatically when the resolution changes so as a workaround - // we need to detect when display metrics change or displays are added/removed and toggle the - // fullscreen manually. - if (!this.useNativeFullScreen() && this.isFullScreen) { - this.setFullScreen(false); - this.setFullScreen(true); - } - })); - } - // Window (Un)Maximize this._win.on('maximize', (e: Event) => { if (this.currentConfig) { @@ -574,7 +558,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { switch (type) { case WindowError.CRASHED: - this.logService.error(`CodeWindow: renderer process crashed (detail: ${typeof details === 'string' ? details : details?.reason})`); + this.logService.error(`CodeWindow: renderer process crashed (detail: ${typeof details === 'string' ? details : details?.reason}, code: ${typeof details === 'string' ? '' : details?.exitCode ?? ''})`); break; case WindowError.UNRESPONSIVE: this.logService.error('CodeWindow: detected unresponsive'); @@ -668,8 +652,8 @@ export class CodeWindow extends Disposable implements ICodeWindow { } private destroyWindow(): void { - this._onDidDestroy.fire(); // 'close' event will not be fired on destroy(), so signal crash via explicit event - this._win.destroy(); // make sure to destroy the window as it has crashed + this._onDidDestroy.fire(); // 'close' event will not be fired on destroy(), so signal crash via explicit event + this._win.destroy(); // make sure to destroy the window as it has crashed } private onDidDeleteUntitledWorkspace(workspace: IWorkspaceIdentifier): void { @@ -806,6 +790,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { // Update window related properties configuration.fullscreen = this.isFullScreen; configuration.maximized = this._win.isMaximized(); + configuration.partsSplash = this.themeMainService.getWindowSplash(); // Update with latest perf marks mark('code/willOpenNewWindow'); diff --git a/lib/vscode/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts similarity index 100% rename from lib/vscode/src/vs/platform/windows/electron-main/windows.ts rename to src/vs/platform/windows/electron-main/windows.ts diff --git a/lib/vscode/src/vs/platform/windows/electron-main/windowsFinder.ts b/src/vs/platform/windows/electron-main/windowsFinder.ts similarity index 98% rename from lib/vscode/src/vs/platform/windows/electron-main/windowsFinder.ts rename to src/vs/platform/windows/electron-main/windowsFinder.ts index 30f7601832d5..aaa765af3787 100644 --- a/lib/vscode/src/vs/platform/windows/electron-main/windowsFinder.ts +++ b/src/vs/platform/windows/electron-main/windowsFinder.ts @@ -8,7 +8,7 @@ import { IWorkspaceIdentifier, IResolvedWorkspace, isWorkspaceIdentifier, isSing import { extUriBiasedIgnorePathCase } from 'vs/base/common/resources'; import { ICodeWindow } from 'vs/platform/windows/electron-main/windows'; -export function findWindowOnFile(windows: ICodeWindow[], fileUri: URI, localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null): ICodeWindow | undefined { +export function findWindowOnFile(windows: ICodeWindow[], fileUri: URI, localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | undefined): ICodeWindow | undefined { // First check for windows with workspaces that have a parent folder of the provided path opened for (const window of windows) { diff --git a/lib/vscode/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts similarity index 99% rename from lib/vscode/src/vs/platform/windows/electron-main/windowsMainService.ts rename to src/vs/platform/windows/electron-main/windowsMainService.ts index 4f66b0be81fa..991c9585ec6e 100644 --- a/lib/vscode/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -14,7 +14,7 @@ import { IBackupMainService } from 'vs/platform/backup/electron-main/backup'; import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup'; import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; -import { IStateService } from 'vs/platform/state/node/state'; +import { IStateMainService } from 'vs/platform/state/electron-main/state'; import { CodeWindow } from 'vs/platform/windows/electron-main/window'; import { app, BrowserWindow, MessageBoxOptions, nativeTheme, WebContents } from 'electron'; import { ILifecycleMainService, UnloadReason } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; @@ -139,13 +139,13 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic private readonly _onDidChangeWindowsCount = this._register(new Emitter()); readonly onDidChangeWindowsCount = this._onDidChangeWindowsCount.event; - private readonly windowsStateHandler = this._register(new WindowsStateHandler(this, this.stateService, this.lifecycleMainService, this.logService, this.configurationService)); + private readonly windowsStateHandler = this._register(new WindowsStateHandler(this, this.stateMainService, this.lifecycleMainService, this.logService, this.configurationService)); constructor( private readonly machineId: string, private readonly initialUserEnv: IProcessEnvironment, @ILogService private readonly logService: ILogService, - @IStateService private readonly stateService: IStateService, + @IStateMainService private readonly stateMainService: IStateMainService, @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService, @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @IBackupMainService private readonly backupMainService: IBackupMainService, @@ -409,7 +409,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic let windowToUseForFiles: ICodeWindow | undefined = undefined; if (fileToCheck?.fileUri && !openFilesInNewWindow) { if (openConfig.context === OpenContext.DESKTOP || openConfig.context === OpenContext.CLI || openConfig.context === OpenContext.DOCK) { - windowToUseForFiles = findWindowOnFile(windows, fileToCheck.fileUri, workspace => workspace.configPath.scheme === Schemas.file ? this.workspacesManagementMainService.resolveLocalWorkspaceSync(workspace.configPath) : null); + windowToUseForFiles = findWindowOnFile(windows, fileToCheck.fileUri, workspace => workspace.configPath.scheme === Schemas.file ? this.workspacesManagementMainService.resolveLocalWorkspaceSync(workspace.configPath) : undefined); } if (!windowToUseForFiles) { @@ -1169,7 +1169,6 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic appRoot: this.environmentMainService.appRoot, execPath: process.execPath, nodeCachedDataDir: this.environmentMainService.nodeCachedDataDir, - partsSplashPath: join(this.environmentMainService.userDataPath, 'rapid_render.json'), // If we know the backup folder upfront (for empty windows to restore), we can set it // directly here which helps for restoring UI state associated with that window. // For all other cases we first call into registerEmptyWindowBackupSync() to set it before diff --git a/lib/vscode/src/vs/platform/windows/electron-main/windowsStateHandler.ts b/src/vs/platform/windows/electron-main/windowsStateHandler.ts similarity index 93% rename from lib/vscode/src/vs/platform/windows/electron-main/windowsStateHandler.ts rename to src/vs/platform/windows/electron-main/windowsStateHandler.ts index 75c96494b804..b24443601c2e 100644 --- a/lib/vscode/src/vs/platform/windows/electron-main/windowsStateHandler.ts +++ b/src/vs/platform/windows/electron-main/windowsStateHandler.ts @@ -11,7 +11,7 @@ import { URI } from 'vs/base/common/uri'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { ILogService } from 'vs/platform/log/common/log'; -import { IStateService } from 'vs/platform/state/node/state'; +import { IStateMainService } from 'vs/platform/state/electron-main/state'; import { INativeWindowConfiguration, IWindowSettings } from 'vs/platform/windows/common/windows'; import { defaultWindowState, ICodeWindow, IWindowsMainService, IWindowState as IWindowUIState, WindowMode } from 'vs/platform/windows/electron-main/windows'; import { isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; @@ -53,7 +53,7 @@ export class WindowsStateHandler extends Disposable { private static readonly windowsStateStorageKey = 'windowsState'; get state() { return this._state; } - private readonly _state = restoreWindowsState(this.stateService.getItem(WindowsStateHandler.windowsStateStorageKey)); + private readonly _state = restoreWindowsState(this.stateMainService.getItem(WindowsStateHandler.windowsStateStorageKey)); private lastClosedState: IWindowState | undefined = undefined; @@ -61,7 +61,7 @@ export class WindowsStateHandler extends Disposable { constructor( @IWindowsMainService private readonly windowsMainService: IWindowsMainService, - @IStateService private readonly stateService: IStateService, + @IStateMainService private readonly stateMainService: IStateMainService, @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService, @ILogService private readonly logService: ILogService, @IConfigurationService private readonly configurationService: IConfigurationService @@ -177,7 +177,7 @@ export class WindowsStateHandler extends Disposable { // Persist const state = getWindowsStateStoreData(currentWindowsState); - this.stateService.setItem(WindowsStateHandler.windowsStateStorageKey, state); + this.stateMainService.setItem(WindowsStateHandler.windowsStateStorageKey, state); if (this.shuttingDown) { this.logService.trace('[WindowsStateHandler] onBeforeShutdown', state); @@ -232,9 +232,11 @@ export class WindowsStateHandler extends Disposable { const windowConfig = this.configurationService.getValue('window'); // Window state is not from a previous session: only allow fullscreen if we inherit it or user wants fullscreen + // or to address a Electron issue on macOS (https://github.com/microsoft/vscode/issues/125122) let allowFullscreen: boolean; if (state.hasDefaultState) { - allowFullscreen = !!(windowConfig?.newWindowDimensions && ['fullscreen', 'inherit', 'offset'].indexOf(windowConfig.newWindowDimensions) >= 0); + const configAllowsFullScreen = !!(windowConfig?.newWindowDimensions && ['fullscreen', 'inherit', 'offset'].indexOf(windowConfig.newWindowDimensions) >= 0); + allowFullscreen = configAllowsFullScreen || (isMacintosh && windowConfig?.nativeFullScreen !== false); } // Window state is from a previous session: only allow fullscreen when we got updated or user wants to restore @@ -337,14 +339,22 @@ export class WindowsStateHandler extends Disposable { // Compute x/y based on display bounds // Note: important to use Math.round() because Electron does not seem to be too happy about // display coordinates that are not absolute numbers. - let state = defaultWindowState(); + let state: INewWindowState = defaultWindowState(); state.x = Math.round(displayToUse.bounds.x + (displayToUse.bounds.width / 2) - (state.width! / 2)); state.y = Math.round(displayToUse.bounds.y + (displayToUse.bounds.height / 2) - (state.height! / 2)); - // Check for newWindowDimensions setting and adjust accordingly const windowConfig = this.configurationService.getValue('window'); let ensureNoOverlap = true; - if (windowConfig?.newWindowDimensions) { + + // TODO@electron macOS: if the current window is fullscreen and native fullscreen + // is not disabled, always open a new window in fullscreen. This is a workaround + // for regression https://github.com/microsoft/vscode/issues/125122 + if (isMacintosh && windowConfig?.nativeFullScreen !== false && lastActive?.isFullScreen) { + state.mode = WindowMode.Fullscreen; + } + + // Adjust according to `newWindowDimensions` user setting + else if (windowConfig?.newWindowDimensions) { if (windowConfig.newWindowDimensions === 'maximized') { state.mode = WindowMode.Maximized; ensureNoOverlap = false; @@ -367,7 +377,7 @@ export class WindowsStateHandler extends Disposable { state = this.ensureNoOverlap(state); } - (state as INewWindowState).hasDefaultState = true; // flag as default state + state.hasDefaultState = true; // flag as default state return state; } diff --git a/lib/vscode/src/vs/platform/windows/electron-sandbox/window.ts b/src/vs/platform/windows/electron-sandbox/window.ts similarity index 100% rename from lib/vscode/src/vs/platform/windows/electron-sandbox/window.ts rename to src/vs/platform/windows/electron-sandbox/window.ts diff --git a/lib/vscode/src/vs/platform/windows/node/windowTracker.ts b/src/vs/platform/windows/node/windowTracker.ts similarity index 100% rename from lib/vscode/src/vs/platform/windows/node/windowTracker.ts rename to src/vs/platform/windows/node/windowTracker.ts diff --git a/lib/vscode/src/vs/platform/windows/test/electron-main/windowsFinder.test.ts b/src/vs/platform/windows/test/electron-main/windowsFinder.test.ts similarity index 99% rename from lib/vscode/src/vs/platform/windows/test/electron-main/windowsFinder.test.ts rename to src/vs/platform/windows/test/electron-main/windowsFinder.test.ts index 8a1b2999b6ef..f26f2765f750 100644 --- a/lib/vscode/src/vs/platform/windows/test/electron-main/windowsFinder.test.ts +++ b/src/vs/platform/windows/test/electron-main/windowsFinder.test.ts @@ -28,7 +28,7 @@ suite('WindowsFinder', () => { }; const testWorkspaceFolders = toWorkspaceFolders([{ path: join(fixturesFolder, 'vscode_workspace_1_folder') }, { path: join(fixturesFolder, 'vscode_workspace_2_folder') }], testWorkspace.configPath, extUriBiasedIgnorePathCase); - const localWorkspaceResolver = (workspace: any) => { return workspace === testWorkspace ? { id: testWorkspace.id, configPath: workspace.configPath, folders: testWorkspaceFolders } : null; }; + const localWorkspaceResolver = (workspace: any) => { return workspace === testWorkspace ? { id: testWorkspace.id, configPath: workspace.configPath, folders: testWorkspaceFolders } : undefined; }; function createTestCodeWindow(options: { lastFocusTime: number, openedFolderUri?: URI, openedWorkspace?: IWorkspaceIdentifier }): ICodeWindow { return new class implements ICodeWindow { diff --git a/lib/vscode/src/vs/platform/windows/test/electron-main/windowsStateHandler.test.ts b/src/vs/platform/windows/test/electron-main/windowsStateHandler.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/windows/test/electron-main/windowsStateHandler.test.ts rename to src/vs/platform/windows/test/electron-main/windowsStateHandler.test.ts diff --git a/lib/vscode/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts similarity index 100% rename from lib/vscode/src/vs/platform/workspace/common/workspace.ts rename to src/vs/platform/workspace/common/workspace.ts diff --git a/lib/vscode/src/vs/platform/workspace/common/workspaceTrust.ts b/src/vs/platform/workspace/common/workspaceTrust.ts similarity index 65% rename from lib/vscode/src/vs/platform/workspace/common/workspaceTrust.ts rename to src/vs/platform/workspace/common/workspaceTrust.ts index 1a303f1482dc..275035ffa398 100644 --- a/lib/vscode/src/vs/platform/workspace/common/workspaceTrust.ts +++ b/src/vs/platform/workspace/common/workspaceTrust.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -29,27 +30,43 @@ export interface WorkspaceTrustRequestButton { export interface WorkspaceTrustRequestOptions { readonly buttons?: WorkspaceTrustRequestButton[]; readonly message?: string; - readonly modal: boolean; } -export type WorkspaceTrustChangeEvent = Event; export const IWorkspaceTrustManagementService = createDecorator('workspaceTrustManagementService'); export interface IWorkspaceTrustManagementService { readonly _serviceBrand: undefined; - onDidChangeTrust: WorkspaceTrustChangeEvent; + onDidChangeTrust: Event; onDidChangeTrustedFolders: Event; + readonly workspaceTrustEnabled: boolean; + readonly workspaceResolved: Promise; + readonly workspaceTrustInitialized: Promise; + acceptsOutOfWorkspaceFiles: boolean; + isWorkpaceTrusted(): boolean; + isWorkspaceTrustForced(): boolean; + canSetParentFolderTrust(): boolean; - setParentFolderTrust(trusted: boolean): void; + setParentFolderTrust(trusted: boolean): Promise; + canSetWorkspaceTrust(): boolean; - setWorkspaceTrust(trusted: boolean): void; - getFolderTrustInfo(folder: URI): IWorkspaceTrustUriInfo; - setFoldersTrust(folders: URI[], trusted: boolean): void; - getTrustedFolders(): URI[]; - setTrustedFolders(folders: URI[]): void; + setWorkspaceTrust(trusted: boolean): Promise; + + getUriTrustInfo(uri: URI): Promise; + setUrisTrust(uri: URI[], trusted: boolean): Promise; + + getTrustedUris(): URI[]; + setTrustedUris(uris: URI[]): Promise; + + addWorkspaceTrustTransitionParticipant(participant: IWorkspaceTrustTransitionParticipant): IDisposable; +} + +export const enum WorkspaceTrustUriResponse { + Open = 1, + OpenInNewWindow = 2, + Cancel = 3 } export const IWorkspaceTrustRequestService = createDecorator('workspaceTrustRequestService'); @@ -57,14 +74,18 @@ export const IWorkspaceTrustRequestService = createDecorator; - readonly onDidCompleteWorkspaceTrustRequest: Event; + readonly onDidInitiateWorkspaceTrustRequest: Event; + requestOpenUris(uris: URI[]): Promise; cancelRequest(): void; - completeRequest(trusted?: boolean): void; + completeRequest(trusted?: boolean): Promise; requestWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Promise; } +export interface IWorkspaceTrustTransitionParticipant { + participate(trusted: boolean): Promise; +} + export interface IWorkspaceTrustUriInfo { uri: URI, trusted: boolean diff --git a/lib/vscode/src/vs/platform/workspace/test/common/testWorkspace.ts b/src/vs/platform/workspace/test/common/testWorkspace.ts similarity index 100% rename from lib/vscode/src/vs/platform/workspace/test/common/testWorkspace.ts rename to src/vs/platform/workspace/test/common/testWorkspace.ts diff --git a/lib/vscode/src/vs/platform/workspace/test/common/workspace.test.ts b/src/vs/platform/workspace/test/common/workspace.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/workspace/test/common/workspace.test.ts rename to src/vs/platform/workspace/test/common/workspace.test.ts diff --git a/lib/vscode/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts similarity index 97% rename from lib/vscode/src/vs/platform/workspaces/common/workspaces.ts rename to src/vs/platform/workspaces/common/workspaces.ts index 811a44f2c4ac..7a11eafa2eb4 100644 --- a/lib/vscode/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -39,7 +39,7 @@ export interface IWorkspacesService { readonly _serviceBrand: undefined; // Workspaces Management - enterWorkspace(path: URI): Promise; + enterWorkspace(path: URI): Promise; createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise; deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise; getWorkspaceIdentifier(workspacePath: URI): Promise; @@ -320,7 +320,7 @@ export function toWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], const relativeTo = extUri.dirname(workspaceConfigFile); for (let configuredFolder of configuredFolders) { - let uri: URI | null = null; + let uri: URI | undefined = undefined; if (isRawFileWorkspaceFolder(configuredFolder)) { if (configuredFolder.path) { uri = extUri.resolvePath(relativeTo, configuredFolder.path); @@ -328,16 +328,16 @@ export function toWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], } else if (isRawUriWorkspaceFolder(configuredFolder)) { try { uri = URI.parse(configuredFolder.uri); - // this makes sure all workspace folder are absolute if (uri.path[0] !== '/') { - uri = uri.with({ path: '/' + uri.path }); + uri = uri.with({ path: '/' + uri.path }); // this makes sure all workspace folder are absolute } } catch (e) { - console.warn(e); - // ignore + console.warn(e); // ignore } } + if (uri) { + // remove duplicates let comparisonKey = extUri.getComparisonKey(uri); if (!seen.has(comparisonKey)) { @@ -369,11 +369,9 @@ export function rewriteWorkspaceFileForNewLocation(rawWorkspaceContents: string, const folderURI = isRawFileWorkspaceFolder(folder) ? extUri.resolvePath(sourceConfigFolder, folder.path) : URI.parse(folder.uri); let absolute; if (isFromUntitledWorkspace) { - // if it was an untitled workspace, try to make paths relative - absolute = false; + absolute = false; // if it was an untitled workspace, try to make paths relative } else { - // for existing workspaces, preserve whether a path was absolute or relative - absolute = !isRawFileWorkspaceFolder(folder) || isAbsolute(folder.path); + absolute = !isRawFileWorkspaceFolder(folder) || isAbsolute(folder.path); // for existing workspaces, preserve whether a path was absolute or relative } rewrittenFolders.push(getStoredWorkspaceFolder(folderURI, absolute, folder.name, targetConfigFolder, slashForPath, extUri)); } diff --git a/lib/vscode/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts similarity index 97% rename from lib/vscode/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts rename to src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts index dd246999d7b8..62c029d242bb 100644 --- a/lib/vscode/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts @@ -5,7 +5,7 @@ import { localize } from 'vs/nls'; import { coalesce } from 'vs/base/common/arrays'; -import { IStateService } from 'vs/platform/state/node/state'; +import { IStateMainService } from 'vs/platform/state/electron-main/state'; import { app, JumpListCategory, JumpListItem } from 'electron'; import { ILogService } from 'vs/platform/log/common/log'; import { normalizeDriveLetter, splitName } from 'vs/base/common/labels'; @@ -62,7 +62,7 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa private readonly macOSRecentDocumentsUpdater = this._register(new ThrottledDelayer(800)); constructor( - @IStateService private readonly stateService: IStateService, + @IStateMainService private readonly stateMainService: IStateMainService, @ILogService private readonly logService: ILogService, @IWorkspacesManagementMainService private readonly workspacesManagementMainService: IWorkspacesManagementMainService, @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService @@ -291,7 +291,7 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa } private getRecentlyOpenedFromStorage(): IRecentlyOpened { - const storedRecents = this.stateService.getItem(WorkspacesHistoryMainService.recentlyOpenedStorageKey); + const storedRecents = this.stateMainService.getItem(WorkspacesHistoryMainService.recentlyOpenedStorageKey); return restoreRecentlyOpened(storedRecents, this.logService); } @@ -299,7 +299,7 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa private saveRecentlyOpened(recent: IRecentlyOpened): void { const serialized = toStoreData(recent); - this.stateService.setItem(WorkspacesHistoryMainService.recentlyOpenedStorageKey, serialized); + this.stateMainService.setItem(WorkspacesHistoryMainService.recentlyOpenedStorageKey, serialized); } updateWindowsJumpList(): void { diff --git a/lib/vscode/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts similarity index 98% rename from lib/vscode/src/vs/platform/workspaces/electron-main/workspacesMainService.ts rename to src/vs/platform/workspaces/electron-main/workspacesMainService.ts index 67a5e54db3fb..88d90f9e74eb 100644 --- a/lib/vscode/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -25,13 +25,13 @@ export class WorkspacesMainService implements AddFirstParameterToFunctions { + async enterWorkspace(windowId: number, path: URI): Promise { const window = this.windowsMainService.getWindowById(windowId); if (window) { return this.workspacesManagementMainService.enterWorkspace(window, this.windowsMainService.getWindows(), path); } - return null; + return undefined; } createUntitledWorkspace(windowId: number, folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise { diff --git a/lib/vscode/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts similarity index 94% rename from lib/vscode/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts rename to src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts index 4a510b7ffb80..47a5be15c909 100644 --- a/lib/vscode/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts @@ -6,8 +6,8 @@ import { toWorkspaceFolders, IWorkspaceIdentifier, hasWorkspaceFileExtension, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, IUntitledWorkspaceInfo, getStoredWorkspaceFolder, IEnterWorkspaceResult, isUntitledWorkspace, isWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; import { join, dirname } from 'vs/base/common/path'; -import { writeFile, rimrafSync, readdirSync, writeFileSync } from 'vs/base/node/pfs'; -import { promises, readFileSync, existsSync, mkdirSync, statSync, Stats } from 'fs'; +import { writeFile, rimrafSync, readdirSync, writeFileSync, Promises } from 'vs/base/node/pfs'; +import { readFileSync, existsSync, mkdirSync, statSync, Stats } from 'fs'; import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; import { Event, Emitter } from 'vs/base/common/event'; import { ILogService } from 'vs/platform/log/common/log'; @@ -41,7 +41,7 @@ export interface IWorkspacesManagementMainService { readonly onDidDeleteUntitledWorkspace: Event; readonly onDidEnterWorkspace: Event; - enterWorkspace(intoWindow: ICodeWindow, openedWindows: ICodeWindow[], path: URI): Promise; + enterWorkspace(intoWindow: ICodeWindow, openedWindows: ICodeWindow[], path: URI): Promise; createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise; createUntitledWorkspaceSync(folders?: IWorkspaceFolderCreationData[]): IWorkspaceIdentifier; @@ -52,7 +52,7 @@ export interface IWorkspacesManagementMainService { getUntitledWorkspacesSync(): IUntitledWorkspaceInfo[]; isUntitledWorkspace(workspace: IWorkspaceIdentifier): boolean; - resolveLocalWorkspaceSync(path: URI): IResolvedWorkspace | null; + resolveLocalWorkspaceSync(path: URI): IResolvedWorkspace | undefined; getWorkspaceIdentifier(workspacePath: URI): Promise; } @@ -83,20 +83,20 @@ export class WorkspacesManagementMainService extends Disposable implements IWork super(); } - resolveLocalWorkspaceSync(uri: URI): IResolvedWorkspace | null { + resolveLocalWorkspaceSync(uri: URI): IResolvedWorkspace | undefined { if (!this.isWorkspacePath(uri)) { - return null; // does not look like a valid workspace config file + return undefined; // does not look like a valid workspace config file } if (uri.scheme !== Schemas.file) { - return null; + return undefined; } let contents: string; try { contents = readFileSync(uri.fsPath, 'utf8'); } catch (error) { - return null; // invalid workspace + return undefined; // invalid workspace } return this.doResolveWorkspace(uri, contents); @@ -106,7 +106,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork return isUntitledWorkspace(uri, this.environmentMainService) || hasWorkspaceFileExtension(uri); } - private doResolveWorkspace(path: URI, contents: string): IResolvedWorkspace | null { + private doResolveWorkspace(path: URI, contents: string): IResolvedWorkspace | undefined { try { const workspace = this.doParseStoredWorkspace(path, contents); const workspaceIdentifier = getWorkspaceIdentifier(path); @@ -120,7 +120,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork this.logService.warn(error.toString()); } - return null; + return undefined; } private doParseStoredWorkspace(path: URI, contents: string): IStoredWorkspace { @@ -142,7 +142,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork const { workspace, storedWorkspace } = this.newUntitledWorkspace(folders, remoteAuthority); const configPath = workspace.configPath.fsPath; - await promises.mkdir(dirname(configPath), { recursive: true }); + await Promises.mkdir(dirname(configPath), { recursive: true }); await writeFile(configPath, JSON.stringify(storedWorkspace, null, '\t')); return workspace; @@ -238,19 +238,19 @@ export class WorkspacesManagementMainService extends Disposable implements IWork return untitledWorkspaces; } - async enterWorkspace(window: ICodeWindow, windows: ICodeWindow[], path: URI): Promise { + async enterWorkspace(window: ICodeWindow, windows: ICodeWindow[], path: URI): Promise { if (!window || !window.win || !window.isReady) { - return null; // return early if the window is not ready or disposed + return undefined; // return early if the window is not ready or disposed } const isValid = await this.isValidTargetWorkspacePath(window, windows, path); if (!isValid) { - return null; // return early if the workspace is not valid + return undefined; // return early if the workspace is not valid } const result = this.doEnterWorkspace(window, getWorkspaceIdentifier(path)); if (!result) { - return null; + return undefined; } // Emit as event @@ -287,9 +287,9 @@ export class WorkspacesManagementMainService extends Disposable implements IWork return true; // OK } - private doEnterWorkspace(window: ICodeWindow, workspace: IWorkspaceIdentifier): IEnterWorkspaceResult | null { + private doEnterWorkspace(window: ICodeWindow, workspace: IWorkspaceIdentifier): IEnterWorkspaceResult | undefined { if (!window.config) { - return null; + return undefined; } window.focus(); diff --git a/lib/vscode/src/vs/platform/workspaces/test/common/workspaces.test.ts b/src/vs/platform/workspaces/test/common/workspaces.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/workspaces/test/common/workspaces.test.ts rename to src/vs/platform/workspaces/test/common/workspaces.test.ts diff --git a/lib/vscode/src/vs/platform/workspaces/test/electron-main/workspacesHistoryStorage.test.ts b/src/vs/platform/workspaces/test/electron-main/workspacesHistoryStorage.test.ts similarity index 100% rename from lib/vscode/src/vs/platform/workspaces/test/electron-main/workspacesHistoryStorage.test.ts rename to src/vs/platform/workspaces/test/electron-main/workspacesHistoryStorage.test.ts diff --git a/lib/vscode/src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts b/src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts similarity index 99% rename from lib/vscode/src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts rename to src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts index 1b524310e9c1..3769d7324bb7 100644 --- a/lib/vscode/src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts @@ -109,7 +109,7 @@ flakySuite('WorkspacesManagementMainService', () => { service = new WorkspacesManagementMainService(environmentMainService, new NullLogService(), new TestBackupMainService(), new TestDialogMainService(), productService); - return fs.promises.mkdir(untitledWorkspacesHomePath, { recursive: true }); + return pfs.Promises.mkdir(untitledWorkspacesHomePath, { recursive: true }); }); teardown(() => { diff --git a/lib/vscode/src/vs/vscode.d.ts b/src/vs/vscode.d.ts similarity index 78% rename from lib/vscode/src/vs/vscode.d.ts rename to src/vs/vscode.d.ts index ad38c32f8bbd..77b7c5465dc4 100644 --- a/lib/vscode/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -24,7 +24,7 @@ declare module 'vscode' { /** * The identifier of the actual command handler. - * @see [commands.registerCommand](#commands.registerCommand). + * @see {@link commands.registerCommand} */ command: string; @@ -43,7 +43,7 @@ declare module 'vscode' { /** * Represents a line of text, such as a line of source code. * - * TextLine objects are __immutable__. When a [document](#TextDocument) changes, + * TextLine objects are __immutable__. When a {@link TextDocument document} changes, * previously retrieved lines will not represent the latest state. */ export interface TextLine { @@ -76,14 +76,14 @@ declare module 'vscode' { /** * Whether this line is whitespace only, shorthand - * for [TextLine.firstNonWhitespaceCharacterIndex](#TextLine.firstNonWhitespaceCharacterIndex) === [TextLine.text.length](#TextLine.text). + * for {@link TextLine.firstNonWhitespaceCharacterIndex} === {@link TextLine.text TextLine.text.length}. */ readonly isEmptyOrWhitespace: boolean; } /** * Represents a text document, such as a source file. Text documents have - * [lines](#TextLine) and knowledge about an underlying resource like a file. + * {@link TextLine lines} and knowledge about an underlying resource like a file. */ export interface TextDocument { @@ -93,21 +93,21 @@ declare module 'vscode' { * *Note* that most documents use the `file`-scheme, which means they are files on disk. However, **not** all documents are * saved on disk and therefore the `scheme` must be checked before trying to access the underlying file or siblings on disk. * - * @see [FileSystemProvider](#FileSystemProvider) - * @see [TextDocumentContentProvider](#TextDocumentContentProvider) + * @see {@link FileSystemProvider} + * @see {@link TextDocumentContentProvider} */ readonly uri: Uri; /** * The file system path of the associated resource. Shorthand - * notation for [TextDocument.uri.fsPath](#TextDocument.uri). Independent of the uri scheme. + * notation for {@link TextDocument.uri TextDocument.uri.fsPath}. Independent of the uri scheme. */ readonly fileName: string; /** * Is this document representing an untitled file which has never been saved yet. *Note* that - * this does not mean the document will be saved to disk, use [`uri.scheme`](#Uri.scheme) - * to figure out where a document will be [saved](#FileSystemProvider), e.g. `file`, `ftp` etc. + * this does not mean the document will be saved to disk, use {@link Uri.scheme `uri.scheme`} + * to figure out where a document will be {@link FileSystemProvider saved}, e.g. `file`, `ftp` etc. */ readonly isUntitled: boolean; @@ -143,7 +143,7 @@ declare module 'vscode' { save(): Thenable; /** - * The [end of line](#EndOfLine) sequence that is predominately + * The {@link EndOfLine end of line} sequence that is predominately * used in this document. */ readonly eol: EndOfLine; @@ -159,7 +159,7 @@ declare module 'vscode' { * document are not reflected. * * @param line A line number in [0, lineCount). - * @return A [line](#TextLine). + * @return A {@link TextLine line}. */ lineAt(line: number): TextLine; @@ -168,18 +168,19 @@ declare module 'vscode' { * that the returned object is *not* live and changes to the * document are not reflected. * - * The position will be [adjusted](#TextDocument.validatePosition). + * The position will be {@link TextDocument.validatePosition adjusted}. + * + * @see {@link TextDocument.lineAt} * - * @see [TextDocument.lineAt](#TextDocument.lineAt) * @param position A position. - * @return A [line](#TextLine). + * @return A {@link TextLine line}. */ lineAt(position: Position): TextLine; /** * Converts the position to a zero-based offset. * - * The position will be [adjusted](#TextDocument.validatePosition). + * The position will be {@link TextDocument.validatePosition adjusted}. * * @param position A position. * @return A valid zero-based offset. @@ -190,13 +191,13 @@ declare module 'vscode' { * Converts a zero-based offset to a position. * * @param offset A zero-based offset. - * @return A valid [position](#Position). + * @return A valid {@link Position}. */ positionAt(offset: number): Position; /** * Get the text of this document. A substring can be retrieved by providing - * a range. The range will be [adjusted](#TextDocument.validateRange). + * a range. The range will be {@link TextDocument.validateRange adjusted}. * * @param range Include only the text included by the range. * @return The text inside the provided range or the entire text. @@ -206,16 +207,16 @@ declare module 'vscode' { /** * Get a word-range at the given position. By default words are defined by * common separators, like space, -, _, etc. In addition, per language custom - * [word definitions](#LanguageConfiguration.wordPattern) can be defined. It + * [word definitions} can be defined. It * is also possible to provide a custom regular expression. * * * *Note 1:* A custom regular expression must not match the empty string and * if it does, it will be ignored. * * *Note 2:* A custom regular expression will fail to match multiline strings * and in the name of speed regular expressions should not match words with - * spaces. Use [`TextLine.text`](#TextLine.text) for more complex, non-wordy, scenarios. + * spaces. Use {@link TextLine.text `TextLine.text`} for more complex, non-wordy, scenarios. * - * The position will be [adjusted](#TextDocument.validatePosition). + * The position will be {@link TextDocument.validatePosition adjusted}. * * @param position A position. * @param regex Optional regular expression that describes what a word is. @@ -244,8 +245,8 @@ declare module 'vscode' { * Represents a line and character position, such as * the position of the cursor. * - * Position objects are __immutable__. Use the [with](#Position.with) or - * [translate](#Position.translate) methods to derive new positions + * Position objects are __immutable__. Use the {@link Position.with with} or + * {@link Position.translate translate} methods to derive new positions * from an existing position. */ export class Position { @@ -343,8 +344,8 @@ declare module 'vscode' { /** * Create a new position derived from this position. * - * @param line Value that should be used as line value, default is the [existing value](#Position.line) - * @param character Value that should be used as character value, default is the [existing value](#Position.character) + * @param line Value that should be used as line value, default is the {@link Position.line existing value} + * @param character Value that should be used as character value, default is the {@link Position.character existing value} * @return A position where line and character are replaced by the given values. */ with(line?: number, character?: number): Position; @@ -361,21 +362,21 @@ declare module 'vscode' { /** * A range represents an ordered pair of two positions. - * It is guaranteed that [start](#Range.start).isBeforeOrEqual([end](#Range.end)) + * It is guaranteed that {@link Range.start start}.isBeforeOrEqual({@link Range.end end}) * - * Range objects are __immutable__. Use the [with](#Range.with), - * [intersection](#Range.intersection), or [union](#Range.union) methods + * Range objects are __immutable__. Use the {@link Range.with with}, + * {@link Range.intersection intersection}, or {@link Range.union union} methods * to derive new ranges from an existing range. */ export class Range { /** - * The start position. It is before or equal to [end](#Range.end). + * The start position. It is before or equal to {@link Range.end end}. */ readonly start: Position; /** - * The end position. It is after or equal to [start](#Range.start). + * The end position. It is after or equal to {@link Range.start start}. */ readonly end: Position; @@ -422,7 +423,7 @@ declare module 'vscode' { * Check if `other` equals this range. * * @param other A range. - * @return `true` when start and end are [equal](#Position.isEqual) to + * @return `true` when start and end are {@link Position.isEqual equal} to * start and end of this range. */ isEqual(other: Range): boolean; @@ -448,8 +449,8 @@ declare module 'vscode' { /** * Derived a new range from this range. * - * @param start A position that should be used as start. The default value is the [current start](#Range.start). - * @param end A position that should be used as end. The default value is the [current end](#Range.end). + * @param start A position that should be used as start. The default value is the {@link Range.start current start}. + * @param end A position that should be used as end. The default value is the {@link Range.end current end}. * @return A range derived from this range with the given start and end position. * If start and end are not different `this` range will be returned. */ @@ -472,13 +473,13 @@ declare module 'vscode' { /** * The position at which the selection starts. - * This position might be before or after [active](#Selection.active). + * This position might be before or after {@link Selection.active active}. */ anchor: Position; /** * The position of the cursor. - * This position might be before or after [anchor](#Selection.anchor). + * This position might be before or after {@link Selection.anchor anchor}. */ active: Position; @@ -501,13 +502,13 @@ declare module 'vscode' { constructor(anchorLine: number, anchorCharacter: number, activeLine: number, activeCharacter: number); /** - * A selection is reversed if [active](#Selection.active).isBefore([anchor](#Selection.anchor)). + * A selection is reversed if {@link Selection.active active}.isBefore({@link Selection.anchor anchor}). */ isReversed: boolean; } /** - * Represents sources that can cause [selection change events](#window.onDidChangeTextEditorSelection). + * Represents sources that can cause {@link window.onDidChangeTextEditorSelection selection change events}. */ export enum TextEditorSelectionChangeKind { /** @@ -525,62 +526,62 @@ declare module 'vscode' { } /** - * Represents an event describing the change in a [text editor's selections](#TextEditor.selections). + * Represents an event describing the change in a {@link TextEditor.selections text editor's selections}. */ export interface TextEditorSelectionChangeEvent { /** - * The [text editor](#TextEditor) for which the selections have changed. + * The {@link TextEditor text editor} for which the selections have changed. */ readonly textEditor: TextEditor; /** - * The new value for the [text editor's selections](#TextEditor.selections). + * The new value for the {@link TextEditor.selections text editor's selections}. */ - readonly selections: ReadonlyArray; + readonly selections: readonly Selection[]; /** - * The [change kind](#TextEditorSelectionChangeKind) which has triggered this + * The {@link TextEditorSelectionChangeKind change kind} which has triggered this * event. Can be `undefined`. */ readonly kind?: TextEditorSelectionChangeKind; } /** - * Represents an event describing the change in a [text editor's visible ranges](#TextEditor.visibleRanges). + * Represents an event describing the change in a {@link TextEditor.visibleRanges text editor's visible ranges}. */ export interface TextEditorVisibleRangesChangeEvent { /** - * The [text editor](#TextEditor) for which the visible ranges have changed. + * The {@link TextEditor text editor} for which the visible ranges have changed. */ readonly textEditor: TextEditor; /** - * The new value for the [text editor's visible ranges](#TextEditor.visibleRanges). + * The new value for the {@link TextEditor.visibleRanges text editor's visible ranges}. */ - readonly visibleRanges: ReadonlyArray; + readonly visibleRanges: readonly Range[]; } /** - * Represents an event describing the change in a [text editor's options](#TextEditor.options). + * Represents an event describing the change in a {@link TextEditor.options text editor's options}. */ export interface TextEditorOptionsChangeEvent { /** - * The [text editor](#TextEditor) for which the options have changed. + * The {@link TextEditor text editor} for which the options have changed. */ readonly textEditor: TextEditor; /** - * The new value for the [text editor's options](#TextEditor.options). + * The new value for the {@link TextEditor.options text editor's options}. */ readonly options: TextEditorOptions; } /** - * Represents an event describing the change of a [text editor's view column](#TextEditor.viewColumn). + * Represents an event describing the change of a {@link TextEditor.viewColumn text editor's view column}. */ export interface TextEditorViewColumnChangeEvent { /** - * The [text editor](#TextEditor) for which the view column has changed. + * The {@link TextEditor text editor} for which the view column has changed. */ readonly textEditor: TextEditor; /** - * The new value for the [text editor's view column](#TextEditor.viewColumn). + * The new value for the {@link TextEditor.viewColumn text editor's view column}. */ readonly viewColumn: ViewColumn; } @@ -634,14 +635,14 @@ declare module 'vscode' { } /** - * Represents a [text editor](#TextEditor)'s [options](#TextEditor.options). + * Represents a {@link TextEditor text editor}'s {@link TextEditor.options options}. */ export interface TextEditorOptions { /** * The size in spaces a tab takes. This is used for two purposes: * - the rendering width of a tab character; - * - the number of spaces to insert when [insertSpaces](#TextEditorOptions.insertSpaces) is true. + * - the number of spaces to insert when {@link TextEditorOptions.insertSpaces insertSpaces} is true. * * When getting a text editor's options, this property will always be a number (resolved). * When setting a text editor's options, this property is optional and it can be a number or `"auto"`. @@ -649,7 +650,7 @@ declare module 'vscode' { tabSize?: number | string; /** - * When pressing Tab insert [n](#TextEditorOptions.tabSize) spaces. + * When pressing Tab insert {@link TextEditorOptions.tabSize n} spaces. * When getting a text editor's options, this property will always be a boolean (resolved). * When setting a text editor's options, this property is optional and it can be a boolean or `"auto"`. */ @@ -672,10 +673,10 @@ declare module 'vscode' { /** * Represents a handle to a set of decorations - * sharing the same [styling options](#DecorationRenderOptions) in a [text editor](#TextEditor). + * sharing the same {@link DecorationRenderOptions styling options} in a {@link TextEditor text editor}. * * To get an instance of a `TextEditorDecorationType` use - * [createTextEditorDecorationType](#window.createTextEditorDecorationType). + * {@link window.createTextEditorDecorationType createTextEditorDecorationType}. */ export interface TextEditorDecorationType { @@ -691,7 +692,7 @@ declare module 'vscode' { } /** - * Represents different [reveal](#TextEditor.revealRange) strategies in a text editor. + * Represents different {@link TextEditor.revealRange reveal} strategies in a text editor. */ export enum TextEditorRevealType { /** @@ -714,7 +715,7 @@ declare module 'vscode' { } /** - * Represents different positions for rendering a decoration in an [overview ruler](#DecorationRenderOptions.overviewRulerLane). + * Represents different positions for rendering a decoration in an {@link DecorationRenderOptions.overviewRulerLane overview ruler}. * The overview ruler supports three lanes. */ export enum OverviewRulerLane { @@ -747,31 +748,31 @@ declare module 'vscode' { } /** - * Represents options to configure the behavior of showing a [document](#TextDocument) in an [editor](#TextEditor). + * Represents options to configure the behavior of showing a {@link TextDocument document} in an {@link TextEditor editor}. */ export interface TextDocumentShowOptions { /** - * An optional view column in which the [editor](#TextEditor) should be shown. - * The default is the [active](#ViewColumn.Active), other values are adjusted to - * be `Min(column, columnCount + 1)`, the [active](#ViewColumn.Active)-column is - * not adjusted. Use [`ViewColumn.Beside`](#ViewColumn.Beside) to open the + * An optional view column in which the {@link TextEditor editor} should be shown. + * The default is the {@link ViewColumn.Active active}, other values are adjusted to + * be `Min(column, columnCount + 1)`, the {@link ViewColumn.Active active}-column is + * not adjusted. Use {@link ViewColumn.Beside `ViewColumn.Beside`} to open the * editor to the side of the currently active one. */ viewColumn?: ViewColumn; /** - * An optional flag that when `true` will stop the [editor](#TextEditor) from taking focus. + * An optional flag that when `true` will stop the {@link TextEditor editor} from taking focus. */ preserveFocus?: boolean; /** - * An optional flag that controls if an [editor](#TextEditor)-tab will be replaced + * An optional flag that controls if an {@link TextEditor editor}-tab will be replaced * with the next editor or if it will be kept. */ preview?: boolean; /** - * An optional selection to apply for the document in the [editor](#TextEditor). + * An optional selection to apply for the document in the {@link TextEditor editor}. */ selection?: Range; } @@ -790,7 +791,7 @@ declare module 'vscode' { } /** - * A reference to a named icon. Currently, [File](#ThemeIcon.File), [Folder](#ThemeIcon.Folder), + * A reference to a named icon. Currently, {@link ThemeIcon.File File}, {@link ThemeIcon.Folder Folder}, * and [ThemeIcon ids](https://code.visualstudio.com/api/references/icons-in-labels#icon-listing) are supported. * Using a theme icon is preferred over a custom icon as it gives product theme authors the possibility to change the icons. * @@ -814,25 +815,25 @@ declare module 'vscode' { readonly id: string; /** - * The optional ThemeColor of the icon. The color is currently only used in [TreeItem](#TreeItem). + * The optional ThemeColor of the icon. The color is currently only used in {@link TreeItem}. */ readonly color?: ThemeColor; /** * Creates a reference to a theme icon. * @param id id of the icon. The available icons are listed in https://code.visualstudio.com/api/references/icons-in-labels#icon-listing. - * @param color optional `ThemeColor` for the icon. The color is currently only used in [TreeItem](#TreeItem). + * @param color optional `ThemeColor` for the icon. The color is currently only used in {@link TreeItem}. */ constructor(id: string, color?: ThemeColor); } /** - * Represents theme specific rendering styles for a [text editor decoration](#TextEditorDecorationType). + * Represents theme specific rendering styles for a {@link TextEditorDecorationType text editor decoration}. */ export interface ThemableDecorationRenderOptions { /** * Background color of the decoration. Use rgba() and define transparent background colors to play well with other decorations. - * Alternatively a color from the color registry can be [referenced](#ThemeColor). + * Alternatively a color from the color registry can be {@link ThemeColor referenced}. */ backgroundColor?: string | ThemeColor; @@ -1010,7 +1011,7 @@ declare module 'vscode' { } /** - * Represents rendering styles for a [text editor decoration](#TextEditorDecorationType). + * Represents rendering styles for a {@link TextEditorDecorationType text editor decoration}. */ export interface DecorationRenderOptions extends ThemableDecorationRenderOptions { /** @@ -1042,7 +1043,7 @@ declare module 'vscode' { } /** - * Represents options for a specific decoration in a [decoration set](#TextEditorDecorationType). + * Represents options for a specific decoration in a {@link TextEditorDecorationType decoration set}. */ export interface DecorationOptions { @@ -1088,7 +1089,7 @@ declare module 'vscode' { } /** - * Represents an editor that is attached to a [document](#TextDocument). + * Represents an editor that is attached to a {@link TextDocument document}. */ export interface TextEditor { @@ -1128,18 +1129,18 @@ declare module 'vscode' { /** * Perform an edit on the document associated with this text editor. * - * The given callback-function is invoked with an [edit-builder](#TextEditorEdit) which must + * The given callback-function is invoked with an {@link TextEditorEdit edit-builder} which must * be used to make edits. Note that the edit-builder is only valid while the * callback executes. * - * @param callback A function which can create edits using an [edit-builder](#TextEditorEdit). + * @param callback A function which can create edits using an {@link TextEditorEdit edit-builder}. * @param options The undo/redo behavior around this edit. By default, undo stops will be created before and after this edit. * @return A promise that resolves with a value indicating if the edits could be applied. */ edit(callback: (editBuilder: TextEditorEdit) => void, options?: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable; /** - * Insert a [snippet](#SnippetString) and put the editor into snippet mode. "Snippet mode" + * Insert a {@link SnippetString snippet} and put the editor into snippet mode. "Snippet mode" * means the editor adds placeholders and additional cursors so that the user can complete * or accept the snippet. * @@ -1149,18 +1150,20 @@ declare module 'vscode' { * @return A promise that resolves with a value indicating if the snippet could be inserted. Note that the promise does not signal * that the snippet is completely filled-in or accepted. */ - insertSnippet(snippet: SnippetString, location?: Position | Range | ReadonlyArray | ReadonlyArray, options?: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable; + insertSnippet(snippet: SnippetString, location?: Position | Range | readonly Position[] | readonly Range[], options?: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable; /** * Adds a set of decorations to the text editor. If a set of decorations already exists with - * the given [decoration type](#TextEditorDecorationType), they will be replaced. + * the given {@link TextEditorDecorationType decoration type}, they will be replaced. If + * `rangesOrOptions` is empty, the existing decorations with the given {@link TextEditorDecorationType decoration type} + * will be removed. * - * @see [createTextEditorDecorationType](#window.createTextEditorDecorationType). + * @see {@link window.createTextEditorDecorationType createTextEditorDecorationType}. * * @param decorationType A decoration type. - * @param rangesOrOptions Either [ranges](#Range) or more detailed [options](#DecorationOptions). + * @param rangesOrOptions Either {@link Range ranges} or more detailed {@link DecorationOptions options}. */ - setDecorations(decorationType: TextEditorDecorationType, rangesOrOptions: Range[] | DecorationOptions[]): void; + setDecorations(decorationType: TextEditorDecorationType, rangesOrOptions: readonly Range[] | readonly DecorationOptions[]): void; /** * Scroll as indicated by `revealType` in order to reveal the given range. @@ -1173,9 +1176,9 @@ declare module 'vscode' { /** * Show the text editor. * - * @deprecated Use [window.showTextDocument](#window.showTextDocument) instead. + * @deprecated Use {@link window.showTextDocument} instead. * - * @param column The [column](#ViewColumn) in which to show this editor. + * @param column The {@link ViewColumn column} in which to show this editor. * This method shows unexpected behavior and will be removed in the next major update. */ show(column?: ViewColumn): void; @@ -1190,7 +1193,7 @@ declare module 'vscode' { } /** - * Represents an end of line character sequence in a [document](#TextDocument). + * Represents an end of line character sequence in a {@link TextDocument document}. */ export enum EndOfLine { /** @@ -1206,12 +1209,12 @@ declare module 'vscode' { /** * A complex edit that will be applied in one transaction on a TextEditor. * This holds a description of the edits and if the edits are valid (i.e. no overlapping regions, document was not changed in the meantime, etc.) - * they can be applied on a [document](#TextDocument) associated with a [text editor](#TextEditor). + * they can be applied on a {@link TextDocument document} associated with a {@link TextEditor text editor}. */ export interface TextEditorEdit { /** * Replace a certain text region with a new value. - * You can use \r\n or \n in `value` and they will be normalized to the current [document](#TextDocument). + * You can use \r\n or \n in `value` and they will be normalized to the current {@link TextDocument document}. * * @param location The range this operation should remove. * @param value The new text this operation should insert after removing `location`. @@ -1220,8 +1223,8 @@ declare module 'vscode' { /** * Insert text at a location. - * You can use \r\n or \n in `value` and they will be normalized to the current [document](#TextDocument). - * Although the equivalent text edit can be made with [replace](#TextEditorEdit.replace), `insert` will produce a different resulting selection (it will get moved). + * You can use \r\n or \n in `value` and they will be normalized to the current {@link TextDocument document}. + * Although the equivalent text edit can be made with {@link TextEditorEdit.replace replace}, `insert` will produce a different resulting selection (it will get moved). * * @param location The position where the new text should be inserted. * @param value The new text this operation should insert. @@ -1238,7 +1241,7 @@ declare module 'vscode' { /** * Set the end of line sequence. * - * @param endOfLine The new end of line for the [document](#TextDocument). + * @param endOfLine The new end of line for the {@link TextDocument document}. */ setEndOfLine(endOfLine: EndOfLine): void; } @@ -1257,7 +1260,7 @@ declare module 'vscode' { * as all uris should have a scheme. To avoid breakage of existing code the optional * `strict`-argument has been added. We *strongly* advise to use it, e.g. `Uri.parse('my:uri', true)` * - * @see [Uri.toString](#Uri.toString) + * @see {@link Uri.toString} * @param value The string value of an Uri. * @param strict Throw an error when `value` is empty or when no `scheme` can be parsed. * @return A new Uri instance. @@ -1265,10 +1268,10 @@ declare module 'vscode' { static parse(value: string, strict?: boolean): Uri; /** - * Create an URI from a file system path. The [scheme](#Uri.scheme) + * Create an URI from a file system path. The {@link Uri.scheme scheme} * will be `file`. * - * The *difference* between `Uri#parse` and `Uri#file` is that the latter treats the argument + * The *difference* between {@link Uri.parse} and {@link Uri.file} is that the latter treats the argument * as path, not as stringified-uri. E.g. `Uri.file(path)` is *not* the same as * `Uri.parse('file://' + path)` because the path might contain characters that are * interpreted (# and ?). See the following sample: @@ -1311,6 +1314,15 @@ declare module 'vscode' { */ static joinPath(base: Uri, ...pathSegments: string[]): Uri; + /** + * Create an URI from its component parts + * + * @see {@link Uri.toString} + * @param components The component parts of an Uri. + * @return A new Uri instance. + */ + static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string }): Uri; + /** * Use the `file` and `parse` factory functions to create new `Uri` objects. */ @@ -1354,7 +1366,7 @@ declare module 'vscode' { * * The resulting string shall *not* be used for display purposes but * for disk operations, like `readFile` et al. * - * The *difference* to the [`path`](#Uri.path)-property is the use of the platform specific + * The *difference* to the {@link Uri.path `path`}-property is the use of the platform specific * path separator and the handling of UNC paths. The sample below outlines the difference: * ```ts const u = URI.parse('file://server/c$/folder/file.txt') @@ -1385,7 +1397,7 @@ declare module 'vscode' { * Returns a string representation of this Uri. The representation and normalization * of a URI depends on the scheme. * - * * The resulting string can be safely used with [Uri.parse](#Uri.parse). + * * The resulting string can be safely used with {@link Uri.parse}. * * The resulting string shall *not* be used for display purposes. * * *Note* that the implementation will encode _aggressive_ which often leads to unexpected, @@ -1414,7 +1426,7 @@ declare module 'vscode' { * for completion items because the user continued to type. * * To get an instance of a `CancellationToken` use a - * [CancellationTokenSource](#CancellationTokenSource). + * {@link CancellationTokenSource}. */ export interface CancellationToken { @@ -1424,13 +1436,13 @@ declare module 'vscode' { isCancellationRequested: boolean; /** - * An [event](#Event) which fires upon cancellation. + * An {@link Event} which fires upon cancellation. */ onCancellationRequested: Event; } /** - * A cancellation source creates and controls a [cancellation token](#CancellationToken). + * A cancellation source creates and controls a {@link CancellationToken cancellation token}. */ export class CancellationTokenSource { @@ -1453,7 +1465,7 @@ declare module 'vscode' { /** * An error type that should be used to signal cancellation of an operation. * - * This type can be used in response to a [cancellation token](#CancellationToken) + * This type can be used in response to a {@link CancellationToken cancellation token} * being cancelled or when an operation is being cancelled by the * executor of that operation. */ @@ -1512,18 +1524,18 @@ declare module 'vscode' { * * @param listener The listener function will be called when the event happens. * @param thisArgs The `this`-argument which will be used when calling the event listener. - * @param disposables An array to which a [disposable](#Disposable) will be added. + * @param disposables An array to which a {@link Disposable} will be added. * @return A disposable which unsubscribes the event listener. */ (listener: (e: T) => any, thisArgs?: any, disposables?: Disposable[]): Disposable; } /** - * An event emitter can be used to create and manage an [event](#Event) for others + * An event emitter can be used to create and manage an {@link Event} for others * to subscribe to. One emitter always owns one event. * * Use this class if you want to provide event from within your extension, for instance - * inside a [TextDocumentContentProvider](#TextDocumentContentProvider) or when providing + * inside a {@link TextDocumentContentProvider} or when providing * API to other extensions. */ export class EventEmitter { @@ -1534,7 +1546,7 @@ declare module 'vscode' { event: Event; /** - * Notify all subscribers of the [event](#EventEmitter.event). Failure + * Notify all subscribers of the {@link EventEmitter.event event}. Failure * of one or more listener will not fail this function call. * * @param data The event object. @@ -1549,10 +1561,10 @@ declare module 'vscode' { /** * A file system watcher notifies about changes to files and folders - * on disk or from other [FileSystemProviders](#FileSystemProvider). + * on disk or from other {@link FileSystemProvider FileSystemProviders}. * * To get an instance of a `FileSystemWatcher` use - * [createFileSystemWatcher](#workspace.createFileSystemWatcher). + * {@link workspace.createFileSystemWatcher createFileSystemWatcher}. */ export interface FileSystemWatcher extends Disposable { @@ -1594,9 +1606,9 @@ declare module 'vscode' { * A text document content provider allows to add readonly documents * to the editor, such as source from a dll or generated html from md. * - * Content providers are [registered](#workspace.registerTextDocumentContentProvider) - * for a [uri-scheme](#Uri.scheme). When a uri with that scheme is to - * be [loaded](#workspace.openTextDocument) the content provider is + * Content providers are {@link workspace.registerTextDocumentContentProvider registered} + * for a {@link Uri.scheme uri-scheme}. When a uri with that scheme is to + * be {@link workspace.openTextDocument loaded} the content provider is * asked. */ export interface TextDocumentContentProvider { @@ -1610,13 +1622,13 @@ declare module 'vscode' { * Provide textual content for a given uri. * * The editor will use the returned string-content to create a readonly - * [document](#TextDocument). Resources allocated should be released when - * the corresponding document has been [closed](#workspace.onDidCloseTextDocument). + * {@link TextDocument document}. Resources allocated should be released when + * the corresponding document has been {@link workspace.onDidCloseTextDocument closed}. * - * **Note**: The contents of the created [document](#TextDocument) might not be + * **Note**: The contents of the created {@link TextDocument document} might not be * identical to the provided text due to end-of-line-sequence normalization. * - * @param uri An uri which scheme matches the scheme this provider was [registered](#workspace.registerTextDocumentContentProvider) for. + * @param uri An uri which scheme matches the scheme this provider was {@link workspace.registerTextDocumentContentProvider registered} for. * @param token A cancellation token. * @return A string or a thenable that resolves to such. */ @@ -1630,20 +1642,20 @@ declare module 'vscode' { export interface QuickPickItem { /** - * A human-readable string which is rendered prominent. Supports rendering of [theme icons](#ThemeIcon) via + * A human-readable string which is rendered prominent. Supports rendering of {@link ThemeIcon theme icons} via * the `$()`-syntax. */ label: string; /** * A human-readable string which is rendered less prominent in the same line. Supports rendering of - * [theme icons](#ThemeIcon) via the `$()`-syntax. + * {@link ThemeIcon theme icons} via the `$()`-syntax. */ description?: string; /** * A human-readable string which is rendered less prominent in a separate line. Supports rendering of - * [theme icons](#ThemeIcon) via the `$()`-syntax. + * {@link ThemeIcon theme icons} via the `$()`-syntax. */ detail?: string; @@ -1651,7 +1663,7 @@ declare module 'vscode' { * Optional flag indicating if this item is picked initially. * (Only honored when the picker allows multiple selections.) * - * @see [QuickPickOptions.canPickMany](#QuickPickOptions.canPickMany) + * @see {@link QuickPickOptions.canPickMany} */ picked?: boolean; @@ -1703,7 +1715,7 @@ declare module 'vscode' { } /** - * Options to configure the behaviour of the [workspace folder](#WorkspaceFolder) pick UI. + * Options to configure the behaviour of the {@link WorkspaceFolder workspace folder} pick UI. */ export interface WorkspaceFolderPickOptions { @@ -1812,9 +1824,9 @@ declare module 'vscode' { * Represents an action that is shown with an information, warning, or * error message. * - * @see [showInformationMessage](#window.showInformationMessage) - * @see [showWarningMessage](#window.showWarningMessage) - * @see [showErrorMessage](#window.showErrorMessage) + * @see {@link window.showInformationMessage showInformationMessage} + * @see {@link window.showWarningMessage showWarningMessage} + * @see {@link window.showErrorMessage showErrorMessage} */ export interface MessageItem { @@ -1836,9 +1848,9 @@ declare module 'vscode' { /** * Options to configure the behavior of the message. * - * @see [showInformationMessage](#window.showInformationMessage) - * @see [showWarningMessage](#window.showWarningMessage) - * @see [showErrorMessage](#window.showErrorMessage) + * @see {@link window.showInformationMessage showInformationMessage} + * @see {@link window.showWarningMessage showWarningMessage} + * @see {@link window.showErrorMessage showErrorMessage} */ export interface MessageOptions { @@ -1864,7 +1876,7 @@ declare module 'vscode' { value?: string; /** - * Selection of the prefilled [`value`](#InputBoxOptions.value). Defined as tuple of two number where the + * Selection of the prefilled {@link InputBoxOptions.value `value`}. Defined as tuple of two number where the * first is the inclusive start index and the second the exclusive end index. When `undefined` the whole * word will be selected, when empty (start equals end) only the cursor will be set, * otherwise the defined range will be selected. @@ -1905,7 +1917,7 @@ declare module 'vscode' { /** * A relative pattern is a helper to construct glob patterns that are matched * relatively to a base file path. The base path can either be an absolute file - * path as string or uri or a [workspace folder](#WorkspaceFolder), which is the + * path as string or uri or a {@link WorkspaceFolder workspace folder}, which is the * preferred way of creating the relative pattern. */ export class RelativePattern { @@ -1942,7 +1954,7 @@ declare module 'vscode' { * ``` * * @param base A base to which this pattern will be matched against relatively. It is recommended - * to pass in a [workspace folder](#WorkspaceFolder) if the pattern should match inside the workspace. + * to pass in a {@link WorkspaceFolder workspace folder} if the pattern should match inside the workspace. * Otherwise, a uri or string should only be used if the pattern is for a file path outside the workspace. * @param pattern A file glob pattern like `*.{ts,js}` that will be matched on paths relative to the base. */ @@ -1951,7 +1963,7 @@ declare module 'vscode' { /** * A file glob pattern to match file paths against. This can either be a glob pattern string - * (like `**​/*.{ts,js}` or `*.{ts,js}`) or a [relative pattern](#RelativePattern). + * (like `**​/*.{ts,js}` or `*.{ts,js}`) or a {@link RelativePattern relative pattern}. * * Glob patterns can have the following syntax: * * `*` to match one or more characters in a path segment @@ -1962,7 +1974,7 @@ declare module 'vscode' { * * `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) * * Note: a backslash (`\`) is not valid within a glob pattern. If you have an existing file - * path to match against, consider to use the [relative pattern](#RelativePattern) support + * path to match against, consider to use the {@link RelativePattern relative pattern} support * that takes care of converting any backslash into slash. Otherwise, make sure to convert * any backslash to slash when creating the glob pattern. */ @@ -1970,8 +1982,8 @@ declare module 'vscode' { /** * A document filter denotes a document by different properties like - * the [language](#TextDocument.languageId), the [scheme](#Uri.scheme) of - * its resource, or a glob-pattern that is applied to the [path](#TextDocument.fileName). + * the {@link TextDocument.languageId language}, the {@link Uri.scheme scheme} of + * its resource, or a glob-pattern that is applied to the {@link TextDocument.fileName path}. * * @example A language filter that applies to typescript files on disk * { language: 'typescript', scheme: 'file' } @@ -1987,20 +1999,20 @@ declare module 'vscode' { readonly language?: string; /** - * A Uri [scheme](#Uri.scheme), like `file` or `untitled`. + * A Uri {@link Uri.scheme scheme}, like `file` or `untitled`. */ readonly scheme?: string; /** - * A [glob pattern](#GlobPattern) that is matched on the absolute path of the document. Use a [relative pattern](#RelativePattern) - * to filter documents to a [workspace folder](#WorkspaceFolder). + * A {@link GlobPattern glob pattern} that is matched on the absolute path of the document. Use a {@link RelativePattern relative pattern} + * to filter documents to a {@link WorkspaceFolder workspace folder}. */ readonly pattern?: GlobPattern; } /** * A language selector is the combination of one or many language identifiers - * and [language filters](#DocumentFilter). + * and {@link DocumentFilter language filters}. * * *Note* that a document selector that is just a language identifier selects *all* * documents, even those that are not saved on disk. Only use such selectors when @@ -2013,12 +2025,12 @@ declare module 'vscode' { export type DocumentSelector = DocumentFilter | string | ReadonlyArray; /** - * A provider result represents the values a provider, like the [`HoverProvider`](#HoverProvider), + * A provider result represents the values a provider, like the {@link HoverProvider `HoverProvider`}, * may return. For once this is the actual result type `T`, like `Hover`, or a thenable that resolves * to that type `T`. In addition, `null` and `undefined` can be returned - either directly or from a * thenable. * - * The snippets below are all valid implementations of the [`HoverProvider`](#HoverProvider): + * The snippets below are all valid implementations of the {@link HoverProvider `HoverProvider`}: * * ```ts * let a: HoverProvider = { @@ -2049,7 +2061,7 @@ declare module 'vscode' { * * Kinds are a hierarchical list of identifiers separated by `.`, e.g. `"refactor.extract.function"`. * - * Code action kinds are used by VS Code for UI elements such as the refactoring context menu. Users + * Code action kinds are used by the editor for UI elements such as the refactoring context menu. Users * can also trigger code actions with a specific kind with the `editor.action.codeAction` command. */ export class CodeActionKind { @@ -2188,7 +2200,7 @@ declare module 'vscode' { /** * Contains additional diagnostic information about the context in which - * a [code action](#CodeActionProvider.provideCodeActions) is run. + * a {@link CodeActionProvider.provideCodeActions code action} is run. */ export interface CodeActionContext { /** @@ -2199,7 +2211,7 @@ declare module 'vscode' { /** * An array of diagnostics. */ - readonly diagnostics: ReadonlyArray; + readonly diagnostics: readonly Diagnostic[]; /** * Requested kind of actions to return. @@ -2213,7 +2225,7 @@ declare module 'vscode' { * A code action represents a change that can be performed in code, e.g. to fix a problem or * to refactor code. * - * A CodeAction must set either [`edit`](#CodeAction.edit) and/or a [`command`](#CodeAction.command). If both are supplied, the `edit` is applied first, then the command is executed. + * A CodeAction must set either {@link CodeAction.edit `edit`} and/or a {@link CodeAction.command `command`}. If both are supplied, the `edit` is applied first, then the command is executed. */ export class CodeAction { @@ -2223,25 +2235,25 @@ declare module 'vscode' { title: string; /** - * A [workspace edit](#WorkspaceEdit) this code action performs. + * A {@link WorkspaceEdit workspace edit} this code action performs. */ edit?: WorkspaceEdit; /** - * [Diagnostics](#Diagnostic) that this code action resolves. + * {@link Diagnostic Diagnostics} that this code action resolves. */ diagnostics?: Diagnostic[]; /** - * A [command](#Command) this code action executes. + * A {@link Command} this code action executes. * - * If this command throws an exception, VS Code displays the exception message to users in the editor at the + * If this command throws an exception, the editor displays the exception message to users in the editor at the * current cursor position. */ command?: Command; /** - * [Kind](#CodeActionKind) of the code action. + * {@link CodeActionKind Kind} of the code action. * * Used to filter code actions. */ @@ -2266,7 +2278,7 @@ declare module 'vscode' { * of code action, such as refactorings. * * - If the user has a [keybinding](https://code.visualstudio.com/docs/editor/refactoring#_keybindings-for-code-actions) - * that auto applies a code action and only a disabled code actions are returned, VS Code will show the user an + * that auto applies a code action and only a disabled code actions are returned, the editor will show the user an * error message with `reason` in the editor. */ disabled?: { @@ -2281,8 +2293,8 @@ declare module 'vscode' { /** * Creates a new code action. * - * A code action must have at least a [title](#CodeAction.title) and [edits](#CodeAction.edit) - * and/or a [command](#CodeAction.command). + * A code action must have at least a {@link CodeAction.title title} and {@link CodeAction.edit edits} + * and/or a {@link CodeAction.command command}. * * @param title The title of the code action. * @param kind The kind of the code action. @@ -2294,7 +2306,7 @@ declare module 'vscode' { * The code action interface defines the contract between extensions and * the [lightbulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) feature. * - * A code action can be any command that is [known](#commands.getCommands) to the system. + * A code action can be any command that is {@link commands.getCommands known} to the system. */ export interface CodeActionProvider { /** @@ -2315,7 +2327,7 @@ declare module 'vscode' { provideCodeActions(document: TextDocument, range: Range | Selection, context: CodeActionContext, token: CancellationToken): ProviderResult<(Command | T)[]>; /** - * Given a code action fill in its [`edit`](#CodeAction.edit)-property. Changes to + * Given a code action fill in its {@link CodeAction.edit `edit`}-property. Changes to * all other properties, like title, are ignored. A code action that has an edit * will not be resolved. * @@ -2332,28 +2344,28 @@ declare module 'vscode' { } /** - * Metadata about the type of code actions that a [CodeActionProvider](#CodeActionProvider) provides. + * Metadata about the type of code actions that a {@link CodeActionProvider} provides. */ export interface CodeActionProviderMetadata { /** - * List of [CodeActionKinds](#CodeActionKind) that a [CodeActionProvider](#CodeActionProvider) may return. + * List of {@link CodeActionKind CodeActionKinds} that a {@link CodeActionProvider} may return. * * This list is used to determine if a given `CodeActionProvider` should be invoked or not. * To avoid unnecessary computation, every `CodeActionProvider` should list use `providedCodeActionKinds`. The * list of kinds may either be generic, such as `[CodeActionKind.Refactor]`, or list out every kind provided, * such as `[CodeActionKind.Refactor.Extract.append('function'), CodeActionKind.Refactor.Extract.append('constant'), ...]`. */ - readonly providedCodeActionKinds?: ReadonlyArray; + readonly providedCodeActionKinds?: readonly CodeActionKind[]; /** * Static documentation for a class of code actions. * * Documentation from the provider is shown in the code actions menu if either: * - * - Code actions of `kind` are requested by VS Code. In this case, VS Code will show the documentation that + * - Code actions of `kind` are requested by the editor. In this case, the editor will show the documentation that * most closely matches the requested code action kind. For example, if a provider has documentation for * both `Refactor` and `RefactorExtract`, when the user requests code actions for `RefactorExtract`, - * VS Code will use the documentation for `RefactorExtract` instead of the documentation for `Refactor`. + * the editor will use the documentation for `RefactorExtract` instead of the documentation for `Refactor`. * * - Any code actions of `kind` are returned by the provider. * @@ -2372,23 +2384,23 @@ declare module 'vscode' { /** * Command that displays the documentation to the user. * - * This can display the documentation directly in VS Code or open a website using [`env.openExternal`](#env.openExternal); + * This can display the documentation directly in the editor or open a website using {@link env.openExternal `env.openExternal`}; * - * The title of this documentation code action is taken from [`Command.title`](#Command.title) + * The title of this documentation code action is taken from {@link Command.title `Command.title`} */ readonly command: Command; }>; } /** - * A code lens represents a [command](#Command) that should be shown along with + * A code lens represents a {@link Command} that should be shown along with * source text, like the number of references, a way to run tests, etc. * * A code lens is _unresolved_ when no command is associated to it. For performance * reasons the creation of a code lens and resolving should be done to two stages. * - * @see [CodeLensProvider.provideCodeLenses](#CodeLensProvider.provideCodeLenses) - * @see [CodeLensProvider.resolveCodeLens](#CodeLensProvider.resolveCodeLens) + * @see {@link CodeLensProvider.provideCodeLenses} + * @see {@link CodeLensProvider.resolveCodeLens} */ export class CodeLens { @@ -2417,7 +2429,7 @@ declare module 'vscode' { } /** - * A code lens provider adds [commands](#Command) to source text. The commands will be shown + * A code lens provider adds {@link Command commands} to source text. The commands will be shown * as dedicated horizontal lines in between the source text. */ export interface CodeLensProvider { @@ -2428,9 +2440,9 @@ declare module 'vscode' { onDidChangeCodeLenses?: Event; /** - * Compute a list of [lenses](#CodeLens). This call should return as fast as possible and if + * Compute a list of {@link CodeLens lenses}. This call should return as fast as possible and if * computing the commands is expensive implementors should only return code lens objects with the - * range set and implement [resolve](#CodeLensProvider.resolveCodeLens). + * range set and implement {@link CodeLensProvider.resolveCodeLens resolve}. * * @param document The document in which the command was invoked. * @param token A cancellation token. @@ -2441,7 +2453,7 @@ declare module 'vscode' { /** * This function will be called for each visible code lens, usually when scrolling and after - * calls to [compute](#CodeLensProvider.provideCodeLenses)-lenses. + * calls to {@link CodeLensProvider.provideCodeLenses compute}-lenses. * * @param codeLens Code lens that must be resolved. * @param token A cancellation token. @@ -2453,7 +2465,7 @@ declare module 'vscode' { /** * Information about where a symbol is defined. * - * Provides additional metadata over normal {@link Location location} definitions, including the range of + * Provides additional metadata over normal {@link Location} definitions, including the range of * the defining symbol */ export type DefinitionLink = LocationLink; @@ -2521,8 +2533,8 @@ declare module 'vscode' { } /** - * The declaration of a symbol representation as one or many [locations](#Location) - * or [location links](#LocationLink). + * The declaration of a symbol representation as one or many {@link Location locations} + * or {@link LocationLink location links}. */ export type Declaration = Location | Location[] | LocationLink[]; @@ -2548,7 +2560,7 @@ declare module 'vscode' { * The MarkdownString represents human-readable text that supports formatting via the * markdown syntax. Standard markdown is supported, also tables, but no embedded html. * - * When created with `supportThemeIcons` then rendering of [theme icons](#ThemeIcon) via + * When created with `supportThemeIcons` then rendering of {@link ThemeIcon theme icons} via * the `$()`-syntax is supported. */ export class MarkdownString { @@ -2565,7 +2577,7 @@ declare module 'vscode' { isTrusted?: boolean; /** - * Indicates that this markdown string can contain [ThemeIcons](#ThemeIcon), e.g. `$(zap)`. + * Indicates that this markdown string can contain {@link ThemeIcon ThemeIcons}, e.g. `$(zap)`. */ readonly supportThemeIcons?: boolean; @@ -2573,7 +2585,7 @@ declare module 'vscode' { * Creates a new markdown string with the given value. * * @param value Optional, initial value. - * @param supportThemeIcons Optional, Specifies whether [ThemeIcons](#ThemeIcon) are supported within the [`MarkdownString`](#MarkdownString). + * @param supportThemeIcons Optional, Specifies whether {@link ThemeIcon ThemeIcons} are supported within the {@link MarkdownString `MarkdownString`}. */ constructor(value?: string, supportThemeIcons?: boolean); @@ -2584,7 +2596,7 @@ declare module 'vscode' { appendText(value: string): MarkdownString; /** - * Appends the given string 'as is' to this markdown string. When [`supportThemeIcons`](#MarkdownString.supportThemeIcons) is `true`, [ThemeIcons](#ThemeIcon) in the `value` will be iconified. + * Appends the given string 'as is' to this markdown string. When {@link MarkdownString.supportThemeIcons `supportThemeIcons`} is `true`, {@link ThemeIcon ThemeIcons} in the `value` will be iconified. * @param value Markdown string. */ appendMarkdown(value: string): MarkdownString; @@ -2592,7 +2604,7 @@ declare module 'vscode' { /** * Appends the given string as codeblock using the provided language. * @param value A code snippet. - * @param language An optional [language identifier](#languages.getLanguages). + * @param language An optional {@link languages.getLanguages language identifier}. */ appendCodeblock(value: string, language?: string): MarkdownString; } @@ -2602,7 +2614,7 @@ declare module 'vscode' { * or a code-block that provides a language and a code snippet. Note that * markdown strings will be sanitized - that means html will be escaped. * - * @deprecated This type is deprecated, please use [`MarkdownString`](#MarkdownString) instead. + * @deprecated This type is deprecated, please use {@link MarkdownString `MarkdownString`} instead. */ export type MarkedString = MarkdownString | string | { language: string; value: string }; @@ -2684,13 +2696,13 @@ declare module 'vscode' { /** * The evaluatable expression provider interface defines the contract between extensions and * the debug hover. In this contract the provider returns an evaluatable expression for a given position - * in a document and VS Code evaluates this expression in the active debug session and shows the result in a debug hover. + * in a document and the editor evaluates this expression in the active debug session and shows the result in a debug hover. */ export interface EvaluatableExpressionProvider { /** * Provide an evaluatable expression for the given document and position. - * VS Code will evaluate this expression in the active debug session and will show the result in the debug hover. + * The editor will evaluate this expression in the active debug session and will show the result in the debug hover. * The expression can be implicitly specified by the range in the underlying document or by explicitly returning an expression. * * @param document The document for which the debug hover is about to appear. @@ -2811,7 +2823,7 @@ declare module 'vscode' { /** * An optional event to signal that inline values have changed. - * @see [EventEmitter](#EventEmitter) + * @see {@link EventEmitter} */ onDidChangeInlineValues?: Event | undefined; @@ -2864,7 +2876,7 @@ declare module 'vscode' { range: Range; /** - * The highlight kind, default is [text](#DocumentHighlightKind.Text). + * The highlight kind, default is {@link DocumentHighlightKind.Text text}. */ kind?: DocumentHighlightKind; @@ -2872,7 +2884,7 @@ declare module 'vscode' { * Creates a new document highlight object. * * @param range The range the highlight applies to. - * @param kind The highlight kind, default is [text](#DocumentHighlightKind.Text). + * @param kind The highlight kind, default is {@link DocumentHighlightKind.Text text}. */ constructor(range: Range, kind?: DocumentHighlightKind); } @@ -2963,7 +2975,7 @@ declare module 'vscode' { /** * Tags for this symbol. */ - tags?: ReadonlyArray; + tags?: readonly SymbolTag[]; /** * The location of this symbol. @@ -2983,7 +2995,7 @@ declare module 'vscode' { /** * Creates a new symbol information object. * - * @deprecated Please use the constructor taking a [location](#Location) object. + * @deprecated Please use the constructor taking a {@link Location} object. * * @param name The name of the symbol. * @param kind The kind of the symbol. @@ -3019,7 +3031,7 @@ declare module 'vscode' { /** * Tags for this symbol. */ - tags?: ReadonlyArray; + tags?: readonly SymbolTag[]; /** * The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. @@ -3028,7 +3040,7 @@ declare module 'vscode' { /** * The range that should be selected and reveal when this symbol is being picked, e.g. the name of a function. - * Must be contained by the [`range`](#DocumentSymbol.range). + * Must be contained by the {@link DocumentSymbol.range `range`}. */ selectionRange: Range; @@ -3091,7 +3103,7 @@ declare module 'vscode' { * strict matching. * * To improve performance implementors can implement `resolveWorkspaceSymbol` and then provide symbols with partial - * [location](#SymbolInformation.location)-objects, without a `range` defined. The editor will then call + * {@link SymbolInformation.location location}-objects, without a `range` defined. The editor will then call * `resolveWorkspaceSymbol` for selected symbols only, e.g. when opening a workspace symbol. * * @param query A query string, can be the empty string in which case all symbols should be returned. @@ -3102,9 +3114,9 @@ declare module 'vscode' { provideWorkspaceSymbols(query: string, token: CancellationToken): ProviderResult; /** - * Given a symbol fill in its [location](#SymbolInformation.location). This method is called whenever a symbol + * Given a symbol fill in its {@link SymbolInformation.location location}. This method is called whenever a symbol * is selected in the UI. Providers can implement this method and return incomplete symbols from - * [`provideWorkspaceSymbols`](#WorkspaceSymbolProvider.provideWorkspaceSymbols) which often helps to improve + * {@link WorkspaceSymbolProvider.provideWorkspaceSymbols `provideWorkspaceSymbols`} which often helps to improve * performance. * * @param symbol The symbol that is to be resolved. Guaranteed to be an instance of an object returned from an @@ -3237,7 +3249,7 @@ declare module 'vscode' { description?: string; /** - * The icon path or [ThemeIcon](#ThemeIcon) for the edit. + * The icon path or {@link ThemeIcon} for the edit. */ iconPath?: Uri | { light: Uri; dark: Uri } | ThemeIcon; } @@ -3246,7 +3258,7 @@ declare module 'vscode' { * A workspace edit is a collection of textual and files changes for * multiple resources and documents. * - * Use the [applyEdit](#workspace.applyEdit)-function to apply a workspace edit. + * Use the {@link workspace.applyEdit applyEdit}-function to apply a workspace edit. */ export class WorkspaceEdit { @@ -3368,7 +3380,7 @@ declare module 'vscode' { /** * Builder-function that appends the given string to - * the [`value`](#SnippetString.value) of this snippet string. + * the {@link SnippetString.value `value`} of this snippet string. * * @param string A value to append 'as given'. The string will be escaped. * @return This snippet string. @@ -3377,7 +3389,7 @@ declare module 'vscode' { /** * Builder-function that appends a tabstop (`$1`, `$2` etc) to - * the [`value`](#SnippetString.value) of this snippet string. + * the {@link SnippetString.value `value`} of this snippet string. * * @param number The number of this tabstop, defaults to an auto-increment * value starting at 1. @@ -3387,7 +3399,7 @@ declare module 'vscode' { /** * Builder-function that appends a placeholder (`${1:value}`) to - * the [`value`](#SnippetString.value) of this snippet string. + * the {@link SnippetString.value `value`} of this snippet string. * * @param value The value of this placeholder - either a string or a function * with which a nested snippet can be created. @@ -3399,7 +3411,7 @@ declare module 'vscode' { /** * Builder-function that appends a choice (`${1|a,b,c|}`) to - * the [`value`](#SnippetString.value) of this snippet string. + * the {@link SnippetString.value `value`} of this snippet string. * * @param values The values for choices - the array of strings * @param number The number of this tabstop, defaults to an auto-increment @@ -3410,7 +3422,7 @@ declare module 'vscode' { /** * Builder-function that appends a variable (`${VAR}`) to - * the [`value`](#SnippetString.value) of this snippet string. + * the {@link SnippetString.value `value`} of this snippet string. * * @param name The name of the variable - excluding the `$`. * @param defaultValue The default value which is used when the variable name cannot @@ -3508,8 +3520,8 @@ declare module 'vscode' { /** * Represents semantic tokens, either in a range or in an entire document. - * @see [provideDocumentSemanticTokens](#DocumentSemanticTokensProvider.provideDocumentSemanticTokens) for an explanation of the format. - * @see [SemanticTokensBuilder](#SemanticTokensBuilder) for a helper to create an instance. + * @see {@link DocumentSemanticTokensProvider.provideDocumentSemanticTokens provideDocumentSemanticTokens} for an explanation of the format. + * @see {@link SemanticTokensBuilder} for a helper to create an instance. */ export class SemanticTokens { /** @@ -3520,7 +3532,7 @@ declare module 'vscode' { readonly resultId?: string; /** * The actual tokens data. - * @see [provideDocumentSemanticTokens](#DocumentSemanticTokensProvider.provideDocumentSemanticTokens) for an explanation of the format. + * @see {@link DocumentSemanticTokensProvider.provideDocumentSemanticTokens provideDocumentSemanticTokens} for an explanation of the format. */ readonly data: Uint32Array; @@ -3529,7 +3541,7 @@ declare module 'vscode' { /** * Represents edits to semantic tokens. - * @see [provideDocumentSemanticTokensEdits](#DocumentSemanticTokensProvider.provideDocumentSemanticTokensEdits) for an explanation of the format. + * @see {@link DocumentSemanticTokensProvider.provideDocumentSemanticTokensEdits provideDocumentSemanticTokensEdits} for an explanation of the format. */ export class SemanticTokensEdits { /** @@ -3549,7 +3561,7 @@ declare module 'vscode' { /** * Represents an edit to semantic tokens. - * @see [provideDocumentSemanticTokensEdits](#DocumentSemanticTokensProvider.provideDocumentSemanticTokensEdits) for an explanation of the format. + * @see {@link DocumentSemanticTokensProvider.provideDocumentSemanticTokensEdits provideDocumentSemanticTokensEdits} for an explanation of the format. */ export class SemanticTokensEdit { /** @@ -3633,7 +3645,7 @@ declare module 'vscode' { * [ 2,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] * ``` * - * @see [SemanticTokensBuilder](#SemanticTokensBuilder) for a helper to encode tokens as integers. + * @see {@link SemanticTokensBuilder} for a helper to encode tokens as integers. * *NOTE*: When doing edits, it is possible that multiple edits occur until VS Code decides to invoke the semantic tokens provider. * *NOTE*: If the provider cannot temporarily compute semantic tokens, it can indicate this by throwing an error with the message 'Busy'. */ @@ -3677,7 +3689,7 @@ declare module 'vscode' { */ export interface DocumentRangeSemanticTokensProvider { /** - * @see [provideDocumentSemanticTokens](#DocumentSemanticTokensProvider.provideDocumentSemanticTokens). + * @see {@link DocumentSemanticTokensProvider.provideDocumentSemanticTokens provideDocumentSemanticTokens}. */ provideDocumentRangeSemanticTokens(document: TextDocument, range: Range, token: CancellationToken): ProviderResult; } @@ -3778,8 +3790,8 @@ declare module 'vscode' { * The label of this signature. * * Either a string or inclusive start and exclusive end offsets within its containing - * [signature label](#SignatureInformation.label). *Note*: A label of type string must be - * a substring of its containing signature information's [label](#SignatureInformation.label). + * {@link SignatureInformation.label signature label}. *Note*: A label of type string must be + * a substring of its containing signature information's {@link SignatureInformation.label label}. */ label: string | [number, number]; @@ -3825,7 +3837,7 @@ declare module 'vscode' { /** * The index of the active parameter. * - * If provided, this is used in place of [`SignatureHelp.activeSignature`](#SignatureHelp.activeSignature). + * If provided, this is used in place of {@link SignatureHelp.activeSignature `SignatureHelp.activeSignature`}. */ activeParameter?: number; @@ -3862,7 +3874,7 @@ declare module 'vscode' { } /** - * How a [`SignatureHelpProvider`](#SignatureHelpProvider) was triggered. + * How a {@link SignatureHelpProvider `SignatureHelpProvider`} was triggered. */ export enum SignatureHelpTriggerKind { /** @@ -3883,7 +3895,7 @@ declare module 'vscode' { /** * Additional information about the context in which a - * [`SignatureHelpProvider`](#SignatureHelpProvider.provideSignatureHelp) was triggered. + * {@link SignatureHelpProvider.provideSignatureHelp `SignatureHelpProvider`} was triggered. */ export interface SignatureHelpContext { /** @@ -3908,7 +3920,7 @@ declare module 'vscode' { readonly isRetrigger: boolean; /** - * The currently active [`SignatureHelp`](#SignatureHelp). + * The currently active {@link SignatureHelp `SignatureHelp`}. * * The `activeSignatureHelp` has its [`SignatureHelp.activeSignature`] field updated based on * the user arrowing through available signatures. @@ -3937,13 +3949,13 @@ declare module 'vscode' { } /** - * Metadata about a registered [`SignatureHelpProvider`](#SignatureHelpProvider). + * Metadata about a registered {@link SignatureHelpProvider `SignatureHelpProvider`}. */ export interface SignatureHelpProviderMetadata { /** * List of characters that trigger signature help. */ - readonly triggerCharacters: ReadonlyArray; + readonly triggerCharacters: readonly string[]; /** * List of characters that re-trigger signature help. @@ -3951,7 +3963,7 @@ declare module 'vscode' { * These trigger characters are only active when signature help is already showing. All trigger characters * are also counted as re-trigger characters. */ - readonly retriggerCharacters: ReadonlyArray; + readonly retriggerCharacters: readonly string[]; } /** @@ -4001,17 +4013,17 @@ declare module 'vscode' { /** * A completion item represents a text snippet that is proposed to complete text that is being typed. * - * It is sufficient to create a completion item from just a [label](#CompletionItem.label). In that - * case the completion item will replace the [word](#TextDocument.getWordRangeAtPosition) - * until the cursor with the given label or [insertText](#CompletionItem.insertText). Otherwise the - * given [edit](#CompletionItem.textEdit) is used. + * It is sufficient to create a completion item from just a {@link CompletionItem.label label}. In that + * case the completion item will replace the {@link TextDocument.getWordRangeAtPosition word} + * until the cursor with the given label or {@link CompletionItem.insertText insertText}. Otherwise the + * given {@link CompletionItem.textEdit edit} is used. * * When selecting a completion item in the editor its defined or synthesized text edit will be applied - * to *all* cursors/selections whereas [additionalTextEdits](#CompletionItem.additionalTextEdits) will be + * to *all* cursors/selections whereas {@link CompletionItem.additionalTextEdits additionalTextEdits} will be * applied as provided. * - * @see [CompletionItemProvider.provideCompletionItems](#CompletionItemProvider.provideCompletionItems) - * @see [CompletionItemProvider.resolveCompletionItem](#CompletionItemProvider.resolveCompletionItem) + * @see {@link CompletionItemProvider.provideCompletionItems} + * @see {@link CompletionItemProvider.resolveCompletionItem} */ export class CompletionItem { @@ -4031,7 +4043,7 @@ declare module 'vscode' { /** * Tags for this completion item. */ - tags?: ReadonlyArray; + tags?: readonly CompletionItemTag[]; /** * A human-readable string with additional information @@ -4046,25 +4058,25 @@ declare module 'vscode' { /** * A string that should be used when comparing this item - * with other items. When `falsy` the [label](#CompletionItem.label) + * with other items. When `falsy` the {@link CompletionItem.label label} * is used. * * Note that `sortText` is only used for the initial ordering of completion * items. When having a leading word (prefix) ordering is based on how * well completions match that prefix and the initial ordering is only used * when completions match equally well. The prefix is defined by the - * [`range`](#CompletionItem.range)-property and can therefore be different + * {@link CompletionItem.range `range`}-property and can therefore be different * for each completion. */ sortText?: string; /** * A string that should be used when filtering a set of - * completion items. When `falsy` the [label](#CompletionItem.label) + * completion items. When `falsy` the {@link CompletionItem.label label} * is used. * * Note that the filter text is matched against the leading word (prefix) which is defined - * by the [`range`](#CompletionItem.range)-property. + * by the {@link CompletionItem.range `range`}-property. */ filterText?: string; @@ -4077,7 +4089,7 @@ declare module 'vscode' { /** * A string or snippet that should be inserted in a document when selecting - * this completion. When `falsy` the [label](#CompletionItem.label) + * this completion. When `falsy` the {@link CompletionItem.label label} * is used. */ insertText?: string | SnippetString; @@ -4085,12 +4097,12 @@ declare module 'vscode' { /** * A range or a insert and replace range selecting the text that should be replaced by this completion item. * - * When omitted, the range of the [current word](#TextDocument.getWordRangeAtPosition) is used as replace-range - * and as insert-range the start of the [current word](#TextDocument.getWordRangeAtPosition) to the + * When omitted, the range of the {@link TextDocument.getWordRangeAtPosition current word} is used as replace-range + * and as insert-range the start of the {@link TextDocument.getWordRangeAtPosition current word} to the * current position is used. * - * *Note 1:* A range must be a [single line](#Range.isSingleLine) and it must - * [contain](#Range.contains) the position at which completion has been [requested](#CompletionItemProvider.provideCompletionItems). + * *Note 1:* A range must be a {@link Range.isSingleLine single line} and it must + * {@link Range.contains contain} the position at which completion has been {@link CompletionItemProvider.provideCompletionItems requested}. * *Note 2:* A insert range must be a prefix of a replace range, that means it must be contained and starting at the same position. */ range?: Range | { inserting: Range; replacing: Range; }; @@ -4103,7 +4115,7 @@ declare module 'vscode' { commitCharacters?: string[]; /** - * Keep whitespace of the [insertText](#CompletionItem.insertText) as is. By default, the editor adjusts leading + * Keep whitespace of the {@link CompletionItem.insertText insertText} as is. By default, the editor adjusts leading * whitespace of new lines so that they match the indentation of the line for which the item is accepted - setting * this to `true` will prevent that. */ @@ -4112,43 +4124,43 @@ declare module 'vscode' { /** * @deprecated Use `CompletionItem.insertText` and `CompletionItem.range` instead. * - * An [edit](#TextEdit) which is applied to a document when selecting + * An {@link TextEdit edit} which is applied to a document when selecting * this completion. When an edit is provided the value of - * [insertText](#CompletionItem.insertText) is ignored. + * {@link CompletionItem.insertText insertText} is ignored. * - * The [range](#Range) of the edit must be single-line and on the same - * line completions were [requested](#CompletionItemProvider.provideCompletionItems) at. + * The {@link Range} of the edit must be single-line and on the same + * line completions were {@link CompletionItemProvider.provideCompletionItems requested} at. */ textEdit?: TextEdit; /** - * An optional array of additional [text edits](#TextEdit) that are applied when - * selecting this completion. Edits must not overlap with the main [edit](#CompletionItem.textEdit) + * An optional array of additional {@link TextEdit text edits} that are applied when + * selecting this completion. Edits must not overlap with the main {@link CompletionItem.textEdit edit} * nor with themselves. */ additionalTextEdits?: TextEdit[]; /** - * An optional [command](#Command) that is executed *after* inserting this completion. *Note* that + * An optional {@link Command} that is executed *after* inserting this completion. *Note* that * additional modifications to the current document should be described with the - * [additionalTextEdits](#CompletionItem.additionalTextEdits)-property. + * {@link CompletionItem.additionalTextEdits additionalTextEdits}-property. */ command?: Command; /** * Creates a new completion item. * - * Completion items must have at least a [label](#CompletionItem.label) which then + * Completion items must have at least a {@link CompletionItem.label label} which then * will be used as insert text as well as for sorting and filtering. * * @param label The label of the completion. - * @param kind The [kind](#CompletionItemKind) of the completion. + * @param kind The {@link CompletionItemKind kind} of the completion. */ constructor(label: string, kind?: CompletionItemKind); } /** - * Represents a collection of [completion items](#CompletionItem) to be presented + * Represents a collection of {@link CompletionItem completion items} to be presented * in the editor. */ export class CompletionList { @@ -4174,7 +4186,7 @@ declare module 'vscode' { } /** - * How a [completion provider](#CompletionItemProvider) was triggered + * How a {@link CompletionItemProvider completion provider} was triggered */ export enum CompletionTriggerKind { /** @@ -4193,7 +4205,7 @@ declare module 'vscode' { /** * Contains additional information about the context in which - * [completion provider](#CompletionItemProvider.provideCompletionItems) is triggered. + * {@link CompletionItemProvider.provideCompletionItems completion provider} is triggered. */ export interface CompletionContext { /** @@ -4215,9 +4227,9 @@ declare module 'vscode' { * The completion item provider interface defines the contract between extensions and * [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense). * - * Providers can delay the computation of the [`detail`](#CompletionItem.detail) - * and [`documentation`](#CompletionItem.documentation) properties by implementing the - * [`resolveCompletionItem`](#CompletionItemProvider.resolveCompletionItem)-function. However, properties that + * Providers can delay the computation of the {@link CompletionItem.detail `detail`} + * and {@link CompletionItem.documentation `documentation`} properties by implementing the + * {@link CompletionItemProvider.resolveCompletionItem `resolveCompletionItem`}-function. However, properties that * are needed for the initial sorting and filtering, like `sortText`, `filterText`, `insertText`, and `range`, must * not be changed during resolve. * @@ -4234,22 +4246,22 @@ declare module 'vscode' { * @param token A cancellation token. * @param context How the completion was triggered. * - * @return An array of completions, a [completion list](#CompletionList), or a thenable that resolves to either. + * @return An array of completions, a {@link CompletionList completion list}, or a thenable that resolves to either. * The lack of a result can be signaled by returning `undefined`, `null`, or an empty array. */ provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken, context: CompletionContext): ProviderResult>; /** - * Given a completion item fill in more data, like [doc-comment](#CompletionItem.documentation) - * or [details](#CompletionItem.detail). + * Given a completion item fill in more data, like {@link CompletionItem.documentation doc-comment} + * or {@link CompletionItem.detail details}. * * The editor will only resolve a completion item once. * * *Note* that this function is called when completion items are already showing in the UI or when an item has been * selected for insertion. Because of that, no property that changes the presentation (label, sorting, filtering etc) - * or the (primary) insert behaviour ([insertText](#CompletionItem.insertText)) can be changed. + * or the (primary) insert behaviour ({@link CompletionItem.insertText insertText}) can be changed. * - * This function may fill in [additionalTextEdits](#CompletionItem.additionalTextEdits). However, that means an item might be + * This function may fill in {@link CompletionItem.additionalTextEdits additionalTextEdits}. However, that means an item might be * inserted *before* resolving is done and in that case the editor will do a best effort to still apply those additional * text edits. * @@ -4307,15 +4319,15 @@ declare module 'vscode' { * * @param document The document in which the command was invoked. * @param token A cancellation token. - * @return An array of [document links](#DocumentLink) or a thenable that resolves to such. The lack of a result + * @return An array of {@link DocumentLink document links} or a thenable that resolves to such. The lack of a result * can be signaled by returning `undefined`, `null`, or an empty array. */ provideDocumentLinks(document: TextDocument, token: CancellationToken): ProviderResult; /** - * Given a link fill in its [target](#DocumentLink.target). This method is called when an incomplete + * Given a link fill in its {@link DocumentLink.target target}. This method is called when an incomplete * link is selected in the UI. Providers can implement this method and return incomplete links - * (without target) from the [`provideDocumentLinks`](#DocumentLinkProvider.provideDocumentLinks) method which + * (without target) from the {@link DocumentLinkProvider.provideDocumentLinks `provideDocumentLinks`} method which * often helps to improve performance. * * @param link The link that is to be resolved. @@ -4386,7 +4398,7 @@ declare module 'vscode' { } /** - * A color presentation object describes how a [`color`](#Color) should be represented as text and what + * A color presentation object describes how a {@link Color `color`} should be represented as text and what * edits are required to refer to it from source code. * * For some languages one color can have multiple presentations, e.g. css can represent the color red with @@ -4403,15 +4415,15 @@ declare module 'vscode' { label: string; /** - * An [edit](#TextEdit) which is applied to a document when selecting - * this presentation for the color. When `falsy` the [label](#ColorPresentation.label) + * An {@link TextEdit edit} which is applied to a document when selecting + * this presentation for the color. When `falsy` the {@link ColorPresentation.label label} * is used. */ textEdit?: TextEdit; /** - * An optional array of additional [text edits](#TextEdit) that are applied when - * selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves. + * An optional array of additional {@link TextEdit text edits} that are applied when + * selecting this color presentation. Edits must not overlap with the main {@link ColorPresentation.textEdit edit} nor with themselves. */ additionalTextEdits?: TextEdit[]; @@ -4434,13 +4446,13 @@ declare module 'vscode' { * * @param document The document in which the command was invoked. * @param token A cancellation token. - * @return An array of [color information](#ColorInformation) or a thenable that resolves to such. The lack of a result + * @return An array of {@link ColorInformation color information} or a thenable that resolves to such. The lack of a result * can be signaled by returning `undefined`, `null`, or an empty array. */ provideDocumentColors(document: TextDocument, token: CancellationToken): ProviderResult; /** - * Provide [representations](#ColorPresentation) for a color. + * Provide {@link ColorPresentation representations} for a color. * * @param color The color to show and insert. * @param context A context object with additional information @@ -4470,10 +4482,10 @@ declare module 'vscode' { end: number; /** - * Describes the [Kind](#FoldingRangeKind) of the folding range such as [Comment](#FoldingRangeKind.Comment) or - * [Region](#FoldingRangeKind.Region). The kind is used to categorize folding ranges and used by commands + * Describes the {@link FoldingRangeKind Kind} of the folding range such as {@link FoldingRangeKind.Comment Comment} or + * {@link FoldingRangeKind.Region Region}. The kind is used to categorize folding ranges and used by commands * like 'Fold all comments'. See - * [FoldingRangeKind](#FoldingRangeKind) for an enumeration of all kinds. + * {@link FoldingRangeKind} for an enumeration of all kinds. * If not set, the range is originated from a syntax element. */ kind?: FoldingRangeKind; @@ -4489,7 +4501,7 @@ declare module 'vscode' { } /** - * An enumeration of specific folding range kinds. The kind is an optional field of a [FoldingRange](#FoldingRange) + * An enumeration of specific folding range kinds. The kind is an optional field of a {@link FoldingRange} * and is used to distinguish specific folding ranges such as ranges originated from comments. The kind is used by commands like * `Fold all comments` or `Fold all regions`. * If the kind is not set on the range, the range originated from a syntax element other than comments, imports or region markers. @@ -4543,7 +4555,7 @@ declare module 'vscode' { export class SelectionRange { /** - * The [range](#Range) of this selection range. + * The {@link Range} of this selection range. */ range: Range; @@ -4567,7 +4579,7 @@ declare module 'vscode' { * * Selection ranges should be computed individually and independent for each position. The editor will merge * and deduplicate ranges but providers must return hierarchies of selection ranges so that a range - * is [contained](#Range.contains) by its parent. + * is {@link Range.contains contained} by its parent. * * @param document The document in which the command was invoked. * @param positions The positions at which the command was invoked. @@ -4596,7 +4608,7 @@ declare module 'vscode' { /** * Tags for this item. */ - tags?: ReadonlyArray; + tags?: readonly SymbolTag[]; /** * More detail for this item, e.g. the signature of a function. @@ -4615,7 +4627,7 @@ declare module 'vscode' { /** * The range that should be selected and revealed when this symbol is being picked, e.g. the name of a function. - * Must be contained by the [`range`](#CallHierarchyItem.range). + * Must be contained by the {@link CallHierarchyItem.range `range`}. */ selectionRange: Range; @@ -4637,7 +4649,7 @@ declare module 'vscode' { /** * The range at which at which the calls appears. This is relative to the caller - * denoted by [`this.from`](#CallHierarchyIncomingCall.from). + * denoted by {@link CallHierarchyIncomingCall.from `this.from`}. */ fromRanges: Range[]; @@ -4662,8 +4674,8 @@ declare module 'vscode' { /** * The range at which this item is called. This is the range relative to the caller, e.g the item - * passed to [`provideCallHierarchyOutgoingCalls`](#CallHierarchyProvider.provideCallHierarchyOutgoingCalls) - * and not [`this.to`](#CallHierarchyOutgoingCall.to). + * passed to {@link CallHierarchyProvider.provideCallHierarchyOutgoingCalls `provideCallHierarchyOutgoingCalls`} + * and not {@link CallHierarchyOutgoingCall.to `this.to`}. */ fromRanges: Range[]; @@ -4970,10 +4982,10 @@ declare module 'vscode' { * - *Default Settings* * - *Global (User) Settings* * - *Workspace settings* - * - *Workspace Folder settings* - From one of the [Workspace Folders](#workspace.workspaceFolders) under which requested resource belongs to. + * - *Workspace Folder settings* - From one of the {@link workspace.workspaceFolders Workspace Folders} under which requested resource belongs to. * - *Language settings* - Settings defined under requested language. * - * The *effective* value (returned by [`get`](#WorkspaceConfiguration.get)) is computed by overriding or merging the values in the following order. + * The *effective* value (returned by {@link WorkspaceConfiguration.get `get`}) is computed by overriding or merging the values in the following order. * * ``` * `defaultValue` (if defined in `package.json` otherwise derived from the value's type) @@ -5059,7 +5071,7 @@ declare module 'vscode' { * Retrieve all information about a configuration setting. A configuration value * often consists of a *default* value, a global or installation-wide value, * a workspace-specific value, folder-specific value - * and language-specific values (if [WorkspaceConfiguration](#WorkspaceConfiguration) is scoped to a language). + * and language-specific values (if {@link WorkspaceConfiguration} is scoped to a language). * * Also provides all language ids under which the given configuration setting is defined. * @@ -5091,20 +5103,20 @@ declare module 'vscode' { * * A value can be changed in * - * - [Global settings](#ConfigurationTarget.Global): Changes the value for all instances of the editor. - * - [Workspace settings](#ConfigurationTarget.Workspace): Changes the value for current workspace, if available. - * - [Workspace folder settings](#ConfigurationTarget.WorkspaceFolder): Changes the value for settings from one of the [Workspace Folders](#workspace.workspaceFolders) under which the requested resource belongs to. + * - {@link ConfigurationTarget.Global Global settings}: Changes the value for all instances of the editor. + * - {@link ConfigurationTarget.Workspace Workspace settings}: Changes the value for current workspace, if available. + * - {@link ConfigurationTarget.WorkspaceFolder Workspace folder settings}: Changes the value for settings from one of the {@link workspace.workspaceFolders Workspace Folders} under which the requested resource belongs to. * - Language settings: Changes the value for the requested languageId. * * *Note:* To remove a configuration value use `undefined`, like so: `config.update('somekey', undefined)` * * @param section Configuration name, supports _dotted_ names. * @param value The new value. - * @param configurationTarget The [configuration target](#ConfigurationTarget) or a boolean value. - * - If `true` updates [Global settings](#ConfigurationTarget.Global). - * - If `false` updates [Workspace settings](#ConfigurationTarget.Workspace). - * - If `undefined` or `null` updates to [Workspace folder settings](#ConfigurationTarget.WorkspaceFolder) if configuration is resource specific, - * otherwise to [Workspace settings](#ConfigurationTarget.Workspace). + * @param configurationTarget The {@link ConfigurationTarget configuration target} or a boolean value. + * - If `true` updates {@link ConfigurationTarget.Global Global settings}. + * - If `false` updates {@link ConfigurationTarget.Workspace Workspace settings}. + * - If `undefined` or `null` updates to {@link ConfigurationTarget.WorkspaceFolder Workspace folder settings} if configuration is resource specific, + * otherwise to {@link ConfigurationTarget.Workspace Workspace settings}. * @param overrideInLanguage Whether to update the value in the scope of requested languageId or not. * - If `true` updates the value under the requested languageId. * - If `undefined` updates the value under the requested languageId only if the configuration is defined for the language. @@ -5113,7 +5125,7 @@ declare module 'vscode' { * - window configuration to workspace folder * - configuration to workspace or workspace folder when no workspace is opened. * - configuration to workspace folder when there is no workspace folder settings. - * - configuration to workspace folder when [WorkspaceConfiguration](#WorkspaceConfiguration) is not scoped to a resource. + * - configuration to workspace folder when {@link WorkspaceConfiguration} is not scoped to a resource. */ update(section: string, value: any, configurationTarget?: ConfigurationTarget | boolean, overrideInLanguage?: boolean): Thenable; @@ -5149,7 +5161,7 @@ declare module 'vscode' { } /** - * Represents the connection of two locations. Provides additional metadata over normal [locations](#Location), + * Represents the connection of two locations. Provides additional metadata over normal {@link Location locations}, * including an origin range. */ export interface LocationLink { @@ -5185,7 +5197,7 @@ declare module 'vscode' { /** * An array of resources for which diagnostics have changed. */ - readonly uris: ReadonlyArray; + readonly uris: readonly Uri[]; } /** @@ -5282,7 +5294,7 @@ declare module 'vscode' { message: string; /** - * The severity, default is [error](#DiagnosticSeverity.Error). + * The severity, default is {@link DiagnosticSeverity.Error error}. */ severity: DiagnosticSeverity; @@ -5294,12 +5306,12 @@ declare module 'vscode' { /** * A code or identifier for this diagnostic. - * Should be used for later processing, e.g. when providing [code actions](#CodeActionContext). + * Should be used for later processing, e.g. when providing {@link CodeActionContext code actions}. */ code?: string | number | { /** * A code or identifier for this diagnostic. - * Should be used for later processing, e.g. when providing [code actions](#CodeActionContext). + * Should be used for later processing, e.g. when providing {@link CodeActionContext code actions}. */ value: string | number; @@ -5325,18 +5337,18 @@ declare module 'vscode' { * * @param range The range to which this diagnostic applies. * @param message The human-readable message. - * @param severity The severity, default is [error](#DiagnosticSeverity.Error). + * @param severity The severity, default is {@link DiagnosticSeverity.Error error}. */ constructor(range: Range, message: string, severity?: DiagnosticSeverity); } /** * A diagnostics collection is a container that manages a set of - * [diagnostics](#Diagnostic). Diagnostics are always scopes to a + * {@link Diagnostic diagnostics}. Diagnostics are always scopes to a * diagnostics collection and a resource. * * To get an instance of a `DiagnosticCollection` use - * [createDiagnosticCollection](#languages.createDiagnosticCollection). + * {@link languages.createDiagnosticCollection createDiagnosticCollection}. */ export interface DiagnosticCollection { @@ -5354,7 +5366,7 @@ declare module 'vscode' { * @param uri A resource identifier. * @param diagnostics Array of diagnostics or `undefined` */ - set(uri: Uri, diagnostics: ReadonlyArray | undefined): void; + set(uri: Uri, diagnostics: readonly Diagnostic[] | undefined): void; /** * Replace diagnostics for multiple resources in this collection. @@ -5366,7 +5378,7 @@ declare module 'vscode' { * * @param entries An array of tuples, like `[[file1, [d1, d2]], [file2, [d3, d4, d5]]]`, or `undefined`. */ - set(entries: ReadonlyArray<[Uri, ReadonlyArray | undefined]>): void; + set(entries: ReadonlyArray<[Uri, readonly Diagnostic[] | undefined]>): void; /** * Remove all diagnostics from this collection that belong @@ -5388,16 +5400,16 @@ declare module 'vscode' { * @param callback Function to execute for each entry. * @param thisArg The `this` context used when invoking the handler function. */ - forEach(callback: (uri: Uri, diagnostics: ReadonlyArray, collection: DiagnosticCollection) => any, thisArg?: any): void; + forEach(callback: (uri: Uri, diagnostics: readonly Diagnostic[], collection: DiagnosticCollection) => any, thisArg?: any): void; /** * Get the diagnostics for a given resource. *Note* that you cannot * modify the diagnostics-array returned from this call. * * @param uri A resource identifier. - * @returns An immutable array of [diagnostics](#Diagnostic) or `undefined`. + * @returns An immutable array of {@link Diagnostic diagnostics} or `undefined`. */ - get(uri: Uri): ReadonlyArray | undefined; + get(uri: Uri): readonly Diagnostic[] | undefined; /** * Check if this collection contains diagnostics for a @@ -5410,7 +5422,7 @@ declare module 'vscode' { /** * Dispose and free associated resources. Calls - * [clear](#DiagnosticCollection.clear). + * {@link DiagnosticCollection.clear clear}. */ dispose(): void; } @@ -5423,13 +5435,13 @@ declare module 'vscode' { export enum ViewColumn { /** * A *symbolic* editor column representing the currently active column. This value - * can be used when opening editors, but the *resolved* [viewColumn](#TextEditor.viewColumn)-value + * can be used when opening editors, but the *resolved* {@link TextEditor.viewColumn viewColumn}-value * of editors will always be `One`, `Two`, `Three`,... or `undefined` but never `Active`. */ Active = -1, /** * A *symbolic* editor column representing the column to the side of the active one. This value - * can be used when opening editors, but the *resolved* [viewColumn](#TextEditor.viewColumn)-value + * can be used when opening editors, but the *resolved* {@link TextEditor.viewColumn viewColumn}-value * of editors will always be `One`, `Two`, `Three`,... or `undefined` but never `Beside`. */ Beside = -2, @@ -5475,7 +5487,7 @@ declare module 'vscode' { * An output channel is a container for readonly textual information. * * To get an instance of an `OutputChannel` use - * [createOutputChannel](#window.createOutputChannel). + * {@link window.createOutputChannel createOutputChannel}. */ export interface OutputChannel { @@ -5572,6 +5584,14 @@ declare module 'vscode' { */ export interface StatusBarItem { + /** + * The identifier of this item. + * + * *Note*: if no identifier was provided by the {@link window.createStatusBarItem `window.createStatusBarItem`} + * method, the identifier will match the {@link Extension.id extension identifier}. + */ + readonly id: string; + /** * The alignment of this item. */ @@ -5583,6 +5603,13 @@ declare module 'vscode' { */ readonly priority?: number; + /** + * The name of the entry, like 'Python Language Indicator', 'Git Status' etc. + * Try to keep the length of the name short, yet descriptive enough that + * users can understand what the status bar item is about. + */ + name: string | undefined; + /** * The text to show for the entry. You can embed icons in the text by leveraging the syntax: * @@ -5616,17 +5643,17 @@ declare module 'vscode' { backgroundColor: ThemeColor | undefined; /** - * [`Command`](#Command) or identifier of a command to run on click. + * {@link Command `Command`} or identifier of a command to run on click. * - * The command must be [known](#commands.getCommands). + * The command must be {@link commands.getCommands known}. * - * Note that if this is a [`Command`](#Command) object, only the [`command`](#Command.command) and [`arguments`](#Command.arguments) + * Note that if this is a {@link Command `Command`} object, only the {@link Command.command `command`} and {@link Command.arguments `arguments`} * are used by VS Code. */ command: string | Command | undefined; /** - * Accessibility information used when screen reader interacts with this StatusBar item + * Accessibility information used when a screen reader interacts with this StatusBar item */ accessibilityInformation?: AccessibilityInformation; @@ -5642,7 +5669,7 @@ declare module 'vscode' { /** * Dispose and free associated resources. Call - * [hide](#StatusBarItem.hide). + * {@link StatusBarItem.hide hide}. */ dispose(): void; } @@ -5767,12 +5794,12 @@ declare module 'vscode' { */ export interface TerminalLink { /** - * The start index of the link on [TerminalLinkContext.line](#TerminalLinkContext.line]. + * The start index of the link on {@link TerminalLinkContext.line}. */ startIndex: number; /** - * The length of the link on [TerminalLinkContext.line](#TerminalLinkContext.line] + * The length of the link on {@link TerminalLinkContext.line}. */ length: number; @@ -5833,7 +5860,7 @@ declare module 'vscode' { * * *Note* that this event should be used to propagate information about children. * - * @see [EventEmitter](#EventEmitter) + * @see {@link EventEmitter} */ onDidChangeFileDecorations?: Event; @@ -5842,7 +5869,7 @@ declare module 'vscode' { * * *Note* that this function is only called when a file gets rendered in the UI. * This means a decoration from a descendent that propagates upwards must be signaled - * to the editor via the [onDidChangeFileDecorations](#FileDecorationProvider.onDidChangeFileDecorations)-event. + * to the editor via the {@link FileDecorationProvider.onDidChangeFileDecorations onDidChangeFileDecorations}-event. * * @param uri The uri of the file to provide a decoration for. * @param token A cancellation token. @@ -5872,7 +5899,7 @@ declare module 'vscode' { /** * Represents an extension. * - * To get an instance of an `Extension` use [getExtension](#extensions.getExtension). + * To get an instance of an `Extension` use {@link extensions.getExtension getExtension}. */ export interface Extension { @@ -5888,7 +5915,7 @@ declare module 'vscode' { /** * The absolute file path of the directory containing this extension. Shorthand - * notation for [Extension.extensionUri.fsPath](#Extension.extensionUri) (independent of the uri scheme). + * notation for {@link Extension.extensionUri Extension.extensionUri.fsPath} (independent of the uri scheme). */ readonly extensionPath: string; @@ -5907,7 +5934,7 @@ declare module 'vscode' { * or if an extension runs where the remote extension host runs. The extension kind * is defined in the `package.json`-file of extensions but can also be refined * via the `remote.extensionKind`-setting. When no remote extension host exists, - * the value is [`ExtensionKind.UI`](#ExtensionKind.UI). + * the value is {@link ExtensionKind.UI `ExtensionKind.UI`}. */ extensionKind: ExtensionKind; @@ -5966,13 +5993,13 @@ declare module 'vscode' { /** * A memento object that stores state in the context - * of the currently opened [workspace](#workspace.workspaceFolders). + * of the currently opened {@link workspace.workspaceFolders workspace}. */ readonly workspaceState: Memento; /** * A memento object that stores state independent - * of the current opened [workspace](#workspace.workspaceFolders). + * of the current opened {@link workspace.workspaceFolders workspace}. */ readonly globalState: Memento & { /** @@ -5988,11 +6015,12 @@ declare module 'vscode' { * * @param keys The set of keys whose values are synced. */ - setKeysForSync(keys: string[]): void; + setKeysForSync(keys: readonly string[]): void; }; /** - * A storage utility for secrets. + * A storage utility for secrets. Secrets are persisted across reloads and are independent of the + * current opened {@link workspace.workspaceFolders workspace}. */ readonly secrets: SecretStorage; @@ -6003,7 +6031,7 @@ declare module 'vscode' { /** * The absolute file path of the directory containing the extension. Shorthand - * notation for [ExtensionContext.extensionUri.fsPath](#TextDocument.uri) (independent of the uri scheme). + * notation for {@link TextDocument.uri ExtensionContext.extensionUri.fsPath} (independent of the uri scheme). */ readonly extensionPath: string; @@ -6016,8 +6044,8 @@ declare module 'vscode' { /** * Get the absolute path of a resource contained in the extension. * - * *Note* that an absolute uri can be constructed via [`Uri.joinPath`](#Uri.joinPath) and - * [`extensionUri`](#ExtensionContext.extensionUri), e.g. `vscode.Uri.joinPath(context.extensionUri, relativePath);` + * *Note* that an absolute uri can be constructed via {@link Uri.joinPath `Uri.joinPath`} and + * {@link ExtensionContext.extensionUri `extensionUri`}, e.g. `vscode.Uri.joinPath(context.extensionUri, relativePath);` * * @param relativePath A relative path to a resource contained in the extension. * @return The absolute path of the resource. @@ -6030,10 +6058,10 @@ declare module 'vscode' { * up to the extension. However, the parent directory is guaranteed to be existent. * The value is `undefined` when no workspace nor folder has been opened. * - * Use [`workspaceState`](#ExtensionContext.workspaceState) or - * [`globalState`](#ExtensionContext.globalState) to store key value data. + * Use {@link ExtensionContext.workspaceState `workspaceState`} or + * {@link ExtensionContext.globalState `globalState`} to store key value data. * - * @see [`workspace.fs`](#FileSystem) for how to read and write files and folders from + * @see {@link FileSystem `workspace.fs`} for how to read and write files and folders from * an uri. */ readonly storageUri: Uri | undefined; @@ -6043,10 +6071,10 @@ declare module 'vscode' { * can store private state. The directory might not exist on disk and creation is * up to the extension. However, the parent directory is guaranteed to be existent. * - * Use [`workspaceState`](#ExtensionContext.workspaceState) or - * [`globalState`](#ExtensionContext.globalState) to store key value data. + * Use {@link ExtensionContext.workspaceState `workspaceState`} or + * {@link ExtensionContext.globalState `globalState`} to store key value data. * - * @deprecated Use [storageUri](#ExtensionContext.storageUri) instead. + * @deprecated Use {@link ExtensionContext.storageUri storageUri} instead. */ readonly storagePath: string | undefined; @@ -6055,9 +6083,9 @@ declare module 'vscode' { * The directory might not exist on disk and creation is * up to the extension. However, the parent directory is guaranteed to be existent. * - * Use [`globalState`](#ExtensionContext.globalState) to store key value data. + * Use {@link ExtensionContext.globalState `globalState`} to store key value data. * - * @see [`workspace.fs`](#FileSystem) for how to read and write files and folders from + * @see {@link FileSystem `workspace.fs`} for how to read and write files and folders from * an uri. */ readonly globalStorageUri: Uri; @@ -6067,9 +6095,9 @@ declare module 'vscode' { * The directory might not exist on disk and creation is * up to the extension. However, the parent directory is guaranteed to be existent. * - * Use [`globalState`](#ExtensionContext.globalState) to store key value data. + * Use {@link ExtensionContext.globalState `globalState`} to store key value data. * - * @deprecated Use [globalStorageUri](#ExtensionContext.globalStorageUri) instead. + * @deprecated Use {@link ExtensionContext.globalStorageUri globalStorageUri} instead. */ readonly globalStoragePath: string; @@ -6078,7 +6106,7 @@ declare module 'vscode' { * The directory might not exist on disk and creation is up to the extension. However, * the parent directory is guaranteed to be existent. * - * @see [`workspace.fs`](#FileSystem) for how to read and write files and folders from + * @see {@link FileSystem `workspace.fs`} for how to read and write files and folders from * an uri. */ readonly logUri: Uri; @@ -6088,7 +6116,7 @@ declare module 'vscode' { * The directory might not exist on disk and creation is up to the extension. However, * the parent directory is guaranteed to be existent. * - * @deprecated Use [logUri](#ExtensionContext.logUri) instead. + * @deprecated Use {@link ExtensionContext.logUri logUri} instead. */ readonly logPath: string; @@ -6561,9 +6589,9 @@ declare module 'vscode' { /** * Constructs a CustomExecution task object. The callback will be executed when the task is run, at which point the * extension should return the Pseudoterminal it will "run in". The task should wait to do further execution until - * [Pseudoterminal.open](#Pseudoterminal.open) is called. Task cancellation should be handled using - * [Pseudoterminal.close](#Pseudoterminal.close). When the task is complete fire - * [Pseudoterminal.onDidClose](#Pseudoterminal.onDidClose). + * {@link Pseudoterminal.open} is called. Task cancellation should be handled using + * {@link Pseudoterminal.close}. When the task is complete fire + * {@link Pseudoterminal.onDidClose}. * @param callback The callback that will be called when the task is started by a user. Any ${} style variables that * were in the task definition will be resolved and passed into the callback as `resolvedDefinition`. */ @@ -6646,7 +6674,7 @@ declare module 'vscode' { /** * A human-readable string which is rendered less prominently on a separate line in places - * where the task's name is displayed. Supports rendering of [theme icons](#ThemeIcon) + * where the task's name is displayed. Supports rendering of {@link ThemeIcon theme icons} * via the `$()`-syntax. */ detail?: string; @@ -6663,7 +6691,7 @@ declare module 'vscode' { /** * A human-readable string describing the source of this shell task, e.g. 'gulp' - * or 'npm'. Supports rendering of [theme icons](#ThemeIcon) via the `$()`-syntax. + * or 'npm'. Supports rendering of {@link ThemeIcon theme icons} via the `$()`-syntax. */ source: string; @@ -6694,7 +6722,7 @@ declare module 'vscode' { /** * A task provider allows to add tasks to the task service. - * A task provider is registered via #tasks.registerTaskProvider. + * A task provider is registered via {@link tasks.registerTaskProvider}. */ export interface TaskProvider { /** @@ -6705,7 +6733,7 @@ declare module 'vscode' { provideTasks(token: CancellationToken): ProviderResult; /** - * Resolves a task that has no [`execution`](#Task.execution) set. Tasks are + * Resolves a task that has no {@link Task.execution `execution`} set. Tasks are * often created from information found in the `tasks.json`-file. Such tasks miss * the information on how to execute them and a task provider must fill in * the missing information in the `resolveTask`-method. This method will not be @@ -6823,7 +6851,7 @@ declare module 'vscode' { * * @param type The task kind type this provider is registered for. * @param provider A task provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerTaskProvider(type: string, provider: TaskProvider): Disposable; @@ -6851,7 +6879,7 @@ declare module 'vscode' { /** * The currently active task executions or an empty array. */ - export const taskExecutions: ReadonlyArray; + export const taskExecutions: readonly TaskExecution[]; /** * Fires when a task starts. @@ -6991,7 +7019,7 @@ declare module 'vscode' { /** * A code that identifies this error. * - * Possible values are names of errors, like [`FileNotFound`](#FileSystemError.FileNotFound), + * Possible values are names of errors, like {@link FileSystemError.FileNotFound `FileNotFound`}, * or `Unknown` for unspecified errors. */ readonly code: string; @@ -7039,22 +7067,22 @@ declare module 'vscode' { * and to manage files and folders. It allows extensions to serve files from remote places, * like ftp-servers, and to seamlessly integrate those into the editor. * - * * *Note 1:* The filesystem provider API works with [uris](#Uri) and assumes hierarchical + * * *Note 1:* The filesystem provider API works with {@link Uri uris} and assumes hierarchical * paths, e.g. `foo:/my/path` is a child of `foo:/my/` and a parent of `foo:/my/path/deeper`. * * *Note 2:* There is an activation event `onFileSystem:` that fires when a file * or folder is being accessed. - * * *Note 3:* The word 'file' is often used to denote all [kinds](#FileType) of files, e.g. + * * *Note 3:* The word 'file' is often used to denote all {@link FileType kinds} of files, e.g. * folders, symbolic links, and regular files. */ export interface FileSystemProvider { /** * An event to signal that a resource has been created, changed, or deleted. This - * event should fire for resources that are being [watched](#FileSystemProvider.watch) + * event should fire for resources that are being {@link FileSystemProvider.watch watched} * by clients of this provider. * * *Note:* It is important that the metadata of the file that changed provides an - * updated `mtime` that advanced from the previous value in the [stat](#FileStat) and a + * updated `mtime` that advanced from the previous value in the {@link FileStat stat} and a * correct `size` value. Otherwise there may be optimizations in place that will not show * the change in an editor for example. */ @@ -7077,21 +7105,21 @@ declare module 'vscode' { * Retrieve metadata about a file. * * Note that the metadata for symbolic links should be the metadata of the file they refer to. - * Still, the [SymbolicLink](#FileType.SymbolicLink)-type must be used in addition to the actual type, e.g. + * Still, the {@link FileType.SymbolicLink SymbolicLink}-type must be used in addition to the actual type, e.g. * `FileType.SymbolicLink | FileType.Directory`. * * @param uri The uri of the file to retrieve metadata about. * @return The file metadata about the file. - * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when `uri` doesn't exist. + * @throws {@link FileSystemError.FileNotFound `FileNotFound`} when `uri` doesn't exist. */ stat(uri: Uri): FileStat | Thenable; /** - * Retrieve all entries of a [directory](#FileType.Directory). + * Retrieve all entries of a {@link FileType.Directory directory}. * * @param uri The uri of the folder. * @return An array of name/type-tuples or a thenable that resolves to such. - * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when `uri` doesn't exist. + * @throws {@link FileSystemError.FileNotFound `FileNotFound`} when `uri` doesn't exist. */ readDirectory(uri: Uri): [string, FileType][] | Thenable<[string, FileType][]>; @@ -7099,9 +7127,9 @@ declare module 'vscode' { * Create a new directory (Note, that new files are created via `write`-calls). * * @param uri The uri of the new folder. - * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when the parent of `uri` doesn't exist, e.g. no mkdirp-logic required. - * @throws [`FileExists`](#FileSystemError.FileExists) when `uri` already exists. - * @throws [`NoPermissions`](#FileSystemError.NoPermissions) when permissions aren't sufficient. + * @throws {@link FileSystemError.FileNotFound `FileNotFound`} when the parent of `uri` doesn't exist, e.g. no mkdirp-logic required. + * @throws {@link FileSystemError.FileExists `FileExists`} when `uri` already exists. + * @throws {@link FileSystemError.NoPermissions `NoPermissions`} when permissions aren't sufficient. */ createDirectory(uri: Uri): void | Thenable; @@ -7110,7 +7138,7 @@ declare module 'vscode' { * * @param uri The uri of the file. * @return An array of bytes or a thenable that resolves to such. - * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when `uri` doesn't exist. + * @throws {@link FileSystemError.FileNotFound `FileNotFound`} when `uri` doesn't exist. */ readFile(uri: Uri): Uint8Array | Thenable; @@ -7120,10 +7148,10 @@ declare module 'vscode' { * @param uri The uri of the file. * @param content The new content of the file. * @param options Defines if missing files should or must be created. - * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when `uri` doesn't exist and `create` is not set. - * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when the parent of `uri` doesn't exist and `create` is set, e.g. no mkdirp-logic required. - * @throws [`FileExists`](#FileSystemError.FileExists) when `uri` already exists, `create` is set but `overwrite` is not set. - * @throws [`NoPermissions`](#FileSystemError.NoPermissions) when permissions aren't sufficient. + * @throws {@link FileSystemError.FileNotFound `FileNotFound`} when `uri` doesn't exist and `create` is not set. + * @throws {@link FileSystemError.FileNotFound `FileNotFound`} when the parent of `uri` doesn't exist and `create` is set, e.g. no mkdirp-logic required. + * @throws {@link FileSystemError.FileExists `FileExists`} when `uri` already exists, `create` is set but `overwrite` is not set. + * @throws {@link FileSystemError.NoPermissions `NoPermissions`} when permissions aren't sufficient. */ writeFile(uri: Uri, content: Uint8Array, options: { create: boolean, overwrite: boolean }): void | Thenable; @@ -7132,8 +7160,8 @@ declare module 'vscode' { * * @param uri The resource that is to be deleted. * @param options Defines if deletion of folders is recursive. - * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when `uri` doesn't exist. - * @throws [`NoPermissions`](#FileSystemError.NoPermissions) when permissions aren't sufficient. + * @throws {@link FileSystemError.FileNotFound `FileNotFound`} when `uri` doesn't exist. + * @throws {@link FileSystemError.NoPermissions `NoPermissions`} when permissions aren't sufficient. */ delete(uri: Uri, options: { recursive: boolean }): void | Thenable; @@ -7143,10 +7171,10 @@ declare module 'vscode' { * @param oldUri The existing file. * @param newUri The new location. * @param options Defines if existing files should be overwritten. - * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when `oldUri` doesn't exist. - * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when parent of `newUri` doesn't exist, e.g. no mkdirp-logic required. - * @throws [`FileExists`](#FileSystemError.FileExists) when `newUri` exists and when the `overwrite` option is not `true`. - * @throws [`NoPermissions`](#FileSystemError.NoPermissions) when permissions aren't sufficient. + * @throws {@link FileSystemError.FileNotFound `FileNotFound`} when `oldUri` doesn't exist. + * @throws {@link FileSystemError.FileNotFound `FileNotFound`} when parent of `newUri` doesn't exist, e.g. no mkdirp-logic required. + * @throws {@link FileSystemError.FileExists `FileExists`} when `newUri` exists and when the `overwrite` option is not `true`. + * @throws {@link FileSystemError.NoPermissions `NoPermissions`} when permissions aren't sufficient. */ rename(oldUri: Uri, newUri: Uri, options: { overwrite: boolean }): void | Thenable; @@ -7157,21 +7185,21 @@ declare module 'vscode' { * @param source The existing file. * @param destination The destination location. * @param options Defines if existing files should be overwritten. - * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when `source` doesn't exist. - * @throws [`FileNotFound`](#FileSystemError.FileNotFound) when parent of `destination` doesn't exist, e.g. no mkdirp-logic required. - * @throws [`FileExists`](#FileSystemError.FileExists) when `destination` exists and when the `overwrite` option is not `true`. - * @throws [`NoPermissions`](#FileSystemError.NoPermissions) when permissions aren't sufficient. + * @throws {@link FileSystemError.FileNotFound `FileNotFound`} when `source` doesn't exist. + * @throws {@link FileSystemError.FileNotFound `FileNotFound`} when parent of `destination` doesn't exist, e.g. no mkdirp-logic required. + * @throws {@link FileSystemError.FileExists `FileExists`} when `destination` exists and when the `overwrite` option is not `true`. + * @throws {@link FileSystemError.NoPermissions `NoPermissions`} when permissions aren't sufficient. */ copy?(source: Uri, destination: Uri, options: { overwrite: boolean }): void | Thenable; } /** * The file system interface exposes the editor's built-in and contributed - * [file system providers](#FileSystemProvider). It allows extensions to work + * {@link FileSystemProvider file system providers}. It allows extensions to work * with files from the local disk as well as files from remote places, like the * remote extension host or ftp-servers. * - * *Note* that an instance of this interface is available as [`workspace.fs`](#workspace.fs). + * *Note* that an instance of this interface is available as {@link workspace.fs `workspace.fs`}. */ export interface FileSystem { @@ -7184,7 +7212,7 @@ declare module 'vscode' { stat(uri: Uri): Thenable; /** - * Retrieve all entries of a [directory](#FileType.Directory). + * Retrieve all entries of a {@link FileType.Directory directory}. * * @param uri The uri of the folder. * @return An array of name/type-tuples or a thenable that resolves to such. @@ -7299,7 +7327,7 @@ declare module 'vscode' { * * Pass in an empty array to disallow access to any local resources. */ - readonly localResourceRoots?: ReadonlyArray; + readonly localResourceRoots?: readonly Uri[]; /** * Mappings of localhost ports used inside the webview. @@ -7314,7 +7342,7 @@ declare module 'vscode' { * *Note* that port mappings only work for `http` or `https` urls. Websocket urls (e.g. `ws://localhost:3000`) * cannot be mapped to another port. */ - readonly portMapping?: ReadonlyArray; + readonly portMapping?: readonly WebviewPortMapping[]; } /** @@ -7332,7 +7360,7 @@ declare module 'vscode' { * This should be a complete, valid html document. Changing this property causes the webview to be reloaded. * * Webviews are sandboxed from normal extension process, so all communication with the webview must use - * message passing. To send a message from the extension to the webview, use [`postMessage`](#Webview.postMessage). + * message passing. To send a message from the extension to the webview, use {@link Webview.postMessage `postMessage`}. * To send message from the webview back to an extension, use the `acquireVsCodeApi` function inside the webview * to get a handle to VS Code's api and then call `.postMessage()`: * @@ -7343,8 +7371,8 @@ declare module 'vscode' { * * ``` * - * To load a resources from the workspace inside a webview, use the `[asWebviewUri](#Webview.asWebviewUri)` method - * and ensure the resource's directory is listed in [`WebviewOptions.localResourceRoots`](#WebviewOptions.localResourceRoots). + * To load a resources from the workspace inside a webview, use the `{@link Webview.asWebviewUri asWebviewUri}` method + * and ensure the resource's directory is listed in {@link WebviewOptions.localResourceRoots `WebviewOptions.localResourceRoots`}. * * Keep in mind that even though webviews are sandboxed, they still allow running scripts and loading arbitrary content, * so extensions must follow all standard web security best practices when working with webviews. This includes @@ -7369,6 +7397,16 @@ declare module 'vscode' { * background with `retainContextWhenHidden`). * * @param message Body of the message. This must be a string or other json serializable object. + * + * For older versions of vscode, if an `ArrayBuffer` is included in `message`, + * it will not be serialized properly and will not be received by the webview. + * Similarly any TypedArrays, such as a `Uint8Array`, will be very inefficiently + * serialized and will also not be recreated as a typed array inside the webview. + * + * However if your extension targets vscode 1.57+ in the `engines` field of its + * `package.json`, any `ArrayBuffer` values that appear in `message` will be more + * efficiently transferred to the webview and will also be correctly recreated inside + * of the webview. */ postMessage(message: any): Thenable; @@ -7447,7 +7485,7 @@ declare module 'vscode' { iconPath?: Uri | { light: Uri; dark: Uri }; /** - * [`Webview`](#Webview) belonging to the panel. + * {@link Webview `Webview`} belonging to the panel. */ readonly webview: Webview; @@ -7692,7 +7730,7 @@ declare module 'vscode' { /** * Provider for text based custom editors. * - * Text based custom editors use a [`TextDocument`](#TextDocument) as their data model. This considerably simplifies + * Text based custom editors use a {@link TextDocument `TextDocument`} as their data model. This considerably simplifies * implementing a custom editor as it allows VS Code to handle many common operations such as * undo and backup. The provider is responsible for synchronizing text changes between the webview and the `TextDocument`. */ @@ -7711,7 +7749,7 @@ declare module 'vscode' { * * During resolve, the provider must fill in the initial html for the content webview panel and hook up all * the event listeners on it that it is interested in. The provider can also hold onto the `WebviewPanel` to - * use later for example in a command. See [`WebviewPanel`](#WebviewPanel) for additional details. + * use later for example in a command. See {@link WebviewPanel `WebviewPanel`} for additional details. * * @param token A cancellation token that indicates the result is no longer needed. * @@ -7721,7 +7759,7 @@ declare module 'vscode' { } /** - * Represents a custom document used by a [`CustomEditorProvider`](#CustomEditorProvider). + * Represents a custom document used by a {@link CustomEditorProvider `CustomEditorProvider`}. * * Custom documents are only used within a given `CustomEditorProvider`. The lifecycle of a `CustomDocument` is * managed by VS Code. When no more references remain to a `CustomDocument`, it is disposed of. @@ -7742,9 +7780,9 @@ declare module 'vscode' { } /** - * Event triggered by extensions to signal to VS Code that an edit has occurred on an [`CustomDocument`](#CustomDocument). + * Event triggered by extensions to signal to VS Code that an edit has occurred on an {@link CustomDocument `CustomDocument`}. * - * @see [`CustomDocumentProvider.onDidChangeCustomDocument`](#CustomDocumentProvider.onDidChangeCustomDocument). + * @see {@link CustomEditorProvider.onDidChangeCustomDocument `CustomEditorProvider.onDidChangeCustomDocument`}. */ interface CustomDocumentEditEvent { @@ -7780,10 +7818,10 @@ declare module 'vscode' { } /** - * Event triggered by extensions to signal to VS Code that the content of a [`CustomDocument`](#CustomDocument) + * Event triggered by extensions to signal to VS Code that the content of a {@link CustomDocument `CustomDocument`} * has changed. * - * @see [`CustomDocumentProvider.onDidChangeCustomDocument`](#CustomDocumentProvider.onDidChangeCustomDocument). + * @see {@link CustomEditorProvider.onDidChangeCustomDocument `CustomEditorProvider.onDidChangeCustomDocument`}. */ interface CustomDocumentContentChangeEvent { /** @@ -7793,7 +7831,7 @@ declare module 'vscode' { } /** - * A backup for an [`CustomDocument`](#CustomDocument). + * A backup for an {@link CustomDocument `CustomDocument`}. */ interface CustomDocumentBackup { /** @@ -7813,7 +7851,7 @@ declare module 'vscode' { } /** - * Additional information used to implement [`CustomEditableDocument.backup`](#CustomEditableDocument.backup). + * Additional information used to implement {@link CustomEditableDocument.backup `CustomEditableDocument.backup`}. */ interface CustomDocumentBackupContext { /** @@ -7851,10 +7889,10 @@ declare module 'vscode' { /** * Provider for readonly custom editors that use a custom document model. * - * Custom editors use [`CustomDocument`](#CustomDocument) as their document model instead of a [`TextDocument`](#TextDocument). + * Custom editors use {@link CustomDocument `CustomDocument`} as their document model instead of a {@link TextDocument `TextDocument`}. * * You should use this type of custom editor when dealing with binary files or more complex scenarios. For simple - * text based documents, use [`CustomTextEditorProvider`](#CustomTextEditorProvider) instead. + * text based documents, use {@link CustomTextEditorProvider `CustomTextEditorProvider`} instead. * * @param T Type of the custom document returned by this provider. */ @@ -7889,7 +7927,7 @@ declare module 'vscode' { * * During resolve, the provider must fill in the initial html for the content webview panel and hook up all * the event listeners on it that it is interested in. The provider can also hold onto the `WebviewPanel` to - * use later for example in a command. See [`WebviewPanel`](#WebviewPanel) for additional details. + * use later for example in a command. See {@link WebviewPanel `WebviewPanel`} for additional details. * * @param token A cancellation token that indicates the result is no longer needed. * @@ -7901,11 +7939,11 @@ declare module 'vscode' { /** * Provider for editable custom editors that use a custom document model. * - * Custom editors use [`CustomDocument`](#CustomDocument) as their document model instead of a [`TextDocument`](#TextDocument). + * Custom editors use {@link CustomDocument `CustomDocument`} as their document model instead of a {@link TextDocument `TextDocument`}. * This gives extensions full control over actions such as edit, save, and backup. * * You should use this type of custom editor when dealing with binary files or more complex scenarios. For simple - * text based documents, use [`CustomTextEditorProvider`](#CustomTextEditorProvider) instead. + * text based documents, use {@link CustomTextEditorProvider `CustomTextEditorProvider`} instead. * * @param T Type of the custom document returned by this provider. */ @@ -8097,7 +8135,7 @@ declare module 'vscode' { export const isTelemetryEnabled: boolean; /** - * An [event](#Event) which fires when the user enabled or disables telemetry. + * An {@link Event} which fires when the user enabled or disables telemetry. * `true` if the user has enabled telemetry or `false` if the user has disabled telemetry. */ export const onDidChangeTelemetryEnabled: Event; @@ -8108,7 +8146,7 @@ declare module 'vscode' { * * *Note* that the value is `undefined` when there is no remote extension host but that the * value is defined in all extension hosts (local and remote) in case a remote extension host - * exists. Use [`Extension#extensionKind`](#Extension.extensionKind) to know if + * exists. Use {@link Extension.extensionKind} to know if * a specific extension runs remote or not. */ export const remoteName: string | undefined; @@ -8134,7 +8172,7 @@ declare module 'vscode' { * * a mail client (`mailto:`) * * VSCode itself (`vscode:` from `vscode.env.uriScheme`) * - * *Note* that [`showTextDocument`](#window.showTextDocument) is the right + * *Note* that {@link window.showTextDocument `showTextDocument`} is the right * way to open a text document inside the editor, not this function. * * @param target The uri that should be opened. @@ -8161,7 +8199,7 @@ declare module 'vscode' { * * #### `vscode.env.uriScheme` * - * Creates a uri that - if opened in a browser (e.g. via `openExternal`) - will result in a registered [UriHandler](#UriHandler) + * Creates a uri that - if opened in a browser (e.g. via `openExternal`) - will result in a registered {@link UriHandler} * to trigger. * * Extensions should not make any assumptions about the resulting uri and should not alter it in anyway. @@ -8169,7 +8207,7 @@ declare module 'vscode' { * argument to the server to authenticate to. * * *Note* that if the server decides to add additional query parameters to the uri (e.g. a token or secret), it - * will appear in the uri that is passed to the [UriHandler](#UriHandler). + * will appear in the uri that is passed to the {@link UriHandler}. * * **Example** of an authentication flow: * ```typescript @@ -8198,9 +8236,9 @@ declare module 'vscode' { * Namespace for dealing with commands. In short, a command is a function with a * unique identifier. The function is sometimes also called _command handler_. * - * Commands can be added to the editor using the [registerCommand](#commands.registerCommand) - * and [registerTextEditorCommand](#commands.registerTextEditorCommand) functions. Commands - * can be executed [manually](#commands.executeCommand) or from a UI gesture. Those are: + * Commands can be added to the editor using the {@link commands.registerCommand registerCommand} + * and {@link commands.registerTextEditorCommand registerTextEditorCommand} functions. Commands + * can be executed {@link commands.executeCommand manually} or from a UI gesture. Those are: * * * palette - Use the `commands`-section in `package.json` to make a command show in * the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette). @@ -8250,14 +8288,14 @@ declare module 'vscode' { * Registers a text editor command that can be invoked via a keyboard shortcut, * a menu item, an action, or directly. * - * Text editor commands are different from ordinary [commands](#commands.registerCommand) as + * Text editor commands are different from ordinary {@link commands.registerCommand commands} as * they only execute when there is an active editor when the command is called. Also, the * command handler of an editor command has access to the active editor and to an - * [edit](#TextEditorEdit)-builder. Note that the edit-builder is only valid while the + * {@link TextEditorEdit edit}-builder. Note that the edit-builder is only valid while the * callback executes. * * @param command A unique identifier for the command. - * @param callback A command handler function with access to an [editor](#TextEditor) and an [edit](#TextEditorEdit). + * @param callback A command handler function with access to an {@link TextEditor editor} and an {@link TextEditorEdit edit}. * @param thisArg The `this` context used when invoking the handler function. * @return Disposable which unregisters this command on disposal. */ @@ -8268,7 +8306,7 @@ declare module 'vscode' { * * * *Note 1:* When executing an editor command not all types are allowed to * be passed as arguments. Allowed are the primitive types `string`, `boolean`, - * `number`, `undefined`, and `null`, as well as [`Position`](#Position), [`Range`](#Range), [`Uri`](#Uri) and [`Location`](#Location). + * `number`, `undefined`, and `null`, as well as {@link Position `Position`}, {@link Range `Range`}, {@link Uri `Uri`} and {@link Location `Location`}. * * *Note 2:* There are no restrictions when executing commands that have been contributed * by extensions. * @@ -8301,16 +8339,16 @@ declare module 'vscode' { } /** - * A uri handler is responsible for handling system-wide [uris](#Uri). + * A uri handler is responsible for handling system-wide {@link Uri uris}. * - * @see [window.registerUriHandler](#window.registerUriHandler). + * @see {@link window.registerUriHandler}. */ export interface UriHandler { /** - * Handle the provided system-wide [uri](#Uri). + * Handle the provided system-wide {@link Uri}. * - * @see [window.registerUriHandler](#window.registerUriHandler). + * @see {@link window.registerUriHandler}. */ handleUri(uri: Uri): ProviderResult; } @@ -8335,42 +8373,42 @@ declare module 'vscode' { export let visibleTextEditors: TextEditor[]; /** - * An [event](#Event) which fires when the [active editor](#window.activeTextEditor) + * An {@link Event} which fires when the {@link window.activeTextEditor active editor} * has changed. *Note* that the event also fires when the active editor changes * to `undefined`. */ export const onDidChangeActiveTextEditor: Event; /** - * An [event](#Event) which fires when the array of [visible editors](#window.visibleTextEditors) + * An {@link Event} which fires when the array of {@link window.visibleTextEditors visible editors} * has changed. */ export const onDidChangeVisibleTextEditors: Event; /** - * An [event](#Event) which fires when the selection in an editor has changed. + * An {@link Event} which fires when the selection in an editor has changed. */ export const onDidChangeTextEditorSelection: Event; /** - * An [event](#Event) which fires when the visible ranges of an editor has changed. + * An {@link Event} which fires when the visible ranges of an editor has changed. */ export const onDidChangeTextEditorVisibleRanges: Event; /** - * An [event](#Event) which fires when the options of an editor have changed. + * An {@link Event} which fires when the options of an editor have changed. */ export const onDidChangeTextEditorOptions: Event; /** - * An [event](#Event) which fires when the view column of an editor has changed. + * An {@link Event} which fires when the view column of an editor has changed. */ export const onDidChangeTextEditorViewColumn: Event; /** * The currently opened terminals or an empty array. */ - export const terminals: ReadonlyArray; + export const terminals: readonly Terminal[]; /** * The currently active terminal or `undefined`. The active terminal is the one that @@ -8379,20 +8417,20 @@ declare module 'vscode' { export const activeTerminal: Terminal | undefined; /** - * An [event](#Event) which fires when the [active terminal](#window.activeTerminal) + * An {@link Event} which fires when the {@link window.activeTerminal active terminal} * has changed. *Note* that the event also fires when the active terminal changes * to `undefined`. */ export const onDidChangeActiveTerminal: Event; /** - * An [event](#Event) which fires when a terminal has been created, either through the - * [createTerminal](#window.createTerminal) API or commands. + * An {@link Event} which fires when a terminal has been created, either through the + * {@link window.createTerminal createTerminal} API or commands. */ export const onDidOpenTerminal: Event; /** - * An [event](#Event) which fires when a terminal is disposed. + * An {@link Event} which fires when a terminal is disposed. */ export const onDidCloseTerminal: Event; @@ -8402,42 +8440,42 @@ declare module 'vscode' { export const state: WindowState; /** - * An [event](#Event) which fires when the focus state of the current window + * An {@link Event} which fires when the focus state of the current window * changes. The value of the event represents whether the window is focused. */ export const onDidChangeWindowState: Event; /** - * Show the given document in a text editor. A [column](#ViewColumn) can be provided - * to control where the editor is being shown. Might change the [active editor](#window.activeTextEditor). + * Show the given document in a text editor. A {@link ViewColumn column} can be provided + * to control where the editor is being shown. Might change the {@link window.activeTextEditor active editor}. * * @param document A text document to be shown. - * @param column A view column in which the [editor](#TextEditor) should be shown. The default is the [active](#ViewColumn.Active), other values - * are adjusted to be `Min(column, columnCount + 1)`, the [active](#ViewColumn.Active)-column is not adjusted. Use [`ViewColumn.Beside`](#ViewColumn.Beside) + * @param column A view column in which the {@link TextEditor editor} should be shown. The default is the {@link ViewColumn.Active active}, other values + * are adjusted to be `Min(column, columnCount + 1)`, the {@link ViewColumn.Active active}-column is not adjusted. Use {@link ViewColumn.Beside `ViewColumn.Beside`} * to open the editor to the side of the currently active one. * @param preserveFocus When `true` the editor will not take focus. - * @return A promise that resolves to an [editor](#TextEditor). + * @return A promise that resolves to an {@link TextEditor editor}. */ export function showTextDocument(document: TextDocument, column?: ViewColumn, preserveFocus?: boolean): Thenable; /** - * Show the given document in a text editor. [Options](#TextDocumentShowOptions) can be provided - * to control options of the editor is being shown. Might change the [active editor](#window.activeTextEditor). + * Show the given document in a text editor. {@link TextDocumentShowOptions Options} can be provided + * to control options of the editor is being shown. Might change the {@link window.activeTextEditor active editor}. * * @param document A text document to be shown. - * @param options [Editor options](#TextDocumentShowOptions) to configure the behavior of showing the [editor](#TextEditor). - * @return A promise that resolves to an [editor](#TextEditor). + * @param options {@link TextDocumentShowOptions Editor options} to configure the behavior of showing the {@link TextEditor editor}. + * @return A promise that resolves to an {@link TextEditor editor}. */ export function showTextDocument(document: TextDocument, options?: TextDocumentShowOptions): Thenable; /** * A short-hand for `openTextDocument(uri).then(document => showTextDocument(document, options))`. * - * @see [openTextDocument](#openTextDocument) + * @see {@link openTextDocument} * * @param uri A resource identifier. - * @param options [Editor options](#TextDocumentShowOptions) to configure the behavior of showing the [editor](#TextEditor). - * @return A promise that resolves to an [editor](#TextEditor). + * @param options {@link TextDocumentShowOptions Editor options} to configure the behavior of showing the {@link TextEditor editor}. + * @return A promise that resolves to an {@link TextEditor editor}. */ export function showTextDocument(uri: Uri, options?: TextDocumentShowOptions): Thenable; @@ -8473,7 +8511,7 @@ declare module 'vscode' { /** * Show an information message. * - * @see [showInformationMessage](#window.showInformationMessage) + * @see {@link window.showInformationMessage showInformationMessage} * * @param message The message to show. * @param items A set of items that will be rendered as actions in the message. @@ -8484,7 +8522,7 @@ declare module 'vscode' { /** * Show an information message. * - * @see [showInformationMessage](#window.showInformationMessage) + * @see {@link window.showInformationMessage showInformationMessage} * * @param message The message to show. * @param options Configures the behaviour of the message. @@ -8496,7 +8534,7 @@ declare module 'vscode' { /** * Show a warning message. * - * @see [showInformationMessage](#window.showInformationMessage) + * @see {@link window.showInformationMessage showInformationMessage} * * @param message The message to show. * @param items A set of items that will be rendered as actions in the message. @@ -8507,7 +8545,7 @@ declare module 'vscode' { /** * Show a warning message. * - * @see [showInformationMessage](#window.showInformationMessage) + * @see {@link window.showInformationMessage showInformationMessage} * * @param message The message to show. * @param options Configures the behaviour of the message. @@ -8519,7 +8557,7 @@ declare module 'vscode' { /** * Show a warning message. * - * @see [showInformationMessage](#window.showInformationMessage) + * @see {@link window.showInformationMessage showInformationMessage} * * @param message The message to show. * @param items A set of items that will be rendered as actions in the message. @@ -8530,7 +8568,7 @@ declare module 'vscode' { /** * Show a warning message. * - * @see [showInformationMessage](#window.showInformationMessage) + * @see {@link window.showInformationMessage showInformationMessage} * * @param message The message to show. * @param options Configures the behaviour of the message. @@ -8542,7 +8580,7 @@ declare module 'vscode' { /** * Show an error message. * - * @see [showInformationMessage](#window.showInformationMessage) + * @see {@link window.showInformationMessage showInformationMessage} * * @param message The message to show. * @param items A set of items that will be rendered as actions in the message. @@ -8553,7 +8591,7 @@ declare module 'vscode' { /** * Show an error message. * - * @see [showInformationMessage](#window.showInformationMessage) + * @see {@link window.showInformationMessage showInformationMessage} * * @param message The message to show. * @param options Configures the behaviour of the message. @@ -8565,7 +8603,7 @@ declare module 'vscode' { /** * Show an error message. * - * @see [showInformationMessage](#window.showInformationMessage) + * @see {@link window.showInformationMessage showInformationMessage} * * @param message The message to show. * @param items A set of items that will be rendered as actions in the message. @@ -8576,7 +8614,7 @@ declare module 'vscode' { /** * Show an error message. * - * @see [showInformationMessage](#window.showInformationMessage) + * @see {@link window.showInformationMessage showInformationMessage} * * @param message The message to show. * @param options Configures the behaviour of the message. @@ -8593,7 +8631,7 @@ declare module 'vscode' { * @param token A token that can be used to signal cancellation. * @return A promise that resolves to the selected items or `undefined`. */ - export function showQuickPick(items: string[] | Thenable, options: QuickPickOptions & { canPickMany: true; }, token?: CancellationToken): Thenable; + export function showQuickPick(items: readonly string[] | Thenable, options: QuickPickOptions & { canPickMany: true; }, token?: CancellationToken): Thenable; /** * Shows a selection list. @@ -8603,7 +8641,7 @@ declare module 'vscode' { * @param token A token that can be used to signal cancellation. * @return A promise that resolves to the selection or `undefined`. */ - export function showQuickPick(items: string[] | Thenable, options?: QuickPickOptions, token?: CancellationToken): Thenable; + export function showQuickPick(items: readonly string[] | Thenable, options?: QuickPickOptions, token?: CancellationToken): Thenable; /** * Shows a selection list allowing multiple selections. @@ -8613,7 +8651,7 @@ declare module 'vscode' { * @param token A token that can be used to signal cancellation. * @return A promise that resolves to the selected items or `undefined`. */ - export function showQuickPick(items: T[] | Thenable, options: QuickPickOptions & { canPickMany: true; }, token?: CancellationToken): Thenable; + export function showQuickPick(items: readonly T[] | Thenable, options: QuickPickOptions & { canPickMany: true; }, token?: CancellationToken): Thenable; /** * Shows a selection list. @@ -8623,10 +8661,10 @@ declare module 'vscode' { * @param token A token that can be used to signal cancellation. * @return A promise that resolves to the selected item or `undefined`. */ - export function showQuickPick(items: T[] | Thenable, options?: QuickPickOptions, token?: CancellationToken): Thenable; + export function showQuickPick(items: readonly T[] | Thenable, options?: QuickPickOptions, token?: CancellationToken): Thenable; /** - * Shows a selection list of [workspace folders](#workspace.workspaceFolders) to pick from. + * Shows a selection list of {@link workspace.workspaceFolders workspace folders} to pick from. * Returns `undefined` if no folder is open. * * @param options Configures the behavior of the workspace folder list. @@ -8666,30 +8704,30 @@ declare module 'vscode' { export function showInputBox(options?: InputBoxOptions, token?: CancellationToken): Thenable; /** - * Creates a [QuickPick](#QuickPick) to let the user pick an item from a list + * Creates a {@link QuickPick} to let the user pick an item from a list * of items of type T. * - * Note that in many cases the more convenient [window.showQuickPick](#window.showQuickPick) - * is easier to use. [window.createQuickPick](#window.createQuickPick) should be used - * when [window.showQuickPick](#window.showQuickPick) does not offer the required flexibility. + * Note that in many cases the more convenient {@link window.showQuickPick} + * is easier to use. {@link window.createQuickPick} should be used + * when {@link window.showQuickPick} does not offer the required flexibility. * - * @return A new [QuickPick](#QuickPick). + * @return A new {@link QuickPick}. */ export function createQuickPick(): QuickPick; /** - * Creates a [InputBox](#InputBox) to let the user enter some text input. + * Creates a {@link InputBox} to let the user enter some text input. * - * Note that in many cases the more convenient [window.showInputBox](#window.showInputBox) - * is easier to use. [window.createInputBox](#window.createInputBox) should be used - * when [window.showInputBox](#window.showInputBox) does not offer the required flexibility. + * Note that in many cases the more convenient {@link window.showInputBox} + * is easier to use. {@link window.createInputBox} should be used + * when {@link window.showInputBox} does not offer the required flexibility. * - * @return A new [InputBox](#InputBox). + * @return A new {@link InputBox}. */ export function createInputBox(): InputBox; /** - * Creates a new [output channel](#OutputChannel) with the given name. + * Creates a new {@link OutputChannel output channel} with the given name. * * @param name Human-readable string which will be used to represent the channel in the UI. */ @@ -8709,9 +8747,9 @@ declare module 'vscode' { /** * Set a message to the status bar. This is a short hand for the more powerful - * status bar [items](#window.createStatusBarItem). + * status bar {@link window.createStatusBarItem items}. * - * @param text The message to show, supports icon substitution as in status bar [items](#StatusBarItem.text). + * @param text The message to show, supports icon substitution as in status bar {@link StatusBarItem.text items}. * @param hideAfterTimeout Timeout in milliseconds after which the message will be disposed. * @return A disposable which hides the status bar message. */ @@ -8719,9 +8757,9 @@ declare module 'vscode' { /** * Set a message to the status bar. This is a short hand for the more powerful - * status bar [items](#window.createStatusBarItem). + * status bar {@link window.createStatusBarItem items}. * - * @param text The message to show, supports icon substitution as in status bar [items](#StatusBarItem.text). + * @param text The message to show, supports icon substitution as in status bar {@link StatusBarItem.text items}. * @param hideWhenDone Thenable on which completion (resolve or reject) the message will be disposed. * @return A disposable which hides the status bar message. */ @@ -8729,12 +8767,12 @@ declare module 'vscode' { /** * Set a message to the status bar. This is a short hand for the more powerful - * status bar [items](#window.createStatusBarItem). + * status bar {@link window.createStatusBarItem items}. * * *Note* that status bar messages stack and that they must be disposed when no * longer used. * - * @param text The message to show, supports icon substitution as in status bar [items](#StatusBarItem.text). + * @param text The message to show, supports icon substitution as in status bar {@link StatusBarItem.text items}. * @return A disposable which hides the status bar message. */ export function setStatusBarMessage(text: string): Disposable; @@ -8746,7 +8784,7 @@ declare module 'vscode' { * @deprecated Use `withProgress` instead. * * @param task A callback returning a promise. Progress increments can be reported with - * the provided [progress](#Progress)-object. + * the provided {@link Progress}-object. * @return The thenable the task did return. */ export function withScmProgress(task: (progress: Progress) => Thenable): Thenable; @@ -8754,17 +8792,17 @@ declare module 'vscode' { /** * Show progress in the editor. Progress is shown while running the given callback * and while the promise it returned isn't resolved nor rejected. The location at which - * progress should show (and other details) is defined via the passed [`ProgressOptions`](#ProgressOptions). + * progress should show (and other details) is defined via the passed {@link ProgressOptions `ProgressOptions`}. * * @param task A callback returning a promise. Progress state can be reported with - * the provided [progress](#Progress)-object. + * the provided {@link Progress}-object. * * To report discrete progress, use `increment` to indicate how much work has been completed. Each call with * a `increment` value will be summed up and reflected as overall progress until 100% is reached (a value of * e.g. `10` accounts for `10%` of work done). * Note that currently only `ProgressLocation.Notification` is capable of showing discrete progress. * - * To monitor if the operation has been cancelled by the user, use the provided [`CancellationToken`](#CancellationToken). + * To monitor if the operation has been cancelled by the user, use the provided {@link CancellationToken `CancellationToken`}. * Note that currently only `ProgressLocation.Notification` is supporting to show a cancel button to cancel the * long running operation. * @@ -8773,7 +8811,7 @@ declare module 'vscode' { export function withProgress(options: ProgressOptions, task: (progress: Progress<{ message?: string; increment?: number }>, token: CancellationToken) => Thenable): Thenable; /** - * Creates a status bar [item](#StatusBarItem). + * Creates a status bar {@link StatusBarItem item}. * * @param alignment The alignment of the item. * @param priority The priority of the item. Higher values mean the item should be shown more to the left. @@ -8782,7 +8820,17 @@ declare module 'vscode' { export function createStatusBarItem(alignment?: StatusBarAlignment, priority?: number): StatusBarItem; /** - * Creates a [Terminal](#Terminal) with a backing shell process. The cwd of the terminal will be the workspace + * Creates a status bar {@link StatusBarItem item}. + * + * @param id The unique identifier of the item. + * @param alignment The alignment of the item. + * @param priority The priority of the item. Higher values mean the item should be shown more to the left. + * @return A new status bar item. + */ + export function createStatusBarItem(id: string, alignment?: StatusBarAlignment, priority?: number): StatusBarItem; + + /** + * Creates a {@link Terminal} with a backing shell process. The cwd of the terminal will be the workspace * directory if it exists. * * @param name Optional human-readable string which will be used to represent the terminal in the UI. @@ -8796,7 +8844,7 @@ declare module 'vscode' { export function createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): Terminal; /** - * Creates a [Terminal](#Terminal) with a backing shell process. + * Creates a {@link Terminal} with a backing shell process. * * @param options A TerminalOptions object describing the characteristics of the new terminal. * @return A new Terminal. @@ -8805,35 +8853,35 @@ declare module 'vscode' { export function createTerminal(options: TerminalOptions): Terminal; /** - * Creates a [Terminal](#Terminal) where an extension controls its input and output. + * Creates a {@link Terminal} where an extension controls its input and output. * - * @param options An [ExtensionTerminalOptions](#ExtensionTerminalOptions) object describing + * @param options An {@link ExtensionTerminalOptions} object describing * the characteristics of the new terminal. * @return A new Terminal. */ export function createTerminal(options: ExtensionTerminalOptions): Terminal; /** - * Register a [TreeDataProvider](#TreeDataProvider) for the view contributed using the extension point `views`. - * This will allow you to contribute data to the [TreeView](#TreeView) and update if the data changes. + * Register a {@link TreeDataProvider} for the view contributed using the extension point `views`. + * This will allow you to contribute data to the {@link TreeView} and update if the data changes. * - * **Note:** To get access to the [TreeView](#TreeView) and perform operations on it, use [createTreeView](#window.createTreeView). + * **Note:** To get access to the {@link TreeView} and perform operations on it, use {@link window.createTreeView createTreeView}. * * @param viewId Id of the view contributed using the extension point `views`. - * @param treeDataProvider A [TreeDataProvider](#TreeDataProvider) that provides tree data for the view + * @param treeDataProvider A {@link TreeDataProvider} that provides tree data for the view */ export function registerTreeDataProvider(viewId: string, treeDataProvider: TreeDataProvider): Disposable; /** - * Create a [TreeView](#TreeView) for the view contributed using the extension point `views`. + * Create a {@link TreeView} for the view contributed using the extension point `views`. * @param viewId Id of the view contributed using the extension point `views`. - * @param options Options for creating the [TreeView](#TreeView) - * @returns a [TreeView](#TreeView). + * @param options Options for creating the {@link TreeView} + * @returns a {@link TreeView}. */ export function createTreeView(viewId: string, options: TreeViewOptions): TreeView; /** - * Registers a [uri handler](#UriHandler) capable of handling system-wide [uris](#Uri). + * Registers a {@link UriHandler uri handler} capable of handling system-wide {@link Uri uris}. * In case there are multiple windows open, the topmost window will handle the uri. * A uri handler is scoped to the extension it is contributed from; it will only * be able to handle uris which are directed to the extension itself. A uri must respect @@ -8859,7 +8907,7 @@ declare module 'vscode' { * Registers a webview panel serializer. * * Extensions that support reviving should have an `"onWebviewPanel:viewType"` activation event and - * make sure that [registerWebviewPanelSerializer](#registerWebviewPanelSerializer) is called during activation. + * make sure that {@link registerWebviewPanelSerializer} is called during activation. * * Only a single serializer may be registered at a time for a given `viewType`. * @@ -8888,7 +8936,7 @@ declare module 'vscode' { * * Normally the webview's html context is created when the view becomes visible * and destroyed when it is hidden. Extensions that have complex state - * or UI can set the `retainContextWhenHidden` to make VS Code keep the webview + * or UI can set the `retainContextWhenHidden` to make the editor keep the webview * context around, even when the webview moves to a background tab. When a webview using * `retainContextWhenHidden` becomes hidden, its scripts and other dynamic content are suspended. * When the view becomes visible again, the context is automatically restored @@ -8905,9 +8953,9 @@ declare module 'vscode' { /** * Register a provider for custom editors for the `viewType` contributed by the `customEditors` extension point. * - * When a custom editor is opened, VS Code fires an `onCustomEditor:viewType` activation event. Your extension - * must register a [`CustomTextEditorProvider`](#CustomTextEditorProvider), [`CustomReadonlyEditorProvider`](#CustomReadonlyEditorProvider), - * [`CustomEditorProvider`](#CustomEditorProvider)for `viewType` as part of activation. + * When a custom editor is opened, an `onCustomEditor:viewType` activation event is fired. Your extension + * must register a {@link CustomTextEditorProvider `CustomTextEditorProvider`}, {@link CustomReadonlyEditorProvider `CustomReadonlyEditorProvider`}, + * {@link CustomEditorProvider `CustomEditorProvider`}for `viewType` as part of activation. * * @param viewType Unique identifier for the custom editor provider. This should match the `viewType` from the * `customEditors` contribution point. @@ -8928,7 +8976,7 @@ declare module 'vscode' { * Indicates that the provider allows multiple editor instances to be open at the same time for * the same resource. * - * By default, VS Code only allows one editor instance to be open at a time for each resource. If the + * By default, the editor only allows one editor instance to be open at a time for each resource. If the * user tries to open a second editor instance for the resource, the first one is instead moved to where * the second one was to be opened. * @@ -8949,8 +8997,8 @@ declare module 'vscode' { /** * Register a file decoration provider. * - * @param provider A [FileDecorationProvider](#FileDecorationProvider). - * @return A [disposable](#Disposable) that unregisters the provider. + * @param provider A {@link FileDecorationProvider}. + * @return A {@link Disposable} that unregisters the provider. */ export function registerFileDecorationProvider(provider: FileDecorationProvider): Disposable; @@ -8961,13 +9009,13 @@ declare module 'vscode' { export let activeColorTheme: ColorTheme; /** - * An [event](#Event) which fires when the active color theme is changed or has changes. + * An {@link Event} which fires when the active color theme is changed or has changes. */ export const onDidChangeActiveColorTheme: Event; } /** - * Options for creating a [TreeView](#TreeView) + * Options for creating a {@link TreeView} */ export interface TreeViewOptions { @@ -8990,7 +9038,7 @@ declare module 'vscode' { } /** - * The event that is fired when an element in the [TreeView](#TreeView) is expanded or collapsed + * The event that is fired when an element in the {@link TreeView} is expanded or collapsed */ export interface TreeViewExpansionEvent { @@ -9002,7 +9050,7 @@ declare module 'vscode' { } /** - * The event that is fired when there is a change in [tree view's selection](#TreeView.selection) + * The event that is fired when there is a change in {@link TreeView.selection tree view's selection} */ export interface TreeViewSelectionChangeEvent { @@ -9014,12 +9062,12 @@ declare module 'vscode' { } /** - * The event that is fired when there is a change in [tree view's visibility](#TreeView.visible) + * The event that is fired when there is a change in {@link TreeView.visible tree view's visibility} */ export interface TreeViewVisibilityChangeEvent { /** - * `true` if the [tree view](#TreeView) is visible otherwise `false`. + * `true` if the {@link TreeView tree view} is visible otherwise `false`. */ readonly visible: boolean; @@ -9046,17 +9094,17 @@ declare module 'vscode' { readonly selection: T[]; /** - * Event that is fired when the [selection](#TreeView.selection) has changed + * Event that is fired when the {@link TreeView.selection selection} has changed */ readonly onDidChangeSelection: Event>; /** - * `true` if the [tree view](#TreeView) is visible otherwise `false`. + * `true` if the {@link TreeView tree view} is visible otherwise `false`. */ readonly visible: boolean; /** - * Event that is fired when [visibility](#TreeView.visible) has changed + * Event that is fired when {@link TreeView.visible visibility} has changed */ readonly onDidChangeVisibility: Event; @@ -9088,7 +9136,7 @@ declare module 'vscode' { * In order to expand the revealed element, set the option `expand` to `true`. To expand recursively set `expand` to the number of levels to expand. * **NOTE:** You can expand only to 3 levels maximum. * - * **NOTE:** The [TreeDataProvider](#TreeDataProvider) that the `TreeView` [is registered with](#window.createTreeView) with must implement [getParent](#TreeDataProvider.getParent) method to access this API. + * **NOTE:** The {@link TreeDataProvider} that the `TreeView` {@link window.createTreeView is registered with} with must implement {@link TreeDataProvider.getParent getParent} method to access this API. */ reveal(element: T, options?: { select?: boolean, focus?: boolean, expand?: boolean | number }): Thenable; } @@ -9105,10 +9153,10 @@ declare module 'vscode' { onDidChangeTreeData?: Event; /** - * Get [TreeItem](#TreeItem) representation of the `element` + * Get {@link TreeItem} representation of the `element` * - * @param element The element for which [TreeItem](#TreeItem) representation is asked for. - * @return [TreeItem](#TreeItem) representation of the element + * @param element The element for which {@link TreeItem} representation is asked for. + * @return {@link TreeItem} representation of the element */ getTreeItem(element: T): TreeItem | Thenable; @@ -9124,7 +9172,7 @@ declare module 'vscode' { * Optional method to return the parent of `element`. * Return `null` or `undefined` if `element` is a child of root. * - * **NOTE:** This method should be implemented in order to access [reveal](#TreeView.reveal) API. + * **NOTE:** This method should be implemented in order to access {@link TreeView.reveal reveal} API. * * @param element The element for which the parent has to be returned. * @return Parent of `element`. @@ -9132,8 +9180,8 @@ declare module 'vscode' { getParent?(element: T): ProviderResult; /** - * Called on hover to resolve the [TreeItem](#TreeItem.tooltip) property if it is undefined. - * Called on tree item click/open to resolve the [TreeItem](#TreeItem.command) property if it is undefined. + * Called on hover to resolve the {@link TreeItem.tooltip TreeItem} property if it is undefined. + * Called on tree item click/open to resolve the {@link TreeItem.command TreeItem} property if it is undefined. * Only properties that were undefined can be resolved in `resolveTreeItem`. * Functionality may be expanded later to include being called to resolve other missing * properties on selection and/or on open. @@ -9157,7 +9205,7 @@ declare module 'vscode' { export class TreeItem { /** - * A human-readable string describing this item. When `falsy`, it is derived from [resourceUri](#TreeItem.resourceUri). + * A human-readable string describing this item. When `falsy`, it is derived from {@link TreeItem.resourceUri resourceUri}. */ label?: string | TreeItemLabel; @@ -9169,23 +9217,23 @@ declare module 'vscode' { id?: string; /** - * The icon path or [ThemeIcon](#ThemeIcon) for the tree item. - * When `falsy`, [Folder Theme Icon](#ThemeIcon.Folder) is assigned, if item is collapsible otherwise [File Theme Icon](#ThemeIcon.File). - * When a file or folder [ThemeIcon](#ThemeIcon) is specified, icon is derived from the current file icon theme for the specified theme icon using [resourceUri](#TreeItem.resourceUri) (if provided). + * The icon path or {@link ThemeIcon} for the tree item. + * When `falsy`, {@link ThemeIcon.Folder Folder Theme Icon} is assigned, if item is collapsible otherwise {@link ThemeIcon.File File Theme Icon}. + * When a file or folder {@link ThemeIcon} is specified, icon is derived from the current file icon theme for the specified theme icon using {@link TreeItem.resourceUri resourceUri} (if provided). */ iconPath?: string | Uri | { light: string | Uri; dark: string | Uri } | ThemeIcon; /** * A human-readable string which is rendered less prominent. - * When `true`, it is derived from [resourceUri](#TreeItem.resourceUri) and when `falsy`, it is not shown. + * When `true`, it is derived from {@link TreeItem.resourceUri resourceUri} and when `falsy`, it is not shown. */ description?: string | boolean; /** - * The [uri](#Uri) of the resource representing this item. + * The {@link Uri} of the resource representing this item. * - * Will be used to derive the [label](#TreeItem.label), when it is not provided. - * Will be used to derive the icon from current file icon theme, when [iconPath](#TreeItem.iconPath) has [ThemeIcon](#ThemeIcon) value. + * Will be used to derive the {@link TreeItem.label label}, when it is not provided. + * Will be used to derive the icon from current file icon theme, when {@link TreeItem.iconPath iconPath} has {@link ThemeIcon} value. */ resourceUri?: Uri; @@ -9195,7 +9243,7 @@ declare module 'vscode' { tooltip?: string | MarkdownString | undefined; /** - * The [command](#Command) that should be executed when the tree item is selected. + * The {@link Command} that should be executed when the tree item is selected. * * Please use `vscode.open` or `vscode.diff` as command IDs when the tree item is opening * something in the editor. Using these commands ensures that the resulting editor will @@ -9204,7 +9252,7 @@ declare module 'vscode' { command?: Command; /** - * [TreeItemCollapsibleState](#TreeItemCollapsibleState) of the tree item. + * {@link TreeItemCollapsibleState} of the tree item. */ collapsibleState?: TreeItemCollapsibleState; @@ -9237,13 +9285,13 @@ declare module 'vscode' { /** * @param label A human-readable string describing this item - * @param collapsibleState [TreeItemCollapsibleState](#TreeItemCollapsibleState) of the tree item. Default is [TreeItemCollapsibleState.None](#TreeItemCollapsibleState.None) + * @param collapsibleState {@link TreeItemCollapsibleState} of the tree item. Default is {@link TreeItemCollapsibleState.None} */ constructor(label: string | TreeItemLabel, collapsibleState?: TreeItemCollapsibleState); /** - * @param resourceUri The [uri](#Uri) of the resource representing this item. - * @param collapsibleState [TreeItemCollapsibleState](#TreeItemCollapsibleState) of the tree item. Default is [TreeItemCollapsibleState.None](#TreeItemCollapsibleState.None) + * @param resourceUri The {@link Uri} of the resource representing this item. + * @param collapsibleState {@link TreeItemCollapsibleState} of the tree item. Default is {@link TreeItemCollapsibleState.None} */ constructor(resourceUri: Uri, collapsibleState?: TreeItemCollapsibleState); } @@ -9267,12 +9315,12 @@ declare module 'vscode' { } /** - * Label describing the [Tree item](#TreeItem) + * Label describing the {@link TreeItem Tree item} */ export interface TreeItemLabel { /** - * A human-readable string describing the [Tree item](#TreeItem). + * A human-readable string describing the {@link TreeItem Tree item}. */ label: string; @@ -9330,6 +9378,13 @@ declare module 'vscode' { * as normal. */ hideFromUser?: boolean; + + /** + * A message to write to the terminal on first launch, note that this is not sent to the + * process but, rather written directly to the terminal. This supports escape sequences such + * a setting text style. + */ + message?: string; } /** @@ -9342,7 +9397,7 @@ declare module 'vscode' { name: string; /** - * An implementation of [Pseudoterminal](#Pseudoterminal) that allows an extension to + * An implementation of {@link Pseudoterminal} that allows an extension to * control a terminal. */ pty: Pseudoterminal; @@ -9354,7 +9409,7 @@ declare module 'vscode' { interface Pseudoterminal { /** * An event that when fired will write data to the terminal. Unlike - * [Terminal.sendText](#Terminal.sendText) which sends text to the underlying child + * {@link Terminal.sendText} which sends text to the underlying child * pseudo-device (the child), this will write the text to parent pseudo-device (the * _terminal_ itself). * @@ -9380,7 +9435,7 @@ declare module 'vscode' { onDidWrite: Event; /** - * An event that when fired allows overriding the [dimensions](#Pseudoterminal.setDimensions) of the + * An event that when fired allows overriding the {@link Pseudoterminal.setDimensions dimensions} of the * terminal. Note that when set, the overridden dimensions will only take effect when they * are lower than the actual dimensions of the terminal (ie. there will never be a scroll * bar). Set to `undefined` for the terminal to go back to the regular dimensions (fit to @@ -9449,7 +9504,7 @@ declare module 'vscode' { /** * Implement to handle incoming keystrokes in the terminal or when an extension calls - * [Terminal.sendText](#Terminal.sendText). `data` contains the keystrokes/text serialized into + * {@link Terminal.sendText}. `data` contains the keystrokes/text serialized into * their corresponding VT sequence representation. * * @param data The incoming data. @@ -9476,7 +9531,7 @@ declare module 'vscode' { * as the size of a terminal isn't known until it shows up in the user interface. * * When dimensions are overridden by - * [onDidOverrideDimensions](#Pseudoterminal.onDidOverrideDimensions), `setDimensions` will + * {@link Pseudoterminal.onDidOverrideDimensions onDidOverrideDimensions}, `setDimensions` will * continue to be called with the regular panel dimensions, allowing the extension continue * to react dimension changes. * @@ -9672,23 +9727,23 @@ declare module 'vscode' { /** * A light-weight user input UI that is initially not visible. After * configuring it through its properties the extension can make it - * visible by calling [QuickInput.show](#QuickInput.show). + * visible by calling {@link QuickInput.show}. * * There are several reasons why this UI might have to be hidden and - * the extension will be notified through [QuickInput.onDidHide](#QuickInput.onDidHide). - * (Examples include: an explicit call to [QuickInput.hide](#QuickInput.hide), + * the extension will be notified through {@link QuickInput.onDidHide}. + * (Examples include: an explicit call to {@link QuickInput.hide}, * the user pressing Esc, some other input UI opening, etc.) * * A user pressing Enter or some other gesture implying acceptance * of the current state does not automatically hide this UI component. * It is up to the extension to decide whether to accept the user's input - * and if the UI should indeed be hidden through a call to [QuickInput.hide](#QuickInput.hide). + * and if the UI should indeed be hidden through a call to {@link QuickInput.hide}. * * When the extension no longer needs this input UI, it should - * [QuickInput.dispose](#QuickInput.dispose) it to allow for freeing up + * {@link QuickInput.dispose} it to allow for freeing up * any resources associated with it. * - * See [QuickPick](#QuickPick) and [InputBox](#InputBox) for concrete UIs. + * See {@link QuickPick} and {@link InputBox} for concrete UIs. */ export interface QuickInput { @@ -9730,12 +9785,12 @@ declare module 'vscode' { /** * Makes the input UI visible in its current configuration. Any other input - * UI will first fire an [QuickInput.onDidHide](#QuickInput.onDidHide) event. + * UI will first fire an {@link QuickInput.onDidHide} event. */ show(): void; /** - * Hides this input UI. This will also fire an [QuickInput.onDidHide](#QuickInput.onDidHide) + * Hides this input UI. This will also fire an {@link QuickInput.onDidHide} * event. */ hide(): void; @@ -9744,8 +9799,8 @@ declare module 'vscode' { * An event signaling when this input UI is hidden. * * There are several reasons why this UI might have to be hidden and - * the extension will be notified through [QuickInput.onDidHide](#QuickInput.onDidHide). - * (Examples include: an explicit call to [QuickInput.hide](#QuickInput.hide), + * the extension will be notified through {@link QuickInput.onDidHide}. + * (Examples include: an explicit call to {@link QuickInput.hide}, * the user pressing Esc, some other input UI opening, etc.) */ onDidHide: Event; @@ -9760,14 +9815,14 @@ declare module 'vscode' { } /** - * A concrete [QuickInput](#QuickInput) to let the user pick an item from a + * A concrete {@link QuickInput} to let the user pick an item from a * list of items of type T. The items can be filtered through a filter text field and - * there is an option [canSelectMany](#QuickPick.canSelectMany) to allow for + * there is an option {@link QuickPick.canSelectMany canSelectMany} to allow for * selecting multiple items. * - * Note that in many cases the more convenient [window.showQuickPick](#window.showQuickPick) - * is easier to use. [window.createQuickPick](#window.createQuickPick) should be used - * when [window.showQuickPick](#window.showQuickPick) does not offer the required flexibility. + * Note that in many cases the more convenient {@link window.showQuickPick} + * is easier to use. {@link window.createQuickPick} should be used + * when {@link window.showQuickPick} does not offer the required flexibility. */ export interface QuickPick extends QuickInput { @@ -9794,7 +9849,7 @@ declare module 'vscode' { /** * Buttons for actions in the UI. */ - buttons: ReadonlyArray; + buttons: readonly QuickInputButton[]; /** * An event signaling when a button was triggered. @@ -9802,9 +9857,9 @@ declare module 'vscode' { readonly onDidTriggerButton: Event; /** - * Items to pick from. + * Items to pick from. This can be read and updated by the extension. */ - items: ReadonlyArray; + items: readonly T[]; /** * If multiple items can be selected at the same time. Defaults to false. @@ -9824,7 +9879,7 @@ declare module 'vscode' { /** * Active items. This can be read and updated by the extension. */ - activeItems: ReadonlyArray; + activeItems: readonly T[]; /** * An event signaling when the active items have changed. @@ -9834,7 +9889,7 @@ declare module 'vscode' { /** * Selected items. This can be read and updated by the extension. */ - selectedItems: ReadonlyArray; + selectedItems: readonly T[]; /** * An event signaling when the selected items have changed. @@ -9843,11 +9898,11 @@ declare module 'vscode' { } /** - * A concrete [QuickInput](#QuickInput) to let the user input a text value. + * A concrete {@link QuickInput} to let the user input a text value. * - * Note that in many cases the more convenient [window.showInputBox](#window.showInputBox) - * is easier to use. [window.createInputBox](#window.createInputBox) should be used - * when [window.showInputBox](#window.showInputBox) does not offer the required flexibility. + * Note that in many cases the more convenient {@link window.showInputBox} + * is easier to use. {@link window.createInputBox} should be used + * when {@link window.showInputBox} does not offer the required flexibility. */ export interface InputBox extends QuickInput { @@ -9879,7 +9934,7 @@ declare module 'vscode' { /** * Buttons for actions in the UI. */ - buttons: ReadonlyArray; + buttons: readonly QuickInputButton[]; /** * An event signaling when a button was triggered. @@ -9898,7 +9953,7 @@ declare module 'vscode' { } /** - * Button for an action in a [QuickPick](#QuickPick) or [InputBox](#InputBox). + * Button for an action in a {@link QuickPick} or {@link InputBox}. */ export interface QuickInputButton { @@ -9914,12 +9969,12 @@ declare module 'vscode' { } /** - * Predefined buttons for [QuickPick](#QuickPick) and [InputBox](#InputBox). + * Predefined buttons for {@link QuickPick} and {@link InputBox}. */ export class QuickInputButtons { /** - * A back button for [QuickPick](#QuickPick) and [InputBox](#InputBox). + * A back button for {@link QuickPick} and {@link InputBox}. * * When a navigation 'back' button is needed this one should be used for consistency. * It comes with a predefined icon, tooltip and location. @@ -9933,7 +9988,7 @@ declare module 'vscode' { } /** - * An event describing an individual change in the text of a [document](#TextDocument). + * An event describing an individual change in the text of a {@link TextDocument document}. */ export interface TextDocumentContentChangeEvent { /** @@ -9955,7 +10010,7 @@ declare module 'vscode' { } /** - * An event describing a transactional [document](#TextDocument) change. + * An event describing a transactional {@link TextDocument document} change. */ export interface TextDocumentChangeEvent { @@ -9967,7 +10022,7 @@ declare module 'vscode' { /** * An array of content changes. */ - readonly contentChanges: ReadonlyArray; + readonly contentChanges: readonly TextDocumentContentChangeEvent[]; } /** @@ -9993,11 +10048,11 @@ declare module 'vscode' { } /** - * An event that is fired when a [document](#TextDocument) will be saved. + * An event that is fired when a {@link TextDocument document} will be saved. * * To make modifications to the document before it is being saved, call the - * [`waitUntil`](#TextDocumentWillSaveEvent.waitUntil)-function with a thenable - * that resolves to an array of [text edits](#TextEdit). + * {@link TextDocumentWillSaveEvent.waitUntil `waitUntil`}-function with a thenable + * that resolves to an array of {@link TextEdit text edits}. */ export interface TextDocumentWillSaveEvent { @@ -10012,7 +10067,7 @@ declare module 'vscode' { readonly reason: TextDocumentSaveReason; /** - * Allows to pause the event loop and to apply [pre-save-edits](#TextEdit). + * Allows to pause the event loop and to apply {@link TextEdit pre-save-edits}. * Edits of subsequent calls to this function will be applied in order. The * edits will be *ignored* if concurrent modifications of the document happened. * @@ -10029,7 +10084,7 @@ declare module 'vscode' { * }) * ``` * - * @param thenable A thenable that resolves to [pre-save-edits](#TextEdit). + * @param thenable A thenable that resolves to {@link TextEdit pre-save-edits}. */ waitUntil(thenable: Thenable): void; @@ -10047,18 +10102,18 @@ declare module 'vscode' { * An event that is fired when files are going to be created. * * To make modifications to the workspace before the files are created, - * call the [`waitUntil](#FileWillCreateEvent.waitUntil)-function with a - * thenable that resolves to a [workspace edit](#WorkspaceEdit). + * call the {@link FileWillCreateEvent.waitUntil `waitUntil`}-function with a + * thenable that resolves to a {@link WorkspaceEdit workspace edit}. */ export interface FileWillCreateEvent { /** * The files that are going to be created. */ - readonly files: ReadonlyArray; + readonly files: readonly Uri[]; /** - * Allows to pause the event and to apply a [workspace edit](#WorkspaceEdit). + * Allows to pause the event and to apply a {@link WorkspaceEdit workspace edit}. * * *Note:* This function can only be called during event dispatch and not * in an asynchronous manner: @@ -10095,25 +10150,25 @@ declare module 'vscode' { /** * The files that got created. */ - readonly files: ReadonlyArray; + readonly files: readonly Uri[]; } /** * An event that is fired when files are going to be deleted. * * To make modifications to the workspace before the files are deleted, - * call the [`waitUntil](#FileWillCreateEvent.waitUntil)-function with a - * thenable that resolves to a [workspace edit](#WorkspaceEdit). + * call the {@link FileWillCreateEvent.waitUntil `waitUntil}-function with a + * thenable that resolves to a {@link WorkspaceEdit workspace edit}. */ export interface FileWillDeleteEvent { /** * The files that are going to be deleted. */ - readonly files: ReadonlyArray; + readonly files: readonly Uri[]; /** - * Allows to pause the event and to apply a [workspace edit](#WorkspaceEdit). + * Allows to pause the event and to apply a {@link WorkspaceEdit workspace edit}. * * *Note:* This function can only be called during event dispatch and not * in an asynchronous manner: @@ -10150,25 +10205,25 @@ declare module 'vscode' { /** * The files that got deleted. */ - readonly files: ReadonlyArray; + readonly files: readonly Uri[]; } /** * An event that is fired when files are going to be renamed. * * To make modifications to the workspace before the files are renamed, - * call the [`waitUntil](#FileWillCreateEvent.waitUntil)-function with a - * thenable that resolves to a [workspace edit](#WorkspaceEdit). + * call the {@link FileWillCreateEvent.waitUntil `waitUntil}-function with a + * thenable that resolves to a {@link WorkspaceEdit workspace edit}. */ export interface FileWillRenameEvent { /** * The files that are going to be renamed. */ - readonly files: ReadonlyArray<{ oldUri: Uri, newUri: Uri }>; + readonly files: ReadonlyArray<{ readonly oldUri: Uri, readonly newUri: Uri }>; /** - * Allows to pause the event and to apply a [workspace edit](#WorkspaceEdit). + * Allows to pause the event and to apply a {@link WorkspaceEdit workspace edit}. * * *Note:* This function can only be called during event dispatch and not * in an asynchronous manner: @@ -10205,22 +10260,22 @@ declare module 'vscode' { /** * The files that got renamed. */ - readonly files: ReadonlyArray<{ oldUri: Uri, newUri: Uri }>; + readonly files: ReadonlyArray<{ readonly oldUri: Uri, readonly newUri: Uri }>; } /** - * An event describing a change to the set of [workspace folders](#workspace.workspaceFolders). + * An event describing a change to the set of {@link workspace.workspaceFolders workspace folders}. */ export interface WorkspaceFoldersChangeEvent { /** * Added workspace folders. */ - readonly added: ReadonlyArray; + readonly added: readonly WorkspaceFolder[]; /** * Removed workspace folders. */ - readonly removed: ReadonlyArray; + readonly removed: readonly WorkspaceFolder[]; } /** @@ -10232,14 +10287,14 @@ declare module 'vscode' { /** * The associated uri for this workspace folder. * - * *Note:* The [Uri](#Uri)-type was intentionally chosen such that future releases of the editor can support + * *Note:* The {@link Uri}-type was intentionally chosen such that future releases of the editor can support * workspace folders that are not stored on the local disk, e.g. `ftp://server/workspaces/foo`. */ readonly uri: Uri; /** * The name of this workspace folder. Defaults to - * the basename of its [uri-path](#Uri.path) + * the basename of its {@link Uri.path uri-path} */ readonly name: string; @@ -10261,14 +10316,14 @@ declare module 'vscode' { * Refer to https://code.visualstudio.com/docs/editor/workspaces for more information on * the concept of workspaces in VS Code. * - * The workspace offers support for [listening](#workspace.createFileSystemWatcher) to fs - * events and for [finding](#workspace.findFiles) files. Both perform well and run _outside_ + * The workspace offers support for {@link workspace.createFileSystemWatcher listening} to fs + * events and for {@link workspace.findFiles finding} files. Both perform well and run _outside_ * the editor-process so that they should be always used instead of nodejs-equivalents. */ export namespace workspace { /** - * A [file system](#FileSystem) instance that allows to interact with local and remote + * A {@link FileSystem file system} instance that allows to interact with local and remote * files, e.g. `vscode.workspace.fs.readDirectory(someUri)` allows to retrieve all entries * of a directory or `vscode.workspace.fs.stat(anotherUri)` returns the meta data for a * file. @@ -10282,12 +10337,12 @@ declare module 'vscode' { * Refer to https://code.visualstudio.com/docs/editor/workspaces for more information * on workspaces in VS Code. * - * @deprecated Use [`workspaceFolders`](#workspace.workspaceFolders) instead. + * @deprecated Use {@link workspace.workspaceFolders `workspaceFolders`} instead. */ export const rootPath: string | undefined; /** - * List of workspace folders that are open in VS Code. `undefined when no workspace + * List of workspace folders that are open in VS Code. `undefined` when no workspace * has been opened. * * Refer to https://code.visualstudio.com/docs/editor/workspaces for more information @@ -10295,7 +10350,7 @@ declare module 'vscode' { * * *Note* that the first entry corresponds to the value of `rootPath`. */ - export const workspaceFolders: ReadonlyArray | undefined; + export const workspaceFolders: readonly WorkspaceFolder[] | undefined; /** * The name of the workspace. `undefined` when no workspace @@ -10346,7 +10401,7 @@ declare module 'vscode' { export const onDidChangeWorkspaceFolders: Event; /** - * Returns the [workspace folder](#WorkspaceFolder) that contains a given uri. + * Returns the {@link WorkspaceFolder workspace folder} that contains a given uri. * * returns `undefined` when the given uri doesn't match any workspace folder * * returns the *input* when the given uri is a workspace folder itself * @@ -10358,10 +10413,10 @@ declare module 'vscode' { /** * Returns a path that is relative to the workspace folder or folders. * - * When there are no [workspace folders](#workspace.workspaceFolders) or when the path + * When there are no {@link workspace.workspaceFolders workspace folders} or when the path * is not contained in them, the input is returned. * - * @param pathOrUri A path or uri. When a uri is given its [fsPath](#Uri.fsPath) is used. + * @param pathOrUri A path or uri. When a uri is given its {@link Uri.fsPath fsPath} is used. * @param includeWorkspaceFolder When `true` and when the given path is contained inside a * workspace folder the name of the workspace is prepended. Defaults to `true` when there are * multiple workspace folders and `false` otherwise. @@ -10370,7 +10425,7 @@ declare module 'vscode' { export function asRelativePath(pathOrUri: string | Uri, includeWorkspaceFolder?: boolean): string; /** - * This method replaces `deleteCount` [workspace folders](#workspace.workspaceFolders) starting at index `start` + * This method replaces `deleteCount` {@link workspace.workspaceFolders workspace folders} starting at index `start` * by an optional set of `workspaceFoldersToAdd` on the `vscode.workspace.workspaceFolders` array. This "splice" * behavior can be used to add, remove and change workspace folders in a single operation. * @@ -10378,7 +10433,7 @@ declare module 'vscode' { * one that called this method) will be terminated and restarted so that the (deprecated) `rootPath` property is * updated to point to the first workspace folder. * - * Use the [`onDidChangeWorkspaceFolders()`](#onDidChangeWorkspaceFolders) event to get notified when the + * Use the {@link onDidChangeWorkspaceFolders `onDidChangeWorkspaceFolders()`} event to get notified when the * workspace folders have been updated. * * **Example:** adding a new workspace folder at the end of workspace folders @@ -10399,10 +10454,10 @@ declare module 'vscode' { * It is valid to remove an existing workspace folder and add it again with a different name * to rename that folder. * - * **Note:** it is not valid to call [updateWorkspaceFolders()](#updateWorkspaceFolders) multiple times - * without waiting for the [`onDidChangeWorkspaceFolders()`](#onDidChangeWorkspaceFolders) to fire. + * **Note:** it is not valid to call {@link updateWorkspaceFolders updateWorkspaceFolders()} multiple times + * without waiting for the {@link onDidChangeWorkspaceFolders `onDidChangeWorkspaceFolders()`} to fire. * - * @param start the zero-based location in the list of currently opened [workspace folders](#WorkspaceFolder) + * @param start the zero-based location in the list of currently opened {@link WorkspaceFolder workspace folders} * from which to start deleting workspace folders. * @param deleteCount the optional number of workspace folders to remove. * @param workspaceFoldersToAdd the optional variable set of workspace folders to add in place of the deleted ones. @@ -10418,12 +10473,12 @@ declare module 'vscode' { * A glob pattern that filters the file events on their absolute path must be provided. Optionally, * flags to ignore certain kinds of events can be provided. To stop listening to events the watcher must be disposed. * - * *Note* that only files within the current [workspace folders](#workspace.workspaceFolders) can be watched. + * *Note* that only files within the current {@link workspace.workspaceFolders workspace folders} can be watched. * *Note* that when watching for file changes such as '**​/*.js', notifications will not be sent when a parent folder is * moved or deleted (this is a known limitation of the current implementation and may change in the future). * - * @param globPattern A [glob pattern](#GlobPattern) that is applied to the absolute paths of created, changed, - * and deleted files. Use a [relative pattern](#RelativePattern) to limit events to a certain [workspace folder](#WorkspaceFolder). + * @param globPattern A {@link GlobPattern glob pattern} that is applied to the absolute paths of created, changed, + * and deleted files. Use a {@link RelativePattern relative pattern} to limit events to a certain {@link WorkspaceFolder workspace folder}. * @param ignoreCreateEvents Ignore when files have been created. * @param ignoreChangeEvents Ignore when files have been changed. * @param ignoreDeleteEvents Ignore when files have been deleted. @@ -10432,21 +10487,21 @@ declare module 'vscode' { export function createFileSystemWatcher(globPattern: GlobPattern, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean): FileSystemWatcher; /** - * Find files across all [workspace folders](#workspace.workspaceFolders) in the workspace. + * Find files across all {@link workspace.workspaceFolders workspace folders} in the workspace. * * @example * findFiles('**​/*.js', '**​/node_modules/**', 10) * - * @param include A [glob pattern](#GlobPattern) that defines the files to search for. The glob pattern - * will be matched against the file paths of resulting matches relative to their workspace. Use a [relative pattern](#RelativePattern) - * to restrict the search results to a [workspace folder](#WorkspaceFolder). - * @param exclude A [glob pattern](#GlobPattern) that defines files and folders to exclude. The glob pattern - * will be matched against the file paths of resulting matches relative to their workspace. When `undefined` only default excludes will - * apply, when `null` no excludes will apply. + * @param include A {@link GlobPattern glob pattern} that defines the files to search for. The glob pattern + * will be matched against the file paths of resulting matches relative to their workspace. Use a {@link RelativePattern relative pattern} + * to restrict the search results to a {@link WorkspaceFolder workspace folder}. + * @param exclude A {@link GlobPattern glob pattern} that defines files and folders to exclude. The glob pattern + * will be matched against the file paths of resulting matches relative to their workspace. When `undefined`, default excludes and the user's + * configured excludes will apply. When `null`, no excludes will apply. * @param maxResults An upper-bound for the result. * @param token A token that can be used to signal cancellation to the underlying search engine. * @return A thenable that resolves to an array of resource identifiers. Will return no results if no - * [workspace folders](#workspace.workspaceFolders) are opened. + * {@link workspace.workspaceFolders workspace folders} are opened. */ export function findFiles(include: GlobPattern, exclude?: GlobPattern | null, maxResults?: number, token?: CancellationToken): Thenable; @@ -10460,7 +10515,7 @@ declare module 'vscode' { /** * Make changes to one or many resources or create, delete, and rename resources as defined by the given - * [workspace edit](#WorkspaceEdit). + * {@link WorkspaceEdit workspace edit}. * * All changes of a workspace edit are applied in the same order in which they have been added. If * multiple textual inserts are made at the same position, these strings appear in the resulting text @@ -10477,36 +10532,36 @@ declare module 'vscode' { export function applyEdit(edit: WorkspaceEdit): Thenable; /** - * All text documents currently known to the system. + * All text documents currently known to the editor. */ - export const textDocuments: ReadonlyArray; + export const textDocuments: readonly TextDocument[]; /** * Opens a document. Will return early if this document is already open. Otherwise - * the document is loaded and the [didOpen](#workspace.onDidOpenTextDocument)-event fires. + * the document is loaded and the {@link workspace.onDidOpenTextDocument didOpen}-event fires. * - * The document is denoted by an [uri](#Uri). Depending on the [scheme](#Uri.scheme) the + * The document is denoted by an {@link Uri}. Depending on the {@link Uri.scheme scheme} the * following rules apply: * * `file`-scheme: Open a file on disk, will be rejected if the file does not exist or cannot be loaded. * * `untitled`-scheme: A new file that should be saved on disk, e.g. `untitled:c:\frodo\new.js`. The language * will be derived from the file name. - * * For all other schemes contributed [text document content providers](#TextDocumentContentProvider) and - * [file system providers](#FileSystemProvider) are consulted. + * * For all other schemes contributed {@link TextDocumentContentProvider text document content providers} and + * {@link FileSystemProvider file system providers} are consulted. * * *Note* that the lifecycle of the returned document is owned by the editor and not by the extension. That means an - * [`onDidClose`](#workspace.onDidCloseTextDocument)-event can occur at any time after opening it. + * {@link workspace.onDidCloseTextDocument `onDidClose`}-event can occur at any time after opening it. * * @param uri Identifies the resource to open. - * @return A promise that resolves to a [document](#TextDocument). + * @return A promise that resolves to a {@link TextDocument document}. */ export function openTextDocument(uri: Uri): Thenable; /** * A short-hand for `openTextDocument(Uri.file(fileName))`. * - * @see [openTextDocument](#openTextDocument) + * @see {@link openTextDocument} * @param fileName A name of a file on disk. - * @return A promise that resolves to a [document](#TextDocument). + * @return A promise that resolves to a {@link TextDocument document}. */ export function openTextDocument(fileName: string): Thenable; @@ -10516,7 +10571,7 @@ declare module 'vscode' { * specify the *language* and/or the *content* of the document. * * @param options Options to control how the document will be created. - * @return A promise that resolves to a [document](#TextDocument). + * @return A promise that resolves to a {@link TextDocument document}. */ export function openTextDocument(options?: { language?: string; content?: string; }): Thenable; @@ -10527,30 +10582,30 @@ declare module 'vscode' { * * @param scheme The uri-scheme to register for. * @param provider A content provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerTextDocumentContentProvider(scheme: string, provider: TextDocumentContentProvider): Disposable; /** - * An event that is emitted when a [text document](#TextDocument) is opened or when the language id - * of a text document [has been changed](#languages.setTextDocumentLanguage). + * An event that is emitted when a {@link TextDocument text document} is opened or when the language id + * of a text document {@link languages.setTextDocumentLanguage has been changed}. * - * To add an event listener when a visible text document is opened, use the [TextEditor](#TextEditor) events in the - * [window](#window) namespace. Note that: + * To add an event listener when a visible text document is opened, use the {@link TextEditor} events in the + * {@link window} namespace. Note that: * - * - The event is emitted before the [document](#TextDocument) is updated in the - * [active text editor](#window.activeTextEditor) - * - When a [text document](#TextDocument) is already open (e.g.: open in another [visible text editor](#window.visibleTextEditors)) this event is not emitted + * - The event is emitted before the {@link TextDocument document} is updated in the + * {@link window.activeTextEditor active text editor} + * - When a {@link TextDocument text document} is already open (e.g.: open in another {@link window.visibleTextEditors visible text editor}) this event is not emitted * */ export const onDidOpenTextDocument: Event; /** - * An event that is emitted when a [text document](#TextDocument) is disposed or when the language id - * of a text document [has been changed](#languages.setTextDocumentLanguage). + * An event that is emitted when a {@link TextDocument text document} is disposed or when the language id + * of a text document {@link languages.setTextDocumentLanguage has been changed}. * * *Note 1:* There is no guarantee that this event fires when an editor tab is closed, use the - * [`onDidChangeVisibleTextEditors`](#window.onDidChangeVisibleTextEditors)-event to know when editors change. + * {@link window.onDidChangeVisibleTextEditors `onDidChangeVisibleTextEditors`}-event to know when editors change. * * *Note 2:* A document can be open but not shown in an editor which means this event can fire * for a document that has not been shown in an editor. @@ -10558,19 +10613,19 @@ declare module 'vscode' { export const onDidCloseTextDocument: Event; /** - * An event that is emitted when a [text document](#TextDocument) is changed. This usually happens - * when the [contents](#TextDocument.getText) changes but also when other things like the - * [dirty](#TextDocument.isDirty)-state changes. + * An event that is emitted when a {@link TextDocument text document} is changed. This usually happens + * when the {@link TextDocument.getText contents} changes but also when other things like the + * {@link TextDocument.isDirty dirty}-state changes. */ export const onDidChangeTextDocument: Event; /** - * An event that is emitted when a [text document](#TextDocument) will be saved to disk. + * An event that is emitted when a {@link TextDocument text document} will be saved to disk. * * *Note 1:* Subscribers can delay saving by registering asynchronous work. For the sake of data integrity the editor * might save without firing this event. For instance when shutting down with dirty files. * - * *Note 2:* Subscribers are called sequentially and they can [delay](#TextDocumentWillSaveEvent.waitUntil) saving + * *Note 2:* Subscribers are called sequentially and they can {@link TextDocumentWillSaveEvent.waitUntil delay} saving * by registering asynchronous work. Protection against misbehaving listeners is implemented as such: * * there is an overall time budget that all listeners share and if that is exhausted no further listener is called * * listeners that take a long time or produce errors frequently will not be called anymore @@ -10580,17 +10635,76 @@ declare module 'vscode' { export const onWillSaveTextDocument: Event; /** - * An event that is emitted when a [text document](#TextDocument) is saved to disk. + * An event that is emitted when a {@link TextDocument text document} is saved to disk. */ export const onDidSaveTextDocument: Event; + /** + * All notebook documents currently known to the editor. + */ + export const notebookDocuments: readonly NotebookDocument[]; + + /** + * Open a notebook. Will return early if this notebook is already {@link notebook.notebookDocuments loaded}. Otherwise + * the notebook is loaded and the {@link notebook.onDidOpenNotebookDocument `onDidOpenNotebookDocument`}-event fires. + * + * *Note* that the lifecycle of the returned notebook is owned by the editor and not by the extension. That means an + * {@link notebook.onDidCloseNotebookDocument `onDidCloseNotebookDocument`}-event can occur at any time after. + * + * *Note* that opening a notebook does not show a notebook editor. This function only returns a notebook document which + * can be showns in a notebook editor but it can also be used for other things. + * + * @param uri The resource to open. + * @returns A promise that resolves to a {@link NotebookDocument notebook} + */ + export function openNotebookDocument(uri: Uri): Thenable; + + /** + * Open an untitled notebook. The editor will prompt the user for a file + * path when the document is to be saved. + * + * @see {@link openNotebookDocument} + * @param notebookType The notebook type that should be used. + * @param content The initial contents of the notebook. + * @returns A promise that resolves to a {@link NotebookDocument notebook}. + */ + export function openNotebookDocument(notebookType: string, content?: NotebookData): Thenable; + + /** + * Register a {@link NotebookSerializer notebook serializer}. + * + * A notebook serializer must be contributed through the `notebooks` extension point. When opening a notebook file, the editor will send + * the `onNotebook:` activation event, and extensions must register their serializer in return. + * + * @param notebookType A notebook. + * @param serializer A notebook serialzier. + * @param options Optional context options that define what parts of a notebook should be persisted + * @return A {@link Disposable} that unregisters this serializer when being disposed. + */ + export function registerNotebookSerializer(notebookType: string, serializer: NotebookSerializer, options?: NotebookDocumentContentOptions): Disposable; + + /** + * An event that is emitted when a {@link NotebookDocument notebook} is opened. + */ + export const onDidOpenNotebookDocument: Event; + + /** + * An event that is emitted when a {@link NotebookDocument notebook} is disposed. + * + * *Note 1:* There is no guarantee that this event fires when an editor tab is closed. + * + * *Note 2:* A notebook can be open but not shown in an editor which means this event can fire + * for a notebook that has not been shown in an editor. + */ + export const onDidCloseNotebookDocument: Event; + /** * An event that is emitted when files are being created. * * *Note 1:* This event is triggered by user gestures, like creating a file from the - * explorer, or from the [`workspace.applyEdit`](#workspace.applyEdit)-api. This event is *not* fired when + * explorer, or from the {@link workspace.applyEdit `workspace.applyEdit`}-api. This event is *not* fired when * files change on disk, e.g triggered by another application, or when using the - * [`workspace.fs`](#FileSystem)-api. + * {@link FileSystem `workspace.fs`}-api. * * *Note 2:* When this event is fired, edits to files that are are being created cannot be applied. */ @@ -10600,9 +10714,9 @@ declare module 'vscode' { * An event that is emitted when files have been created. * * *Note:* This event is triggered by user gestures, like creating a file from the - * explorer, or from the [`workspace.applyEdit`](#workspace.applyEdit)-api, but this event is *not* fired when + * explorer, or from the {@link workspace.applyEdit `workspace.applyEdit`}-api, but this event is *not* fired when * files change on disk, e.g triggered by another application, or when using the - * [`workspace.fs`](#FileSystem)-api. + * {@link FileSystem `workspace.fs`}-api. */ export const onDidCreateFiles: Event; @@ -10610,9 +10724,9 @@ declare module 'vscode' { * An event that is emitted when files are being deleted. * * *Note 1:* This event is triggered by user gestures, like deleting a file from the - * explorer, or from the [`workspace.applyEdit`](#workspace.applyEdit)-api, but this event is *not* fired when + * explorer, or from the {@link workspace.applyEdit `workspace.applyEdit`}-api, but this event is *not* fired when * files change on disk, e.g triggered by another application, or when using the - * [`workspace.fs`](#FileSystem)-api. + * {@link FileSystem `workspace.fs`}-api. * * *Note 2:* When deleting a folder with children only one event is fired. */ @@ -10622,9 +10736,9 @@ declare module 'vscode' { * An event that is emitted when files have been deleted. * * *Note 1:* This event is triggered by user gestures, like deleting a file from the - * explorer, or from the [`workspace.applyEdit`](#workspace.applyEdit)-api, but this event is *not* fired when + * explorer, or from the {@link workspace.applyEdit `workspace.applyEdit`}-api, but this event is *not* fired when * files change on disk, e.g triggered by another application, or when using the - * [`workspace.fs`](#FileSystem)-api. + * {@link FileSystem `workspace.fs`}-api. * * *Note 2:* When deleting a folder with children only one event is fired. */ @@ -10634,9 +10748,9 @@ declare module 'vscode' { * An event that is emitted when files are being renamed. * * *Note 1:* This event is triggered by user gestures, like renaming a file from the - * explorer, and from the [`workspace.applyEdit`](#workspace.applyEdit)-api, but this event is *not* fired when + * explorer, and from the {@link workspace.applyEdit `workspace.applyEdit`}-api, but this event is *not* fired when * files change on disk, e.g triggered by another application, or when using the - * [`workspace.fs`](#FileSystem)-api. + * {@link FileSystem `workspace.fs`}-api. * * *Note 2:* When renaming a folder with children only one event is fired. */ @@ -10646,9 +10760,9 @@ declare module 'vscode' { * An event that is emitted when files have been renamed. * * *Note 1:* This event is triggered by user gestures, like renaming a file from the - * explorer, and from the [`workspace.applyEdit`](#workspace.applyEdit)-api, but this event is *not* fired when + * explorer, and from the {@link workspace.applyEdit `workspace.applyEdit`}-api, but this event is *not* fired when * files change on disk, e.g triggered by another application, or when using the - * [`workspace.fs`](#FileSystem)-api. + * {@link FileSystem `workspace.fs`}-api. * * *Note 2:* When renaming a folder with children only one event is fired. */ @@ -10670,7 +10784,7 @@ declare module 'vscode' { export function getConfiguration(section?: string | undefined, scope?: ConfigurationScope | null): WorkspaceConfiguration; /** - * An event that is emitted when the [configuration](#WorkspaceConfiguration) changed. + * An event that is emitted when the {@link WorkspaceConfiguration configuration} changed. */ export const onDidChangeConfiguration: Event; @@ -10681,7 +10795,7 @@ declare module 'vscode' { * * @param type The task kind type this provider is registered for. * @param provider A task provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerTaskProvider(type: string, provider: TaskProvider): Disposable; @@ -10691,10 +10805,10 @@ declare module 'vscode' { * There can only be one provider per scheme and an error is being thrown when a scheme * has been claimed by another provider or when it is reserved. * - * @param scheme The uri-[scheme](#Uri.scheme) the provider registers for. + * @param scheme The uri-{@link Uri.scheme scheme} the provider registers for. * @param provider The filesystem provider. * @param options Immutable metadata about the provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerFileSystemProvider(scheme: string, provider: FileSystemProvider, options?: { readonly isCaseSensitive?: boolean, readonly isReadonly?: boolean }): Disposable; @@ -10712,8 +10826,8 @@ declare module 'vscode' { /** * The configuration scope which can be a * a 'resource' or a languageId or both or - * a '[TextDocument](#TextDocument)' or - * a '[WorkspaceFolder](#WorkspaceFolder)' + * a '{@link TextDocument}' or + * a '{@link WorkspaceFolder}' */ export type ConfigurationScope = Uri | TextDocument | WorkspaceFolder | { uri?: Uri, languageId: string }; @@ -10743,7 +10857,7 @@ declare module 'vscode' { * * The editor provides an API that makes it simple to provide such common features by having all UI and actions already in place and * by allowing you to participate by providing data only. For instance, to contribute a hover all you have to do is provide a function - * that can be called with a [TextDocument](#TextDocument) and a [Position](#Position) returning hover info. The rest, like tracking the + * that can be called with a {@link TextDocument} and a {@link Position} returning hover info. The rest, like tracking the * mouse, positioning the hover, keeping the hover stable etc. is taken care of by the editor. * * ```javascript @@ -10754,11 +10868,11 @@ declare module 'vscode' { * }); * ``` * - * Registration is done using a [document selector](#DocumentSelector) which is either a language id, like `javascript` or - * a more complex [filter](#DocumentFilter) like `{ language: 'typescript', scheme: 'file' }`. Matching a document against such - * a selector will result in a [score](#languages.match) that is used to determine if and how a provider shall be used. When - * scores are equal the provider that came last wins. For features that allow full arity, like [hover](#languages.registerHoverProvider), - * the score is only checked to be `>0`, for other features, like [IntelliSense](#languages.registerCompletionItemProvider) the + * Registration is done using a {@link DocumentSelector document selector} which is either a language id, like `javascript` or + * a more complex {@link DocumentFilter filter} like `{ language: 'typescript', scheme: 'file' }`. Matching a document against such + * a selector will result in a {@link languages.match score} that is used to determine if and how a provider shall be used. When + * scores are equal the provider that came last wins. For features that allow full arity, like {@link languages.registerHoverProvider hover}, + * the score is only checked to be `>0`, for other features, like {@link languages.registerCompletionItemProvider IntelliSense} the * score is used for determining the order in which providers are asked to participate. */ export namespace languages { @@ -10770,11 +10884,11 @@ declare module 'vscode' { export function getLanguages(): Thenable; /** - * Set (and change) the [language](#TextDocument.languageId) that is associated + * Set (and change) the {@link TextDocument.languageId language} that is associated * with the given document. * - * *Note* that calling this function will trigger the [`onDidCloseTextDocument`](#workspace.onDidCloseTextDocument) event - * followed by the [`onDidOpenTextDocument`](#workspace.onDidOpenTextDocument) event. + * *Note* that calling this function will trigger the {@link workspace.onDidCloseTextDocument `onDidCloseTextDocument`} event + * followed by the {@link workspace.onDidOpenTextDocument `onDidOpenTextDocument`} event. * * @param document The document which language is to be changed * @param languageId The new language identifier. @@ -10783,13 +10897,13 @@ declare module 'vscode' { export function setTextDocumentLanguage(document: TextDocument, languageId: string): Thenable; /** - * Compute the match between a document [selector](#DocumentSelector) and a document. Values + * Compute the match between a document {@link DocumentSelector selector} and a document. Values * greater than zero mean the selector matches the document. * * A match is computed according to these rules: - * 1. When [`DocumentSelector`](#DocumentSelector) is an array, compute the match for each contained `DocumentFilter` or language identifier and take the maximum value. - * 2. A string will be desugared to become the `language`-part of a [`DocumentFilter`](#DocumentFilter), so `"fooLang"` is like `{ language: "fooLang" }`. - * 3. A [`DocumentFilter`](#DocumentFilter) will be matched against the document by comparing its parts with the document. The following rules apply: + * 1. When {@link DocumentSelector `DocumentSelector`} is an array, compute the match for each contained `DocumentFilter` or language identifier and take the maximum value. + * 2. A string will be desugared to become the `language`-part of a {@link DocumentFilter `DocumentFilter`}, so `"fooLang"` is like `{ language: "fooLang" }`. + * 3. A {@link DocumentFilter `DocumentFilter`} will be matched against the document by comparing its parts with the document. The following rules apply: * 1. When the `DocumentFilter` is empty (`{}`) the result is `0` * 2. When `scheme`, `language`, or `pattern` are defined but one doesn’t match, the result is `0` * 3. Matching against `*` gives a score of `5`, matching via equality or via a glob-pattern gives a score of `10` @@ -10822,7 +10936,7 @@ declare module 'vscode' { export function match(selector: DocumentSelector, document: TextDocument): number; /** - * An [event](#Event) which fires when the global set of diagnostics changes. This is + * An {@link Event} which fires when the global set of diagnostics changes. This is * newly added and removed diagnostics. */ export const onDidChangeDiagnostics: Event; @@ -10831,7 +10945,7 @@ declare module 'vscode' { * Get all diagnostics for a given resource. * * @param resource A resource - * @returns An array of [diagnostics](#Diagnostic) objects or an empty array. + * @returns An array of {@link Diagnostic diagnostics} objects or an empty array. */ export function getDiagnostics(resource: Uri): Diagnostic[]; @@ -10845,7 +10959,7 @@ declare module 'vscode' { /** * Create a diagnostics collection. * - * @param name The [name](#DiagnosticCollection.name) of the collection. + * @param name The {@link DiagnosticCollection.name name} of the collection. * @return A new diagnostic collection. */ export function createDiagnosticCollection(name?: string): DiagnosticCollection; @@ -10854,20 +10968,20 @@ declare module 'vscode' { * Register a completion provider. * * Multiple providers can be registered for a language. In that case providers are sorted - * by their [score](#languages.match) and groups of equal score are sequentially asked for + * by their {@link languages.match score} and groups of equal score are sequentially asked for * completion items. The process stops when one or many providers of a group return a * result. A failing provider (rejected promise or exception) will not fail the whole * operation. * * A completion item provider can be associated with a set of `triggerCharacters`. When trigger * characters are being typed, completions are requested but only from providers that registered - * the typed character. Because of that trigger characters should be different than [word characters](#LanguageConfiguration.wordPattern), + * the typed character. Because of that trigger characters should be different than {@link LanguageConfiguration.wordPattern word characters}, * a common trigger character is `.` to trigger member completions. * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A completion provider. * @param triggerCharacters Trigger completion when the user types one of the characters. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerCompletionItemProvider(selector: DocumentSelector, provider: CompletionItemProvider, ...triggerCharacters: string[]): Disposable; @@ -10881,7 +10995,7 @@ declare module 'vscode' { * @param selector A selector that defines the documents this provider is applicable to. * @param provider A code action provider. * @param metadata Metadata about the kind of code actions the provider provides. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerCodeActionsProvider(selector: DocumentSelector, provider: CodeActionProvider, metadata?: CodeActionProviderMetadata): Disposable; @@ -10894,7 +11008,7 @@ declare module 'vscode' { * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A code lens provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerCodeLensProvider(selector: DocumentSelector, provider: CodeLensProvider): Disposable; @@ -10907,7 +11021,7 @@ declare module 'vscode' { * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A definition provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerDefinitionProvider(selector: DocumentSelector, provider: DefinitionProvider): Disposable; @@ -10920,7 +11034,7 @@ declare module 'vscode' { * * @param selector A selector that defines the documents this provider is applicable to. * @param provider An implementation provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerImplementationProvider(selector: DocumentSelector, provider: ImplementationProvider): Disposable; @@ -10933,7 +11047,7 @@ declare module 'vscode' { * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A type definition provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerTypeDefinitionProvider(selector: DocumentSelector, provider: TypeDefinitionProvider): Disposable; @@ -10946,7 +11060,7 @@ declare module 'vscode' { * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A declaration provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerDeclarationProvider(selector: DocumentSelector, provider: DeclarationProvider): Disposable; @@ -10959,7 +11073,7 @@ declare module 'vscode' { * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A hover provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerHoverProvider(selector: DocumentSelector, provider: HoverProvider): Disposable; @@ -10971,7 +11085,7 @@ declare module 'vscode' { * * @param selector A selector that defines the documents this provider is applicable to. * @param provider An evaluatable expression provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerEvaluatableExpressionProvider(selector: DocumentSelector, provider: EvaluatableExpressionProvider): Disposable; @@ -10986,7 +11100,7 @@ declare module 'vscode' { * * @param selector A selector that defines the documents this provider is applicable to. * @param provider An inline values provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerInlineValuesProvider(selector: DocumentSelector, provider: InlineValuesProvider): Disposable; @@ -10994,12 +11108,12 @@ declare module 'vscode' { * Register a document highlight provider. * * Multiple providers can be registered for a language. In that case providers are sorted - * by their [score](#languages.match) and groups sequentially asked for document highlights. + * by their {@link languages.match score} and groups sequentially asked for document highlights. * The process stops when a provider returns a `non-falsy` or `non-failure` result. * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A document highlight provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerDocumentHighlightProvider(selector: DocumentSelector, provider: DocumentHighlightProvider): Disposable; @@ -11013,7 +11127,7 @@ declare module 'vscode' { * @param selector A selector that defines the documents this provider is applicable to. * @param provider A document symbol provider. * @param metaData metadata about the provider - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerDocumentSymbolProvider(selector: DocumentSelector, provider: DocumentSymbolProvider, metaData?: DocumentSymbolProviderMetadata): Disposable; @@ -11025,7 +11139,7 @@ declare module 'vscode' { * a failure of the whole operation. * * @param provider A workspace symbol provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerWorkspaceSymbolProvider(provider: WorkspaceSymbolProvider): Disposable; @@ -11038,7 +11152,7 @@ declare module 'vscode' { * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A reference provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerReferenceProvider(selector: DocumentSelector, provider: ReferenceProvider): Disposable; @@ -11046,12 +11160,12 @@ declare module 'vscode' { * Register a rename provider. * * Multiple providers can be registered for a language. In that case providers are sorted - * by their [score](#languages.match) and asked in sequence. The first provider producing a result + * by their {@link languages.match score} and asked in sequence. The first provider producing a result * defines the result of the whole operation. * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A rename provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerRenameProvider(selector: DocumentSelector, provider: RenameProvider): Disposable; @@ -11059,12 +11173,12 @@ declare module 'vscode' { * Register a semantic tokens provider for a whole document. * * Multiple providers can be registered for a language. In that case providers are sorted - * by their [score](#languages.match) and the best-matching provider is used. Failure + * by their {@link languages.match score} and the best-matching provider is used. Failure * of the selected provider will cause a failure of the whole operation. * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A document semantic tokens provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerDocumentSemanticTokensProvider(selector: DocumentSelector, provider: DocumentSemanticTokensProvider, legend: SemanticTokensLegend): Disposable; @@ -11078,12 +11192,12 @@ declare module 'vscode' { * will be used. * * Multiple providers can be registered for a language. In that case providers are sorted - * by their [score](#languages.match) and the best-matching provider is used. Failure + * by their {@link languages.match score} and the best-matching provider is used. Failure * of the selected provider will cause a failure of the whole operation. * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A document range semantic tokens provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerDocumentRangeSemanticTokensProvider(selector: DocumentSelector, provider: DocumentRangeSemanticTokensProvider, legend: SemanticTokensLegend): Disposable; @@ -11091,29 +11205,29 @@ declare module 'vscode' { * Register a formatting provider for a document. * * Multiple providers can be registered for a language. In that case providers are sorted - * by their [score](#languages.match) and the best-matching provider is used. Failure + * by their {@link languages.match score} and the best-matching provider is used. Failure * of the selected provider will cause a failure of the whole operation. * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A document formatting edit provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerDocumentFormattingEditProvider(selector: DocumentSelector, provider: DocumentFormattingEditProvider): Disposable; /** * Register a formatting provider for a document range. * - * *Note:* A document range provider is also a [document formatter](#DocumentFormattingEditProvider) - * which means there is no need to [register](#languages.registerDocumentFormattingEditProvider) a document + * *Note:* A document range provider is also a {@link DocumentFormattingEditProvider document formatter} + * which means there is no need to {@link languages.registerDocumentFormattingEditProvider register} a document * formatter when also registering a range provider. * * Multiple providers can be registered for a language. In that case providers are sorted - * by their [score](#languages.match) and the best-matching provider is used. Failure + * by their {@link languages.match score} and the best-matching provider is used. Failure * of the selected provider will cause a failure of the whole operation. * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A document range formatting edit provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerDocumentRangeFormattingEditProvider(selector: DocumentSelector, provider: DocumentRangeFormattingEditProvider): Disposable; @@ -11121,14 +11235,14 @@ declare module 'vscode' { * Register a formatting provider that works on type. The provider is active when the user enables the setting `editor.formatOnType`. * * Multiple providers can be registered for a language. In that case providers are sorted - * by their [score](#languages.match) and the best-matching provider is used. Failure + * by their {@link languages.match score} and the best-matching provider is used. Failure * of the selected provider will cause a failure of the whole operation. * * @param selector A selector that defines the documents this provider is applicable to. * @param provider An on type formatting edit provider. * @param firstTriggerCharacter A character on which formatting should be triggered, like `}`. * @param moreTriggerCharacter More trigger characters. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerOnTypeFormattingEditProvider(selector: DocumentSelector, provider: OnTypeFormattingEditProvider, firstTriggerCharacter: string, ...moreTriggerCharacter: string[]): Disposable; @@ -11136,14 +11250,14 @@ declare module 'vscode' { * Register a signature help provider. * * Multiple providers can be registered for a language. In that case providers are sorted - * by their [score](#languages.match) and called sequentially until a provider returns a + * by their {@link languages.match score} and called sequentially until a provider returns a * valid result. * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A signature help provider. * @param triggerCharacters Trigger signature help when the user types one of the characters, like `,` or `(`. * @param metadata Information about the provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerSignatureHelpProvider(selector: DocumentSelector, provider: SignatureHelpProvider, ...triggerCharacters: string[]): Disposable; export function registerSignatureHelpProvider(selector: DocumentSelector, provider: SignatureHelpProvider, metadata: SignatureHelpProviderMetadata): Disposable; @@ -11157,7 +11271,7 @@ declare module 'vscode' { * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A document link provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerDocumentLinkProvider(selector: DocumentSelector, provider: DocumentLinkProvider): Disposable; @@ -11170,7 +11284,7 @@ declare module 'vscode' { * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A color provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerColorProvider(selector: DocumentSelector, provider: DocumentColorProvider): Disposable; @@ -11187,7 +11301,7 @@ declare module 'vscode' { * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A folding range provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerFoldingRangeProvider(selector: DocumentSelector, provider: FoldingRangeProvider): Disposable; @@ -11200,7 +11314,7 @@ declare module 'vscode' { * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A selection range provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerSelectionRangeProvider(selector: DocumentSelector, provider: SelectionRangeProvider): Disposable; @@ -11209,7 +11323,7 @@ declare module 'vscode' { * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A call hierarchy provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerCallHierarchyProvider(selector: DocumentSelector, provider: CallHierarchyProvider): Disposable; @@ -11217,26 +11331,825 @@ declare module 'vscode' { * Register a linked editing range provider. * * Multiple providers can be registered for a language. In that case providers are sorted - * by their [score](#languages.match) and the best-matching provider that has a result is used. Failure + * by their {@link languages.match score} and the best-matching provider that has a result is used. Failure * of the selected provider will cause a failure of the whole operation. * * @param selector A selector that defines the documents this provider is applicable to. * @param provider A linked editing range provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerLinkedEditingRangeProvider(selector: DocumentSelector, provider: LinkedEditingRangeProvider): Disposable; /** - * Set a [language configuration](#LanguageConfiguration) for a language. + * Set a {@link LanguageConfiguration language configuration} for a language. * * @param language A language identifier like `typescript`. * @param configuration Language configuration. - * @return A [disposable](#Disposable) that unsets this configuration. + * @return A {@link Disposable} that unsets this configuration. */ export function setLanguageConfiguration(language: string, configuration: LanguageConfiguration): Disposable; } + /** + * A notebook cell kind. + */ + export enum NotebookCellKind { + + /** + * A markup-cell is formatted source that is used for display. + */ + Markup = 1, + + /** + * A code-cell is source that can be {@link NotebookController executed} and that + * produces {@link NotebookCellOutput output}. + */ + Code = 2 + } + + /** + * Represents a cell of a {@link NotebookDocument notebook}, either a {@link NotebookCellKind.Code code}-cell + * or {@link NotebookCellKind.Markup markup}-cell. + * + * NotebookCell instances are immutable and are kept in sync for as long as they are part of their notebook. + */ + export interface NotebookCell { + + /** + * The index of this cell in its {@link NotebookDocument.cellAt containing notebook}. The + * index is updated when a cell is moved within its notebook. The index is `-1` + * when the cell has been removed from its notebook. + */ + readonly index: number; + + /** + * The {@link NotebookDocument notebook} that contains this cell. + */ + readonly notebook: NotebookDocument; + + /** + * The kind of this cell. + */ + readonly kind: NotebookCellKind; + + /** + * The {@link TextDocument text} of this cell, represented as text document. + */ + readonly document: TextDocument; + + /** + * The metadata of this cell. Can be anything but must be JSON-stringifyable. + */ + readonly metadata: { [key: string]: any } + + /** + * The outputs of this cell. + */ + readonly outputs: readonly NotebookCellOutput[]; + + /** + * The most recent {@link NotebookCellExecutionSummary excution summary} for this cell. + */ + readonly executionSummary?: NotebookCellExecutionSummary; + } + + /** + * Represents a notebook which itself is a sequence of {@link NotebookCell code or markup cells}. Notebook documents are + * created from {@link NotebookData notebook data}. + */ + export interface NotebookDocument { + + /** + * The associated uri for this notebook. + * + * *Note* that most notebooks use the `file`-scheme, which means they are files on disk. However, **not** all notebooks are + * saved on disk and therefore the `scheme` must be checked before trying to access the underlying file or siblings on disk. + * + * @see {@link FileSystemProvider} + */ + readonly uri: Uri; + + /** + * The type of notebook. + */ + readonly notebookType: string; + + /** + * The version number of this notebook (it will strictly increase after each + * change, including undo/redo). + */ + readonly version: number; + + /** + * `true` if there are unpersisted changes. + */ + readonly isDirty: boolean; + + /** + * Is this notebook representing an untitled file which has not been saved yet. + */ + readonly isUntitled: boolean; + + /** + * `true` if the notebook has been closed. A closed notebook isn't synchronized anymore + * and won't be re-used when the same resource is opened again. + */ + readonly isClosed: boolean; + + /** + * Arbitrary metadata for this notebook. Can be anything but must be JSON-stringifyable. + */ + readonly metadata: { [key: string]: any }; + + /** + * The number of cells in the notebook. + */ + readonly cellCount: number; + + /** + * Return the cell at the specified index. The index will be adjusted to the notebook. + * + * @param index - The index of the cell to retrieve. + * @return A {@link NotebookCell cell}. + */ + cellAt(index: number): NotebookCell; + + /** + * Get the cells of this notebook. A subset can be retrieved by providing + * a range. The range will be adjuset to the notebook. + * + * @param range A notebook range. + * @returns The cells contained by the range or all cells. + */ + getCells(range?: NotebookRange): NotebookCell[]; + + /** + * Save the document. The saving will be handled by the corresponding {@link NotebookSerializer serializer}. + * + * @return A promise that will resolve to true when the document + * has been saved. Will return false if the file was not dirty or when save failed. + */ + save(): Thenable; + } + + /** + * The summary of a notebook cell execution. + */ + export interface NotebookCellExecutionSummary { + + /** + * The order in which the execution happened. + */ + readonly executionOrder?: number; + + /** + * If the exclusive finished successfully. + */ + readonly success?: boolean; + + /** + * The times at which execution started and ended, as unix timestamps + */ + readonly timing?: { startTime: number, endTime: number }; + } + + /** + * A notebook range represents an ordered pair of two cell indicies. + * It is guaranteed that start is less than or equal to end. + */ + export class NotebookRange { + + /** + * The zero-based start index of this range. + */ + readonly start: number; + + /** + * The exclusive end index of this range (zero-based). + */ + readonly end: number; + + /** + * `true` if `start` and `end` are equal. + */ + readonly isEmpty: boolean; + + /** + * Create a new notebook range. If `start` is not + * before or equal to `end`, the values will be swapped. + * + * @param start start index + * @param end end index. + */ + constructor(start: number, end: number); + + /** + * Derive a new range for this range. + * + * @param change An object that describes a change to this range. + * @return A range that reflects the given change. Will return `this` range if the change + * is not changing anything. + */ + with(change: { start?: number, end?: number }): NotebookRange; + } + + /** + * One representation of a {@link NotebookCellOutput notebook output}, defined by MIME type and data. + */ + export class NotebookCellOutputItem { + + /** + * Factory function to create a `NotebookCellOutputItem` from a string. + * + * *Note* that an UTF-8 encoder is used to create bytes for the string. + * + * @param value A string. + * @param mime Optional MIME type, defaults to `text/plain`. + * @returns A new output item object. + */ + static text(value: string, mime?: string): NotebookCellOutputItem; + + /** + * Factory function to create a `NotebookCellOutputItem` from + * a JSON object. + * + * *Note* that this function is not expecting "stringified JSON" but + * an object that can be stringified. This function will throw an error + * when the passed value cannot be JSON-stringified. + * + * @param value A JSON-stringifyable value. + * @param mime Optional MIME type, defaults to `application/json` + * @returns A new output item object. + */ + static json(value: any, mime?: string): NotebookCellOutputItem; + + /** + * Factory function to create a `NotebookCellOutputItem` that uses + * uses the `application/vnd.code.notebook.stdout` mime type. + * + * @param value A string. + * @returns A new output item object. + */ + static stdout(value: string): NotebookCellOutputItem; + + /** + * Factory function to create a `NotebookCellOutputItem` that uses + * uses the `application/vnd.code.notebook.stderr` mime type. + * + * @param value A string. + * @returns A new output item object. + */ + static stderr(value: string): NotebookCellOutputItem; + + /** + * Factory function to create a `NotebookCellOutputItem` that uses + * uses the `application/vnd.code.notebook.error` mime type. + * + * @param value An error object. + * @returns A new output item object. + */ + static error(value: Error): NotebookCellOutputItem; + + /** + * The mime type which determines how the {@link NotebookCellOutputItem.data `data`}-property + * is interpreted. + * + * Notebooks have built-in support for certain mime-types, extensions can add support for new + * types and override existing types. + */ + mime: string; + + /** + * The data of this output item. Must always be an array of unsigned 8-bit integers. + */ + data: Uint8Array; + + /** + * Create a new notbook cell output item. + * + * @param data The value of the output item. + * @param mime The mime type of the output item. + */ + constructor(data: Uint8Array, mime: string); + } + + /** + * Notebook cell output represents a result of executing a cell. It is a container type for multiple + * {@link NotebookCellOutputItem output items} where contained items represent the same result but + * use different MIME types. + */ + export class NotebookCellOutput { + + /** + * The output items of this output. Each item must represent the same result. _Note_ that repeated + * MIME types per output is invalid and that the editor will just pick one of them. + * + * ```ts + * new vscode.NotebookCellOutput([ + * vscode.NotebookCellOutputItem.text('Hello', 'text/plain'), + * vscode.NotebookCellOutputItem.text('Hello', 'text/html'), + * vscode.NotebookCellOutputItem.text('_Hello_', 'text/markdown'), + * vscode.NotebookCellOutputItem.text('Hey', 'text/plain'), // INVALID: repeated type, editor will pick just one + * ]) + * ``` + */ + items: NotebookCellOutputItem[]; + + /** + * Arbitrary metadata for this cell output. Can be anything but must be JSON-stringifyable. + */ + metadata?: { [key: string]: any }; + + /** + * Create new notebook output. + * + * @param items Notebook output items. + * @param metadata Optional metadata. + */ + constructor(items: NotebookCellOutputItem[], metadata?: { [key: string]: any }); + } + + /** + * NotebookCellData is the raw representation of notebook cells. Its is part of {@link NotebookData `NotebookData`}. + */ + export class NotebookCellData { + + /** + * The {@link NotebookCellKind kind} of this cell data. + */ + kind: NotebookCellKind; + + /** + * The source value of this cell data - either source code or formatted text. + */ + value: string; + + /** + * The language identifier of the source value of this cell data. Any value from + * {@link languages.getLanguages `getLanguages`} is possible. + */ + languageId: string; + + /** + * The outputs of this cell data. + */ + outputs?: NotebookCellOutput[]; + + /** + * Arbitrary metadata of this cell data. Can be anything but must be JSON-stringifyable. + */ + metadata?: { [key: string]: any }; + + /** + * The execution summary of this cell data. + */ + executionSummary?: NotebookCellExecutionSummary; + + /** + * Create new cell data. Minimal cell data specifies its kind, its source value, and the + * language identifier of its source. + * + * @param kind The kind. + * @param value The source value. + * @param languageId The language identifier of the source value. + */ + constructor(kind: NotebookCellKind, value: string, languageId: string); + } + + /** + * NotebookData is the raw representation of notebooks. + * + * Extensions are responsible to create {@link NotebookData `NotebookData`} so that the editor + * can create a {@link NotebookDocument `NotebookDocument`}. + * + * @see {@link NotebookSerializer} + */ + export class NotebookData { + /** + * The cell data of this notebook data. + */ + cells: NotebookCellData[]; + + /** + * Arbitrary metadata of notebook data. + */ + metadata?: { [key: string]: any }; + + /** + * Create new notebook data. + * + * @param cells An array of cell data. + */ + constructor(cells: NotebookCellData[]); + } + + /** + * The notebook serializer enables the editor to open notebook files. + * + * At its core the editor only knows a {@link NotebookData notebook data structure} but not + * how that data structure is written to a file, nor how it is read from a file. The + * notebook serializer bridges this gap by deserializing bytes into notebook data and + * vice versa. + */ + export interface NotebookSerializer { + + /** + * Deserialize contents of a notebook file into the notebook data structure. + * + * @param content Contents of a notebook file. + * @param token A cancellation token. + * @return Notebook data or a thenable that resolves to such. + */ + deserializeNotebook(content: Uint8Array, token: CancellationToken): NotebookData | Thenable; + + /** + * Serialize notebook data into file contents. + * + * @param data A notebook data structure. + * @param token A cancellation token. + * @returns An array of bytes or a thenable that resolves to such. + */ + serializeNotebook(data: NotebookData, token: CancellationToken): Uint8Array | Thenable; + } + + /** + * Notebook content options define what parts of a notebook are persisted. Note + * + * For instance, a notebook serializer can opt-out of saving outputs and in that case the editor doesn't mark a + * notebooks as {@link NotebookDocument.isDirty dirty} when its output has changed. + */ + export interface NotebookDocumentContentOptions { + /** + * Controls if outputs change will trigger notebook document content change and if it will be used in the diff editor + * Default to false. If the content provider doesn't persisit the outputs in the file document, this should be set to true. + */ + transientOutputs?: boolean; + + /** + * Controls if a cell metadata property change will trigger notebook document content change and if it will be used in the diff editor + * Default to false. If the content provider doesn't persisit a metadata property in the file document, it should be set to true. + */ + transientCellMetadata?: { [key: string]: boolean | undefined }; + + /** + * Controls if a document metadata property change will trigger notebook document content change and if it will be used in the diff editor + * Default to false. If the content provider doesn't persisit a metadata property in the file document, it should be set to true. + */ + transientDocumentMetadata?: { [key: string]: boolean | undefined }; + } + + /** + * Notebook controller affinity for notebook documents. + * + * @see {@link NotebookController.updateNotebookAffinity} + */ + export enum NotebookControllerAffinity { + /** + * Default affinity. + */ + Default = 1, + /** + * A controller is preferred for a notebook. + */ + Preferred = 2 + } + + /** + * A notebook controller represents an entity that can execute notebook cells. This is often referred to as a kernel. + * + * There can be multiple controllers and the editor will let users choose which controller to use for a certain notebook. The + * {@link NotebookController.notebookType `notebookType`}-property defines for what kind of notebooks a controller is for and + * the {@link NotebookController.updateNotebookAffinity `updateNotebookAffinity`}-function allows controllers to set a preference + * for specific notebook documents. When a controller has been selected its + * {@link NotebookController.onDidChangeSelectedNotebooks onDidChangeSelectedNotebooks}-event fires. + * + * When a cell is being run the editor will invoke the {@link NotebookController.executeHandler `executeHandler`} and a controller + * is expected to create and finalize a {@link NotebookCellExecution notebook cell execution}. However, controllers are also free + * to create executions by themselves. + */ + export interface NotebookController { + + /** + * The identifier of this notebook controller. + * + * _Note_ that controllers are remembered by their identifier and that extensions should use + * stable identifiers across sessions. + */ + readonly id: string; + + /** + * The notebook type this controller is for. + */ + readonly notebookType: string; + + /** + * An array of language identifiers that are supported by this + * controller. Any language identifier from {@link languages.getLanguages `getLanguages`} + * is possible. When falsy all languages are supported. + * + * Samples: + * ```js + * // support JavaScript and TypeScript + * myController.supportedLanguages = ['javascript', 'typescript'] + * + * // support all languages + * myController.supportedLanguages = undefined; // falsy + * myController.supportedLanguages = []; // falsy + * ``` + */ + supportedLanguages?: string[]; + + /** + * The human-readable label of this notebook controller. + */ + label: string; + + /** + * The human-readable description which is rendered less prominent. + */ + description?: string; + + /** + * The human-readable detail which is rendered less prominent. + */ + detail?: string; + + /** + * Whether this controller supports execution order so that the + * editor can render placeholders for them. + */ + supportsExecutionOrder?: boolean; + + /** + * Create a cell execution task. + * + * _Note_ that there can only be one execution per cell at a time and that an error is thrown if + * a cell execution is created while another is still active. + * + * This should be used in response to the {@link NotebookController.executeHandler execution handler} + * being called or when cell execution has been started else, e.g when a cell was already + * executing or when cell execution was triggered from another source. + * + * @param cell The notebook cell for which to create the execution. + * @returns A notebook cell execution. + */ + createNotebookCellExecution(cell: NotebookCell): NotebookCellExecution; + + /** + * The execute handler is invoked when the run gestures in the UI are selected, e.g Run Cell, Run All, + * Run Selection etc. The execute handler is responsible for creating and managing {@link NotebookCellExecution execution}-objects. + */ + executeHandler: (cells: NotebookCell[], notebook: NotebookDocument, controller: NotebookController) => void | Thenable; + + /** + * Optional interrupt handler. + * + * By default cell execution is canceled via {@link NotebookCellExecution.token tokens}. Cancellation + * tokens require that a controller can keep track of its execution so that it can cancel a specific execution at a later + * point. Not all scenarios allow for that, eg. REPL-style controllers often work by interrupting whatever is currently + * running. For those cases the interrupt handler exists - it can be thought of as the equivalent of `SIGINT` + * or `Control+C` in terminals. + * + * _Note_ that supporting {@link NotebookCellExecution.token cancellation tokens} is preferred and that interrupt handlers should + * only be used when tokens cannot be supported. + */ + interruptHandler?: (notebook: NotebookDocument) => void | Thenable; + + /** + * An event that fires whenever a controller has been selected or un-selected for a notebook document. + * + * There can be multiple controllers for a notebook and in that case a controllers needs to be _selected_. This is a user gesture + * and happens either explicitly or implicitly when interacting with a notebook for which a controller was _suggested_. When possible, + * the editor _suggests_ a controller that is most likely to be _selected_. + * + * _Note_ that controller selection is persisted (by the controllers {@link NotebookController.id id}) and restored as soon as a + * controller is re-created or as a notebook is {@link workspace.onDidOpenNotebookDocument opened}. + */ + readonly onDidChangeSelectedNotebooks: Event<{ notebook: NotebookDocument, selected: boolean }>; + + /** + * A controller can set affinities for specific notebook documents. This allows a controller + * to be presented more prominent for some notebooks. + * + * @param notebook The notebook for which a priority is set. + * @param affinity A controller affinity + */ + updateNotebookAffinity(notebook: NotebookDocument, affinity: NotebookControllerAffinity): void; + + /** + * Dispose and free associated resources. + */ + dispose(): void; + } + + /** + * A NotebookCellExecution is how {@link NotebookController notebook controller} modify a notebook cell as + * it is executing. + * + * When a cell execution object is created, the cell enters the {@link NotebookCellExecutionState.Pending `Pending`} state. + * When {@link NotebookCellExecution.start `start(...)`} is called on the execution task, it enters the {@link NotebookCellExecutionState.Executing `Executing`} state. When + * {@link NotebookCellExecution.end `end(...)`} is called, it enters the {@link NotebookCellExecutionState.Idle `Idle`} state. + */ + export interface NotebookCellExecution { + + /** + * The {@link NotebookCell cell} for which this execution has been created. + */ + readonly cell: NotebookCell; + + /** + * A cancellation token which will be triggered when the cell execution is canceled + * from the UI. + * + * _Note_ that the cancellation token will not be triggered when the {@link NotebookController controller} + * that created this execution uses an {@link NotebookController.interruptHandler interrupt-handler}. + */ + readonly token: CancellationToken; + + /** + * Set and unset the order of this cell execution. + */ + executionOrder: number | undefined; + + /** + * Signal that the execution has begun. + * + * @param startTime The time that execution began, in milliseconds in the Unix epoch. Used to drive the clock + * that shows for how long a cell has been running. If not given, the clock won't be shown. + */ + start(startTime?: number): void; + + /** + * Signal that execution has ended. + * + * @param success If true, a green check is shown on the cell status bar. + * If false, a red X is shown. + * If undefined, no check or X icon is shown. + * @param endTime The time that execution finished, in milliseconds in the Unix epoch. + */ + end(success: boolean | undefined, endTime?: number): void; + + /** + * Clears the output of the cell that is executing or of another cell that is affected by this execution. + * + * @param cell Cell for which output is cleared. Defaults to the {@link NotebookCellExecution.cell cell} of + * this execution. + * @return A thenable that resolves when the operation finished. + */ + clearOutput(cell?: NotebookCell): Thenable; + + /** + * Replace the output of the cell that is executing or of another cell that is affected by this execution. + * + * @param out Output that replaces the current output. + * @param cell Cell for which output is cleared. Defaults to the {@link NotebookCellExecution.cell cell} of + * this execution. + * @return A thenable that resolves when the operation finished. + */ + replaceOutput(out: NotebookCellOutput | NotebookCellOutput[], cell?: NotebookCell): Thenable; + + /** + * Append to the output of the cell that is executing or to another cell that is affected by this execution. + * + * @param out Output that is appended to the current output. + * @param cell Cell for which output is cleared. Defaults to the {@link NotebookCellExecution.cell cell} of + * this execution. + * @return A thenable that resolves when the operation finished. + */ + appendOutput(out: NotebookCellOutput | NotebookCellOutput[], cell?: NotebookCell): Thenable; + + /** + * Replace all output items of existing cell output. + * + * @param items Output items that replace the items of existing output. + * @param output Output object that already exists. + * @return A thenable that resolves when the operation finished. + */ + replaceOutputItems(items: NotebookCellOutputItem | NotebookCellOutputItem[], output: NotebookCellOutput): Thenable; + + /** + * Append output items to existing cell output. + * + * @param items Output items that are append to existing output. + * @param output Output object that already exists. + * @return A thenable that resolves when the operation finished. + */ + appendOutputItems(items: NotebookCellOutputItem | NotebookCellOutputItem[], output: NotebookCellOutput): Thenable; + } + + /** + * Represents the alignment of status bar items. + */ + export enum NotebookCellStatusBarAlignment { + + /** + * Aligned to the left side. + */ + Left = 1, + + /** + * Aligned to the right side. + */ + Right = 2 + } + + /** + * A contribution to a cell's status bar + */ + export class NotebookCellStatusBarItem { + /** + * The text to show for the item. + */ + text: string; + + /** + * Whether the item is aligned to the left or right. + */ + alignment: NotebookCellStatusBarAlignment; + + /** + * An optional {@link Command `Command`} or identifier of a command to run on click. + * + * The command must be {@link commands.getCommands known}. + * + * Note that if this is a {@link Command `Command`} object, only the {@link Command.command `command`} and {@link Command.arguments `arguments`} + * are used by VS Code. + */ + command?: string | Command; + + /** + * A tooltip to show when the item is hovered. + */ + tooltip?: string; + + /** + * The priority of the item. A higher value item will be shown more to the left. + */ + priority?: number; + + /** + * Accessibility information used when a screen reader interacts with this item. + */ + accessibilityInformation?: AccessibilityInformation; + + /** + * Creates a new NotebookCellStatusBarItem. + * @param text The text to show for the item. + * @param alignment Whether the item is aligned to the left or right. + */ + constructor(text: string, alignment: NotebookCellStatusBarAlignment); + } + + /** + * A provider that can contribute items to the status bar that appears below a cell's editor. + */ + export interface NotebookCellStatusBarItemProvider { + /** + * An optional event to signal that statusbar items have changed. The provide method will be called again. + */ + onDidChangeCellStatusBarItems?: Event; + + /** + * The provider will be called when the cell scrolls into view, when its content, outputs, language, or metadata change, and when it changes execution state. + * @param cell The cell for which to return items. + * @param token A token triggered if this request should be cancelled. + * @return One or more {@link NotebookCellStatusBarItem cell statusbar items} + */ + provideCellStatusBarItems(cell: NotebookCell, token: CancellationToken): ProviderResult; + } + + /** + * Namespace for notebooks. + * + * The notebooks functionality is composed of three loosly coupled components: + * + * 1. {@link NotebookSerializer} enable the editor to open, show, and save notebooks + * 2. {@link NotebookController} own the execution of notebooks, e.g they create output from code cells. + * 3. NotebookRenderer present notebook output in the editor. They run in a separate context. + */ + export namespace notebooks { + + /** + * Creates a new notebook controller. + * + * @param id Identifier of the controller. Must be unique per extension. + * @param notebookType A notebook type for which this controller is for. + * @param label The label of the controller. + * @param handler The execute-handler of the controller. + */ + export function createNotebookController(id: string, notebookType: string, label: string, handler?: (cells: NotebookCell[], notebook: NotebookDocument, controller: NotebookController) => void | Thenable): NotebookController; + + /** + * Register a {@link NotebookCellStatusBarItemProvider cell statusbar item provider} for the given notebook type. + * + * @param notebookType The notebook type to register for. + * @param provider A cell status bar provider. + * @return A {@link Disposable} that unregisters this provider when being disposed. + */ + export function registerNotebookCellStatusBarItemProvider(notebookType: string, provider: NotebookCellStatusBarItemProvider): Disposable; + } + /** * Represents the input box in the Source Control viewlet. */ @@ -11261,7 +12174,7 @@ declare module 'vscode' { interface QuickDiffProvider { /** - * Provide a [uri](#Uri) to the original resource of any given resource uri. + * Provide a {@link Uri} to the original resource of any given resource uri. * * @param uri The uri of the resource open in a text editor. * @param token A cancellation token. @@ -11272,38 +12185,38 @@ declare module 'vscode' { /** * The theme-aware decorations for a - * [source control resource state](#SourceControlResourceState). + * {@link SourceControlResourceState source control resource state}. */ export interface SourceControlResourceThemableDecorations { /** * The icon path for a specific - * [source control resource state](#SourceControlResourceState). + * {@link SourceControlResourceState source control resource state}. */ readonly iconPath?: string | Uri; } /** - * The decorations for a [source control resource state](#SourceControlResourceState). + * The decorations for a {@link SourceControlResourceState source control resource state}. * Can be independently specified for light and dark themes. */ export interface SourceControlResourceDecorations extends SourceControlResourceThemableDecorations { /** - * Whether the [source control resource state](#SourceControlResourceState) should + * Whether the {@link SourceControlResourceState source control resource state} should * be striked-through in the UI. */ readonly strikeThrough?: boolean; /** - * Whether the [source control resource state](#SourceControlResourceState) should + * Whether the {@link SourceControlResourceState source control resource state} should * be faded in the UI. */ readonly faded?: boolean; /** * The title for a specific - * [source control resource state](#SourceControlResourceState). + * {@link SourceControlResourceState source control resource state}. */ readonly tooltip?: string; @@ -11320,23 +12233,23 @@ declare module 'vscode' { /** * An source control resource state represents the state of an underlying workspace - * resource within a certain [source control group](#SourceControlResourceGroup). + * resource within a certain {@link SourceControlResourceGroup source control group}. */ export interface SourceControlResourceState { /** - * The [uri](#Uri) of the underlying resource inside the workspace. + * The {@link Uri} of the underlying resource inside the workspace. */ readonly resourceUri: Uri; /** - * The [command](#Command) which should be run when the resource + * The {@link Command} which should be run when the resource * state is open in the Source Control viewlet. */ readonly command?: Command; /** - * The [decorations](#SourceControlResourceDecorations) for this source control + * The {@link SourceControlResourceDecorations decorations} for this source control * resource state. */ readonly decorations?: SourceControlResourceDecorations; @@ -11364,7 +12277,7 @@ declare module 'vscode' { /** * A source control resource group is a collection of - * [source control resource states](#SourceControlResourceState). + * {@link SourceControlResourceState source control resource states}. */ export interface SourceControlResourceGroup { @@ -11380,13 +12293,13 @@ declare module 'vscode' { /** * Whether this source control resource group is hidden when it contains - * no [source control resource states](#SourceControlResourceState). + * no {@link SourceControlResourceState source control resource states}. */ hideWhenEmpty?: boolean; /** * This group's collection of - * [source control resource states](#SourceControlResourceState). + * {@link SourceControlResourceState source control resource states}. */ resourceStates: SourceControlResourceState[]; @@ -11397,7 +12310,7 @@ declare module 'vscode' { } /** - * An source control is able to provide [resource states](#SourceControlResourceState) + * An source control is able to provide {@link SourceControlResourceState resource states} * to the editor and interact with the editor in several source control related ways. */ export interface SourceControl { @@ -11418,21 +12331,21 @@ declare module 'vscode' { readonly rootUri: Uri | undefined; /** - * The [input box](#SourceControlInputBox) for this source control. + * The {@link SourceControlInputBox input box} for this source control. */ readonly inputBox: SourceControlInputBox; /** - * The UI-visible count of [resource states](#SourceControlResourceState) of + * The UI-visible count of {@link SourceControlResourceState resource states} of * this source control. * - * Equals to the total number of [resource state](#SourceControlResourceState) + * Equals to the total number of {@link SourceControlResourceState resource state} * of this source control, if undefined. */ count?: number; /** - * An optional [quick diff provider](#QuickDiffProvider). + * An optional {@link QuickDiffProvider quick diff provider}. */ quickDiffProvider?: QuickDiffProvider; @@ -11460,7 +12373,7 @@ declare module 'vscode' { statusBarCommands?: Command[]; /** - * Create a new [resource group](#SourceControlResourceGroup). + * Create a new {@link SourceControlResourceGroup resource group}. */ createResourceGroup(id: string, label: string): SourceControlResourceGroup; @@ -11473,7 +12386,7 @@ declare module 'vscode' { export namespace scm { /** - * The [input box](#SourceControlInputBox) for the last source control + * The {@link SourceControlInputBox input box} for the last source control * created by the extension. * * @deprecated Use SourceControl.inputBox instead @@ -11481,12 +12394,12 @@ declare module 'vscode' { export const inputBox: SourceControlInputBox; /** - * Creates a new [source control](#SourceControl) instance. + * Creates a new {@link SourceControl source control} instance. * * @param id An `id` for the source control. Something short, e.g.: `git`. * @param label A human-readable string for the source control. E.g.: `Git`. * @param rootUri An optional Uri of the root of the source control. E.g.: `Uri.parse(workspaceRoot)`. - * @return An instance of [source control](#SourceControl). + * @return An instance of {@link SourceControl source control}. */ export function createSourceControl(id: string, label: string, rootUri?: Uri): SourceControl; } @@ -11548,12 +12461,18 @@ declare module 'vscode' { readonly id: string; /** - * The debug session's type from the [debug configuration](#DebugConfiguration). + * The debug session's type from the {@link DebugConfiguration debug configuration}. */ readonly type: string; /** - * The debug session's name is initially taken from the [debug configuration](#DebugConfiguration). + * The parent session of this debug session, if it was created as a child. + * @see DebugSessionOptions.parentSession + */ + readonly parentSession?: DebugSession; + + /** + * The debug session's name is initially taken from the {@link DebugConfiguration debug configuration}. * Any changes will be properly reflected in the UI. */ name: string; @@ -11564,7 +12483,7 @@ declare module 'vscode' { readonly workspaceFolder: WorkspaceFolder | undefined; /** - * The "resolved" [debug configuration](#DebugConfiguration) of this session. + * The "resolved" {@link DebugConfiguration debug configuration} of this session. * "Resolved" means that * - all variables have been substituted and * - platform specific attribute sections have been "flattened" for the matching platform and removed for non-matching platforms. @@ -11580,18 +12499,18 @@ declare module 'vscode' { * Maps a VS Code breakpoint to the corresponding Debug Adapter Protocol (DAP) breakpoint that is managed by the debug adapter of the debug session. * If no DAP breakpoint exists (either because the VS Code breakpoint was not yet registered or because the debug adapter is not interested in the breakpoint), the value `undefined` is returned. * - * @param breakpoint A VS Code [breakpoint](#Breakpoint). + * @param breakpoint A VS Code {@link Breakpoint}. * @return A promise that resolves to the Debug Adapter Protocol breakpoint or `undefined`. */ getDebugProtocolBreakpoint(breakpoint: Breakpoint): Thenable; } /** - * A custom Debug Adapter Protocol event received from a [debug session](#DebugSession). + * A custom Debug Adapter Protocol event received from a {@link DebugSession debug session}. */ export interface DebugSessionCustomEvent { /** - * The [debug session](#DebugSession) for which the custom event was received. + * The {@link DebugSession debug session} for which the custom event was received. */ readonly session: DebugSession; @@ -11609,28 +12528,28 @@ declare module 'vscode' { /** * A debug configuration provider allows to add debug configurations to the debug service * and to resolve launch configurations before they are used to start a debug session. - * A debug configuration provider is registered via #debug.registerDebugConfigurationProvider. + * A debug configuration provider is registered via {@link debug.registerDebugConfigurationProvider}. */ export interface DebugConfigurationProvider { /** - * Provides [debug configuration](#DebugConfiguration) to the debug service. If more than one debug configuration provider is + * Provides {@link DebugConfiguration debug configuration} to the debug service. If more than one debug configuration provider is * registered for the same type, debug configurations are concatenated in arbitrary order. * * @param folder The workspace folder for which the configurations are used or `undefined` for a folderless setup. * @param token A cancellation token. - * @return An array of [debug configurations](#DebugConfiguration). + * @return An array of {@link DebugConfiguration debug configurations}. */ provideDebugConfigurations?(folder: WorkspaceFolder | undefined, token?: CancellationToken): ProviderResult; /** - * Resolves a [debug configuration](#DebugConfiguration) by filling in missing values or by adding/changing/removing attributes. + * Resolves a {@link DebugConfiguration debug configuration} by filling in missing values or by adding/changing/removing attributes. * If more than one debug configuration provider is registered for the same type, the resolveDebugConfiguration calls are chained * in arbitrary order and the initial debug configuration is piped through the chain. * Returning the value 'undefined' prevents the debug session from starting. * Returning the value 'null' prevents the debug session from starting and opens the underlying debug configuration instead. * * @param folder The workspace folder from which the configuration originates from or `undefined` for a folderless setup. - * @param debugConfiguration The [debug configuration](#DebugConfiguration) to resolve. + * @param debugConfiguration The {@link DebugConfiguration debug configuration} to resolve. * @param token A cancellation token. * @return The resolved debug configuration or undefined or null. */ @@ -11638,14 +12557,14 @@ declare module 'vscode' { /** * This hook is directly called after 'resolveDebugConfiguration' but with all variables substituted. - * It can be used to resolve or verify a [debug configuration](#DebugConfiguration) by filling in missing values or by adding/changing/removing attributes. + * It can be used to resolve or verify a {@link DebugConfiguration debug configuration} by filling in missing values or by adding/changing/removing attributes. * If more than one debug configuration provider is registered for the same type, the 'resolveDebugConfigurationWithSubstitutedVariables' calls are chained * in arbitrary order and the initial debug configuration is piped through the chain. * Returning the value 'undefined' prevents the debug session from starting. * Returning the value 'null' prevents the debug session from starting and opens the underlying debug configuration instead. * * @param folder The workspace folder from which the configuration originates from or `undefined` for a folderless setup. - * @param debugConfiguration The [debug configuration](#DebugConfiguration) to resolve. + * @param debugConfiguration The {@link DebugConfiguration debug configuration} to resolve. * @param token A cancellation token. * @return The resolved debug configuration or undefined or null. */ @@ -11775,10 +12694,10 @@ declare module 'vscode' { export interface DebugAdapterDescriptorFactory { /** * 'createDebugAdapterDescriptor' is called at the start of a debug session to provide details about the debug adapter to use. - * These details must be returned as objects of type [DebugAdapterDescriptor](#DebugAdapterDescriptor). + * These details must be returned as objects of type {@link DebugAdapterDescriptor}. * Currently two types of debug adapters are supported: - * - a debug adapter executable is specified as a command path and arguments (see [DebugAdapterExecutable](#DebugAdapterExecutable)), - * - a debug adapter server reachable via a communication port (see [DebugAdapterServer](#DebugAdapterServer)). + * - a debug adapter executable is specified as a command path and arguments (see {@link DebugAdapterExecutable}), + * - a debug adapter server reachable via a communication port (see {@link DebugAdapterServer}). * If the method is not implemented the default behavior is this: * createDebugAdapter(session: DebugSession, executable: DebugAdapterExecutable) { * if (typeof session.configuration.debugServer === 'number') { @@ -11786,9 +12705,9 @@ declare module 'vscode' { * } * return executable; * } - * @param session The [debug session](#DebugSession) for which the debug adapter will be used. + * @param session The {@link DebugSession debug session} for which the debug adapter will be used. * @param executable The debug adapter's executable information as specified in the package.json (or undefined if no such information exists). - * @return a [debug adapter descriptor](#DebugAdapterDescriptor) or undefined. + * @return a {@link DebugAdapterDescriptor debug adapter descriptor} or undefined. */ createDebugAdapterDescriptor(session: DebugSession, executable: DebugAdapterExecutable | undefined): ProviderResult; } @@ -11828,8 +12747,8 @@ declare module 'vscode' { * The method 'createDebugAdapterTracker' is called at the start of a debug session in order * to return a "tracker" object that provides read-access to the communication between VS Code and a debug adapter. * - * @param session The [debug session](#DebugSession) for which the debug adapter tracker will be used. - * @return A [debug adapter tracker](#DebugAdapterTracker) or undefined. + * @param session The {@link DebugSession debug session} for which the debug adapter tracker will be used. + * @return A {@link DebugAdapterTracker debug adapter tracker} or undefined. */ createDebugAdapterTracker(session: DebugSession): ProviderResult; } @@ -11855,23 +12774,23 @@ declare module 'vscode' { } /** - * An event describing the changes to the set of [breakpoints](#Breakpoint). + * An event describing the changes to the set of {@link Breakpoint breakpoints}. */ export interface BreakpointsChangeEvent { /** * Added breakpoints. */ - readonly added: ReadonlyArray; + readonly added: readonly Breakpoint[]; /** * Removed breakpoints. */ - readonly removed: ReadonlyArray; + readonly removed: readonly Breakpoint[]; /** * Changed breakpoints. */ - readonly changed: ReadonlyArray; + readonly changed: readonly Breakpoint[]; } /** @@ -11933,7 +12852,7 @@ declare module 'vscode' { } /** - * Debug console mode used by debug session, see [options](#DebugSessionOptions). + * Debug console mode used by debug session, see {@link DebugSessionOptions options}. */ export enum DebugConsoleMode { /** @@ -11949,7 +12868,7 @@ declare module 'vscode' { } /** - * Options for [starting a debug session](#debug.startDebugging). + * Options for {@link debug.startDebugging starting a debug session}. */ export interface DebugSessionOptions { @@ -11984,7 +12903,7 @@ declare module 'vscode' { * A DebugConfigurationProviderTriggerKind specifies when the `provideDebugConfigurations` method of a `DebugConfigurationProvider` is triggered. * Currently there are two situations: to provide the initial debug configurations for a newly created launch.json or * to provide dynamically generated debug configurations when the user asks for them through the UI (e.g. via the "Select and Start Debugging" command). - * A trigger kind is used when registering a `DebugConfigurationProvider` with #debug.registerDebugConfigurationProvider. + * A trigger kind is used when registering a `DebugConfigurationProvider` with {@link debug.registerDebugConfigurationProvider}. */ export enum DebugConfigurationProviderTriggerKind { /** @@ -12003,14 +12922,14 @@ declare module 'vscode' { export namespace debug { /** - * The currently active [debug session](#DebugSession) or `undefined`. The active debug session is the one + * The currently active {@link DebugSession debug session} or `undefined`. The active debug session is the one * represented by the debug action floating window or the one currently shown in the drop down menu of the debug action floating window. * If no debug session is active, the value is `undefined`. */ export let activeDebugSession: DebugSession | undefined; /** - * The currently active [debug console](#DebugConsole). + * The currently active {@link DebugConsole debug console}. * If no debug session is active, output sent to the debug console is not shown. */ export let activeDebugConsole: DebugConsole; @@ -12021,35 +12940,35 @@ declare module 'vscode' { export let breakpoints: Breakpoint[]; /** - * An [event](#Event) which fires when the [active debug session](#debug.activeDebugSession) + * An {@link Event} which fires when the {@link debug.activeDebugSession active debug session} * has changed. *Note* that the event also fires when the active debug session changes * to `undefined`. */ export const onDidChangeActiveDebugSession: Event; /** - * An [event](#Event) which fires when a new [debug session](#DebugSession) has been started. + * An {@link Event} which fires when a new {@link DebugSession debug session} has been started. */ export const onDidStartDebugSession: Event; /** - * An [event](#Event) which fires when a custom DAP event is received from the [debug session](#DebugSession). + * An {@link Event} which fires when a custom DAP event is received from the {@link DebugSession debug session}. */ export const onDidReceiveDebugSessionCustomEvent: Event; /** - * An [event](#Event) which fires when a [debug session](#DebugSession) has terminated. + * An {@link Event} which fires when a {@link DebugSession debug session} has terminated. */ export const onDidTerminateDebugSession: Event; /** - * An [event](#Event) that is emitted when the set of breakpoints is added, removed, or changed. + * An {@link Event} that is emitted when the set of breakpoints is added, removed, or changed. */ export const onDidChangeBreakpoints: Event; /** - * Register a [debug configuration provider](#DebugConfigurationProvider) for a specific debug type. - * The optional [triggerKind](#DebugConfigurationProviderTriggerKind) can be used to specify when the `provideDebugConfigurations` method of the provider is triggered. + * Register a {@link DebugConfigurationProvider debug configuration provider} for a specific debug type. + * The optional {@link DebugConfigurationProviderTriggerKind triggerKind} can be used to specify when the `provideDebugConfigurations` method of the provider is triggered. * Currently two trigger kinds are possible: with the value `Initial` (or if no trigger kind argument is given) the `provideDebugConfigurations` method is used to provide the initial debug configurations to be copied into a newly created launch.json. * With the trigger kind `Dynamic` the `provideDebugConfigurations` method is used to dynamically determine debug configurations to be presented to the user (in addition to the static configurations from the launch.json). * Please note that the `triggerKind` argument only applies to the `provideDebugConfigurations` method: so the `resolveDebugConfiguration` methods are not affected at all. @@ -12057,20 +12976,20 @@ declare module 'vscode' { * More than one provider can be registered for the same type. * * @param type The debug type for which the provider is registered. - * @param provider The [debug configuration provider](#DebugConfigurationProvider) to register. - * @param triggerKind The [trigger](#DebugConfigurationProviderTrigger) for which the 'provideDebugConfiguration' method of the provider is registered. If `triggerKind` is missing, the value `DebugConfigurationProviderTriggerKind.Initial` is assumed. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @param provider The {@link DebugConfigurationProvider debug configuration provider} to register. + * @param triggerKind The {@link DebugConfigurationProviderTrigger trigger} for which the 'provideDebugConfiguration' method of the provider is registered. If `triggerKind` is missing, the value `DebugConfigurationProviderTriggerKind.Initial` is assumed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerDebugConfigurationProvider(debugType: string, provider: DebugConfigurationProvider, triggerKind?: DebugConfigurationProviderTriggerKind): Disposable; /** - * Register a [debug adapter descriptor factory](#DebugAdapterDescriptorFactory) for a specific debug type. + * Register a {@link DebugAdapterDescriptorFactory debug adapter descriptor factory} for a specific debug type. * An extension is only allowed to register a DebugAdapterDescriptorFactory for the debug type(s) defined by the extension. Otherwise an error is thrown. * Registering more than one DebugAdapterDescriptorFactory for a debug type results in an error. * * @param debugType The debug type for which the factory is registered. - * @param factory The [debug adapter descriptor factory](#DebugAdapterDescriptorFactory) to register. - * @return A [disposable](#Disposable) that unregisters this factory when being disposed. + * @param factory The {@link DebugAdapterDescriptorFactory debug adapter descriptor factory} to register. + * @return A {@link Disposable} that unregisters this factory when being disposed. */ export function registerDebugAdapterDescriptorFactory(debugType: string, factory: DebugAdapterDescriptorFactory): Disposable; @@ -12078,27 +12997,27 @@ declare module 'vscode' { * Register a debug adapter tracker factory for the given debug type. * * @param debugType The debug type for which the factory is registered or '*' for matching all debug types. - * @param factory The [debug adapter tracker factory](#DebugAdapterTrackerFactory) to register. - * @return A [disposable](#Disposable) that unregisters this factory when being disposed. + * @param factory The {@link DebugAdapterTrackerFactory debug adapter tracker factory} to register. + * @return A {@link Disposable} that unregisters this factory when being disposed. */ export function registerDebugAdapterTrackerFactory(debugType: string, factory: DebugAdapterTrackerFactory): Disposable; /** * Start debugging by using either a named launch or named compound configuration, - * or by directly passing a [DebugConfiguration](#DebugConfiguration). + * or by directly passing a {@link DebugConfiguration}. * The named configurations are looked up in '.vscode/launch.json' found in the given folder. * Before debugging starts, all unsaved files are saved and the launch configurations are brought up-to-date. * Folder specific variables used in the configuration (e.g. '${workspaceFolder}') are resolved against the given folder. - * @param folder The [workspace folder](#WorkspaceFolder) for looking up named configurations and resolving variables or `undefined` for a non-folder setup. - * @param nameOrConfiguration Either the name of a debug or compound configuration or a [DebugConfiguration](#DebugConfiguration) object. - * @param parentSessionOrOptions Debug session options. When passed a parent [debug session](#DebugSession), assumes options with just this parent session. + * @param folder The {@link WorkspaceFolder workspace folder} for looking up named configurations and resolving variables or `undefined` for a non-folder setup. + * @param nameOrConfiguration Either the name of a debug or compound configuration or a {@link DebugConfiguration} object. + * @param parentSessionOrOptions Debug session options. When passed a parent {@link DebugSession debug session}, assumes options with just this parent session. * @return A thenable that resolves when debugging could be successfully started. */ export function startDebugging(folder: WorkspaceFolder | undefined, nameOrConfiguration: string | DebugConfiguration, parentSessionOrOptions?: DebugSession | DebugSessionOptions): Thenable; /** * Stop the given debug session or stop all debug sessions if session is omitted. - * @param session The [debug session](#DebugSession) to stop; if omitted all sessions are stopped. + * @param session The {@link DebugSession debug session} to stop; if omitted all sessions are stopped. */ export function stopDebugging(session?: DebugSession): Thenable; @@ -12106,13 +13025,13 @@ declare module 'vscode' { * Add breakpoints. * @param breakpoints The breakpoints to add. */ - export function addBreakpoints(breakpoints: Breakpoint[]): void; + export function addBreakpoints(breakpoints: readonly Breakpoint[]): void; /** * Remove breakpoints. * @param breakpoints The breakpoints to remove. */ - export function removeBreakpoints(breakpoints: Breakpoint[]): void; + export function removeBreakpoints(breakpoints: readonly Breakpoint[]): void; /** * Converts a "Source" descriptor object received via the Debug Adapter Protocol into a Uri that can be used to load its contents. @@ -12130,7 +13049,7 @@ declare module 'vscode' { /** * Namespace for dealing with installed extensions. Extensions are represented - * by an [extension](#Extension)-interface which enables reflection on them. + * by an {@link Extension}-interface which enables reflection on them. * * Extension writers can provide APIs to other extensions by returning their API public * surface from the `activate`-call. @@ -12150,8 +13069,8 @@ declare module 'vscode' { * } * ``` * When depending on the API of another extension add an `extensionDependencies`-entry - * to `package.json`, and use the [getExtension](#extensions.getExtension)-function - * and the [exports](#Extension.exports)-property, like below: + * to `package.json`, and use the {@link extensions.getExtension getExtension}-function + * and the {@link Extension.exports exports}-property, like below: * * ```javascript * let mathExt = extensions.getExtension('genius.math'); @@ -12181,7 +13100,7 @@ declare module 'vscode' { /** * All extensions currently known to the system. */ - export const all: ReadonlyArray>; + export const all: readonly Extension[]; /** * An event which fires when `extensions.all` changes. This can happen when extensions are @@ -12191,7 +13110,7 @@ declare module 'vscode' { } /** - * Collapsible state of a [comment thread](#CommentThread) + * Collapsible state of a {@link CommentThread comment thread} */ export enum CommentThreadCollapsibleState { /** @@ -12206,7 +13125,7 @@ declare module 'vscode' { } /** - * Comment mode of a [comment](#Comment) + * Comment mode of a {@link Comment} */ export enum CommentMode { /** @@ -12221,7 +13140,7 @@ declare module 'vscode' { } /** - * A collection of [comments](#Comment) representing a conversation at a particular range in a document. + * A collection of {@link Comment comments} representing a conversation at a particular range in a document. */ export interface CommentThread { /** @@ -12238,7 +13157,7 @@ declare module 'vscode' { /** * The ordered comments of the thread. */ - comments: ReadonlyArray; + comments: readonly Comment[]; /** * Whether the thread should be collapsed or expanded when opening the document. @@ -12273,7 +13192,7 @@ declare module 'vscode' { contextValue?: string; /** - * The optional human-readable label describing the [Comment Thread](#CommentThread) + * The optional human-readable label describing the {@link CommentThread Comment Thread} */ label?: string; @@ -12286,7 +13205,7 @@ declare module 'vscode' { } /** - * Author information of a [comment](#Comment) + * Author information of a {@link Comment} */ export interface CommentAuthorInformation { /** @@ -12301,7 +13220,7 @@ declare module 'vscode' { } /** - * Reactions of a [comment](#Comment) + * Reactions of a {@link Comment} */ export interface CommentReaction { /** @@ -12335,12 +13254,12 @@ declare module 'vscode' { body: string | MarkdownString; /** - * [Comment mode](#CommentMode) of the comment + * {@link CommentMode Comment mode} of the comment */ mode: CommentMode; /** - * The [author information](#CommentAuthorInformation) of the comment + * The {@link CommentAuthorInformation author information} of the comment */ author: CommentAuthorInformation; @@ -12365,12 +13284,12 @@ declare module 'vscode' { contextValue?: string; /** - * Optional reactions of the [comment](#Comment) + * Optional reactions of the {@link Comment} */ reactions?: CommentReaction[]; /** - * Optional label describing the [Comment](#Comment) + * Optional label describing the {@link Comment} * Label will be rendered next to authorName if exists. */ label?: string; @@ -12381,7 +13300,7 @@ declare module 'vscode' { */ export interface CommentReply { /** - * The active [comment thread](#CommentThread) + * The active {@link CommentThread comment thread} */ thread: CommentThread; @@ -12392,7 +13311,7 @@ declare module 'vscode' { } /** - * Commenting range provider for a [comment controller](#CommentController). + * Commenting range provider for a {@link CommentController comment controller}. */ export interface CommentingRangeProvider { /** @@ -12402,7 +13321,7 @@ declare module 'vscode' { } /** - * Represents a [comment controller](#CommentController)'s [options](#CommentController.options). + * Represents a {@link CommentController comment controller}'s {@link CommentController.options options}. */ export interface CommentOptions { /** @@ -12417,7 +13336,7 @@ declare module 'vscode' { } /** - * A comment controller is able to provide [comments](#CommentThread) support to the editor and + * A comment controller is able to provide {@link CommentThread comments} support to the editor and * provide users various ways to interact with comments. */ export interface CommentController { @@ -12437,31 +13356,31 @@ declare module 'vscode' { options?: CommentOptions; /** - * Optional commenting range provider. Provide a list [ranges](#Range) which support commenting to any given resource uri. + * Optional commenting range provider. Provide a list {@link Range ranges} which support commenting to any given resource uri. * * If not provided, users can leave comments in any document opened in the editor. */ commentingRangeProvider?: CommentingRangeProvider; /** - * Create a [comment thread](#CommentThread). The comment thread will be displayed in visible text editors (if the resource matches) + * Create a {@link CommentThread comment thread}. The comment thread will be displayed in visible text editors (if the resource matches) * and Comments Panel once created. * * @param uri The uri of the document the thread has been created on. * @param range The range the comment thread is located within the document. * @param comments The ordered comments of the thread. */ - createCommentThread(uri: Uri, range: Range, comments: Comment[]): CommentThread; + createCommentThread(uri: Uri, range: Range, comments: readonly Comment[]): CommentThread; /** - * Optional reaction handler for creating and deleting reactions on a [comment](#Comment). + * Optional reaction handler for creating and deleting reactions on a {@link Comment}. */ reactionHandler?: (comment: Comment, reaction: CommentReaction) => Thenable; /** * Dispose this comment controller. * - * Once disposed, all [comment threads](#CommentThread) created by this comment controller will also be removed from the editor + * Once disposed, all {@link CommentThread comment threads} created by this comment controller will also be removed from the editor * and Comments Panel. */ dispose(): void; @@ -12469,11 +13388,11 @@ declare module 'vscode' { namespace comments { /** - * Creates a new [comment controller](#CommentController) instance. + * Creates a new {@link CommentController comment controller} instance. * * @param id An `id` for the comment controller. * @param label A human-readable string for the comment controller. - * @return An instance of [comment controller](#CommentController). + * @return An instance of {@link CommentController comment controller}. */ export function createCommentController(id: string, label: string): CommentController; } @@ -12501,13 +13420,13 @@ declare module 'vscode' { /** * The permissions granted by the session's access token. Available scopes - * are defined by the [AuthenticationProvider](#AuthenticationProvider). + * are defined by the {@link AuthenticationProvider}. */ - readonly scopes: ReadonlyArray; + readonly scopes: readonly string[]; } /** - * The information of an account associated with an [AuthenticationSession](#AuthenticationSession). + * The information of an account associated with an {@link AuthenticationSession}. */ export interface AuthenticationSessionAccountInformation { /** @@ -12523,7 +13442,7 @@ declare module 'vscode' { /** - * Options to be used when getting an [AuthenticationSession](#AuthenticationSession) from an [AuthenticationProvider](#AuthenticationProvider). + * Options to be used when getting an {@link AuthenticationSession} from an {@link AuthenticationProvider}. */ export interface AuthenticationGetSessionOptions { /** @@ -12544,8 +13463,8 @@ declare module 'vscode' { * Whether the existing user session preference should be cleared. * * For authentication providers that support being signed into multiple accounts at once, the user will be - * prompted to select an account to use when [getSession](#authentication.getSession) is called. This preference - * is remembered until [getSession](#authentication.getSession) is called with this flag. + * prompted to select an account to use when {@link authentication.getSession getSession} is called. This preference + * is remembered until {@link authentication.getSession getSession} is called with this flag. * * Defaults to false. */ @@ -12553,7 +13472,7 @@ declare module 'vscode' { } /** - * Basic information about an [authenticationProvider](#AuthenticationProvider) + * Basic information about an {@link AuthenticationProvider} */ export interface AuthenticationProviderInformation { /** @@ -12568,17 +13487,17 @@ declare module 'vscode' { } /** - * An [event](#Event) which fires when an [AuthenticationSession](#AuthenticationSession) is added, removed, or changed. + * An {@link Event} which fires when an {@link AuthenticationSession} is added, removed, or changed. */ export interface AuthenticationSessionsChangeEvent { /** - * The [authenticationProvider](#AuthenticationProvider) that has had its sessions change. + * The {@link AuthenticationProvider} that has had its sessions change. */ readonly provider: AuthenticationProviderInformation; } /** - * Options for creating an [AuthenticationProvider](#AuthenticationProvider). + * Options for creating an {@link AuthenticationProvider}. */ export interface AuthenticationProviderOptions { /** @@ -12589,25 +13508,25 @@ declare module 'vscode' { } /** - * An [event](#Event) which fires when an [AuthenticationSession](#AuthenticationSession) is added, removed, or changed. + * An {@link Event} which fires when an {@link AuthenticationSession} is added, removed, or changed. */ export interface AuthenticationProviderAuthenticationSessionsChangeEvent { /** - * The [AuthenticationSession](#AuthenticationSession)s of the [AuthenticationProvider](#AuthentiationProvider) that have been added. + * The {@link AuthenticationSession}s of the {@link AuthentiationProvider AuthenticationProvider} that have been added. */ - readonly added?: ReadonlyArray; + readonly added?: readonly AuthenticationSession[]; /** - * The [AuthenticationSession](#AuthenticationSession)s of the [AuthenticationProvider](#AuthentiationProvider) that have been removed. + * The {@link AuthenticationSession}s of the {@link AuthentiationProvider AuthenticationProvider} that have been removed. */ - readonly removed?: ReadonlyArray; + readonly removed?: readonly AuthenticationSession[]; /** - * The [AuthenticationSession](#AuthenticationSession)s of the [AuthenticationProvider](#AuthentiationProvider) that have been changed. + * The {@link AuthenticationSession}s of the {@link AuthentiationProvider AuthenticationProvider} that have been changed. * A session changes when its data excluding the id are updated. An example of this is a session refresh that results in a new * access token being set for the session. */ - readonly changed?: ReadonlyArray; + readonly changed?: readonly AuthenticationSession[]; } /** @@ -12615,7 +13534,7 @@ declare module 'vscode' { */ export interface AuthenticationProvider { /** - * An [event](#Event) which fires when the array of sessions has changed, or data + * An {@link Event} which fires when the array of sessions has changed, or data * within a session has changed. */ readonly onDidChangeSessions: Event; @@ -12626,7 +13545,7 @@ declare module 'vscode' { * these permissions, otherwise all sessions should be returned. * @returns A promise that resolves to an array of authentication sessions. */ - getSessions(scopes?: string[]): Thenable>; + getSessions(scopes?: readonly string[]): Thenable; /** * Prompts a user to login. @@ -12641,7 +13560,7 @@ declare module 'vscode' { * @param scopes A list of scopes, permissions, that the new session should be created with. * @returns A promise that resolves to an authentication session. */ - createSession(scopes: string[]): Thenable; + createSession(scopes: readonly string[]): Thenable; /** * Removes the session corresponding to session id. @@ -12669,10 +13588,10 @@ declare module 'vscode' { * to VS Code that implement GitHub and Microsoft authentication: their providerId's are 'github' and 'microsoft'. * @param providerId The id of the provider to use * @param scopes A list of scopes representing the permissions requested. These are dependent on the authentication provider - * @param options The [getSessionOptions](#GetSessionOptions) to use + * @param options The {@link GetSessionOptions} to use * @returns A thenable that resolves to an authentication session */ - export function getSession(providerId: string, scopes: string[], options: AuthenticationGetSessionOptions & { createIfNone: true }): Thenable; + export function getSession(providerId: string, scopes: readonly string[], options: AuthenticationGetSessionOptions & { createIfNone: true }): Thenable; /** * Get an authentication session matching the desired scopes. Rejects if a provider with providerId is not @@ -12684,13 +13603,13 @@ declare module 'vscode' { * to VS Code that implement GitHub and Microsoft authentication: their providerId's are 'github' and 'microsoft'. * @param providerId The id of the provider to use * @param scopes A list of scopes representing the permissions requested. These are dependent on the authentication provider - * @param options The [getSessionOptions](#GetSessionOptions) to use + * @param options The {@link GetSessionOptions} to use * @returns A thenable that resolves to an authentication session if available, or undefined if there are no sessions */ - export function getSession(providerId: string, scopes: string[], options?: AuthenticationGetSessionOptions): Thenable; + export function getSession(providerId: string, scopes: readonly string[], options?: AuthenticationGetSessionOptions): Thenable; /** - * An [event](#Event) which fires when the authentication sessions of an authentication provider have + * An {@link Event} which fires when the authentication sessions of an authentication provider have * been added, removed, or changed. */ export const onDidChangeSessions: Event; @@ -12705,7 +13624,7 @@ declare module 'vscode' { * @param label The human-readable name of the provider. * @param provider The authentication provider provider. * @params options Additional options for the provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerAuthenticationProvider(id: string, label: string, provider: AuthenticationProvider, options?: AuthenticationProviderOptions): Disposable; } diff --git a/lib/vscode/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts similarity index 72% rename from lib/vscode/src/vs/vscode.proposed.d.ts rename to src/vs/vscode.proposed.d.ts index 50c3f1144caa..12d667c74cfb 100644 --- a/lib/vscode/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -19,16 +19,16 @@ declare module 'vscode' { //#region auth provider: https://github.com/microsoft/vscode/issues/88309 /** - * An [event](#Event) which fires when an [AuthenticationProvider](#AuthenticationProvider) is added or removed. + * An {@link Event} which fires when an {@link AuthenticationProvider} is added or removed. */ export interface AuthenticationProvidersChangeEvent { /** - * The ids of the [authenticationProvider](#AuthenticationProvider)s that have been added. + * The ids of the {@link AuthenticationProvider}s that have been added. */ readonly added: ReadonlyArray; /** - * The ids of the [authenticationProvider](#AuthenticationProvider)s that have been removed. + * The ids of the {@link AuthenticationProvider}s that have been removed. */ readonly removed: ReadonlyArray; } @@ -80,16 +80,10 @@ declare module 'vscode' { constructor(host: string, port: number, connectionToken?: string); } - export enum RemoteTrustOption { - Unknown = 0, - DisableTrust = 1, - MachineTrusted = 2 - } - export interface ResolvedOptions { extensionHostEnv?: { [key: string]: string | null; }; - trust?: RemoteTrustOption; + isTrusted?: boolean; } export interface TunnelOptions { @@ -150,7 +144,24 @@ declare module 'vscode' { } export interface RemoteAuthorityResolver { + /** + * Resolve the authority part of the current opened `vscode-remote://` URI. + * + * This method will be invoked once during the startup of VS Code and again each time + * VS Code detects a disconnection. + * + * @param authority The authority part of the current opened `vscode-remote://` URI. + * @param context A context indicating if this is the first call or a subsequent call. + */ resolve(authority: string, context: RemoteAuthorityResolverContext): ResolverResult | Thenable; + + /** + * Get the canonical URI (if applicable) for a `vscode-remote://` URI. + * + * @returns The canonical URI or undefined if the uri is already canonical. + */ + getCanonicalURI?(uri: Uri): ProviderResult; + /** * Can be optionally implemented if the extension can forward ports better than the core. * When not implemented, the core will use its default forwarding logic. @@ -289,7 +300,7 @@ declare module 'vscode' { /** * A file glob pattern to match file paths against. * TODO@roblourens merge this with the GlobPattern docs/definition in vscode.d.ts. - * @see [GlobPattern](#GlobPattern) + * @see {@link GlobPattern} */ export type GlobString = string; @@ -392,13 +403,32 @@ declare module 'vscode' { Warning = 2, } + /** + * A message regarding a completed search. + */ + export interface TextSearchCompleteMessage { + /** + * Markdown text of the message. + */ + text: string, + /** + * Whether the source of the message is trusted, command links are disabled for untrusted message sources. + * Messaged are untrusted by default. + */ + trusted?: boolean, + /** + * The message type, this affects how the message will be rendered. + */ + type: TextSearchCompleteMessageType, + } + /** * Information collected when text search is complete. */ export interface TextSearchComplete { /** * Whether the search hit the limit on the maximum number of search results. - * `maxResults` on [`TextSearchOptions`](#TextSearchOptions) specifies the max number of results. + * `maxResults` on {@link TextSearchOptions `TextSearchOptions`} specifies the max number of results. * - If exactly that number of matches exist, this should be false. * - If `maxResults` matches are returned and more exist, this should be true. * - If search hits an internal limit which is less than `maxResults`, this should be true. @@ -411,8 +441,10 @@ declare module 'vscode' { * Messages with "Information" tyle support links in markdown syntax: * - Click to [run a command](command:workbench.action.OpenQuickPick) * - Click to [open a website](https://aka.ms) + * + * Commands may optionally return { triggerSearch: true } to signal to VS Code that the original search should run be agian. */ - message?: { text: string, type: TextSearchCompleteMessageType } | { text: string, type: TextSearchCompleteMessageType }[]; + message?: TextSearchCompleteMessage | TextSearchCompleteMessage[]; } /** @@ -545,7 +577,7 @@ declare module 'vscode' { * * @param scheme The provider will be invoked for workspace folders that have this file scheme. * @param provider The provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerFileSearchProvider(scheme: string, provider: FileSearchProvider): Disposable; @@ -556,7 +588,7 @@ declare module 'vscode' { * * @param scheme The provider will be invoked for workspace folders that have this file scheme. * @param provider The provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerTextSearchProvider(scheme: string, provider: TextSearchProvider): Disposable; } @@ -570,14 +602,14 @@ declare module 'vscode' { */ export interface FindTextInFilesOptions { /** - * A [glob pattern](#GlobPattern) that defines the files to search for. The glob pattern - * will be matched against the file paths of files relative to their workspace. Use a [relative pattern](#RelativePattern) - * to restrict the search results to a [workspace folder](#WorkspaceFolder). + * A {@link GlobPattern glob pattern} that defines the files to search for. The glob pattern + * will be matched against the file paths of files relative to their workspace. Use a {@link RelativePattern relative pattern} + * to restrict the search results to a {@link WorkspaceFolder workspace folder}. */ include?: GlobPattern; /** - * A [glob pattern](#GlobPattern) that defines files and folders to exclude. The glob pattern + * A {@link GlobPattern glob pattern} that defines files and folders to exclude. The glob pattern * will be matched against the file paths of resulting matches relative to their workspace. When `undefined`, default excludes will * apply. */ @@ -635,7 +667,7 @@ declare module 'vscode' { export namespace workspace { /** - * Search text in files across all [workspace folders](#workspace.workspaceFolders) in the workspace. + * Search text in files across all {@link workspace.workspaceFolders workspace folders} in the workspace. * @param query The query parameters for the search - the search string, whether it's case-sensitive, or a regex, or matches whole words. * @param callback A callback, called for each result * @param token A token that can be used to signal cancellation to the underlying search engine. @@ -644,7 +676,7 @@ declare module 'vscode' { export function findTextInFiles(query: TextSearchQuery, callback: (result: TextSearchResult) => void, token?: CancellationToken): Thenable; /** - * Search text in files across all [workspace folders](#workspace.workspaceFolders) in the workspace. + * Search text in files across all {@link workspace.workspaceFolders workspace folders} in the workspace. * @param query The query parameters for the search - the search string, whether it's case-sensitive, or a regex, or matches whole words. * @param options An optional set of query options. Include and exclude patterns, maxResults, etc. * @param callback A callback, called for each result @@ -674,13 +706,13 @@ declare module 'vscode' { * Registers a diff information command that can be invoked via a keyboard shortcut, * a menu item, an action, or directly. * - * Diff information commands are different from ordinary [commands](#commands.registerCommand) as + * Diff information commands are different from ordinary {@link commands.registerCommand commands} as * they only execute when there is an active diff editor when the command is called, and the diff * information has been computed. Also, the command handler of an editor command has access to * the diff information. * * @param command A unique identifier for the command. - * @param callback A command handler function with access to the [diff information](#LineChange). + * @param callback A command handler function with access to the {@link LineChange diff information}. * @param thisArg The `this` context used when invoking the handler function. * @return Disposable which unregisters this command on disposal. */ @@ -788,7 +820,7 @@ declare module 'vscode' { export interface TerminalDataWriteEvent { /** - * The [terminal](#Terminal) for which the data was written. + * The {@link Terminal} for which the data was written. */ readonly terminal: Terminal; /** @@ -811,22 +843,22 @@ declare module 'vscode' { //#region Terminal dimensions property and change event https://github.com/microsoft/vscode/issues/55718 /** - * An [event](#Event) which fires when a [Terminal](#Terminal)'s dimensions change. + * An {@link Event} which fires when a {@link Terminal}'s dimensions change. */ export interface TerminalDimensionsChangeEvent { /** - * The [terminal](#Terminal) for which the dimensions have changed. + * The {@link Terminal} for which the dimensions have changed. */ readonly terminal: Terminal; /** - * The new value for the [terminal's dimensions](#Terminal.dimensions). + * The new value for the {@link Terminal.dimensions terminal's dimensions}. */ readonly dimensions: TerminalDimensions; } export namespace window { /** - * An event which fires when the [dimensions](#Terminal.dimensions) of the terminal change. + * An event which fires when the {@link Terminal.dimensions dimensions} of the terminal change. */ export const onDidChangeTerminalDimensions: Event; } @@ -842,15 +874,26 @@ declare module 'vscode' { //#endregion - //#region Terminal initial text https://github.com/microsoft/vscode/issues/120368 + //#region Terminal name change event https://github.com/microsoft/vscode/issues/114898 - export interface TerminalOptions { + export interface Pseudoterminal { /** - * A message to write to the terminal on first launch, note that this is not sent to the - * process but, rather written directly to the terminal. This supports escape sequences such - * a setting text style. + * An event that when fired allows changing the name of the terminal. + * + * **Example:** Change the terminal name to "My new terminal". + * ```typescript + * const writeEmitter = new vscode.EventEmitter(); + * const changeNameEmitter = new vscode.EventEmitter(); + * const pty: vscode.Pseudoterminal = { + * onDidWrite: writeEmitter.event, + * onDidChangeName: changeNameEmitter.event, + * open: () => changeNameEmitter.fire('My new terminal'), + * close: () => {} + * }; + * vscode.window.createTerminal({ name: 'My terminal', pty }); + * ``` */ - readonly message?: string; + onDidChangeName?: Event; } //#endregion @@ -859,9 +902,37 @@ declare module 'vscode' { export interface TerminalOptions { /** - * A codicon ID to associate with this terminal. + * The icon path or {@link ThemeIcon} for the terminal. + */ + readonly iconPath?: Uri | { light: Uri; dark: Uri } | ThemeIcon; + } + + export interface ExtensionTerminalOptions { + /** + * A themeIcon, Uri, or light and dark Uris to use as the terminal tab icon + */ + readonly iconPath?: Uri | { light: Uri; dark: Uri } | ThemeIcon; + } + + //#endregion + + //#region Terminal profile provider https://github.com/microsoft/vscode/issues/120369 + + export namespace window { + /** + * Registers a provider for a contributed terminal profile. + * @param id The ID of the contributed terminal profile. + * @param provider The terminal profile provider. + */ + export function registerTerminalProfileProvider(id: string, provider: TerminalProfileProvider): Disposable; + } + + export interface TerminalProfileProvider { + /** + * Provide terminal profile options for the requested terminal. + * @param token A cancellation token that indicates the result is no longer needed. */ - readonly icon?: string; + provideProfileOptions(token: CancellationToken): ProviderResult; } //#endregion @@ -881,66 +952,29 @@ declare module 'vscode' { } //#endregion - //#region Task presentation group: https://github.com/microsoft/vscode/issues/47265 - export interface TaskPresentationOptions { - /** - * Controls whether the task is executed in a specific terminal group using split panes. - */ - group?: string; + //#region Custom Tree View Drag and Drop https://github.com/microsoft/vscode/issues/32592 + export interface TreeViewOptions { + dragAndDropController?: DragAndDropController; } - //#endregion - - //#region Status bar item with ID and Name: https://github.com/microsoft/vscode/issues/74972 - - /** - * Options to configure the status bar item. - */ - export interface StatusBarItemOptions { - - /** - * A unique identifier of the status bar item. The identifier - * is for example used to allow a user to show or hide the - * status bar item in the UI. - */ - id: string; - - /** - * A human readable name of the status bar item. The name is - * for example used as a label in the UI to show or hide the - * status bar item. - */ - name: string; - - /** - * Accessibility information used when screen reader interacts with this status bar item. - */ - accessibilityInformation?: AccessibilityInformation; + export interface DragAndDropController extends Disposable { /** - * The alignment of the status bar item. - */ - alignment?: StatusBarAlignment; - - /** - * The priority of the status bar item. Higher value means the item should - * be shown more to the left. + * Extensions should fire `TreeDataProvider.onDidChangeTreeData` for any elements that need to be refreshed. + * + * @param source + * @param target */ - priority?: number; + onDrop(source: T[], target: T): Thenable; } + //#endregion - export namespace window { - + //#region Task presentation group: https://github.com/microsoft/vscode/issues/47265 + export interface TaskPresentationOptions { /** - * Creates a status bar [item](#StatusBarItem). - * - * @param options The options of the item. If not provided, some default values - * will be assumed. For example, the `StatusBarItemOptions.id` will be the id - * of the extension and the `StatusBarItemOptions.name` will be the extension name. - * @return A new status bar item. + * Controls whether the task is executed in a specific terminal group using split panes. */ - export function createStatusBarItem(options?: StatusBarItemOptions): StatusBarItem; + group?: string; } - //#endregion //#region Custom editor move https://github.com/microsoft/vscode/issues/86146 @@ -978,235 +1012,66 @@ declare module 'vscode' { //#endregion - //#region https://github.com/microsoft/vscode/issues/106744, Notebooks (misc) - - export enum NotebookCellKind { - // todo@API rename/rethink as "Markup" cell - Markdown = 1, - Code = 2 - } - - export class NotebookCellMetadata { - /** - * Whether a code cell's editor is collapsed - */ - readonly inputCollapsed?: boolean; - - /** - * Whether a code cell's outputs are collapsed - */ - readonly outputCollapsed?: boolean; - - /** - * Additional attributes of a cell metadata. - */ - readonly [key: string]: any; - - /** - * Create a new notebook cell metadata. - * - * @param inputCollapsed Whether a code cell's editor is collapsed - * @param outputCollapsed Whether a code cell's outputs are collapsed - */ - constructor(inputCollapsed?: boolean, outputCollapsed?: boolean); - - /** - * Derived a new cell metadata from this metadata. - * - * @param change An object that describes a change to this NotebookCellMetadata. - * @return A new NotebookCellMetadata that reflects the given change. Will return `this` NotebookCellMetadata if the change - * is not changing anything. - */ - with(change: { inputCollapsed?: boolean | null, outputCollapsed?: boolean | null, [key: string]: any }): NotebookCellMetadata; - } - - export interface NotebookCellExecutionSummary { - readonly executionOrder?: number; - readonly success?: boolean; - readonly startTime?: number; - readonly endTime?: number; - } - - // todo@API support ids https://github.com/jupyter/enhancement-proposals/blob/master/62-cell-id/cell-id.md - export interface NotebookCell { - readonly index: number; - readonly notebook: NotebookDocument; - readonly kind: NotebookCellKind; - readonly document: TextDocument; - readonly metadata: NotebookCellMetadata - readonly outputs: ReadonlyArray; - - // todo@API maybe just executionSummary or lastExecutionSummary? - readonly latestExecutionSummary: NotebookCellExecutionSummary | undefined; - } - - export class NotebookDocumentMetadata { - /** - * Whether the document is trusted, default to true - * When false, insecure outputs like HTML, JavaScript, SVG will not be rendered. - */ - readonly trusted: boolean; - - /** - * Additional attributes of the document metadata. - */ - readonly [key: string]: any; - - /** - * Create a new notebook document metadata - * @param trusted Whether the document metadata is trusted. - */ - constructor(trusted?: boolean); + //#region https://github.com/microsoft/vscode/issues/124970, Cell Execution State + /** + * The execution state of a notebook cell. + */ + export enum NotebookCellExecutionState { /** - * Derived a new document metadata from this metadata. - * - * @param change An object that describes a change to this NotebookDocumentMetadata. - * @return A new NotebookDocumentMetadata that reflects the given change. Will return `this` NotebookDocumentMetadata if the change - * is not changing anything. + * The cell is idle. */ - with(change: { trusted?: boolean | null, [key: string]: any }): NotebookDocumentMetadata - } - - export interface NotebookDocumentContentOptions { + Idle = 1, /** - * Controls if outputs change will trigger notebook document content change and if it will be used in the diff editor - * Default to false. If the content provider doesn't persisit the outputs in the file document, this should be set to true. + * Execution for the cell is pending. */ - transientOutputs?: boolean; - + Pending = 2, /** - * Controls if a cell metadata property change will trigger notebook document content change and if it will be used in the diff editor - * Default to false. If the content provider doesn't persisit a metadata property in the file document, it should be set to true. + * The cell is currently executing. */ - transientCellMetadata?: { [K in keyof NotebookCellMetadata]?: boolean }; - - /** - * Controls if a document metadata property change will trigger notebook document content change and if it will be used in the diff editor - * Default to false. If the content provider doesn't persisit a metadata property in the file document, it should be set to true. - */ - transientDocumentMetadata?: { [K in keyof NotebookDocumentMetadata]?: boolean }; + Executing = 3, } /** - * Represents a notebook. Notebooks are composed of cells and metadata. + * An event describing a cell execution state change. */ - export interface NotebookDocument { - - /** - * The associated uri for this notebook. - * - * *Note* that most notebooks use the `file`-scheme, which means they are files on disk. However, **not** all notebooks are - * saved on disk and therefore the `scheme` must be checked before trying to access the underlying file or siblings on disk. - * - * @see [FileSystemProvider](#FileSystemProvider) - * @see [TextDocumentContentProvider](#TextDocumentContentProvider) - */ - readonly uri: Uri; - - // todo@API should we really expose this? - // todo@API should this be called `notebookType` or `notebookKind` - readonly viewType: string; - + export interface NotebookCellExecutionStateChangeEvent { /** - * The version number of this notebook (it will strictly increase after each - * change, including undo/redo). + * The {@link NotebookCell cell} for which the execution state has changed. */ - readonly version: number; + readonly cell: NotebookCell; /** - * `true` if there are unpersisted changes. + * The new execution state of the cell. */ - readonly isDirty: boolean; + readonly state: NotebookCellExecutionState; + } - /** - * Is this notebook representing an untitled file which has not been saved yet. - */ - readonly isUntitled: boolean; + export namespace notebooks { /** - * `true` if the notebook has been closed. A closed notebook isn't synchronized anymore - * and won't be re-used when the same resource is opened again. + * An {@link Event} which fires when the execution state of a cell has changed. */ - readonly isClosed: boolean; + // todo@API this is an event that is fired for a property that cells don't have and that makes me wonder + // how a correct consumer works, e.g the consumer could have been late and missed an event? + export const onDidChangeNotebookCellExecutionState: Event; + } - /** - * The [metadata](#NotebookDocumentMetadata) for this notebook. - */ - readonly metadata: NotebookDocumentMetadata; + //#endregion - /** - * The number of cells in the notebook. - */ - readonly cellCount: number; + //#region https://github.com/microsoft/vscode/issues/106744, Notebook, deprecated & misc - /** - * Return the cell at the specified index. The index will be adjusted to the notebook. - * - * @param index - The index of the cell to retrieve. - * @return A [cell](#NotebookCell). - */ - cellAt(index: number): NotebookCell; + export interface NotebookCellOutput { + id: string; + } - /** - * Get the cells of this notebook. A subset can be retrieved by providing - * a range. The range will be adjuset to the notebook. - * - * @param range A notebook range. - * @returns The cells contained by the range or all cells. - */ - getCells(range?: NotebookRange): NotebookCell[]; + //#endregion - /** - * Save the document. The saving will be handled by the corresponding content provider - * - * @return A promise that will resolve to true when the document - * has been saved. If the file was not dirty or the save failed, - * will return false. - */ - save(): Thenable; - } + //#region https://github.com/microsoft/vscode/issues/106744, NotebookEditor /** - * A notebook range represents on ordered pair of two cell indicies. - * It is guaranteed that start is less than or equal to end. + * Represents a notebook editor that is attached to a {@link NotebookDocument notebook}. */ - export class NotebookRange { - - /** - * The zero-based start index of this range. - */ - readonly start: number; - - /** - * The exclusive end index of this range (zero-based). - */ - readonly end: number; - - /** - * `true` if `start` and `end` are equal. - */ - readonly isEmpty: boolean; - - /** - * Create a new notebook range. If `start` is not - * before or equal to `end`, the values will be swapped. - * - * @param start start index - * @param end end index. - */ - constructor(start: number, end: number); - - /** - * Derive a new range for this range. - * - * @param change An object that describes a change to this range. - * @return A range that reflects the given change. Will return `this` range if the change - * is not changing anything. - */ - with(change: { start?: number, end?: number }): NotebookRange; - } - export enum NotebookEditorRevealType { /** * The range will be revealed with as little scrolling as possible. @@ -1230,10 +1095,14 @@ declare module 'vscode' { AtTop = 3 } + /** + * Represents a notebook editor that is attached to a {@link NotebookDocument notebook}. + */ export interface NotebookEditor { /** * The document associated with this notebook editor. */ + //todo@api rename to notebook? readonly document: NotebookDocument; /** @@ -1264,8 +1133,9 @@ declare module 'vscode' { export interface NotebookDocumentMetadataChangeEvent { /** - * The [notebook document](#NotebookDocument) for which the document metadata have changed. + * The {@link NotebookDocument notebook document} for which the document metadata have changed. */ + //todo@API rename to notebook? readonly document: NotebookDocument; } @@ -1281,31 +1151,36 @@ declare module 'vscode' { export interface NotebookCellsChangeEvent { /** - * The [notebook document](#NotebookDocument) for which the cells have changed. + * The {@link NotebookDocument notebook document} for which the cells have changed. */ + //todo@API rename to notebook? readonly document: NotebookDocument; readonly changes: ReadonlyArray; } export interface NotebookCellOutputsChangeEvent { /** - * The [notebook document](#NotebookDocument) for which the cell outputs have changed. + * The {@link NotebookDocument notebook document} for which the cell outputs have changed. */ + //todo@API remove? use cell.notebook instead? readonly document: NotebookDocument; + // NotebookCellOutputsChangeEvent.cells vs NotebookCellMetadataChangeEvent.cell readonly cells: NotebookCell[]; } export interface NotebookCellMetadataChangeEvent { /** - * The [notebook document](#NotebookDocument) for which the cell metadata have changed. + * The {@link NotebookDocument notebook document} for which the cell metadata have changed. */ + //todo@API remove? use cell.notebook instead? readonly document: NotebookDocument; + // NotebookCellOutputsChangeEvent.cells vs NotebookCellMetadataChangeEvent.cell readonly cell: NotebookCell; } export interface NotebookEditorSelectionChangeEvent { /** - * The [notebook editor](#NotebookEditor) for which the selections have changed. + * The {@link NotebookEditor notebook editor} for which the selections have changed. */ readonly notebookEditor: NotebookEditor; readonly selections: ReadonlyArray @@ -1313,40 +1188,12 @@ declare module 'vscode' { export interface NotebookEditorVisibleRangesChangeEvent { /** - * The [notebook editor](#NotebookEditor) for which the visible ranges have changed. + * The {@link NotebookEditor notebook editor} for which the visible ranges have changed. */ readonly notebookEditor: NotebookEditor; readonly visibleRanges: ReadonlyArray; } - export interface NotebookCellExecutionStateChangeEvent { - /** - * The [notebook document](#NotebookDocument) for which the cell execution state has changed. - */ - readonly document: NotebookDocument; - readonly cell: NotebookCell; - readonly executionState: NotebookCellExecutionState; - } - - // todo@API support ids https://github.com/jupyter/enhancement-proposals/blob/master/62-cell-id/cell-id.md - export class NotebookCellData { - kind: NotebookCellKind; - // todo@API better names: value? text? - source: string; - // todo@API languageId (as in TextDocument) - language: string; - outputs?: NotebookCellOutput[]; - metadata?: NotebookCellMetadata; - // todo@API just executionSummary or lastExecutionSummary - latestExecutionSummary?: NotebookCellExecutionSummary; - constructor(kind: NotebookCellKind, source: string, language: string, outputs?: NotebookCellOutput[], metadata?: NotebookCellMetadata, latestExecutionSummary?: NotebookCellExecutionSummary); - } - - export class NotebookData { - cells: NotebookCellData[]; - metadata: NotebookDocumentMetadata; - constructor(cells: NotebookCellData[], metadata?: NotebookDocumentMetadata); - } export interface NotebookDocumentShowOptions { viewColumn?: ViewColumn; @@ -1355,19 +1202,12 @@ declare module 'vscode' { selections?: NotebookRange[]; } - export namespace notebook { + export namespace notebooks { - export function openNotebookDocument(uri: Uri): Thenable; - export const onDidOpenNotebookDocument: Event; - export const onDidCloseNotebookDocument: Event; export const onDidSaveNotebookDocument: Event; - /** - * All currently known notebook documents. - */ - export const notebookDocuments: ReadonlyArray; export const onDidChangeNotebookDocumentMetadata: Event; export const onDidChangeNotebookCells: Event; @@ -1392,38 +1232,6 @@ declare module 'vscode' { //#endregion - //#region https://github.com/microsoft/vscode/issues/106744, NotebookCellOutput - - // code specific mime types - // application/x.notebook.error-traceback - // application/x.notebook.stdout - // application/x.notebook.stderr - // application/x.notebook.stream - export class NotebookCellOutputItem { - - // todo@API - // add factory functions for common mime types - // static textplain(value:string): NotebookCellOutputItem; - // static errortrace(value:any): NotebookCellOutputItem; - - mime: string; - value: unknown; - metadata?: Record; - - constructor(mime: string, value: unknown, metadata?: Record); - } - - // @jrieken transient - export class NotebookCellOutput { - id: string; - outputs: NotebookCellOutputItem[]; - metadata?: Record; - constructor(outputs: NotebookCellOutputItem[], metadata?: Record); - constructor(outputs: NotebookCellOutputItem[], id: string, metadata?: Record); - } - - //#endregion - //#region https://github.com/microsoft/vscode/issues/106744, NotebookEditorEdit // todo@API add NotebookEdit-type which handles all these cases? @@ -1444,26 +1252,26 @@ declare module 'vscode' { export interface WorkspaceEdit { // todo@API add NotebookEdit-type which handles all these cases? - replaceNotebookMetadata(uri: Uri, value: NotebookDocumentMetadata): void; + replaceNotebookMetadata(uri: Uri, value: { [key: string]: any }): void; replaceNotebookCells(uri: Uri, range: NotebookRange, cells: NotebookCellData[], metadata?: WorkspaceEditEntryMetadata): void; - replaceNotebookCellMetadata(uri: Uri, index: number, cellMetadata: NotebookCellMetadata, metadata?: WorkspaceEditEntryMetadata): void; + replaceNotebookCellMetadata(uri: Uri, index: number, cellMetadata: { [key: string]: any }, metadata?: WorkspaceEditEntryMetadata): void; } export interface NotebookEditorEdit { - replaceMetadata(value: NotebookDocumentMetadata): void; + replaceMetadata(value: { [key: string]: any }): void; replaceCells(start: number, end: number, cells: NotebookCellData[]): void; - replaceCellMetadata(index: number, metadata: NotebookCellMetadata): void; + replaceCellMetadata(index: number, metadata: { [key: string]: any }): void; } export interface NotebookEditor { /** * Perform an edit on the notebook associated with this notebook editor. * - * The given callback-function is invoked with an [edit-builder](#NotebookEditorEdit) which must + * The given callback-function is invoked with an {@link NotebookEditorEdit edit-builder} which must * be used to make edits. Note that the edit-builder is only valid while the * callback executes. * - * @param callback A function which can create edits using an [edit-builder](#NotebookEditorEdit). + * @param callback A function which can create edits using an {@link NotebookEditorEdit edit-builder}. * @return A promise that resolves with a value indicating if the edits could be applied. */ // @jrieken REMOVE maybe @@ -1472,220 +1280,60 @@ declare module 'vscode' { //#endregion - //#region https://github.com/microsoft/vscode/issues/106744, NotebookSerializer - - /** - * The notebook serializer enables the editor to open notebook files. - * - * At its core the editor only knows a [notebook data structure](#NotebookData) but not - * how that data structure is written to a file, nor how it is read from a file. The - * notebook serializer bridges this gap by deserializing bytes into notebook data and - * vice versa. - */ - export interface NotebookSerializer { - - /** - * Deserialize contents of a notebook file into the notebook data structure. - * - * @param content Contents of a notebook file. - * @param token A cancellation token. - * @return Notebook data or a thenable that resolves to such. - */ - deserializeNotebook(content: Uint8Array, token: CancellationToken): NotebookData | Thenable; - - /** - * Serialize notebook data into file contents. - * - * @param data A notebook data structure. - * @param token A cancellation token. - * @returns An array of bytes or a thenable that resolves to such. - */ - serializeNotebook(data: NotebookData, token: CancellationToken): Uint8Array | Thenable; - } - - export namespace notebook { + //#region https://github.com/microsoft/vscode/issues/106744, NotebookEditorDecorationType - // todo@API remove output when notebook marks that as transient, same for metadata - /** - * Register a [notebook serializer](#NotebookSerializer). - * - * @param notebookType A notebook. - * @param serializer A notebook serialzier. - * @param options Optional context options that define what parts of a notebook should be persisted - * @return A [disposable](#Disposable) that unregisters this serializer when being disposed. - */ - export function registerNotebookSerializer(notebookType: string, serializer: NotebookSerializer, options?: NotebookDocumentContentOptions): Disposable; + export interface NotebookEditor { + setDecorations(decorationType: NotebookEditorDecorationType, range: NotebookRange): void; } - //#endregion - - //#region https://github.com/microsoft/vscode/issues/119949 - - - export interface NotebookFilter { - readonly viewType?: string; - readonly scheme?: string; - readonly pattern?: GlobPattern; + export interface NotebookDecorationRenderOptions { + backgroundColor?: string | ThemeColor; + borderColor?: string | ThemeColor; + top: ThemableDecorationAttachmentRenderOptions; } - export type NotebookSelector = NotebookFilter | string | ReadonlyArray; - - export interface NotebookExecuteHandler { - /** - * @param cells The notebook cells to execute. - * @param notebook The notebook for which the execute handler is being called. - * @param controller The controller that the handler is attached to - */ - (this: NotebookController, cells: NotebookCell[], notebook: NotebookDocument, controller: NotebookController): void | Thenable + export interface NotebookEditorDecorationType { + readonly key: string; + dispose(): void; } - export interface NotebookInterruptHandler { - /** - * @param notebook The notebook for which the interrupt handler is being called. - */ - (this: NotebookController, notebook: NotebookDocument): void | Thenable; + export namespace notebooks { + export function createNotebookEditorDecorationType(options: NotebookDecorationRenderOptions): NotebookEditorDecorationType; } - export interface NotebookController { - - /** - * The identifier of this notebook controller. - */ - readonly id: string; - - /** - * The notebook view type this controller is for. - */ - readonly viewType: string; - - /** - * An array of language identifiers that are supported by this - * controller. Any language identifier from [`getLanguages`](#languages.getLanguages) - * is possible. When falsy all languages are supported. - * - * Samples: - * ```js - * // support JavaScript and TypeScript - * myController.supportedLanguages = ['javascript', 'typescript'] - * - * // support all languages - * myController.supportedLanguages = undefined; // falsy - * myController.supportedLanguages = []; // falsy - * ``` - */ - supportedLanguages?: string[]; - - /** - * The human-readable label of this notebook controller. - */ - label: string; - - /** - * The human-readable description which is rendered less prominent. - */ - description?: string; - - /** - * The human-readable detail which is rendered less prominent. - */ - detail?: string; - - /** - * Whether this controller supports execution order so that the - * editor can render placeholders for them. - */ - // todo@API rename to supportsExecutionOrder, usesExecutionOrder - hasExecutionOrder?: boolean; - - /** - * The execute handler is invoked when the run gestures in the UI are selected, e.g Run Cell, Run All, - * Run Selection etc. - */ - executeHandler: NotebookExecuteHandler; - - /** - * The interrupt handler is invoked the interrupt all execution. This is contrary to cancellation (available via - * [`NotebookCellExecutionTask#token`](NotebookCellExecutionTask#token)) and should only be used when - * execution-level cancellation is supported - */ - interruptHandler?: NotebookInterruptHandler - - /** - * Dispose and free associated resources. - */ - dispose(): void; - - /** - * A kernel can apply to one or many notebook documents but a notebook has only one active - * kernel. This event fires whenever a notebook has been associated to a kernel or when - * that association has been removed. - */ - readonly onDidChangeNotebookAssociation: Event<{ notebook: NotebookDocument, selected: boolean }>; - - /** - * Create a cell execution task. - * - * This should be used in response to the [execution handler](#NotebookController.executeHandler) - * being calleed or when cell execution has been started else, e.g when a cell was already - * executing or when cell execution was triggered from another source. - * - * @param cell The notebook cell for which to create the execution. - * @returns A notebook cell execution. - */ - createNotebookCellExecutionTask(cell: NotebookCell): NotebookCellExecutionTask; - - // todo@API find a better name than "preloads" - // todo@API allow add, not remove - // ipc - readonly preloads: NotebookKernelPreload[]; - - /** - * An event that fires when a renderer (see `preloads`) has send a message to the controller. - */ - readonly onDidReceiveMessage: Event<{ editor: NotebookEditor, message: any }>; - - /** - * Send a message to the renderer of notebook editors. - * - * Note that only editors showing documents that are bound to this controller - * are receiving the message. - * - * @param message The message to send. - * @param editor A specific editor to send the message to. When `undefined` all applicable editors are receiving the message. - * @returns A promise that resolves to a boolean indicating if the message has been send or not. - */ - postMessage(message: any, editor?: NotebookEditor): Thenable; + //#endregion - //todo@API validate this works - asWebviewUri(localResource: Uri): Uri; + //#region https://github.com/microsoft/vscode/issues/106744, NotebookConcatTextDocument + export namespace notebooks { /** - * A controller can set affinities for specific notebook documents. This allows a controller - * to be more important for some notebooks. + * Create a document that is the concatenation of all notebook cells. By default all code-cells are included + * but a selector can be provided to narrow to down the set of cells. * - * @param notebook The notebook for which a priority is set. - * @param affinity A controller affinity + * @param notebook + * @param selector */ - updateNotebookAffinity(notebook: NotebookDocument, affinity: NotebookControllerAffinity): void; + // todo@API really needed? we didn't find a user here + export function createConcatTextDocument(notebook: NotebookDocument, selector?: DocumentSelector): NotebookConcatTextDocument; } - export enum NotebookControllerAffinity { - Default = 1, - Preferred = 2 - } + export interface NotebookConcatTextDocument { + readonly uri: Uri; + readonly isClosed: boolean; + dispose(): void; + readonly onDidChange: Event; + readonly version: number; + getText(): string; + getText(range: Range): string; - export namespace notebook { + offsetAt(position: Position): number; + positionAt(offset: number): Position; + validateRange(range: Range): Range; + validatePosition(position: Position): Position; - /** - * Creates a new notebook controller. - * - * @param id Extension-unique identifier of the controller - * @param viewType A notebook type for which this controller is for. - * @param label The label of the controller - * @param handler - * @param preloads - */ - export function createNotebookController(id: string, viewType: string, label: string, handler?: NotebookExecuteHandler, preloads?: NotebookKernelPreload[]): NotebookController; + locationAt(positionOrRange: Position | Range): Location; + positionAt(location: Location): Position; + contains(uri: Uri): boolean; } //#endregion @@ -1727,7 +1375,7 @@ declare module 'vscode' { readonly onDidChangeNotebookContentOptions?: Event; /** - * Content providers should always use [file system providers](#FileSystemProvider) to + * Content providers should always use {@link FileSystemProvider file system providers} to * resolve the raw content for `uri` as the resouce is not necessarily a file on disk. */ openNotebook(uri: Uri, openContext: NotebookDocumentOpenContext, token: CancellationToken): NotebookData | Thenable; @@ -1742,232 +1390,164 @@ declare module 'vscode' { backupNotebook(document: NotebookDocument, context: NotebookDocumentBackupContext, token: CancellationToken): Thenable; } - export interface NotebookDocumentContentOptions { - /** - * Not ready for production or development use yet. - */ - viewOptions?: { - displayName: string; - filenamePattern: (GlobPattern | { include: GlobPattern; exclude: GlobPattern; })[]; - exclusive?: boolean; - }; - } - - export namespace notebook { + export namespace workspace { // TODO@api use NotebookDocumentFilter instead of just notebookType:string? // TODO@API options duplicates the more powerful variant on NotebookContentProvider - export function registerNotebookContentProvider(notebookType: string, provider: NotebookContentProvider, options?: NotebookDocumentContentOptions): Disposable; - } - - //#endregion - - //#region https://github.com/microsoft/vscode/issues/106744, NotebookKernel - - // todo@API make class? - export interface NotebookKernelPreload { - provides?: string | string[]; - uri: Uri; - } - - export interface NotebookCellExecuteStartContext { - /** - * The time that execution began, in milliseconds in the Unix epoch. Used to drive the clock - * that shows for how long a cell has been running. If not given, the clock won't be shown. - */ - startTime?: number; - } - - export interface NotebookCellExecuteEndContext { - /** - * If true, a green check is shown on the cell status bar. - * If false, a red X is shown. - */ - success?: boolean; - - /** - * The time that execution finished, in milliseconds in the Unix epoch. - */ - endTime?: number; - } - - /** - * A NotebookCellExecutionTask is how the kernel modifies a notebook cell as it is executing. When - * [`createNotebookCellExecutionTask`](#notebook.createNotebookCellExecutionTask) is called, the cell - * enters the Pending state. When `start()` is called on the execution task, it enters the Executing state. When - * `end()` is called, it enters the Idle state. While in the Executing state, cell outputs can be - * modified with the methods on the run task. - * - * All outputs methods operate on this NotebookCellExecutionTask's cell by default. They optionally take - * a cellIndex parameter that allows them to modify the outputs of other cells. `appendOutputItems` and - * `replaceOutputItems` operate on the output with the given ID, which can be an output on any cell. They - * all resolve once the output edit has been applied. - */ - export interface NotebookCellExecutionTask { - readonly document: NotebookDocument; - readonly cell: NotebookCell; - - start(context?: NotebookCellExecuteStartContext): void; - executionOrder: number | undefined; - end(result?: NotebookCellExecuteEndContext): void; - readonly token: CancellationToken; - - clearOutput(cellIndex?: number): Thenable; - appendOutput(out: NotebookCellOutput | NotebookCellOutput[], cellIndex?: number): Thenable; - replaceOutput(out: NotebookCellOutput | NotebookCellOutput[], cellIndex?: number): Thenable; - appendOutputItems(items: NotebookCellOutputItem | NotebookCellOutputItem[], outputId: string): Thenable; - replaceOutputItems(items: NotebookCellOutputItem | NotebookCellOutputItem[], outputId: string): Thenable; - } - - export enum NotebookCellExecutionState { - Idle = 1, - Pending = 2, - Executing = 3, - } - - export namespace notebook { - /** @deprecated use NotebookController */ - export function createNotebookCellExecutionTask(uri: Uri, index: number, kernelId: string): NotebookCellExecutionTask | undefined; - - export const onDidChangeCellExecutionState: Event; + export function registerNotebookContentProvider(notebookType: string, provider: NotebookContentProvider, options?: NotebookDocumentContentOptions): Disposable; } //#endregion - //#region https://github.com/microsoft/vscode/issues/106744, NotebookEditorDecorationType - - export interface NotebookEditor { - setDecorations(decorationType: NotebookEditorDecorationType, range: NotebookRange): void; - } - - export interface NotebookDecorationRenderOptions { - backgroundColor?: string | ThemeColor; - borderColor?: string | ThemeColor; - top: ThemableDecorationAttachmentRenderOptions; - } + //#region https://github.com/microsoft/vscode/issues/106744, LiveShare - export interface NotebookEditorDecorationType { - readonly key: string; - dispose(): void; + export interface NotebookRegistrationData { + displayName: string; + filenamePattern: (GlobPattern | { include: GlobPattern; exclude: GlobPattern; })[]; + exclusive?: boolean; } - export namespace notebook { - export function createNotebookEditorDecorationType(options: NotebookDecorationRenderOptions): NotebookEditorDecorationType; + export namespace workspace { + // SPECIAL overload with NotebookRegistrationData + export function registerNotebookContentProvider(notebookType: string, provider: NotebookContentProvider, options?: NotebookDocumentContentOptions, registrationData?: NotebookRegistrationData): Disposable; + // SPECIAL overload with NotebookRegistrationData + export function registerNotebookSerializer(notebookType: string, serializer: NotebookSerializer, options?: NotebookDocumentContentOptions, registration?: NotebookRegistrationData): Disposable; } //#endregion - //#region https://github.com/microsoft/vscode/issues/106744, NotebookCellStatusBarItem - - /** - * Represents the alignment of status bar items. - */ - export enum NotebookCellStatusBarAlignment { + //#region https://github.com/microsoft/vscode/issues/39441 + export interface CompletionItem { /** - * Aligned to the left side. + * Will be merged into CompletionItem#label */ - Left = 1, + label2?: CompletionItemLabel; + } + export interface CompletionItemLabel { /** - * Aligned to the right side. + * The function or variable. Rendered leftmost. */ - Right = 2 - } - - export class NotebookCellStatusBarItem { - text: string; - alignment: NotebookCellStatusBarAlignment; - command?: string | Command; - tooltip?: string; - priority?: number; - accessibilityInformation?: AccessibilityInformation; - - constructor(text: string, alignment: NotebookCellStatusBarAlignment, command?: string | Command, tooltip?: string, priority?: number, accessibilityInformation?: AccessibilityInformation); - } + name: string; - interface NotebookCellStatusBarItemProvider { /** - * Implement and fire this event to signal that statusbar items have changed. The provide method will be called again. + * The parameters without the return type. Render after `name`. */ - onDidChangeCellStatusBarItems?: Event; + parameters?: string; /** - * The provider will be called when the cell scrolls into view, when its content, outputs, language, or metadata change, and when it changes execution state. + * The fully qualified name, like package name or file path. Rendered after `signature`. */ - provideCellStatusBarItems(cell: NotebookCell, token: CancellationToken): ProviderResult; - } + qualifier?: string; - export namespace notebook { - export function registerNotebookCellStatusBarItemProvider(selector: NotebookSelector, provider: NotebookCellStatusBarItemProvider): Disposable; + /** + * The return-type of a function or type of a property/variable. Rendered rightmost. + */ + type?: string; } //#endregion - //#region https://github.com/microsoft/vscode/issues/106744, NotebookConcatTextDocument + //#region @https://github.com/microsoft/vscode/issues/123601, notebook messaging - export namespace notebook { + export interface NotebookRendererMessage { /** - * Create a document that is the concatenation of all notebook cells. By default all code-cells are included - * but a selector can be provided to narrow to down the set of cells. - * - * @param notebook - * @param selector + * Editor that sent the message. */ - // todo@API really needed? we didn't find a user here - export function createConcatTextDocument(notebook: NotebookDocument, selector?: DocumentSelector): NotebookConcatTextDocument; - } + editor: NotebookEditor; - export interface NotebookConcatTextDocument { - readonly uri: Uri; - readonly isClosed: boolean; - dispose(): void; - readonly onDidChange: Event; - readonly version: number; - getText(): string; - getText(range: Range): string; + /** + * Message sent from the webview. + */ + message: T; + } - offsetAt(position: Position): number; - positionAt(offset: number): Position; - validateRange(range: Range): Range; - validatePosition(position: Position): Position; + /** + * Renderer messaging is used to communicate with a single renderer. It's + * returned from {@link notebooks.createRendererMessaging}. + */ + export interface NotebookRendererMessaging { + /** + * Events that fires when a message is received from a renderer. + */ + onDidReceiveMessage: Event>; - locationAt(positionOrRange: Position | Range): Location; - positionAt(location: Location): Position; - contains(uri: Uri): boolean; + /** + * Sends a message to the renderer. + * @param editor Editor to target with the message + * @param message Message to send + */ + postMessage(editor: NotebookEditor, message: TSend): void; } - //#endregion - - //#region https://github.com/microsoft/vscode/issues/39441 + /** + * Represents a script that is loaded into the notebook renderer before rendering output. This allows + * to provide and share functionality for notebook markup and notebook output renderers. + */ + export class NotebookRendererScript { - export interface CompletionItem { /** - * Will be merged into CompletionItem#label + * APIs that the preload provides to the renderer. These are matched + * against the `dependencies` and `optionalDependencies` arrays in the + * notebook renderer contribution point. */ - label2?: CompletionItemLabel; - } + provides: string[]; - export interface CompletionItemLabel { /** - * The function or variable. Rendered leftmost. + * URI for the file to preload */ - name: string; + uri: Uri; /** - * The parameters without the return type. Render after `name`. + * @param uri URI for the file to preload + * @param provides Value for the `provides` property */ - parameters?: string; + constructor(uri: Uri, provides?: string | string[]); + } + + export interface NotebookController { + + // todo@API allow add, not remove + readonly rendererScripts: NotebookRendererScript[]; /** - * The fully qualified name, like package name or file path. Rendered after `signature`. + * An event that fires when a {@link NotebookController.rendererScripts renderer script} has send a message to + * the controller. */ - qualifier?: string; + readonly onDidReceiveMessage: Event<{ editor: NotebookEditor, message: any }>; /** - * The return-type of a function or type of a property/variable. Rendered rightmost. + * Send a message to the renderer of notebook editors. + * + * Note that only editors showing documents that are bound to this controller + * are receiving the message. + * + * @param message The message to send. + * @param editor A specific editor to send the message to. When `undefined` all applicable editors are receiving the message. + * @returns A promise that resolves to a boolean indicating if the message has been send or not. */ - type?: string; + postMessage(message: any, editor?: NotebookEditor): Thenable; + + //todo@API validate this works + asWebviewUri(localResource: Uri): Uri; + } + + export namespace notebooks { + + export function createNotebookController(id: string, viewType: string, label: string, handler?: (cells: NotebookCell[], notebook: NotebookDocument, controller: NotebookController) => void | Thenable, rendererScripts?: NotebookRendererScript[]): NotebookController; + + /** + * Creates a new messaging instance used to communicate with a specific + * renderer. The renderer only has access to messaging if `requiresMessaging` + * is set to `always` or `optional` in its `notebookRenderer ` contribution. + * + * @see https://github.com/microsoft/vscode/issues/123601 + * @param rendererId The renderer ID to communicate with + */ + // todo@API can ANY extension talk to renderer or is there a check that the calling extension + // declared the renderer in its package.json? + export function createRendererMessaging(rendererId: string): NotebookRendererMessaging; } //#endregion @@ -1993,7 +1573,7 @@ declare module 'vscode' { id?: string; /** - * The icon path or [ThemeIcon](#ThemeIcon) for the timeline item. + * The icon path or {@link ThemeIcon} for the timeline item. */ iconPath?: Uri | { light: Uri; dark: Uri; } | ThemeIcon; @@ -2008,7 +1588,7 @@ declare module 'vscode' { detail?: string; /** - * The [command](#Command) that should be executed when the timeline item is selected. + * The {@link Command} that should be executed when the timeline item is selected. */ command?: Command; @@ -2046,7 +1626,7 @@ declare module 'vscode' { export interface TimelineChangeEvent { /** - * The [uri](#Uri) of the resource for which the timeline changed. + * The {@link Uri} of the resource for which the timeline changed. */ uri: Uri; @@ -2066,7 +1646,7 @@ declare module 'vscode' { }; /** - * An array of [timeline items](#TimelineItem). + * An array of {@link TimelineItem timeline items}. */ readonly items: readonly TimelineItem[]; } @@ -2102,12 +1682,12 @@ declare module 'vscode' { readonly label: string; /** - * Provide [timeline items](#TimelineItem) for a [Uri](#Uri). + * Provide {@link TimelineItem timeline items} for a {@link Uri}. * - * @param uri The [uri](#Uri) of the file to provide the timeline for. + * @param uri The {@link Uri} of the file to provide the timeline for. * @param options A set of options to determine how results should be returned. * @param token A cancellation token. - * @return The [timeline result](#TimelineResult) or a thenable that resolves to such. The lack of a result + * @return The {@link TimelineResult timeline result} or a thenable that resolves to such. The lack of a result * can be signaled by returning `undefined`, `null`, or an empty array. */ provideTimeline(uri: Uri, options: TimelineOptions, token: CancellationToken): ProviderResult; @@ -2123,7 +1703,7 @@ declare module 'vscode' { * * @param scheme A scheme or schemes that defines which documents this provider is applicable to. Can be `*` to target all documents. * @param provider A timeline provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ export function registerTimelineProvider(scheme: string | string[], provider: TimelineProvider): Disposable; } @@ -2152,49 +1732,49 @@ declare module 'vscode' { //#region https://github.com/microsoft/vscode/issues/16221 - // todo@API rename to InlayHint + // todo@API Split between Inlay- and OverlayHints (InlayHint are for a position, OverlayHints for a non-empty range) // todo@API add "mini-markdown" for links and styles - // todo@API remove description - // (done:) add InlayHintKind with type, argument, etc + // (done) remove description + // (done) rename to InlayHint + // (done) add InlayHintKind with type, argument, etc export namespace languages { /** - * Register a inline hints provider. + * Register a inlay hints provider. * * Multiple providers can be registered for a language. In that case providers are asked in * parallel and the results are merged. A failing provider (rejected promise or exception) will * not cause a failure of the whole operation. * * @param selector A selector that defines the documents this provider is applicable to. - * @param provider An inline hints provider. - * @return A [disposable](#Disposable) that unregisters this provider when being disposed. + * @param provider An inlay hints provider. + * @return A {@link Disposable} that unregisters this provider when being disposed. */ - export function registerInlineHintsProvider(selector: DocumentSelector, provider: InlineHintsProvider): Disposable; + export function registerInlayHintsProvider(selector: DocumentSelector, provider: InlayHintsProvider): Disposable; } - export enum InlineHintKind { + export enum InlayHintKind { Other = 0, Type = 1, Parameter = 2, } /** - * Inline hint information. + * Inlay hint information. */ - export class InlineHint { + export class InlayHint { /** * The text of the hint. */ text: string; /** - * The range of the hint. + * The position of this hint. */ - range: Range; - - kind?: InlineHintKind; - - // todo@API remove this - description?: string | MarkdownString; + position: Position; + /** + * The kind of this hint. + */ + kind?: InlayHintKind; /** * Whitespace before the hint. */ @@ -2205,29 +1785,29 @@ declare module 'vscode' { whitespaceAfter?: boolean; // todo@API make range first argument - constructor(text: string, range: Range, kind?: InlineHintKind); + constructor(text: string, position: Position, kind?: InlayHintKind); } /** - * The inline hints provider interface defines the contract between extensions and - * the inline hints feature. + * The inlay hints provider interface defines the contract between extensions and + * the inlay hints feature. */ - export interface InlineHintsProvider { + export interface InlayHintsProvider { /** - * An optional event to signal that inline hints have changed. - * @see [EventEmitter](#EventEmitter) + * An optional event to signal that inlay hints have changed. + * @see {@link EventEmitter} */ - onDidChangeInlineHints?: Event; + onDidChangeInlayHints?: Event; /** + * * @param model The document in which the command was invoked. - * @param range The range for which line hints should be computed. + * @param range The range for which inlay hints should be computed. * @param token A cancellation token. - * - * @return A list of arguments labels or a thenable that resolves to such. + * @return A list of inlay hints or a thenable that resolves to such. */ - provideInlineHints(model: TextDocument, range: Range, token: CancellationToken): ProviderResult; + provideInlayHints(model: TextDocument, range: Range, token: CancellationToken): ProviderResult; } //#endregion @@ -2255,7 +1835,7 @@ declare module 'vscode' { export interface TextDocument { /** - * The [notebook](#NotebookDocument) that contains this document as a notebook cell or `undefined` when + * The {@link NotebookDocument notebook} that contains this document as a notebook cell or `undefined` when * the document is not contained by a notebook (this should be the more frequent case). */ notebook: NotebookDocument | undefined; @@ -2540,7 +2120,7 @@ declare module 'vscode' { /** * URI this TestItem is associated with. May be a file or directory. */ - uri: Uri; + uri?: Uri; /** * Display name describing the test item. @@ -2563,7 +2143,7 @@ declare module 'vscode' { /** * URI this TestItem is associated with. May be a file or directory. */ - readonly uri: Uri; + readonly uri?: Uri; /** * A mapping of children by ID to the associated TestItem instances. @@ -2795,7 +2375,7 @@ declare module 'vscode' { /** * URI this TestItem is associated with. May be a file or file. */ - readonly uri: Uri; + readonly uri?: Uri; /** * Display name describing the test case. @@ -3004,12 +2584,76 @@ declare module 'vscode' { //#endregion + //#region @joaomoreno https://github.com/microsoft/vscode/issues/124263 + // This API change only affects behavior and documentation, not API surface. + + namespace env { + + /** + * Resolves a uri to form that is accessible externally. + * + * #### `http:` or `https:` scheme + * + * Resolves an *external* uri, such as a `http:` or `https:` link, from where the extension is running to a + * uri to the same resource on the client machine. + * + * This is a no-op if the extension is running on the client machine. + * + * If the extension is running remotely, this function automatically establishes a port forwarding tunnel + * from the local machine to `target` on the remote and returns a local uri to the tunnel. The lifetime of + * the port forwarding tunnel is managed by VS Code and the tunnel can be closed by the user. + * + * *Note* that uris passed through `openExternal` are automatically resolved and you should not call `asExternalUri` on them. + * + * #### `vscode.env.uriScheme` + * + * Creates a uri that - if opened in a browser (e.g. via `openExternal`) - will result in a registered {@link UriHandler} + * to trigger. + * + * Extensions should not make any assumptions about the resulting uri and should not alter it in anyway. + * Rather, extensions can e.g. use this uri in an authentication flow, by adding the uri as callback query + * argument to the server to authenticate to. + * + * *Note* that if the server decides to add additional query parameters to the uri (e.g. a token or secret), it + * will appear in the uri that is passed to the {@link UriHandler}. + * + * **Example** of an authentication flow: + * ```typescript + * vscode.window.registerUriHandler({ + * handleUri(uri: vscode.Uri): vscode.ProviderResult { + * if (uri.path === '/did-authenticate') { + * console.log(uri.toString()); + * } + * } + * }); + * + * const callableUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://my.extension/did-authenticate`)); + * await vscode.env.openExternal(callableUri); + * ``` + * + * *Note* that extensions should not cache the result of `asExternalUri` as the resolved uri may become invalid due to + * a system or user action — for example, in remote cases, a user may close a port forwarding tunnel that was opened by + * `asExternalUri`. + * + * #### Any other scheme + * + * Any other scheme will be handled as if the provided URI is a workspace URI. In that case, the method will return + * a URI which, when handled, will make VS Code open the workspace. + * + * @return A uri that can be used on the client machine. + */ + export function asExternalUri(target: Uri): Thenable; + } + + //#endregion + //#region https://github.com/Microsoft/vscode/issues/15178 // TODO@API must be a class export interface OpenEditorInfo { name: string; resource: Uri; + isActive: boolean; } export namespace window { @@ -3027,47 +2671,24 @@ declare module 'vscode' { */ export interface WorkspaceTrustRequestOptions { /** - * When true, a modal dialog will be used to request workspace trust. - * When false, a badge will be displayed on the settings gear activity bar item. + * Custom message describing the user action that requires workspace + * trust. If omitted, a generic message will be displayed in the workspace + * trust request dialog. */ - readonly modal: boolean; + readonly message?: string; } export namespace workspace { /** * Prompt the user to chose whether to trust the current workspace * @param options Optional object describing the properties of the - * workspace trust request. Defaults to { modal: false } - * When using a non-modal request, the promise will return immediately. - * Any time trust is not given, it is recommended to use the - * `onDidGrantWorkspaceTrust` event to listen for trust changes. + * workspace trust request. */ export function requestWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Thenable; } //#endregion - //#region https://github.com/microsoft/vscode/issues/115807 - - export interface Webview { - /** - * @param message A json serializable message to send to the webview. - * - * For older versions of vscode, if an `ArrayBuffer` is included in `message`, - * it will not be serialized properly and will not be received by the webview. - * Similarly any TypedArrays, such as a `Uint8Array`, will be very inefficiently - * serialized and will also not be recreated as a typed array inside the webview. - * - * However if your extension targets vscode 1.56+ in the `engines` field of its - * `package.json` any `ArrayBuffer` values that appear in `message` will be more - * efficiently transferred to the webview and will also be recreated inside of - * the webview. - */ - postMessage(message: any): Thenable; - } - - //#endregion - //#region https://github.com/microsoft/vscode/issues/115616 @alexr00 export enum PortAutoForwardAction { Notify = 1, @@ -3077,9 +2698,23 @@ declare module 'vscode' { Ignore = 5 } - export interface PortAttributes { + export class PortAttributes { + /** + * The port number associated with this this set of attributes. + */ port: number; - autoForwardAction: PortAutoForwardAction + + /** + * The action to be taken when this port is detected for auto forwarding. + */ + autoForwardAction: PortAutoForwardAction; + + /** + * Creates a new PortAttributes object + * @param port the port number + * @param autoForwardAction the action to take when this port is detected + */ + constructor(port: number, autoForwardAction: PortAutoForwardAction); } export interface PortAttributesProvider { @@ -3108,7 +2743,7 @@ declare module 'vscode' { } //#endregion - // region https://github.com/microsoft/vscode/issues/119904 @eamodio + //#region https://github.com/microsoft/vscode/issues/119904 @eamodio export interface SourceControlInputBox { @@ -3119,4 +2754,148 @@ declare module 'vscode' { } //#endregion + + //#region https://github.com/microsoft/vscode/issues/124024 @hediet @alexdima + + export namespace languages { + /** + * Registers an inline completion provider. + */ + export function registerInlineCompletionItemProvider(selector: DocumentSelector, provider: InlineCompletionItemProvider): Disposable; + } + + export interface InlineCompletionItemProvider { + /** + * Provides inline completion items for the given position and document. + * If inline completions are enabled, this method will be called whenever the user stopped typing. + * It will also be called when the user explicitly triggers inline completions or asks for the next or previous inline completion. + * Use `context.triggerKind` to distinguish between these scenarios. + */ + provideInlineCompletionItems(document: TextDocument, position: Position, context: InlineCompletionContext, token: CancellationToken): ProviderResult | T[]>; + } + + export interface InlineCompletionContext { + /** + * How the completion was triggered. + */ + readonly triggerKind: InlineCompletionTriggerKind; + } + + /** + * How an {@link InlineCompletionItemProvider inline completion provider} was triggered. + */ + export enum InlineCompletionTriggerKind { + /** + * Completion was triggered automatically while editing. + * It is sufficient to return a single completion item in this case. + */ + Automatic = 0, + + /** + * Completion was triggered explicitly by a user gesture. + * Return multiple completion items to enable cycling through them. + */ + Explicit = 1, + } + + export class InlineCompletionList { + items: T[]; + + constructor(items: T[]); + } + + export class InlineCompletionItem { + /** + * The text to insert. + * If the text contains a line break, the range must end at the end of a line. + * If existing text should be replaced, the existing text must be a prefix of the text to insert. + */ + text: string; + + /** + * The range to replace. + * Must begin and end on the same line. + * + * Prefer replacements over insertions to avoid cache invalidation. + * Instead of reporting a completion that extends a word, + * the whole word should be replaced with the extended word. + */ + range?: Range; + + /** + * An optional {@link Command} that is executed *after* inserting this completion. + */ + command?: Command; + + constructor(text: string, range?: Range, command?: Command); + } + + + /** + * Be aware that this API will not ever be finalized. + */ + export namespace window { + export function getInlineCompletionItemController(provider: InlineCompletionItemProvider): InlineCompletionController; + } + + /** + * Be aware that this API will not ever be finalized. + */ + export interface InlineCompletionController { + /** + * Is fired when an inline completion item is shown to the user. + */ + // eslint-disable-next-line vscode-dts-event-naming + readonly onDidShowCompletionItem: Event>; + } + + /** + * Be aware that this API will not ever be finalized. + */ + export interface InlineCompletionItemDidShowEvent { + completionItem: T; + } + + //#endregion + + //#region FileSystemProvider stat readonly - https://github.com/microsoft/vscode/issues/73122 + + export enum FilePermission { + /** + * The file is readonly. + * + * *Note:* All `FileStat` from a `FileSystemProvider` that is registered with + * the option `isReadonly: true` will be implicitly handled as if `FilePermission.Readonly` + * is set. As a consequence, it is not possible to have a readonly file system provider + * registered where some `FileStat` are not readonly. + */ + Readonly = 1 + } + + /** + * The `FileStat`-type represents metadata about a file + */ + export interface FileStat { + + /** + * The permissions of the file, e.g. whether the file is readonly. + * + * *Note:* This value might be a bitmask, e.g. `FilePermission.Readonly | FilePermission.Other`. + */ + permissions?: FilePermission; + } + + //#endregion + + //#region https://github.com/microsoft/vscode/issues/87110 @eamodio + + export interface Memento { + + /** + * The stored keys. + */ + readonly keys: readonly string[]; + } + + //#endregion } diff --git a/lib/vscode/src/vs/workbench/api/browser/apiCommands.ts b/src/vs/workbench/api/browser/apiCommands.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/apiCommands.ts rename to src/vs/workbench/api/browser/apiCommands.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/extensionHost.contribution.ts b/src/vs/workbench/api/browser/extensionHost.contribution.ts similarity index 99% rename from lib/vscode/src/vs/workbench/api/browser/extensionHost.contribution.ts rename to src/vs/workbench/api/browser/extensionHost.contribution.ts index 524697c3426b..427e98ba553e 100644 --- a/lib/vscode/src/vs/workbench/api/browser/extensionHost.contribution.ts +++ b/src/vs/workbench/api/browser/extensionHost.contribution.ts @@ -65,6 +65,7 @@ import './mainThreadComments'; import './mainThreadNotebook'; import './mainThreadNotebookKernels'; import './mainThreadNotebookDocumentsAndEditors'; +import './mainThreadNotebookRenderers'; import './mainThreadTask'; import './mainThreadLabelService'; import './mainThreadTunnelService'; diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadAuthentication.ts b/src/vs/workbench/api/browser/mainThreadAuthentication.ts similarity index 98% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadAuthentication.ts rename to src/vs/workbench/api/browser/mainThreadAuthentication.ts index f2cc04cd7268..19e704dff861 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadAuthentication.ts +++ b/src/vs/workbench/api/browser/mainThreadAuthentication.ts @@ -40,6 +40,8 @@ export class MainThreadAuthenticationProvider extends Disposable { const quickPick = this.quickInputService.createQuickPick<{ label: string, description: string, extension: AllowedExtension }>(); quickPick.canSelectMany = true; + quickPick.customButton = true; + quickPick.customLabel = nls.localize('manageTrustedExtensions.cancel', 'Cancel'); const usages = readAccountUsages(this.storageService, this.id, accountName); const items = allowedExtensions.map(extension => { const usage = usages.find(usage => extension.id === usage.extensionId); @@ -68,6 +70,10 @@ export class MainThreadAuthenticationProvider extends Disposable { quickPick.dispose(); }); + quickPick.onDidCustom(() => { + quickPick.hide(); + }); + quickPick.show(); } diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadBulkEdits.ts b/src/vs/workbench/api/browser/mainThreadBulkEdits.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadBulkEdits.ts rename to src/vs/workbench/api/browser/mainThreadBulkEdits.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadCLICommands.ts b/src/vs/workbench/api/browser/mainThreadCLICommands.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadCLICommands.ts rename to src/vs/workbench/api/browser/mainThreadCLICommands.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadClipboard.ts b/src/vs/workbench/api/browser/mainThreadClipboard.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadClipboard.ts rename to src/vs/workbench/api/browser/mainThreadClipboard.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadCodeInsets.ts b/src/vs/workbench/api/browser/mainThreadCodeInsets.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadCodeInsets.ts rename to src/vs/workbench/api/browser/mainThreadCodeInsets.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadCommands.ts b/src/vs/workbench/api/browser/mainThreadCommands.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadCommands.ts rename to src/vs/workbench/api/browser/mainThreadCommands.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadComments.ts b/src/vs/workbench/api/browser/mainThreadComments.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadComments.ts rename to src/vs/workbench/api/browser/mainThreadComments.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadConfiguration.ts b/src/vs/workbench/api/browser/mainThreadConfiguration.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadConfiguration.ts rename to src/vs/workbench/api/browser/mainThreadConfiguration.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadConsole.ts b/src/vs/workbench/api/browser/mainThreadConsole.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadConsole.ts rename to src/vs/workbench/api/browser/mainThreadConsole.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadCustomEditors.ts b/src/vs/workbench/api/browser/mainThreadCustomEditors.ts similarity index 86% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadCustomEditors.ts rename to src/vs/workbench/api/browser/mainThreadCustomEditors.ts index 00e0592719eb..413c53b81553 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadCustomEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadCustomEditors.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { multibyteAwareBtoa } from 'vs/base/browser/dom'; -import { CancelablePromise, createCancelablePromise, timeout } from 'vs/base/common/async'; +import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; import { VSBuffer } from 'vs/base/common/buffer'; import { CancellationToken } from 'vs/base/common/cancellation'; import { isPromiseCanceledError, onUnexpectedError } from 'vs/base/common/errors'; @@ -16,7 +16,7 @@ import { isEqual, isEqualOrParent, toLocalResource } from 'vs/base/common/resour import { URI, UriComponents } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { FileChangesEvent, FileChangeType, FileSystemProviderCapabilities, IFileService } from 'vs/platform/files/common/files'; +import { FileOperation, IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILabelService } from 'vs/platform/label/common/label'; import { IUndoRedoService, UndoRedoElementType } from 'vs/platform/undoRedo/common/undoRedo'; @@ -35,9 +35,10 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; -import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService'; +import { IWorkingCopyFileService, WorkingCopyFileEvent } from 'vs/workbench/services/workingCopy/common/workingCopyFileService'; import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { IWorkingCopy, IWorkingCopyBackup, NO_TYPE_ID, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopy'; +import { ResourceWorkingCopy } from 'vs/workbench/services/workingCopy/common/resourceWorkingCopy'; const enum CustomEditorModelType { Custom, @@ -50,6 +51,8 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc private readonly _editorProviders = new Map(); + private readonly _editorRenameBackups = new Map(); + constructor( context: extHostProtocol.IExtHostContext, private readonly mainThreadWebview: MainThreadWebviews, @@ -60,7 +63,7 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc @ICustomEditorService private readonly _customEditorService: ICustomEditorService, @IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService, @IWebviewWorkbenchService private readonly _webviewWorkbenchService: IWebviewWorkbenchService, - @IInstantiationService private readonly _instantiationService: IInstantiationService + @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { super(); @@ -89,6 +92,9 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc }, resolveWebview: () => { throw new Error('not implemented'); } })); + + // Working copy operations + this._register(workingCopyFileService.onWillRunWorkingCopyFileOperation(async e => this.onWillRunWorkingCopyFileOperation(e))); } override dispose() { @@ -137,9 +143,18 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc webviewInput.webview.options = options; webviewInput.webview.extension = extension; + // If there's an old resource this was a move and we must resolve the backup at the same time as the webview + // This is because the backup must be ready upon model creation, and the input resolve method comes after + let backupId = webviewInput.backupId; + if (webviewInput.oldResource && !webviewInput.backupId) { + const backup = this._editorRenameBackups.get(webviewInput.oldResource.toString()); + backupId = backup?.backupId; + this._editorRenameBackups.delete(webviewInput.oldResource.toString()); + } + let modelRef: IReference; try { - modelRef = await this.getOrCreateCustomEditorModel(modelType, resource, viewType, { backupId: webviewInput.backupId }, cancellation); + modelRef = await this.getOrCreateCustomEditorModel(modelType, resource, viewType, { backupId }, cancellation); } catch (error) { onUnexpectedError(error); webviewInput.webview.html = this.mainThreadWebview.getWebviewResolvedFailedContent(viewType); @@ -252,6 +267,31 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc } return model; } + + //#region Working Copy + private async onWillRunWorkingCopyFileOperation(e: WorkingCopyFileEvent) { + if (e.operation !== FileOperation.MOVE) { + return; + } + e.waitUntil((async () => { + const models = []; + for (const file of e.files) { + if (file.source) { + models.push(...(await this._customEditorService.models.getAllModels(file.source))); + } + } + for (const model of models) { + if (model instanceof MainThreadCustomEditorModel && model.isDirty()) { + const workingCopy = await model.backup(CancellationToken.None); + if (workingCopy.meta) { + // This cast is safe because we do an instanceof check above and a custom document backup data is always returned + this._editorRenameBackups.set(model.editorResource.toString(), workingCopy.meta as CustomDocumentBackupData); + } + } + } + })()); + } + //#endregion } namespace HotExitState { @@ -276,9 +316,7 @@ namespace HotExitState { } -class MainThreadCustomEditorModel extends Disposable implements ICustomEditorModel, IWorkingCopy { - - #isDisposed = false; +class MainThreadCustomEditorModel extends ResourceWorkingCopy implements ICustomEditorModel { private _fromBackup: boolean = false; private _hotExitState: HotExitState.State = HotExitState.Allowed; @@ -288,13 +326,9 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod private _savePoint: number = -1; private readonly _edits: Array = []; private _isDirtyFromContentChange = false; - private _inOrphaned = false; private _ongoingSave?: CancelablePromise; - private readonly _onDidChangeOrphaned = this._register(new Emitter()); - public readonly onDidChangeOrphaned = this._onDidChangeOrphaned.event; - // TODO@mjbvz consider to enable a `typeId` that is specific for custom // editors. Using a distinct `typeId` allows the working copy to have // any resource (including file based resources) even if other working @@ -322,7 +356,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod untitledDocumentData = editors[0].untitledDocumentData; } const { editable } = await proxy.$createCustomDocument(resource, viewType, options.backupId, untitledDocumentData, cancellation); - return instantiationService.createInstance(MainThreadCustomEditorModel, proxy, viewType, resource, !!options.backupId, editable, getEditors); + return instantiationService.createInstance(MainThreadCustomEditorModel, proxy, viewType, resource, !!options.backupId, editable, !!untitledDocumentData, getEditors); } constructor( @@ -331,16 +365,17 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod private readonly _editorResource: URI, fromBackup: boolean, private readonly _editable: boolean, + startDirty: boolean, private readonly _getEditors: () => CustomEditorInput[], @IFileDialogService private readonly _fileDialogService: IFileDialogService, - @IFileService private readonly _fileService: IFileService, + @IFileService fileService: IFileService, @ILabelService private readonly _labelService: ILabelService, @IUndoRedoService private readonly _undoService: IUndoRedoService, @IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService, @IWorkingCopyService workingCopyService: IWorkingCopyService, - @IPathService private readonly _pathService: IPathService + @IPathService private readonly _pathService: IPathService, ) { - super(); + super(MainThreadCustomEditorModel.toWorkingCopyResource(_viewType, _editorResource), fileService); this._fromBackup = fromBackup; @@ -348,7 +383,10 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod this._register(workingCopyService.registerWorkingCopy(this)); } - this._register(_fileService.onDidFilesChange(e => this.onDidFilesChange(e))); + // Normally means we're re-opening an untitled file + if (startDirty) { + this._isDirtyFromContentChange = true; + } } get editorResource() { @@ -356,8 +394,6 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod } override dispose() { - this.#isDisposed = true; - if (this._editable) { this._undoService.removeElements(this._editorResource); } @@ -369,11 +405,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod //#region IWorkingCopy - public get resource() { - // Make sure each custom editor has a unique resource for backup and edits - return MainThreadCustomEditorModel.toWorkingCopyResource(this._viewType, this._editorResource); - } - + // Make sure each custom editor has a unique resource for backup and edits private static toWorkingCopyResource(viewType: string, resource: URI) { const authority = viewType.replace(/[^a-z0-9\-_]/gi, '-'); const path = `/${multibyteAwareBtoa(resource.with({ query: null, fragment: null }).toString(true))}`; @@ -403,10 +435,6 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod return this._fromBackup; } - public isOrphaned(): boolean { - return this._inOrphaned; - } - private isUntitled() { return this._editorResource.scheme === Schemas.untitled; } @@ -417,66 +445,12 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod private readonly _onDidChangeContent: Emitter = this._register(new Emitter()); readonly onDidChangeContent: Event = this._onDidChangeContent.event; - //#endregion - - private async onDidFilesChange(e: FileChangesEvent): Promise { - let fileEventImpactsModel = false; - let newInOrphanModeGuess: boolean | undefined; - - // If we are currently orphaned, we check if the model file was added back - if (this._inOrphaned) { - const modelFileAdded = e.contains(this.editorResource, FileChangeType.ADDED); - if (modelFileAdded) { - newInOrphanModeGuess = false; - fileEventImpactsModel = true; - } - } - - // Otherwise we check if the model file was deleted - else { - const modelFileDeleted = e.contains(this.editorResource, FileChangeType.DELETED); - if (modelFileDeleted) { - newInOrphanModeGuess = true; - fileEventImpactsModel = true; - } - } - - if (fileEventImpactsModel && this._inOrphaned !== newInOrphanModeGuess) { - let newInOrphanModeValidated: boolean = false; - if (newInOrphanModeGuess) { - // We have received reports of users seeing delete events even though the file still - // exists (network shares issue: https://github.com/microsoft/vscode/issues/13665). - // Since we do not want to mark the model as orphaned, we have to check if the - // file is really gone and not just a faulty file event. - await timeout(100); - - if (this.#isDisposed) { - newInOrphanModeValidated = true; - } else { - const exists = await this._fileService.exists(this.editorResource); - newInOrphanModeValidated = !exists; - } - } + readonly onDidChangeReadonly = Event.None; - if (this._inOrphaned !== newInOrphanModeValidated && !this.#isDisposed) { - this.setOrphaned(newInOrphanModeValidated); - } - } - } - - private setOrphaned(orphaned: boolean): void { - if (this._inOrphaned !== orphaned) { - this._inOrphaned = orphaned; - this._onDidChangeOrphaned.fire(); - } - } - - public isEditable(): boolean { - return this._editable; - } + //#endregion - public isOnReadonlyFileSystem(): boolean { - return this._fileService.hasCapability(this.editorResource, FileSystemProviderCapabilities.Readonly); + public isReadonly(): boolean { + return !this._editable; } public get viewType() { @@ -569,7 +543,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod } } - public async revert(_options?: IRevertOptions) { + public async revert(options?: IRevertOptions) { if (!this._editable) { return; } @@ -578,7 +552,10 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod return; } - this._proxy.$revert(this._editorResource, this.viewType, CancellationToken.None); + if (!options?.soft) { + this._proxy.$revert(this._editorResource, this.viewType, CancellationToken.None); + } + this.change(() => { this._isDirtyFromContentChange = false; this._fromBackup = false; @@ -650,7 +627,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod return true; } else { // Since the editor is readonly, just copy the file over - await this._fileService.copy(resource, targetResource, false /* overwrite */); + await this.fileService.copy(resource, targetResource, false /* overwrite */); return true; } } @@ -698,6 +675,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod pendingState.operation.cancel(); }); + let errorMessage = ''; try { const backupId = await pendingState.operation; // Make sure state has not changed in the meantime @@ -716,12 +694,15 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod if (this._hotExitState === pendingState) { this._hotExitState = HotExitState.NotAllowed; } + if (e.message) { + errorMessage = e.message; + } } if (this._hotExitState === HotExitState.Allowed) { return backupData; } - throw new Error('Cannot back up in this state'); + throw new Error(`Cannot back up in this state: ${errorMessage}`); } } diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadDebugService.ts b/src/vs/workbench/api/browser/mainThreadDebugService.ts similarity index 99% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadDebugService.ts rename to src/vs/workbench/api/browser/mainThreadDebugService.ts index 287bcd08305e..60c3a74c0170 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/browser/mainThreadDebugService.ts @@ -329,7 +329,8 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb type: session.configuration.type, name: session.name, folderUri: session.root ? session.root.uri : undefined, - configuration: session.configuration + configuration: session.configuration, + parent: session.parentSession?.getId(), }; } } diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadDecorations.ts b/src/vs/workbench/api/browser/mainThreadDecorations.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadDecorations.ts rename to src/vs/workbench/api/browser/mainThreadDecorations.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadDiagnostics.ts b/src/vs/workbench/api/browser/mainThreadDiagnostics.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadDiagnostics.ts rename to src/vs/workbench/api/browser/mainThreadDiagnostics.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadDialogs.ts b/src/vs/workbench/api/browser/mainThreadDialogs.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadDialogs.ts rename to src/vs/workbench/api/browser/mainThreadDialogs.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadDocumentContentProviders.ts b/src/vs/workbench/api/browser/mainThreadDocumentContentProviders.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadDocumentContentProviders.ts rename to src/vs/workbench/api/browser/mainThreadDocumentContentProviders.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadDocuments.ts b/src/vs/workbench/api/browser/mainThreadDocuments.ts similarity index 79% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadDocuments.ts rename to src/vs/workbench/api/browser/mainThreadDocuments.ts index 5b0102492cae..f49040e3ad1b 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadDocuments.ts +++ b/src/vs/workbench/api/browser/mainThreadDocuments.ts @@ -20,6 +20,7 @@ import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/commo import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; import { Emitter } from 'vs/base/common/event'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; +import { ResourceMap } from 'vs/base/common/map'; export class BoundModelReferenceCollection { @@ -105,52 +106,39 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen private _onIsCaughtUpWithContentChanges = this._register(new Emitter()); public readonly onIsCaughtUpWithContentChanges = this._onIsCaughtUpWithContentChanges.event; - private readonly _modelService: IModelService; - private readonly _textModelResolverService: ITextModelService; - private readonly _textFileService: ITextFileService; - private readonly _fileService: IFileService; - private readonly _environmentService: IWorkbenchEnvironmentService; - private readonly _uriIdentityService: IUriIdentityService; - - private _modelTrackers: { [modelUrl: string]: ModelTracker; }; private readonly _proxy: ExtHostDocumentsShape; - private readonly _modelIsSynced = new Set(); + private readonly _modelTrackers = new ResourceMap(); + private readonly _modelIsSynced = new ResourceMap(); private readonly _modelReferenceCollection: BoundModelReferenceCollection; constructor( documentsAndEditors: MainThreadDocumentsAndEditors, extHostContext: IExtHostContext, - @IModelService modelService: IModelService, - @ITextFileService textFileService: ITextFileService, - @IFileService fileService: IFileService, - @ITextModelService textModelResolverService: ITextModelService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @IUriIdentityService uriIdentityService: IUriIdentityService, + @IModelService private readonly _modelService: IModelService, + @ITextFileService private readonly _textFileService: ITextFileService, + @IFileService private readonly _fileService: IFileService, + @ITextModelService private readonly _textModelResolverService: ITextModelService, + @IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService, + @IUriIdentityService private readonly _uriIdentityService: IUriIdentityService, @IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService, @IPathService private readonly _pathService: IPathService ) { super(); - this._modelService = modelService; - this._textModelResolverService = textModelResolverService; - this._textFileService = textFileService; - this._fileService = fileService; - this._environmentService = environmentService; - this._uriIdentityService = uriIdentityService; - this._modelReferenceCollection = this._register(new BoundModelReferenceCollection(uriIdentityService.extUri)); + this._modelReferenceCollection = this._register(new BoundModelReferenceCollection(_uriIdentityService.extUri)); this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocuments); this._register(documentsAndEditors.onDocumentAdd(models => models.forEach(this._onModelAdded, this))); this._register(documentsAndEditors.onDocumentRemove(urls => urls.forEach(this._onModelRemoved, this))); - this._register(modelService.onModelModeChanged(this._onModelModeChanged, this)); + this._register(_modelService.onModelModeChanged(this._onModelModeChanged, this)); - this._register(textFileService.files.onDidSave(e => { + this._register(_textFileService.files.onDidSave(e => { if (this._shouldHandleFileEvent(e.model.resource)) { this._proxy.$acceptModelSaved(e.model.resource); } })); - this._register(textFileService.files.onDidChangeDirty(m => { + this._register(_textFileService.files.onDidChangeDirty(m => { if (this._shouldHandleFileEvent(m.resource)) { this._proxy.$acceptDirtyStateChanged(m.resource, m.isDirty()); } @@ -167,22 +155,18 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen } } })); - - this._modelTrackers = Object.create(null); } public override dispose(): void { - Object.keys(this._modelTrackers).forEach((modelUrl) => { - this._modelTrackers[modelUrl].dispose(); - }); - this._modelTrackers = Object.create(null); + dispose(this._modelTrackers.values()); + this._modelTrackers.clear(); super.dispose(); } public isCaughtUpWithContentChanges(resource: URI): boolean { - const modelUrl = resource.toString(); - if (this._modelTrackers[modelUrl]) { - return this._modelTrackers[modelUrl].isCaughtUpWithContentChanges(); + const tracker = this._modelTrackers.get(resource); + if (tracker) { + return tracker.isCaughtUpWithContentChanges(); } return true; } @@ -198,28 +182,25 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen // don't synchronize too large models return; } - const modelUrl = model.uri; - this._modelIsSynced.add(modelUrl.toString()); - this._modelTrackers[modelUrl.toString()] = new ModelTracker(model, this._onIsCaughtUpWithContentChanges, this._proxy, this._textFileService); + this._modelIsSynced.set(model.uri, undefined); + this._modelTrackers.set(model.uri, new ModelTracker(model, this._onIsCaughtUpWithContentChanges, this._proxy, this._textFileService)); } private _onModelModeChanged(event: { model: ITextModel; oldModeId: string; }): void { let { model } = event; - const modelUrl = model.uri; - if (!this._modelIsSynced.has(modelUrl.toString())) { + if (!this._modelIsSynced.has(model.uri)) { return; } this._proxy.$acceptModelModeChanged(model.uri, model.getLanguageIdentifier().language); } private _onModelRemoved(modelUrl: URI): void { - const strModelUrl = modelUrl.toString(); - if (!this._modelIsSynced.has(strModelUrl)) { + if (!this._modelIsSynced.has(modelUrl)) { return; } - this._modelIsSynced.delete(strModelUrl); - this._modelTrackers[strModelUrl].dispose(); - delete this._modelTrackers[strModelUrl]; + this._modelIsSynced.delete(modelUrl); + this._modelTrackers.get(modelUrl)!.dispose(); + this._modelTrackers.delete(modelUrl); } // --- from extension host process @@ -252,7 +233,7 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen return Promise.reject(new Error(`cannot open ${canonicalUri.toString()}`)); } else if (!extUri.isEqual(documentUri, canonicalUri)) { return Promise.reject(new Error(`cannot open ${canonicalUri.toString()}. Detail: Actual document opened as ${documentUri.toString()}`)); - } else if (!this._modelIsSynced.has(canonicalUri.toString())) { + } else if (!this._modelIsSynced.has(canonicalUri)) { return Promise.reject(new Error(`cannot open ${canonicalUri.toString()}. Detail: Files above 50MB cannot be synchronized with extensions.`)); } else { return canonicalUri; @@ -291,7 +272,7 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen }).then(model => { const resource = model.resource; - if (!this._modelIsSynced.has(resource.toString())) { + if (!this._modelIsSynced.has(resource)) { throw new Error(`expected URI ${resource.toString()} to have come to LIFE`); } diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts b/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts rename to src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadDownloadService.ts b/src/vs/workbench/api/browser/mainThreadDownloadService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadDownloadService.ts rename to src/vs/workbench/api/browser/mainThreadDownloadService.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadEditor.ts b/src/vs/workbench/api/browser/mainThreadEditor.ts similarity index 99% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadEditor.ts rename to src/vs/workbench/api/browser/mainThreadEditor.ts index 23f062a36bc0..813c5cb92d5c 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadEditor.ts +++ b/src/vs/workbench/api/browser/mainThreadEditor.ts @@ -414,7 +414,7 @@ export class MainThreadTextEditor { if (!this._codeEditor) { return; } - this._codeEditor.setDecorations(key, ranges); + this._codeEditor.setDecorations('exthost-api', key, ranges); } public setDecorationsFast(key: string, _ranges: number[]): void { diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadEditorTabs.ts b/src/vs/workbench/api/browser/mainThreadEditorTabs.ts similarity index 81% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadEditorTabs.ts rename to src/vs/workbench/api/browser/mainThreadEditorTabs.ts index 2e6aaffa5e46..c9d970717d5d 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadEditorTabs.ts +++ b/src/vs/workbench/api/browser/mainThreadEditorTabs.ts @@ -7,8 +7,9 @@ import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle' import { URI } from 'vs/base/common/uri'; import { ExtHostContext, IExtHostEditorTabsShape, IExtHostContext, MainContext, IEditorTabDto } from 'vs/workbench/api/common/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; -import { Verbosity } from 'vs/workbench/common/editor'; +import { EditorResourceAccessor, Verbosity } from 'vs/workbench/common/editor'; import { GroupChangeKind, IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; export interface ITabInfo { name: string; @@ -27,11 +28,12 @@ export class MainThreadEditorTabs { constructor( extHostContext: IExtHostContext, @IEditorGroupsService private readonly _editorGroupsService: IEditorGroupsService, + @IEditorService editorService: IEditorService ) { this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostEditorTabs); - this._editorGroupsService.groups.forEach(this._subscribeToGroup, this); + this._editorGroupsService.whenReady.then(() => this._editorGroupsService.groups.forEach(this._subscribeToGroup, this)); this._dispoables.add(_editorGroupsService.onDidAddGroup(this._subscribeToGroup, this)); this._dispoables.add(_editorGroupsService.onDidRemoveGroup(e => { const subscription = this._groups.get(e); @@ -41,6 +43,7 @@ export class MainThreadEditorTabs { this._pushEditorTabs(); } })); + this._dispoables.add(editorService.onDidActiveEditorChange(this._pushEditorTabs, this)); this._pushEditorTabs(); } @@ -69,7 +72,8 @@ export class MainThreadEditorTabs { tabs.push({ group: group.id, name: editor.getTitle(Verbosity.SHORT) ?? '', - resource: editor.resource + resource: EditorResourceAccessor.getOriginalUri(editor) ?? editor.resource, + isActive: (this._editorGroupsService.activeGroup === group) && group.isActive(editor) }); } } diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadEditors.ts b/src/vs/workbench/api/browser/mainThreadEditors.ts similarity index 97% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadEditors.ts rename to src/vs/workbench/api/browser/mainThreadEditors.ts index 5587adddb267..c18de551a26d 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadEditors.ts @@ -26,6 +26,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { revive } from 'vs/base/common/marshalling'; import { ResourceNotebookCellEdit } from 'vs/workbench/contrib/bulkEdit/browser/bulkCellEdits'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; export function reviveWorkspaceEditDto2(data: IWorkspaceEditDto | undefined): ResourceEdit[] { if (!data?.edits) { @@ -249,10 +250,10 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { return Promise.resolve(editor.insertSnippet(template, ranges, opts)); } - $registerTextEditorDecorationType(key: string, options: IDecorationRenderOptions): void { + $registerTextEditorDecorationType(extensionId: ExtensionIdentifier, key: string, options: IDecorationRenderOptions): void { key = `${this._instanceId}-${key}`; this._registeredDecorationTypes[key] = true; - this._codeEditorService.registerDecorationType(key, options); + this._codeEditorService.registerDecorationType(`exthost-api-${extensionId}`, key, options); } $removeTextEditorDecorationType(key: string): void { diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadErrors.ts b/src/vs/workbench/api/browser/mainThreadErrors.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadErrors.ts rename to src/vs/workbench/api/browser/mainThreadErrors.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadExtensionService.ts b/src/vs/workbench/api/browser/mainThreadExtensionService.ts similarity index 77% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadExtensionService.ts rename to src/vs/workbench/api/browser/mainThreadExtensionService.ts index 1a5a495c68eb..a3ab550d7eb9 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadExtensionService.ts +++ b/src/vs/workbench/api/browser/mainThreadExtensionService.ts @@ -21,6 +21,7 @@ import { ILocalExtension } from 'vs/platform/extensionManagement/common/extensio import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator'; import { ITimerService } from 'vs/workbench/services/timer/browser/timerService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { ICommandService } from 'vs/platform/commands/common/commands'; @extHostNamedCustomer(MainContext.MainThreadExtensionService) export class MainThreadExtensionService implements MainThreadExtensionServiceShape { @@ -35,6 +36,7 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha @IHostService private readonly _hostService: IHostService, @IWorkbenchExtensionEnablementService private readonly _extensionEnablementService: IWorkbenchExtensionEnablementService, @ITimerService private readonly _timerService: ITimerService, + @ICommandService private readonly _commandService: ICommandService, @IWorkbenchEnvironmentService protected readonly _environmentService: IWorkbenchEnvironmentService, ) { this._extensionHostKind = extHostContext.extensionHostKind; @@ -105,15 +107,36 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha }); } else { const enablementState = this._extensionEnablementService.getEnablementState(missingInstalledDependency); - this._notificationService.notify({ - severity: Severity.Error, - message: localize('disabledDep', "Cannot activate the '{0}' extension because it depends on the '{1}' extension, which is disabled. Would you like to enable the extension and reload the window?", extName, missingInstalledDependency.manifest.displayName || missingInstalledDependency.manifest.name), - actions: { - primary: [new Action('enable', localize('enable dep', "Enable and Reload"), '', true, - () => this._extensionEnablementService.setEnablement([missingInstalledDependency], enablementState === EnablementState.DisabledGlobally ? EnablementState.EnabledGlobally : EnablementState.EnabledWorkspace) - .then(() => this._hostService.reload(), e => this._notificationService.error(e)))] - } - }); + if (enablementState === EnablementState.DisabledByVirtualWorkspace) { + this._notificationService.notify({ + severity: Severity.Error, + message: localize('notSupportedInWorkspace', "Cannot activate the '{0}' extension because it depends on the '{1}' extension which is not supported in the current workspace", extName, missingInstalledDependency.manifest.displayName || missingInstalledDependency.manifest.name), + }); + } else if (enablementState === EnablementState.DisabledByTrustRequirement) { + this._notificationService.notify({ + severity: Severity.Error, + message: localize('restrictedMode', "Cannot activate the '{0}' extension because it depends on the '{1}' extension which is not supported in Restricted Mode", extName, missingInstalledDependency.manifest.displayName || missingInstalledDependency.manifest.name), + actions: { + primary: [new Action('manageWorkspaceTrust', localize('manageWorkspaceTrust', "Manage Workspace Trust"), '', true, + () => this._commandService.executeCommand('workbench.trust.manage'))] + } + }); + } else if (this._extensionEnablementService.canChangeEnablement(missingInstalledDependency)) { + this._notificationService.notify({ + severity: Severity.Error, + message: localize('disabledDep', "Cannot activate the '{0}' extension because it depends on the '{1}' extension which is disabled. Would you like to enable the extension and reload the window?", extName, missingInstalledDependency.manifest.displayName || missingInstalledDependency.manifest.name), + actions: { + primary: [new Action('enable', localize('enable dep', "Enable and Reload"), '', true, + () => this._extensionEnablementService.setEnablement([missingInstalledDependency], enablementState === EnablementState.DisabledGlobally ? EnablementState.EnabledGlobally : EnablementState.EnabledWorkspace) + .then(() => this._hostService.reload(), e => this._notificationService.error(e)))] + } + }); + } else { + this._notificationService.notify({ + severity: Severity.Error, + message: localize('disabledDepNoAction', "Cannot activate the '{0}' extension because it depends on the '{1}' extension which is disabled.", extName, missingInstalledDependency.manifest.displayName || missingInstalledDependency.manifest.name), + }); + } } } diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadFileSystem.ts b/src/vs/workbench/api/browser/mainThreadFileSystem.ts similarity index 96% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadFileSystem.ts rename to src/vs/workbench/api/browser/mainThreadFileSystem.ts index 286f1e540da4..0b8545ea02a7 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/browser/mainThreadFileSystem.ts @@ -6,7 +6,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; -import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileStat, FileOperationError, FileOperationResult, FileSystemProviderErrorCode, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithFileFolderCopyCapability } from 'vs/platform/files/common/files'; +import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileStat, FileOperationError, FileOperationResult, FileSystemProviderErrorCode, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithFileFolderCopyCapability, FilePermission } from 'vs/platform/files/common/files'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../common/extHost.protocol'; import { VSBuffer } from 'vs/base/common/buffer'; @@ -65,6 +65,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { ctime: stat.ctime, mtime: stat.mtime, size: stat.size, + permissions: MainThreadFileSystem._asFilePermission(stat), type: MainThreadFileSystem._asFileType(stat) }; }).catch(MainThreadFileSystem._handleError); @@ -95,6 +96,13 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { return res; } + private static _asFilePermission(stat: IFileStat): FilePermission | undefined { + if (stat.readonly) { + return FilePermission.Readonly; + } + return undefined; + } + $readFile(uri: UriComponents): Promise { return this._fileService.readFile(URI.revive(uri)).then(file => file.value).catch(MainThreadFileSystem._handleError); } diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts b/src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts rename to src/vs/workbench/api/browser/mainThreadFileSystemEventService.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadKeytar.ts b/src/vs/workbench/api/browser/mainThreadKeytar.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadKeytar.ts rename to src/vs/workbench/api/browser/mainThreadKeytar.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadLabelService.ts b/src/vs/workbench/api/browser/mainThreadLabelService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadLabelService.ts rename to src/vs/workbench/api/browser/mainThreadLabelService.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts similarity index 95% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts rename to src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index fd83c6e81a06..16a59acaf5a0 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -11,7 +11,7 @@ import * as search from 'vs/workbench/contrib/search/common/search'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Position as EditorPosition } from 'vs/editor/common/core/position'; import { Range as EditorRange, IRange } from 'vs/editor/common/core/range'; -import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyItemDto, ISuggestDataDto, ICodeActionDto, ISuggestDataDtoField, ISuggestResultDtoField, ICodeActionProviderMetadataDto, ILanguageWordDefinitionDto } from '../common/extHost.protocol'; +import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyItemDto, ISuggestDataDto, ICodeActionDto, ISuggestDataDtoField, ISuggestResultDtoField, ICodeActionProviderMetadataDto, ILanguageWordDefinitionDto, IdentifiableInlineCompletions, IdentifiableInlineCompletion } from '../common/extHost.protocol'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -499,6 +499,21 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha this._registrations.set(handle, modes.CompletionProviderRegistry.register(selector, provider)); } + $registerInlineCompletionsSupport(handle: number, selector: IDocumentFilterDto[]): void { + const provider: modes.InlineCompletionsProvider = { + provideInlineCompletions: async (model: ITextModel, position: EditorPosition, context: modes.InlineCompletionContext, token: CancellationToken): Promise => { + return this._proxy.$provideInlineCompletions(handle, model.uri, position, context, token); + }, + handleItemDidShow: async (completions: IdentifiableInlineCompletions, item: IdentifiableInlineCompletion): Promise => { + return this._proxy.$handleInlineCompletionDidShow(handle, completions.pid, item.idx); + }, + freeInlineCompletions: (completions: IdentifiableInlineCompletions): void => { + this._proxy.$freeInlineCompletionsList(handle, completions.pid); + } + }; + this._registrations.set(handle, modes.InlineCompletionsProviderRegistry.register(selector, provider)); + } + // --- parameter hints $registerSignatureHelpProvider(handle: number, selector: IDocumentFilterDto[], metadata: ISignatureHelpProviderMetadataDto): void { @@ -524,10 +539,10 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha // --- inline hints - $registerInlineHintsProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void { - const provider = { - provideInlineHints: async (model: ITextModel, range: EditorRange, token: CancellationToken): Promise => { - const result = await this._proxy.$provideInlineHints(handle, model.uri, range, token); + $registerInlayHintsProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void { + const provider = { + provideInlayHints: async (model: ITextModel, range: EditorRange, token: CancellationToken): Promise => { + const result = await this._proxy.$provideInlayHints(handle, model.uri, range, token); return result?.hints; } }; @@ -535,13 +550,13 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha if (typeof eventHandle === 'number') { const emitter = new Emitter(); this._registrations.set(eventHandle, emitter); - provider.onDidChangeInlineHints = emitter.event; + provider.onDidChangeInlayHints = emitter.event; } - this._registrations.set(handle, modes.InlineHintsProviderRegistry.register(selector, provider)); + this._registrations.set(handle, modes.InlayHintsProviderRegistry.register(selector, provider)); } - $emitInlineHintsEvent(eventHandle: number, event?: any): void { + $emitInlayHintsEvent(eventHandle: number, event?: any): void { const obj = this._registrations.get(eventHandle); if (obj instanceof Emitter) { obj.fire(event); diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadLanguages.ts b/src/vs/workbench/api/browser/mainThreadLanguages.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadLanguages.ts rename to src/vs/workbench/api/browser/mainThreadLanguages.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadLogService.ts b/src/vs/workbench/api/browser/mainThreadLogService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadLogService.ts rename to src/vs/workbench/api/browser/mainThreadLogService.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadMessageService.ts b/src/vs/workbench/api/browser/mainThreadMessageService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadMessageService.ts rename to src/vs/workbench/api/browser/mainThreadMessageService.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts similarity index 84% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadNotebook.ts rename to src/vs/workbench/api/browser/mainThreadNotebook.ts index acc83786481b..b95e973ad7f0 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -6,13 +6,11 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter } from 'vs/base/common/event'; -import { IRelativePattern } from 'vs/base/common/glob'; import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService'; -import { NotebookSelector } from 'vs/workbench/contrib/notebook/common/notebookSelector'; -import { INotebookCellStatusBarItemProvider, INotebookExclusiveDocumentFilter, NotebookDataDto, TransientCellMetadata, TransientDocumentMetadata, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookCellStatusBarItemProvider, INotebookContributionData, NotebookDataDto, TransientCellMetadata, TransientDocumentMetadata, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookContentProvider, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, MainContext, MainThreadNotebookShape, NotebookExtensionDescription } from '../common/extHost.protocol'; @@ -43,13 +41,8 @@ export class MainThreadNotebooks implements MainThreadNotebookShape { dispose(this._notebookSerializer.values()); } - async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: { - transientOutputs: boolean; - transientCellMetadata: TransientCellMetadata; - transientDocumentMetadata: TransientDocumentMetadata; - viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; }; - }): Promise { - let contentOptions = { transientOutputs: options.transientOutputs, transientCellMetadata: options.transientCellMetadata, transientDocumentMetadata: options.transientDocumentMetadata }; + async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: TransientOptions, data: INotebookContributionData | undefined): Promise { + let contentOptions = { ...options }; const controller: INotebookContentProvider = { get options() { @@ -60,7 +53,6 @@ export class MainThreadNotebooks implements MainThreadNotebookShape { contentOptions.transientDocumentMetadata = newOptions.transientDocumentMetadata; contentOptions.transientOutputs = newOptions.transientOutputs; }, - viewOptions: options.viewOptions, open: async (uri: URI, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken) => { const data = await this._proxy.$openNotebook(viewType, uri, backupId, untitledDocumentData, token); return { @@ -79,7 +71,11 @@ export class MainThreadNotebooks implements MainThreadNotebookShape { } }; - const disposable = this._notebookService.registerNotebookController(viewType, extension, controller); + const disposable = new DisposableStore(); + disposable.add(this._notebookService.registerNotebookController(viewType, extension, controller)); + if (data) { + disposable.add(this._notebookService.registerContributedNotebookType(viewType, data)); + } this._notebookProviders.set(viewType, { controller, disposable }); } @@ -104,7 +100,7 @@ export class MainThreadNotebooks implements MainThreadNotebookShape { } } - $registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions): void { + $registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions, data: INotebookContributionData | undefined): void { const registration = this._notebookService.registerNotebookSerializer(viewType, extension, { options, dataToNotebook: (data: VSBuffer): Promise => { @@ -114,7 +110,12 @@ export class MainThreadNotebooks implements MainThreadNotebookShape { return this._proxy.$notebookToData(handle, data, CancellationToken.None); } }); - this._notebookSerializer.set(handle, registration); + const disposables = new DisposableStore(); + disposables.add(registration); + if (data) { + disposables.add(this._notebookService.registerContributedNotebookType(viewType, data)); + } + this._notebookSerializer.set(handle, disposables); } $unregisterNotebookSerializer(handle: number): void { @@ -129,7 +130,7 @@ export class MainThreadNotebooks implements MainThreadNotebookShape { } } - async $registerNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined, selector: NotebookSelector): Promise { + async $registerNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined, viewType: string): Promise { const that = this; const provider: INotebookCellStatusBarItemProvider = { async provideCellStatusBarItems(uri: URI, index: number, token: CancellationToken) { @@ -143,7 +144,7 @@ export class MainThreadNotebooks implements MainThreadNotebookShape { } }; }, - selector: selector + viewType }; if (typeof eventHandle === 'number') { diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadNotebookDocuments.ts b/src/vs/workbench/api/browser/mainThreadNotebookDocuments.ts similarity index 78% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadNotebookDocuments.ts rename to src/vs/workbench/api/browser/mainThreadNotebookDocuments.ts index d2bf4a13f273..4fbe1ac207ff 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadNotebookDocuments.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebookDocuments.ts @@ -9,13 +9,15 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { BoundModelReferenceCollection } from 'vs/workbench/api/browser/mainThreadDocuments'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; -import { IImmediateCellEditOperation, IMainCellDto, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { IImmediateCellEditOperation, IMainCellDto, NotebookCellsChangeType, NotebookDataDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, MainThreadNotebookDocumentsShape } from '../common/extHost.protocol'; import { MainThreadNotebooksAndEditors } from 'vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { Schemas } from 'vs/base/common/network'; +import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider'; export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsShape { @@ -47,7 +49,6 @@ export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsS this._disposables.dispose(); this._modelReferenceCollection.dispose(); dispose(this._documentEventListenersMapping.values()); - } private _handleNotebooksAdded(notebooks: readonly NotebookTextModel[]): void { @@ -114,18 +115,59 @@ export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsS language: cell.language, cellKind: cell.cellKind, outputs: cell.outputs, - metadata: cell.metadata + metadata: cell.metadata, + internalMetadata: cell.internalMetadata, }; } - async $tryOpenDocument(uriComponents: UriComponents): Promise { + async $tryCreateNotebook(options: { viewType: string, content?: NotebookDataDto }): Promise { + + const info = this._notebookService.getContributedNotebookType(options.viewType); + if (!info) { + throw new Error('UNKNOWN view type: ' + options.viewType); + } + + // find a free URI for the untitled case + const suffix = NotebookProviderInfo.possibleFileEnding(info.selectors) ?? ''; + let uri: URI; + for (let counter = 1; ; counter++) { + let candidate = URI.from({ scheme: Schemas.untitled, path: `Untitled-${counter}${suffix}`, query: options.viewType }); + if (!this._notebookService.getNotebookTextModel(candidate)) { + uri = candidate; + break; + } + } + + const ref = await this._notebookEditorModelResolverService.resolve(uri, options.viewType); + + // untitled notebooks are disposed when they get saved. we should not hold a reference + // to such a disposed notebook and therefore dispose the reference as well + ref.object.notebook.onWillDispose(() => { + ref.dispose(); + }); + + // untitled notebooks are dirty by default + this._proxy.$acceptDirtyStateChanged(uri, true); + + // apply content changes... slightly HACKY -> this triggers a change event + if (options.content) { + ref.object.notebook.reset( + options.content.cells, + options.content.metadata, + ref.object.notebook.transientOptions + ); + } + return uri; + } + + async $tryOpenNotebook(uriComponents: UriComponents): Promise { const uri = URI.revive(uriComponents); const ref = await this._notebookEditorModelResolverService.resolve(uri, undefined); this._modelReferenceCollection.add(uri, ref); return uri; } - async $trySaveDocument(uriComponents: UriComponents) { + async $trySaveNotebook(uriComponents: UriComponents) { const uri = URI.revive(uriComponents); const ref = await this._notebookEditorModelResolverService.resolve(uri); diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts b/src/vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts similarity index 96% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts rename to src/vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts index c0f0aff2d510..be97d15f0960 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts @@ -30,7 +30,7 @@ interface INotebookAndEditorDelta { } class NotebookAndEditorState { - static compute(before: NotebookAndEditorState | undefined, after: NotebookAndEditorState): INotebookAndEditorDelta { + static delta(before: NotebookAndEditorState | undefined, after: NotebookAndEditorState): INotebookAndEditorDelta { if (!before) { return { addedDocuments: [...after.documents], @@ -107,7 +107,7 @@ export class MainThreadNotebooksAndEditors { extHostContext.set(MainContext.MainThreadNotebookDocuments, this._mainThreadNotebooks); extHostContext.set(MainContext.MainThreadNotebookEditors, this._mainThreadEditors); - this._notebookService.onDidCreateNotebookDocument(() => this._updateState(), this, this._disposables); + this._notebookService.onWillAddNotebookDocument(() => this._updateState(), this, this._disposables); this._notebookService.onDidRemoveNotebookDocument(() => this._updateState(), this, this._disposables); this._editorService.onDidActiveEditorChange(() => this._updateState(), this, this._disposables); this._editorService.onDidVisibleEditorsChange(() => this._updateState(), this, this._disposables); @@ -170,7 +170,7 @@ export class MainThreadNotebooksAndEditors { } const newState = new NotebookAndEditorState(new Set(this._notebookService.listNotebookDocuments()), editors, activeEditor, visibleEditorsMap); - this._onDelta(NotebookAndEditorState.compute(this._currentState, newState)); + this._onDelta(NotebookAndEditorState.delta(this._currentState, newState)); this._currentState = newState; } @@ -234,7 +234,8 @@ export class MainThreadNotebooksAndEditors { language: cell.language, cellKind: cell.cellKind, outputs: cell.outputs, - metadata: cell.metadata + metadata: cell.metadata, + internalMetadata: cell.internalMetadata, })) }; } diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadNotebookEditors.ts b/src/vs/workbench/api/browser/mainThreadNotebookEditors.ts similarity index 97% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadNotebookEditors.ts rename to src/vs/workbench/api/browser/mainThreadNotebookEditors.ts index a8ca5a5ac46a..704b1c392b12 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadNotebookEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebookEditors.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { DisposableStore, dispose } from 'vs/base/common/lifecycle'; -import { getNotebookEditorFromEditorPane, INotebookEditor, NotebookEditorOptions } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { getNotebookEditorFromEditorPane, INotebookEditor, INotebookEditorOptions } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService'; import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, INotebookDocumentShowOptions, INotebookEditorViewColumnInfo, MainThreadNotebookEditorsShape, NotebookEditorRevealType } from '../common/extHost.protocol'; import { MainThreadNotebooksAndEditors } from 'vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors'; @@ -124,7 +124,7 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape async $tryShowNotebookDocument(resource: UriComponents, viewType: string, options: INotebookDocumentShowOptions): Promise { - const editorOptions = new NotebookEditorOptions({ + const editorOptions: INotebookEditorOptions = { cellSelections: options.selections, preserveFocus: options.preserveFocus, pinned: options.pinned, @@ -132,8 +132,8 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape // preserve pre 1.38 behaviour to not make group active when preserveFocus: true // but make sure to restore the editor to fix https://github.com/microsoft/vscode/issues/79633 activation: options.preserveFocus ? EditorActivation.RESTORE : undefined, - override: EditorOverride.DISABLED, - }); + override: EditorOverride.DISABLED + }; const input = NotebookEditorInput.create(this._instantiationService, URI.revive(resource), viewType); const editorPane = await this._editorService.openEditor(input, editorOptions, options.position); diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadNotebookKernels.ts b/src/vs/workbench/api/browser/mainThreadNotebookKernels.ts similarity index 93% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadNotebookKernels.ts rename to src/vs/workbench/api/browser/mainThreadNotebookKernels.ts index 308e0964ae04..73bc0ed650e6 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadNotebookKernels.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebookKernels.ts @@ -44,7 +44,7 @@ abstract class MainThreadKernel implements INotebookKernel { constructor(data: INotebookKernelDto2, private _modeService: IModeService) { this.id = data.id; - this.viewType = data.viewType; + this.viewType = data.notebookType; this.extension = data.extensionId; this.implementsInterrupt = data.supportsInterrupt ?? false; @@ -52,7 +52,7 @@ abstract class MainThreadKernel implements INotebookKernel { this.description = data.description; this.detail = data.detail; this.supportedLanguages = isNonEmptyArray(data.supportedLanguages) ? data.supportedLanguages : _modeService.getRegisteredModes(); - this.implementsExecutionOrder = data.hasExecutionOrder ?? false; + this.implementsExecutionOrder = data.supportsExecutionOrder ?? false; this.localResourceRoot = URI.revive(data.extensionLocation); this.preloads = data.preloads?.map(u => ({ uri: URI.revive(u.uri), provides: u.provides })) ?? []; } @@ -77,8 +77,8 @@ abstract class MainThreadKernel implements INotebookKernel { this.supportedLanguages = isNonEmptyArray(data.supportedLanguages) ? data.supportedLanguages : this._modeService.getRegisteredModes(); event.supportedLanguages = true; } - if (data.hasExecutionOrder !== undefined) { - this.implementsExecutionOrder = data.hasExecutionOrder; + if (data.supportsExecutionOrder !== undefined) { + this.implementsExecutionOrder = data.supportsExecutionOrder; event.hasExecutionOrder = true; } this._onDidChange.fire(event); @@ -122,9 +122,6 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape private _onEditorAdd(editor: INotebookEditor) { const ipcListener = editor.onDidReceiveMessage(e => { - if (e.forRenderer) { - return; - } if (!editor.hasModel()) { return; } @@ -134,7 +131,7 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape } for (let [handle, candidate] of this._kernels) { if (candidate[0] === selected) { - this._proxy.$acceptRendererMessage(handle, editor.getId(), e.message); + this._proxy.$acceptKernelMessageFromRenderer(handle, editor.getId(), e.message); break; } } @@ -164,11 +161,11 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape } if (editorId === undefined) { // all editors - editor.postMessage(undefined, message); + editor.postMessage(message); didSend = true; } else if (editor.getId() === editorId) { // selected editors - editor.postMessage(undefined, message); + editor.postMessage(message); didSend = true; break; } @@ -188,16 +185,16 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape await that._proxy.$cancelCells(handle, uri, handles); } }(data, this._modeService); - const registration = this._notebookKernelService.registerKernel(kernel); const listener = this._notebookKernelService.onDidChangeNotebookKernelBinding(e => { if (e.oldKernel === kernel.id) { - this._proxy.$acceptSelection(handle, e.notebook, false); + this._proxy.$acceptNotebookAssociation(handle, e.notebook, false); } else if (e.newKernel === kernel.id) { - this._proxy.$acceptSelection(handle, e.notebook, true); + this._proxy.$acceptNotebookAssociation(handle, e.notebook, true); } }); + const registration = this._notebookKernelService.registerKernel(kernel); this._kernels.set(handle, [kernel, combinedDisposable(listener, registration)]); } diff --git a/src/vs/workbench/api/browser/mainThreadNotebookRenderers.ts b/src/vs/workbench/api/browser/mainThreadNotebookRenderers.ts new file mode 100644 index 000000000000..5adf89ce7a73 --- /dev/null +++ b/src/vs/workbench/api/browser/mainThreadNotebookRenderers.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 { Disposable } from 'vs/base/common/lifecycle'; +import { ExtHostContext, ExtHostNotebookRenderersShape, IExtHostContext, MainContext, MainThreadNotebookRenderersShape } from 'vs/workbench/api/common/extHost.protocol'; +import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; +import { INotebookRendererMessagingService } from 'vs/workbench/contrib/notebook/common/notebookRendererMessagingService'; + +@extHostNamedCustomer(MainContext.MainThreadNotebookRenderers) +export class MainThreadNotebookRenderers extends Disposable implements MainThreadNotebookRenderersShape { + private readonly proxy: ExtHostNotebookRenderersShape; + + constructor( + extHostContext: IExtHostContext, + @INotebookRendererMessagingService private readonly messaging: INotebookRendererMessagingService, + ) { + super(); + this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebookRenderers); + this._register(messaging.onShouldPostMessage(e => { + this.proxy.$postRendererMessage(e.editorId, e.rendererId, e.message); + })); + } + + $postMessage(editorId: string, rendererId: string, message: unknown): void { + this.messaging.fireDidReceiveMessage(editorId, rendererId, message); + } +} diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadOutputService.ts b/src/vs/workbench/api/browser/mainThreadOutputService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadOutputService.ts rename to src/vs/workbench/api/browser/mainThreadOutputService.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadProgress.ts b/src/vs/workbench/api/browser/mainThreadProgress.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadProgress.ts rename to src/vs/workbench/api/browser/mainThreadProgress.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadQuickOpen.ts b/src/vs/workbench/api/browser/mainThreadQuickOpen.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadQuickOpen.ts rename to src/vs/workbench/api/browser/mainThreadQuickOpen.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadRemoteConnectionData.ts b/src/vs/workbench/api/browser/mainThreadRemoteConnectionData.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadRemoteConnectionData.ts rename to src/vs/workbench/api/browser/mainThreadRemoteConnectionData.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadSCM.ts b/src/vs/workbench/api/browser/mainThreadSCM.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadSCM.ts rename to src/vs/workbench/api/browser/mainThreadSCM.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts rename to src/vs/workbench/api/browser/mainThreadSaveParticipant.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadSearch.ts b/src/vs/workbench/api/browser/mainThreadSearch.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadSearch.ts rename to src/vs/workbench/api/browser/mainThreadSearch.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadSecretState.ts b/src/vs/workbench/api/browser/mainThreadSecretState.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadSecretState.ts rename to src/vs/workbench/api/browser/mainThreadSecretState.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadStatusBar.ts b/src/vs/workbench/api/browser/mainThreadStatusBar.ts similarity index 78% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadStatusBar.ts rename to src/vs/workbench/api/browser/mainThreadStatusBar.ts index 3ba387186db1..69f8d2cf92a7 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadStatusBar.ts +++ b/src/vs/workbench/api/browser/mainThreadStatusBar.ts @@ -27,7 +27,7 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape { this.entries.clear(); } - $setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignment: MainThreadStatusBarAlignment, priority: number | undefined, accessibilityInformation: IAccessibilityInformation): void { + $setEntry(entryId: number, id: string, name: string, text: string, tooltip: string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignment: MainThreadStatusBarAlignment, priority: number | undefined, accessibilityInformation: IAccessibilityInformation): void { // if there are icons in the text use the tooltip for the aria label let ariaLabel: string; let role: string | undefined = undefined; @@ -37,23 +37,23 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape { } else { ariaLabel = getCodiconAriaLabel(text); } - const entry: IStatusbarEntry = { text, tooltip, command, color, backgroundColor, ariaLabel, role }; + const entry: IStatusbarEntry = { name, text, tooltip, command, color, backgroundColor, ariaLabel, role }; if (typeof priority === 'undefined') { priority = 0; } // Reset existing entry if alignment or priority changed - let existingEntry = this.entries.get(id); + let existingEntry = this.entries.get(entryId); if (existingEntry && (existingEntry.alignment !== alignment || existingEntry.priority !== priority)) { dispose(existingEntry.accessor); - this.entries.delete(id); + this.entries.delete(entryId); existingEntry = undefined; } // Create new entry if not existing if (!existingEntry) { - this.entries.set(id, { accessor: this.statusbarService.addEntry(entry, statusId, statusName, alignment, priority), alignment, priority }); + this.entries.set(entryId, { accessor: this.statusbarService.addEntry(entry, id, alignment, priority), alignment, priority }); } // Otherwise update diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadStorage.ts b/src/vs/workbench/api/browser/mainThreadStorage.ts similarity index 93% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadStorage.ts rename to src/vs/workbench/api/browser/mainThreadStorage.ts index 0206ff96b173..5cb658e91d1c 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadStorage.ts +++ b/src/vs/workbench/api/browser/mainThreadStorage.ts @@ -62,12 +62,12 @@ export class MainThreadStorage implements MainThreadStorageShape { return JSON.parse(jsonValue); } - async $setValue(shared: boolean, key: string, value: object): Promise { + $setValue(shared: boolean, key: string, value: object): Promise { let jsonValue: string; try { jsonValue = JSON.stringify(value); // Extension state is synced separately through extensions - await this._storageService.store(key, jsonValue, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE, StorageTarget.MACHINE); + this._storageService.store(key, jsonValue, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE, StorageTarget.MACHINE); } catch (err) { return Promise.reject(err); } diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadTask.ts b/src/vs/workbench/api/browser/mainThreadTask.ts similarity index 99% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadTask.ts rename to src/vs/workbench/api/browser/mainThreadTask.ts index c88061cf34d4..8944c4daf423 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadTask.ts +++ b/src/vs/workbench/api/browser/mainThreadTask.ts @@ -702,9 +702,6 @@ export class MainThreadTask implements MainThreadTaskShape { }); }); }, - getDefaultShellAndArgs: (): Promise<{ shell: string, args: string[] | string | undefined }> => { - return Promise.resolve(this._proxy.$getDefaultShellAndArgs()); - }, findExecutable: (command: string, cwd?: string, paths?: string[]): Promise => { return this._proxy.$findExecutable(command, cwd, paths); } diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadTelemetry.ts b/src/vs/workbench/api/browser/mainThreadTelemetry.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadTelemetry.ts rename to src/vs/workbench/api/browser/mainThreadTelemetry.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts similarity index 82% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadTerminalService.ts rename to src/vs/workbench/api/browser/mainThreadTerminalService.ts index 428f24124f6e..7b52f5c75d11 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -3,22 +3,23 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; -import { StopWatch } from 'vs/base/common/stopwatch'; +import { DisposableStore, Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, TerminalLaunchConfig, ITerminalDimensionsDto, TerminalIdentifier } from 'vs/workbench/api/common/extHost.protocol'; +import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { URI } from 'vs/base/common/uri'; +import { StopWatch } from 'vs/base/common/stopwatch'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; -import { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions } from 'vs/platform/terminal/common/terminal'; +import { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions, TitleEventSource } from 'vs/platform/terminal/common/terminal'; import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering'; -import { ExtHostContext, ExtHostTerminalServiceShape, IExtHostContext, ITerminalDimensionsDto, MainContext, MainThreadTerminalServiceShape, TerminalIdentifier, TerminalLaunchConfig } from 'vs/workbench/api/common/extHost.protocol'; -import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { ITerminalExternalLinkProvider, ITerminalInstance, ITerminalInstanceService, ITerminalLink, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { TerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy'; import { IEnvironmentVariableService, ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable'; import { deserializeEnvironmentVariableCollection, serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared'; -import { IAvailableProfilesRequest as IAvailableProfilesRequest, IDefaultShellAndArgsRequest, IStartExtensionTerminalRequest, ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal'; -import { ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions'; +import { IStartExtensionTerminalRequest, ITerminalProcessExtHostProxy, ITerminalProfileResolverService } from 'vs/workbench/contrib/terminal/common/terminal'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { withNullAsUndefined } from 'vs/base/common/types'; +import { OperatingSystem, OS } from 'vs/base/common/platform'; @extHostNamedCustomer(MainContext.MainThreadTerminalService) export class MainThreadTerminalService implements MainThreadTerminalServiceShape { @@ -30,11 +31,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape * This comes in play only when dealing with terminals created on the extension host side */ private _extHostTerminalIds = new Map(); - private _remoteAuthority: string | null; private readonly _toDispose = new DisposableStore(); private readonly _terminalProcessProxies = new Map(); + private readonly _profileProviders = new Map(); private _dataEventTracker: TerminalDataEventTracker | undefined; - private _extHostKind: ExtensionHostKind; /** * A single shared terminal link provider for the exthost. When an ext registers a link * provider, this is registered with the terminal on the renderer side and all links are @@ -43,17 +43,19 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape */ private _linkProvider: IDisposable | undefined; + private _os: OperatingSystem = OS; + constructor( - extHostContext: IExtHostContext, + private readonly _extHostContext: IExtHostContext, @ITerminalService private readonly _terminalService: ITerminalService, @ITerminalInstanceService readonly terminalInstanceService: ITerminalInstanceService, - @IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @IEnvironmentVariableService private readonly _environmentVariableService: IEnvironmentVariableService, @ILogService private readonly _logService: ILogService, + @ITerminalProfileResolverService private readonly _terminalProfileResolverService: ITerminalProfileResolverService, + @IRemoteAgentService remoteAgentService: IRemoteAgentService ) { - this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTerminalService); - this._remoteAuthority = extHostContext.remoteAuthority; + this._proxy = _extHostContext.getProxy(ExtHostContext.ExtHostTerminalService); // ITerminalService listeners this._toDispose.add(_terminalService.onInstanceCreated((instance) => { @@ -61,8 +63,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._onInstanceDimensionsChanged(instance); })); - this._extHostKind = extHostContext.extensionHostKind; - this._toDispose.add(_terminalService.onInstanceDisposed(instance => this._onTerminalDisposed(instance))); this._toDispose.add(_terminalService.onInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance))); this._toDispose.add(_terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance))); @@ -70,12 +70,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._toDispose.add(_terminalService.onInstanceRequestStartExtensionTerminal(e => this._onRequestStartExtensionTerminal(e))); this._toDispose.add(_terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.instanceId : null))); this._toDispose.add(_terminalService.onInstanceTitleChanged(instance => instance && this._onTitleChanged(instance.instanceId, instance.title))); - this._toDispose.add(_terminalService.onRequestAvailableProfiles(e => this._onRequestAvailableProfiles(e))); - - // ITerminalInstanceService listeners - if (terminalInstanceService.onRequestDefaultShellAndArgs) { - this._toDispose.add(terminalInstanceService.onRequestDefaultShellAndArgs(e => this._onRequestDefaultShellAndArgs(e))); - } // Set initial ext host state this._terminalService.terminalInstances.forEach(t => { @@ -94,7 +88,11 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._proxy.$initEnvironmentVariableCollections(serializedCollections); } - this._terminalService.extHostReady(extHostContext.remoteAuthority!); // TODO@Tyriar: remove null assertion + remoteAgentService.getEnvironment().then(async env => { + this._os = env?.os || OS; + this._updateDefaultProfile(); + }); + this._terminalService.onDidChangeAvailableProfiles(() => this._updateDefaultProfile()); } public dispose(): void { @@ -102,6 +100,13 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._linkProvider?.dispose(); } + private async _updateDefaultProfile() { + const remoteAuthority = withNullAsUndefined(this._extHostContext.remoteAuthority); + const defaultProfile = this._terminalProfileResolverService.getDefaultProfile({ remoteAuthority, os: this._os }); + const defaultAutomationProfile = this._terminalProfileResolverService.getDefaultProfile({ remoteAuthority, os: this._os, allowAutomationShell: true }); + this._proxy.$acceptDefaultProfile(...await Promise.all([defaultProfile, defaultAutomationProfile])); + } + private _getTerminalId(id: TerminalIdentifier): number | undefined { if (typeof id === 'number') { return id; @@ -135,9 +140,19 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape : undefined, extHostTerminalId: extHostTerminalId, isFeatureTerminal: launchConfig.isFeatureTerminal, - isExtensionOwnedTerminal: launchConfig.isExtensionOwnedTerminal + isExtensionOwnedTerminal: launchConfig.isExtensionOwnedTerminal, + useShellEnvironment: launchConfig.useShellEnvironment }; - const terminal = this._terminalService.createTerminal(shellLaunchConfig); + let terminal: ITerminalInstance | undefined; + if (launchConfig.isSplitTerminal) { + const activeInstance = this._terminalService.getActiveInstance(); + if (activeInstance) { + terminal = withNullAsUndefined(this._terminalService.splitInstance(activeInstance, shellLaunchConfig)); + } + } + if (!terminal) { + terminal = this._terminalService.createTerminal(shellLaunchConfig); + } this._extHostTerminalIds.set(extHostTerminalId, terminal.instanceId); } @@ -196,6 +211,18 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._terminalService.registerProcessSupport(isSupported); } + public $registerProfileProvider(id: string): void { + // Proxy profile provider requests through the extension host + this._profileProviders.set(id, this._terminalService.registerTerminalProfileProvider(id, { + createContributedTerminalProfile: async (isSplitTerminal) => this._proxy.$createContributedProfileTerminal(id, isSplitTerminal) + })); + } + + public $unregisterProfileProvider(id: string): void { + this._profileProviders.get(id)?.dispose(); + this._profileProviders.delete(id); + } + private _onActiveTerminalChanged(terminalId: number | null): void { this._proxy.$acceptActiveTerminalChanged(terminalId); } @@ -265,7 +292,15 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape } public $sendProcessTitle(terminalId: number, title: string): void { - this._terminalProcessProxies.get(terminalId)?.emitTitle(title); + // Since title events can only come from vscode.Pseudoterminals right now, these are routed + // directly to the instance as API source events such that they will replace the initial + // `name` property provided for the Pseudoterminal. If we support showing both Api and + // Process titles at the same time we may want to pass this through as a Process source + // event. + const instance = this._terminalService.getInstanceFromId(terminalId); + if (instance) { + instance.setTitle(title, TitleEventSource.Api); + } } public $sendProcessData(terminalId: number, data: string): void { @@ -308,28 +343,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._getTerminalProcess(terminalId)?.emitLatency(sum / COUNT); } - private _isPrimaryExtHost(): boolean { - // The "primary" ext host is the remote ext host if there is one, otherwise the local - const conn = this._remoteAgentService.getConnection(); - if (conn) { - return this._remoteAuthority === conn.remoteAuthority; - } - return this._extHostKind !== ExtensionHostKind.LocalWebWorker; - } - - private async _onRequestAvailableProfiles(req: IAvailableProfilesRequest): Promise { - if (this._isPrimaryExtHost()) { - req.callback(await this._proxy.$getAvailableProfiles(req.configuredProfilesOnly)); - } - } - - private async _onRequestDefaultShellAndArgs(req: IDefaultShellAndArgsRequest): Promise { - if (this._isPrimaryExtHost()) { - const res = await this._proxy.$getDefaultShellAndArgs(req.useAutomationShell); - req.callback(res.shell, res.args); - } - } - private _getTerminalProcess(terminalId: number): ITerminalProcessExtHostProxy | undefined { const terminal = this._terminalProcessProxies.get(terminalId); if (!terminal) { diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadTesting.ts b/src/vs/workbench/api/browser/mainThreadTesting.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadTesting.ts rename to src/vs/workbench/api/browser/mainThreadTesting.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadTheming.ts b/src/vs/workbench/api/browser/mainThreadTheming.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadTheming.ts rename to src/vs/workbench/api/browser/mainThreadTheming.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadTimeline.ts b/src/vs/workbench/api/browser/mainThreadTimeline.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadTimeline.ts rename to src/vs/workbench/api/browser/mainThreadTimeline.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadTreeViews.ts b/src/vs/workbench/api/browser/mainThreadTreeViews.ts similarity index 93% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadTreeViews.ts rename to src/vs/workbench/api/browser/mainThreadTreeViews.ts index b70ff475447f..c131a19a431b 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadTreeViews.ts +++ b/src/vs/workbench/api/browser/mainThreadTreeViews.ts @@ -5,7 +5,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { ExtHostContext, MainThreadTreeViewsShape, ExtHostTreeViewsShape, MainContext, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; -import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeView, IViewsRegistry, ITreeViewDescriptor, IRevealOptions, Extensions, ResolvableTreeItem } from 'vs/workbench/common/views'; +import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeView, IViewsRegistry, ITreeViewDescriptor, IRevealOptions, Extensions, ResolvableTreeItem, ITreeViewDragAndDropController } from 'vs/workbench/common/views'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { distinct } from 'vs/base/common/arrays'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -31,18 +31,20 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTreeViews); } - async $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean }): Promise { + async $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean, canDragAndDrop: boolean }): Promise { this.logService.trace('MainThreadTreeViews#$registerTreeViewDataProvider', treeViewId, options); this.extensionService.whenInstalledExtensionsRegistered().then(() => { const dataProvider = new TreeViewDataProvider(treeViewId, this._proxy, this.notificationService); this._dataProviders.set(treeViewId, dataProvider); + const dndController = options.canDragAndDrop ? new TreeViewDragAndDropController(treeViewId, this._proxy) : undefined; const viewer = this.getTreeView(treeViewId); if (viewer) { // Order is important here. The internal tree isn't created until the dataProvider is set. // Set all other properties first! viewer.showCollapseAllAction = !!options.showCollapseAll; viewer.canSelectMany = !!options.canSelectMany; + viewer.dragAndDropController = dndController; viewer.dataProvider = dataProvider; this.registerListeners(treeViewId, viewer); this._proxy.$setVisible(treeViewId, viewer.visible); @@ -161,6 +163,16 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie type TreeItemHandle = string; +class TreeViewDragAndDropController implements ITreeViewDragAndDropController { + + constructor(private readonly treeViewId: string, + private readonly _proxy: ExtHostTreeViewsShape) { } + + onDrop(treeItem: ITreeItem[], targetTreeItem: ITreeItem): Promise { + return this._proxy.$onDrop(this.treeViewId, treeItem.map(item => item.handle), targetTreeItem.handle); + } +} + class TreeViewDataProvider implements ITreeViewDataProvider { private readonly itemsMap: Map = new Map(); diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadTunnelService.ts b/src/vs/workbench/api/browser/mainThreadTunnelService.ts similarity index 98% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadTunnelService.ts rename to src/vs/workbench/api/browser/mainThreadTunnelService.ts index 668e0fae130e..6fc537aa2a9d 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadTunnelService.ts +++ b/src/vs/workbench/api/browser/mainThreadTunnelService.ts @@ -41,7 +41,8 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun } private processFindingEnabled(): boolean { - return (!!this.configurationService.getValue(PORT_AUTO_FORWARD_SETTING)) && (this.configurationService.getValue(PORT_AUTO_SOURCE_SETTING) === PORT_AUTO_SOURCE_SETTING_PROCESS); + return (!!this.configurationService.getValue(PORT_AUTO_FORWARD_SETTING) || this.tunnelService.hasTunnelProvider) + && (this.configurationService.getValue(PORT_AUTO_SOURCE_SETTING) === PORT_AUTO_SOURCE_SETTING_PROCESS); } async $setRemoteTunnelService(processId: number): Promise { diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadUriOpeners.ts b/src/vs/workbench/api/browser/mainThreadUriOpeners.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadUriOpeners.ts rename to src/vs/workbench/api/browser/mainThreadUriOpeners.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadUrls.ts b/src/vs/workbench/api/browser/mainThreadUrls.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadUrls.ts rename to src/vs/workbench/api/browser/mainThreadUrls.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadWebviewManager.ts b/src/vs/workbench/api/browser/mainThreadWebviewManager.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadWebviewManager.ts rename to src/vs/workbench/api/browser/mainThreadWebviewManager.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts b/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts rename to src/vs/workbench/api/browser/mainThreadWebviewPanels.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadWebviewViews.ts b/src/vs/workbench/api/browser/mainThreadWebviewViews.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadWebviewViews.ts rename to src/vs/workbench/api/browser/mainThreadWebviewViews.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadWebviews.ts b/src/vs/workbench/api/browser/mainThreadWebviews.ts similarity index 95% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadWebviews.ts rename to src/vs/workbench/api/browser/mainThreadWebviews.ts index 5f5d3ac3b01b..d3e93066b572 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadWebviews.ts +++ b/src/vs/workbench/api/browser/mainThreadWebviews.ts @@ -14,8 +14,7 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IProductService } from 'vs/platform/product/common/productService'; import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol'; -import { serializeMessage } from 'vs/workbench/api/common/extHostWebview'; -import { deserializeWebviewMessage } from 'vs/workbench/api/common/extHostWebviewMessaging'; +import { serializeWebviewMessage, deserializeWebviewMessage } from 'vs/workbench/api/common/extHostWebviewMessaging'; import { Webview, WebviewContentOptions, WebviewExtensionDescription, WebviewOverlay } from 'vs/workbench/contrib/webview/browser/webview'; export class MainThreadWebviews extends Disposable implements extHostProtocol.MainThreadWebviewsShape { @@ -74,7 +73,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma disposables.add(webview.onDidClickLink((uri) => this.onDidClickLink(handle, uri))); disposables.add(webview.onMessage((message) => { - const serialized = serializeMessage(message.message, options); + const serialized = serializeWebviewMessage(message.message, options); this._proxy.$onMessage(handle, serialized.message, ...serialized.buffers); })); diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadWindow.ts b/src/vs/workbench/api/browser/mainThreadWindow.ts similarity index 95% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadWindow.ts rename to src/vs/workbench/api/browser/mainThreadWindow.ts index 7f10aa334c6b..5dc01ce8c762 100644 --- a/lib/vscode/src/vs/workbench/api/browser/mainThreadWindow.ts +++ b/src/vs/workbench/api/browser/mainThreadWindow.ts @@ -60,8 +60,7 @@ export class MainThreadWindow implements MainThreadWindowShape { } async $asExternalUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise { - const uri = URI.revive(uriComponents); - const result = await this.openerService.resolveExternalUri(uri, options); + const result = await this.openerService.resolveExternalUri(URI.revive(uriComponents), options); return result.resolved; } } diff --git a/lib/vscode/src/vs/workbench/api/browser/mainThreadWorkspace.ts b/src/vs/workbench/api/browser/mainThreadWorkspace.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/mainThreadWorkspace.ts rename to src/vs/workbench/api/browser/mainThreadWorkspace.ts diff --git a/lib/vscode/src/vs/workbench/api/browser/viewsExtensionPoint.ts b/src/vs/workbench/api/browser/viewsExtensionPoint.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/browser/viewsExtensionPoint.ts rename to src/vs/workbench/api/browser/viewsExtensionPoint.ts diff --git a/lib/vscode/src/vs/workbench/api/common/apiCommands.ts b/src/vs/workbench/api/common/apiCommands.ts similarity index 56% rename from lib/vscode/src/vs/workbench/api/common/apiCommands.ts rename to src/vs/workbench/api/common/apiCommands.ts index da918ae31e89..65c0cab492b3 100644 --- a/lib/vscode/src/vs/workbench/api/common/apiCommands.ts +++ b/src/vs/workbench/api/common/apiCommands.ts @@ -7,8 +7,6 @@ import { URI } from 'vs/base/common/uri'; import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import { CommandsRegistry, ICommandService, ICommandHandler } from 'vs/platform/commands/common/commands'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; -import { IWorkspacesService, IRecent } from 'vs/platform/workspaces/common/workspaces'; import { ILogService } from 'vs/platform/log/common/log'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IViewDescriptorService, IViewsService, ViewVisibilityState } from 'vs/workbench/common/views'; @@ -30,100 +28,6 @@ function adjustHandler(handler: (executor: ICommandsExecutor, ...args: any[]) => }; } -interface INewWindowAPICommandOptions { - reuseWindow?: boolean; - /** - * If set, defines the remoteAuthority of the new window. `null` will open a local window. - * If not set, defaults to remoteAuthority of the current window. - */ - remoteAuthority?: string | null; -} - -export class NewWindowAPICommand { - public static readonly ID = 'vscode.newWindow'; - public static execute(executor: ICommandsExecutor, options?: INewWindowAPICommandOptions): Promise { - const commandOptions: IOpenEmptyWindowOptions = { - forceReuseWindow: options && options.reuseWindow, - remoteAuthority: options && options.remoteAuthority - }; - - return executor.executeCommand('_files.newWindow', commandOptions); - } -} -CommandsRegistry.registerCommand({ - id: NewWindowAPICommand.ID, - handler: adjustHandler(NewWindowAPICommand.execute), - description: { - description: 'Opens an new window', - args: [ - ] - } -}); - -CommandsRegistry.registerCommand('_workbench.removeFromRecentlyOpened', function (accessor: ServicesAccessor, uri: URI) { - const workspacesService = accessor.get(IWorkspacesService); - return workspacesService.removeRecentlyOpened([uri]); -}); - -export class RemoveFromRecentlyOpenedAPICommand { - public static readonly ID = 'vscode.removeFromRecentlyOpened'; - public static execute(executor: ICommandsExecutor, path: string | URI): Promise { - if (typeof path === 'string') { - path = path.match(/^[^:/?#]+:\/\//) ? URI.parse(path) : URI.file(path); - } else { - path = URI.revive(path); // called from extension host - } - return executor.executeCommand('_workbench.removeFromRecentlyOpened', path); - } -} -CommandsRegistry.registerCommand(RemoveFromRecentlyOpenedAPICommand.ID, adjustHandler(RemoveFromRecentlyOpenedAPICommand.execute)); - -export interface OpenIssueReporterArgs { - readonly extensionId: string; - readonly issueTitle?: string; - readonly issueBody?: string; -} - -export class OpenIssueReporter { - public static readonly ID = 'vscode.openIssueReporter'; - - public static execute(executor: ICommandsExecutor, args: string | OpenIssueReporterArgs): Promise { - const commandArgs = typeof args === 'string' - ? { extensionId: args } - : args; - return executor.executeCommand('workbench.action.openIssueReporter', commandArgs); - } -} - -interface RecentEntry { - uri: URI; - type: 'workspace' | 'folder' | 'file'; - label?: string; - remoteAuthority?: string; -} - -CommandsRegistry.registerCommand('_workbench.addToRecentlyOpened', async function (accessor: ServicesAccessor, recentEntry: RecentEntry) { - const workspacesService = accessor.get(IWorkspacesService); - let recent: IRecent | undefined = undefined; - const uri = recentEntry.uri; - const label = recentEntry.label; - const remoteAuthority = recentEntry.remoteAuthority; - if (recentEntry.type === 'workspace') { - const workspace = await workspacesService.getWorkspaceIdentifier(uri); - recent = { workspace, label, remoteAuthority }; - } else if (recentEntry.type === 'folder') { - recent = { folderUri: uri, label, remoteAuthority }; - } else { - recent = { fileUri: uri, label, remoteAuthority }; - } - return workspacesService.addRecentlyOpened([recent]); -}); - -CommandsRegistry.registerCommand('_workbench.getRecentlyOpened', async function (accessor: ServicesAccessor) { - const workspacesService = accessor.get(IWorkspacesService); - return workspacesService.getRecentlyOpened(); -}); - CommandsRegistry.registerCommand('_extensionTests.setLogLevel', function (accessor: ServicesAccessor, level: number) { const logService = accessor.get(ILogService); const environmentService = accessor.get(IEnvironmentService); diff --git a/lib/vscode/src/vs/workbench/api/common/cache.ts b/src/vs/workbench/api/common/cache.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/cache.ts rename to src/vs/workbench/api/common/cache.ts diff --git a/lib/vscode/src/vs/workbench/api/common/configurationExtensionPoint.ts b/src/vs/workbench/api/common/configurationExtensionPoint.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/configurationExtensionPoint.ts rename to src/vs/workbench/api/common/configurationExtensionPoint.ts diff --git a/lib/vscode/src/vs/workbench/api/common/exHostSecretState.ts b/src/vs/workbench/api/common/exHostSecretState.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/exHostSecretState.ts rename to src/vs/workbench/api/common/exHostSecretState.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts similarity index 92% rename from lib/vscode/src/vs/workbench/api/common/extHost.api.impl.ts rename to src/vs/workbench/api/common/extHost.api.impl.ts index 14757bf88e99..e4f4400b6c0a 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.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 { CancellationTokenSource } from 'vs/base/common/cancellation'; import * as errors from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; @@ -29,7 +28,7 @@ import { IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocu import { Extension, IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; import { ExtHostFileSystem } from 'vs/workbench/api/common/extHostFileSystem'; import { ExtHostFileSystemEventService } from 'vs/workbench/api/common/extHostFileSystemEventService'; -import { ExtHostLanguageFeatures } from 'vs/workbench/api/common/extHostLanguageFeatures'; +import { ExtHostLanguageFeatures, InlineCompletionController } from 'vs/workbench/api/common/extHostLanguageFeatures'; import { ExtHostLanguages } from 'vs/workbench/api/common/extHostLanguages'; import { ExtHostMessageService } from 'vs/workbench/api/common/extHostMessageService'; import { IExtHostOutputService } from 'vs/workbench/api/common/extHostOutput'; @@ -82,11 +81,13 @@ import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSyste import { ExtHostTesting } from 'vs/workbench/api/common/extHostTesting'; import { ExtHostUriOpeners } from 'vs/workbench/api/common/extHostUriOpener'; import { IExtHostSecretState } from 'vs/workbench/api/common/exHostSecretState'; -import { ExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs'; +import { IExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs'; import { IExtHostTelemetry } from 'vs/workbench/api/common/extHostTelemetry'; import { ExtHostNotebookKernels } from 'vs/workbench/api/common/extHostNotebookKernels'; -import { RemoteTrustOption } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { TextSearchCompleteMessageType } from 'vs/workbench/services/search/common/searchExtTypes'; +import { ExtHostNotebookRenderers } from 'vs/workbench/api/common/extHostNotebookRenderers'; +import { Schemas } from 'vs/base/common/network'; +import { matchesScheme } from 'vs/platform/opener/common/opener'; export interface IExtensionApiFactory { (extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode; @@ -114,6 +115,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostApiDeprecation = accessor.get(IExtHostApiDeprecationService); const extHostWindow = accessor.get(IExtHostWindow); const extHostSecretState = accessor.get(IExtHostSecretState); + const extHostEditorTabs = accessor.get(IExtHostEditorTabs); // register addressable instances rpcProtocol.set(ExtHostContext.ExtHostFileSystemInfo, extHostFileSystemInfo); @@ -126,6 +128,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I rpcProtocol.set(ExtHostContext.ExtHostWindow, extHostWindow); rpcProtocol.set(ExtHostContext.ExtHostSecretState, extHostSecretState); rpcProtocol.set(ExtHostContext.ExtHostTelemetry, extHostTelemetry); + rpcProtocol.set(ExtHostContext.ExtHostEditorTabs, extHostEditorTabs); // automatically create and register addressable instances const extHostDecorations = rpcProtocol.set(ExtHostContext.ExtHostDecorations, accessor.get(IExtHostDecorations)); @@ -138,16 +141,16 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostOutputService = rpcProtocol.set(ExtHostContext.ExtHostOutputService, accessor.get(IExtHostOutputService)); // manually create and register addressable instances - const extHostEditorTabs = rpcProtocol.set(ExtHostContext.ExtHostEditorTabs, new ExtHostEditorTabs()); const extHostUrls = rpcProtocol.set(ExtHostContext.ExtHostUrls, new ExtHostUrls(rpcProtocol)); const extHostDocuments = rpcProtocol.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors)); const extHostDocumentContentProviders = rpcProtocol.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(rpcProtocol, extHostDocumentsAndEditors, extHostLogService)); const extHostDocumentSaveParticipant = rpcProtocol.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostLogService, extHostDocuments, rpcProtocol.getProxy(MainContext.MainThreadBulkEdits))); const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, extHostDocuments, extHostLogService, extensionStoragePaths)); - const extHostNotebookKernels = rpcProtocol.set(ExtHostContext.ExtHostNotebookKernels, new ExtHostNotebookKernels(rpcProtocol, initData, extHostNotebook)); + const extHostNotebookKernels = rpcProtocol.set(ExtHostContext.ExtHostNotebookKernels, new ExtHostNotebookKernels(rpcProtocol, initData, extHostNotebook, extHostLogService)); + const extHostNotebookRenderers = rpcProtocol.set(ExtHostContext.ExtHostNotebookRenderers, new ExtHostNotebookRenderers(rpcProtocol, extHostNotebook)); const extHostEditors = rpcProtocol.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(rpcProtocol, extHostDocumentsAndEditors)); const extHostTreeViews = rpcProtocol.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(rpcProtocol.getProxy(MainContext.MainThreadTreeViews), extHostCommands, extHostLogService)); - const extHostEditorInsets = rpcProtocol.set(ExtHostContext.ExtHostEditorInsets, new ExtHostEditorInsets(rpcProtocol.getProxy(MainContext.MainThreadEditorInsets), extHostEditors, initData.environment)); + const extHostEditorInsets = rpcProtocol.set(ExtHostContext.ExtHostEditorInsets, new ExtHostEditorInsets(rpcProtocol.getProxy(MainContext.MainThreadEditorInsets), extHostEditors, initData)); const extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol, extHostLogService)); const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, uriTransformer, extHostDocuments, extHostCommands, extHostDiagnostics, extHostLogService, extHostApiDeprecation)); const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures)); @@ -160,7 +163,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostTheming = rpcProtocol.set(ExtHostContext.ExtHostTheming, new ExtHostTheming(rpcProtocol)); const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol)); const extHostTimeline = rpcProtocol.set(ExtHostContext.ExtHostTimeline, new ExtHostTimeline(rpcProtocol, extHostCommands)); - const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol, initData.environment, extHostWorkspace, extHostLogService, extHostApiDeprecation)); + const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol, { remote: initData.remote }, extHostWorkspace, extHostLogService, extHostApiDeprecation)); const extHostWebviewPanels = rpcProtocol.set(ExtHostContext.ExtHostWebviewPanels, new ExtHostWebviewPanels(rpcProtocol, extHostWebviews, extHostWorkspace)); const extHostCustomEditors = rpcProtocol.set(ExtHostContext.ExtHostCustomEditors, new ExtHostCustomEditors(rpcProtocol, extHostDocuments, extensionStoragePaths, extHostWebviews, extHostWebviewPanels)); const extHostWebviewViews = rpcProtocol.set(ExtHostContext.ExtHostWebviewViews, new ExtHostWebviewViews(rpcProtocol, extHostWebviews)); @@ -216,7 +219,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I })(); const authentication: typeof vscode.authentication = { - getSession(providerId: string, scopes: string[], options?: vscode.AuthenticationGetSessionOptions) { + getSession(providerId: string, scopes: readonly string[], options?: vscode.AuthenticationGetSessionOptions) { return extHostAuthentication.getSession(extension, providerId, scopes, options as any); }, get onDidChangeSessions(): Event { @@ -295,7 +298,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I get uriScheme() { return initData.environment.appUriScheme; }, get clipboard(): vscode.Clipboard { return extHostClipboard.value; }, get shell() { - return extHostTerminalService.getDefaultShell(false, configProvider); + return extHostTerminalService.getDefaultShell(false); }, get isTelemetryEnabled() { return extHostTelemetry.getTelemetryEnabled(); @@ -313,12 +316,26 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I allowContributedOpeners: options?.allowContributedOpeners, }); }, - asExternalUri(uri: URI) { + async asExternalUri(uri: URI) { if (uri.scheme === initData.environment.appUriScheme) { return extHostUrls.createAppUri(uri); } - return extHostWindow.asExternalUri(uri, { allowTunneling: !!initData.remote.authority }); + const isHttp = matchesScheme(uri, Schemas.http) || matchesScheme(uri, Schemas.https); + + if (!isHttp) { + checkProposedApiEnabled(extension); // https://github.com/microsoft/vscode/issues/124263 + } + + try { + return await extHostWindow.asExternalUri(uri, { allowTunneling: !!initData.remote.authority }); + } catch (err) { + if (isHttp) { + return uri; + } + + throw err; + } }, get remoteName() { return getRemoteName(initData.remote.authority); @@ -479,6 +496,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, ...triggerCharacters: string[]): vscode.Disposable { return extHostLanguageFeatures.registerCompletionItemProvider(extension, checkSelector(selector), provider, triggerCharacters); }, + registerInlineCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.InlineCompletionItemProvider): vscode.Disposable { + checkProposedApiEnabled(extension); + return extHostLanguageFeatures.registerInlineCompletionsProvider(extension, checkSelector(selector), provider); + }, registerDocumentLinkProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable { return extHostLanguageFeatures.registerDocumentLinkProvider(extension, checkSelector(selector), provider); }, @@ -501,9 +522,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I checkProposedApiEnabled(extension); return extHostLanguages.tokenAtPosition(doc, pos); }, - registerInlineHintsProvider(selector: vscode.DocumentSelector, provider: vscode.InlineHintsProvider): vscode.Disposable { + registerInlayHintsProvider(selector: vscode.DocumentSelector, provider: vscode.InlayHintsProvider): vscode.Disposable { checkProposedApiEnabled(extension); - return extHostLanguageFeatures.registerInlineHintsProvider(extension, selector, provider); + return extHostLanguageFeatures.registerInlayHintsProvider(extension, selector, provider); } }; @@ -529,7 +550,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I return extHostEditors.showTextDocument(document, columnOrOptions, preserveFocus); }, createTextEditorDecorationType(options: vscode.DecorationRenderOptions): vscode.TextEditorDecorationType { - return extHostEditors.createTextEditorDecorationType(options); + return extHostEditors.createTextEditorDecorationType(extension, options); }, onDidChangeActiveTextEditor(listener, thisArg?, disposables?) { return extHostEditors.onDidChangeActiveTextEditor(listener, thisArg, disposables); @@ -596,25 +617,21 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I showSaveDialog(options) { return extHostDialogs.showSaveDialog(options); }, - createStatusBarItem(alignmentOrOptions?: vscode.StatusBarAlignment | vscode.StatusBarItemOptions, priority?: number): vscode.StatusBarItem { - let id: string; - let name: string; + createStatusBarItem(alignmentOrId?: vscode.StatusBarAlignment | string, priorityOrAlignment?: number | vscode.StatusBarAlignment, priorityArg?: number): vscode.StatusBarItem { + let id: string | undefined; let alignment: number | undefined; - let accessibilityInformation: vscode.AccessibilityInformation | undefined = undefined; + let priority: number | undefined; - if (alignmentOrOptions && typeof alignmentOrOptions !== 'number') { - id = alignmentOrOptions.id; - name = alignmentOrOptions.name; - alignment = alignmentOrOptions.alignment; - priority = alignmentOrOptions.priority; - accessibilityInformation = alignmentOrOptions.accessibilityInformation; + if (typeof alignmentOrId === 'string') { + id = alignmentOrId; + alignment = priorityOrAlignment; + priority = priorityArg; } else { - id = extension.identifier.value; - name = nls.localize('extensionLabel', "{0} (Extension)", extension.displayName || extension.name); - alignment = alignmentOrOptions; + alignment = alignmentOrId; + priority = priorityOrAlignment; } - return extHostStatusBar.createStatusBarEntry(id, name, alignment, priority, accessibilityInformation); + return extHostStatusBar.createStatusBarEntry(extension, id, alignment, priority); }, setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable): vscode.Disposable { return extHostStatusBar.setStatusBarMessage(text, timeoutOrThenable); @@ -643,18 +660,18 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I if ('pty' in nameOrOptions) { return extHostTerminalService.createExtensionTerminal(nameOrOptions); } - if (nameOrOptions.message) { - checkProposedApiEnabled(extension); - } - if (nameOrOptions.icon) { + if (nameOrOptions.iconPath) { checkProposedApiEnabled(extension); } return extHostTerminalService.createTerminalFromOptions(nameOrOptions); } return extHostTerminalService.createTerminal(nameOrOptions, shellPath, shellArgs); }, - registerTerminalLinkProvider(handler: vscode.TerminalLinkProvider): vscode.Disposable { - return extHostTerminalService.registerLinkProvider(handler); + registerTerminalLinkProvider(provider: vscode.TerminalLinkProvider): vscode.Disposable { + return extHostTerminalService.registerLinkProvider(provider); + }, + registerTerminalProfileProvider(id: string, provider: vscode.TerminalProfileProvider): vscode.Disposable { + return extHostTerminalService.registerProfileProvider(id, provider); }, registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider): vscode.Disposable { return extHostTreeViews.registerTreeDataProvider(viewId, treeDataProvider, extension); @@ -732,6 +749,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I get onDidChangeOpenEditors() { checkProposedApiEnabled(extension); return extHostEditorTabs.onDidChangeTabs; + }, + getInlineCompletionItemController(provider: vscode.InlineCompletionItemProvider): vscode.InlineCompletionController { + checkProposedApiEnabled(extension); + return InlineCompletionController.get(provider); } }; @@ -843,6 +864,34 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I onWillSaveTextDocument: (listener, thisArgs?, disposables?) => { return extHostDocumentSaveParticipant.getOnWillSaveTextDocumentEvent(extension)(listener, thisArgs, disposables); }, + get notebookDocuments(): vscode.NotebookDocument[] { + return extHostNotebook.notebookDocuments.map(d => d.apiNotebook); + }, + async openNotebookDocument(uriOrType?: URI | string, content?: vscode.NotebookData) { + let uri: URI; + if (URI.isUri(uriOrType)) { + uri = uriOrType; + await extHostNotebook.openNotebookDocument(uriOrType); + } else if (typeof uriOrType === 'string') { + uri = URI.revive(await extHostNotebook.createNotebookDocument({ viewType: uriOrType, content })); + } else { + throw new Error('Invalid arguments'); + } + return extHostNotebook.getNotebookDocument(uri).apiNotebook; + }, + get onDidOpenNotebookDocument(): Event { + return extHostNotebook.onDidOpenNotebookDocument; + }, + get onDidCloseNotebookDocument(): Event { + return extHostNotebook.onDidCloseNotebookDocument; + }, + registerNotebookSerializer(viewType: string, serializer: vscode.NotebookSerializer, options?: vscode.NotebookDocumentContentOptions, registration?: vscode.NotebookRegistrationData) { + return extHostNotebook.registerNotebookSerializer(extension, viewType, serializer, options, extension.enableProposedApi ? registration : undefined); + }, + registerNotebookContentProvider: (viewType: string, provider: vscode.NotebookContentProvider, options?: vscode.NotebookDocumentContentOptions, registration?: vscode.NotebookRegistrationData) => { + checkProposedApiEnabled(extension); + return extHostNotebook.registerNotebookContentProvider(extension, viewType, provider, options, extension.enableProposedApi ? registration : undefined); + }, onDidChangeConfiguration: (listener: (_: any) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => { return configProvider.onDidChangeConfiguration(listener, thisArgs, disposables); }, @@ -860,7 +909,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I return extHostTask.registerTaskProvider(extension, type, provider); }, registerFileSystemProvider(scheme, provider, options) { - return extHostFileSystem.registerFileSystemProvider(extension.identifier, scheme, provider, options); + return extHostFileSystem.registerFileSystemProvider(extension.identifier, scheme, provider, options, extension.enableProposedApi); }, get fs() { return extHostConsumerFileSystem.value; @@ -1000,10 +1049,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I stopDebugging(session?: vscode.DebugSession) { return extHostDebugService.stopDebugging(session); }, - addBreakpoints(breakpoints: vscode.Breakpoint[]) { + addBreakpoints(breakpoints: readonly vscode.Breakpoint[]) { return extHostDebugService.addBreakpoints(breakpoints); }, - removeBreakpoints(breakpoints: vscode.Breakpoint[]) { + removeBreakpoints(breakpoints: readonly vscode.Breakpoint[]) { return extHostDebugService.removeBreakpoints(breakpoints); }, asDebugSourceUri(source: vscode.DebugProtocolSource, session?: vscode.DebugSession): vscode.Uri { @@ -1039,43 +1088,25 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I }; // namespace: notebook - const notebook: typeof vscode.notebook = { - openNotebookDocument: (uriComponents) => { - checkProposedApiEnabled(extension); - return extHostNotebook.openNotebookDocument(uriComponents); + const notebooks: typeof vscode.notebooks = { + createNotebookController(id: string, notebookType: string, label: string, handler?, rendererScripts?: vscode.NotebookRendererScript[]) { + return extHostNotebookKernels.createNotebookController(extension, id, notebookType, label, handler, extension.enableProposedApi ? rendererScripts : undefined); }, - get onDidOpenNotebookDocument(): Event { - checkProposedApiEnabled(extension); - return extHostNotebook.onDidOpenNotebookDocument; - }, - get onDidCloseNotebookDocument(): Event { - checkProposedApiEnabled(extension); - return extHostNotebook.onDidCloseNotebookDocument; + registerNotebookCellStatusBarItemProvider: (notebookType: string, provider: vscode.NotebookCellStatusBarItemProvider) => { + return extHostNotebook.registerNotebookCellStatusBarItemProvider(extension, notebookType, provider); }, get onDidSaveNotebookDocument(): Event { checkProposedApiEnabled(extension); return extHostNotebook.onDidSaveNotebookDocument; }, - get notebookDocuments(): vscode.NotebookDocument[] { - checkProposedApiEnabled(extension); - return extHostNotebook.notebookDocuments.map(d => d.apiNotebook); - }, - registerNotebookSerializer(viewType, serializer, options) { - checkProposedApiEnabled(extension); - return extHostNotebook.registerNotebookSerializer(extension, viewType, serializer, options); - }, - registerNotebookContentProvider: (viewType, provider, options) => { - checkProposedApiEnabled(extension); - return extHostNotebook.registerNotebookContentProvider(extension, viewType, provider, options); - }, - registerNotebookCellStatusBarItemProvider: (selector: vscode.NotebookSelector, provider: vscode.NotebookCellStatusBarItemProvider) => { - checkProposedApiEnabled(extension); - return extHostNotebook.registerNotebookCellStatusBarItemProvider(extension, selector, provider); - }, createNotebookEditorDecorationType(options: vscode.NotebookDecorationRenderOptions): vscode.NotebookEditorDecorationType { checkProposedApiEnabled(extension); return extHostNotebook.createNotebookEditorDecorationType(options); }, + createRendererMessaging(rendererId) { + checkProposedApiEnabled(extension); + return extHostNotebookRenderers.createRendererMessaging(rendererId); + }, onDidChangeNotebookDocumentMetadata(listener, thisArgs?, disposables?) { checkProposedApiEnabled(extension); return extHostNotebook.onDidChangeNotebookDocumentMetadata(listener, thisArgs, disposables); @@ -1084,7 +1115,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I checkProposedApiEnabled(extension); return extHostNotebook.onDidChangeNotebookCells(listener, thisArgs, disposables); }, - onDidChangeCellExecutionState(listener, thisArgs?, disposables?) { + onDidChangeNotebookCellExecutionState(listener, thisArgs?, disposables?) { checkProposedApiEnabled(extension); return extHostNotebook.onDidChangeNotebookCellExecutionState(listener, thisArgs, disposables); }, @@ -1100,14 +1131,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I checkProposedApiEnabled(extension); return new ExtHostNotebookConcatDocument(extHostNotebook, extHostDocuments, notebook, selector); }, - createNotebookCellExecutionTask(uri: vscode.Uri, index: number, kernelId: string): vscode.NotebookCellExecutionTask | undefined { - checkProposedApiEnabled(extension); - return extHostNotebook.createNotebookCellExecution(uri, index, kernelId); - }, - createNotebookController(id, viewType, label, executeHandler, preloads) { - checkProposedApiEnabled(extension); - return extHostNotebookKernels.createNotebookController(extension, id, viewType, label, executeHandler, preloads); - } }; return { @@ -1120,7 +1143,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I env, extensions, languages, - notebook, + notebooks, scm, tasks, test, @@ -1173,6 +1196,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I InlineValueText: extHostTypes.InlineValueText, InlineValueVariableLookup: extHostTypes.InlineValueVariableLookup, InlineValueEvaluatableExpression: extHostTypes.InlineValueEvaluatableExpression, + InlineCompletionTriggerKind: extHostTypes.InlineCompletionTriggerKind, EventEmitter: Emitter, ExtensionKind: extHostTypes.ExtensionKind, ExtensionMode: extHostTypes.ExtensionMode, @@ -1181,9 +1205,12 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I FileDecoration: extHostTypes.FileDecoration, FileSystemError: extHostTypes.FileSystemError, FileType: files.FileType, + FilePermission: files.FilePermission, FoldingRange: extHostTypes.FoldingRange, FoldingRangeKind: extHostTypes.FoldingRangeKind, FunctionBreakpoint: extHostTypes.FunctionBreakpoint, + InlineCompletionItem: extHostTypes.InlineSuggestion, + InlineCompletionList: extHostTypes.InlineSuggestions, Hover: extHostTypes.Hover, IndentAction: languageConfiguration.IndentAction, Location: extHostTypes.Location, @@ -1236,10 +1263,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I ViewColumn: extHostTypes.ViewColumn, WorkspaceEdit: extHostTypes.WorkspaceEdit, // proposed api types - InlineHint: extHostTypes.InlineHint, - InlineHintKind: extHostTypes.InlineHintKind, + InlayHint: extHostTypes.InlayHint, + InlayHintKind: extHostTypes.InlayHintKind, RemoteAuthorityResolverError: extHostTypes.RemoteAuthorityResolverError, - RemoteTrustOption: RemoteTrustOption, ResolvedAuthority: extHostTypes.ResolvedAuthority, SourceControlInputBoxValidationType: extHostTypes.SourceControlInputBoxValidationType, ExtensionRuntime: extHostTypes.ExtensionRuntime, @@ -1247,16 +1273,16 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I NotebookRange: extHostTypes.NotebookRange, NotebookCellKind: extHostTypes.NotebookCellKind, NotebookCellExecutionState: extHostTypes.NotebookCellExecutionState, - NotebookDocumentMetadata: extHostTypes.NotebookDocumentMetadata, - NotebookCellMetadata: extHostTypes.NotebookCellMetadata, NotebookCellData: extHostTypes.NotebookCellData, NotebookData: extHostTypes.NotebookData, + NotebookRendererScript: extHostTypes.NotebookRendererScript, NotebookCellStatusBarAlignment: extHostTypes.NotebookCellStatusBarAlignment, NotebookEditorRevealType: extHostTypes.NotebookEditorRevealType, NotebookCellOutput: extHostTypes.NotebookCellOutput, NotebookCellOutputItem: extHostTypes.NotebookCellOutputItem, NotebookCellStatusBarItem: extHostTypes.NotebookCellStatusBarItem, NotebookControllerAffinity: extHostTypes.NotebookControllerAffinity, + PortAttributes: extHostTypes.PortAttributes, LinkedEditingRanges: extHostTypes.LinkedEditingRanges, TestItemStatus: extHostTypes.TestItemStatus, TestResultState: extHostTypes.TestResultState, diff --git a/lib/vscode/src/vs/workbench/api/common/extHost.common.services.ts b/src/vs/workbench/api/common/extHost.common.services.ts similarity index 95% rename from lib/vscode/src/vs/workbench/api/common/extHost.common.services.ts rename to src/vs/workbench/api/common/extHost.common.services.ts index bf894f0cfb4b..1ff423101e9d 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHost.common.services.ts +++ b/src/vs/workbench/api/common/extHost.common.services.ts @@ -23,6 +23,7 @@ import { IExtHostConsumerFileSystem, ExtHostConsumerFileSystem } from 'vs/workbe import { IExtHostFileSystemInfo, ExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo'; import { IExtHostSecretState, ExtHostSecretState } from 'vs/workbench/api/common/exHostSecretState'; import { ExtHostTelemetry, IExtHostTelemetry } from 'vs/workbench/api/common/extHostTelemetry'; +import { ExtHostEditorTabs, IExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs'; registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths); registerSingleton(IExtHostApiDeprecationService, ExtHostApiDeprecationService); @@ -43,3 +44,4 @@ registerSingleton(IExtHostWindow, ExtHostWindow); registerSingleton(IExtHostWorkspace, ExtHostWorkspace); registerSingleton(IExtHostSecretState, ExtHostSecretState); registerSingleton(IExtHostTelemetry, ExtHostTelemetry); +registerSingleton(IExtHostEditorTabs, ExtHostEditorTabs); diff --git a/lib/vscode/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts similarity index 94% rename from lib/vscode/src/vs/workbench/api/common/extHost.protocol.ts rename to src/vs/workbench/api/common/extHost.protocol.ts index f1a42cd27f37..a6bd90d90b8a 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as performance from 'vs/base/common/performance'; import { VSBuffer } from 'vs/base/common/buffer'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IRemoteConsoleLog } from 'vs/base/common/console'; @@ -11,7 +10,10 @@ import { SerializedError } from 'vs/base/common/errors'; import { IRelativePattern } from 'vs/base/common/glob'; import { IMarkdownString } from 'vs/base/common/htmlContent'; import { IDisposable } from 'vs/base/common/lifecycle'; +import { revive } from 'vs/base/common/marshalling'; +import * as performance from 'vs/base/common/performance'; import Severity from 'vs/base/common/severity'; +import { Dto } from 'vs/base/common/types'; import { URI, UriComponents } from 'vs/base/common/uri'; import { RenderLineNumbersType, TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions'; import { IPosition } from 'vs/editor/common/core/position'; @@ -22,8 +24,9 @@ import { EndOfLineSequence, ISingleEditOperation } from 'vs/editor/common/model' import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel'; import * as modes from 'vs/editor/common/modes'; import { CharacterPair, CommentRule, EnterAction } from 'vs/editor/common/modes/languageConfiguration'; +import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility'; import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; -import { ConfigurationTarget, IConfigurationData, IConfigurationChange, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; +import { ConfigurationTarget, IConfigurationChange, IConfigurationData, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration'; import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import * as files from 'vs/platform/files/common/files'; @@ -32,39 +35,34 @@ import { LogLevel } from 'vs/platform/log/common/log'; import { IMarkerData } from 'vs/platform/markers/common/markers'; import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress'; import * as quickInput from 'vs/platform/quickinput/common/quickInput'; -import { RemoteAuthorityResolverErrorCode, ResolverResult, TunnelDescription, IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import * as statusbar from 'vs/workbench/services/statusbar/common/statusbar'; +import { IRemoteConnectionData, RemoteAuthorityResolverErrorCode, ResolverResult, TunnelDescription } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { ProvidedPortAttributes, TunnelCreationOptions, TunnelOptions, TunnelProviderFeatures } from 'vs/platform/remote/common/tunnel'; import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; -import { ThemeColor } from 'vs/platform/theme/common/themeService'; +import { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions, ITerminalEnvironment, ITerminalLaunchError, ITerminalProfile } from 'vs/platform/terminal/common/terminal'; +import { ThemeColor, ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { IExtensionIdWithVersion } from 'vs/platform/userDataSync/common/extensionsStorageSync'; +import { WorkspaceTrustRequestOptions } from 'vs/platform/workspace/common/workspaceTrust'; +import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator'; +import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService'; +import { DebugConfigurationProviderTriggerKind, TestResultState } from 'vs/workbench/api/common/extHostTypes'; import * as tasks from 'vs/workbench/api/common/shared/tasks'; +import { EditorGroupColumn, SaveReason } from 'vs/workbench/common/editor'; import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views'; +import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; import { IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug'; +import { CellKind, ICellEditOperation, IImmediateCellEditOperation, IMainCellDto, INotebookCellStatusBarItem, INotebookContributionData, INotebookDecorationRenderOptions, IOutputDto, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookDataDto, NotebookDocumentMetadata, TransientCellMetadata, TransientDocumentMetadata, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange'; +import { InputValidationType } from 'vs/workbench/contrib/scm/common/scm'; import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder'; -import { ActivationKind, MissingExtensionDependency, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions'; +import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable'; +import { ExtensionRunTestsRequest, InternalTestItem, ISerializedTestResults, ITestItem, ITestMessage, ITestRunTask, RunTestForProviderRequest, RunTestsRequest, TestIdWithSrc, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection'; +import { InternalTimelineOptions, Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor } from 'vs/workbench/contrib/timeline/common/timeline'; +import { ActivationKind, ExtensionHostKind, MissingExtensionDependency } from 'vs/workbench/services/extensions/common/extensions'; 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 { EditorGroupColumn, SaveReason } from 'vs/workbench/common/editor'; -import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator'; -import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService'; -import { TunnelCreationOptions, TunnelProviderFeatures, TunnelOptions, ProvidedPortAttributes } from 'vs/platform/remote/common/tunnel'; -import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline'; -import { revive } from 'vs/base/common/marshalling'; -import { NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, TransientCellMetadata, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter, IOutputDto, TransientOptions, IImmediateCellEditOperation, INotebookCellStatusBarItem, TransientDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange'; -import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; -import { Dto } from 'vs/base/common/types'; -import { DebugConfigurationProviderTriggerKind, TestResultState } from 'vs/workbench/api/common/extHostTypes'; -import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility'; -import { IExtensionIdWithVersion } from 'vs/platform/userDataSync/common/extensionsStorageSync'; -import { InternalTestItem, RunTestForProviderRequest, RunTestsRequest, TestIdWithSrc, TestsDiff, ISerializedTestResults, ITestMessage, ITestItem, ITestRunTask, ExtensionRunTestsRequest } from 'vs/workbench/contrib/testing/common/testCollection'; import { CandidatePort } from 'vs/workbench/services/remote/common/remoteExplorerService'; -import { WorkspaceTrustRequestOptions } from 'vs/platform/workspace/common/workspaceTrust'; -import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable'; -import { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions, ITerminalEnvironment, ITerminalLaunchError } from 'vs/platform/terminal/common/terminal'; -import { ITerminalProfile } from 'vs/workbench/contrib/terminal/common/terminal'; -import { NotebookSelector } from 'vs/workbench/contrib/notebook/common/notebookSelector'; -import { InputValidationType } from 'vs/workbench/contrib/scm/common/scm'; +import * as search from 'vs/workbench/services/search/common/search'; +import * as statusbar from 'vs/workbench/services/statusbar/common/statusbar'; export interface IEnvironment { isExtensionDevelopmentDebug: boolean; @@ -76,8 +74,6 @@ export interface IEnvironment { extensionTestsLocationURI?: URI; globalStorageHome: URI; workspaceStorageHome: URI; - webviewResourceRoot: string; - webviewCspSource: string; useHostProxy?: boolean; } @@ -171,7 +167,7 @@ export interface MainThreadAuthenticationShape extends IDisposable { $unregisterAuthenticationProvider(id: string): void; $ensureProvider(id: string): Promise; $sendDidChangeSessions(providerId: string, event: modes.AuthenticationSessionsChangeEvent): void; - $getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: { createIfNone?: boolean, clearSessionPreference?: boolean }): Promise; + $getSession(providerId: string, scopes: readonly string[], extensionId: string, extensionName: string, options: { createIfNone?: boolean, clearSessionPreference?: boolean }): Promise; $removeSession(providerId: string, sessionId: string): Promise; } @@ -274,7 +270,7 @@ export interface MainThreadBulkEditsShape extends IDisposable { export interface MainThreadTextEditorsShape extends IDisposable { $tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): Promise; - $registerTextEditorDecorationType(key: string, options: editorCommon.IDecorationRenderOptions): void; + $registerTextEditorDecorationType(extensionId: ExtensionIdentifier, key: string, options: editorCommon.IDecorationRenderOptions): void; $removeTextEditorDecorationType(key: string): void; $tryShowEditor(id: string, position: EditorGroupColumn): Promise; $tryHideEditor(id: string): Promise; @@ -289,7 +285,7 @@ export interface MainThreadTextEditorsShape extends IDisposable { } export interface MainThreadTreeViewsShape extends IDisposable { - $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean; }): Promise; + $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean, canDragAndDrop: boolean; }): Promise; $refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem; }): Promise; $reveal(treeViewId: string, itemInfo: { item: ITreeItem, parentChain: ITreeItem[] } | undefined, options: IRevealOptions): Promise; $setMessage(treeViewId: string, message: string): void; @@ -371,6 +367,14 @@ export interface ISignatureHelpProviderMetadataDto { readonly retriggerCharacters: readonly string[]; } +export interface IdentifiableInlineCompletions extends modes.InlineCompletions { + pid: number; +} + +export interface IdentifiableInlineCompletion extends modes.InlineCompletion { + idx: number; +} + export interface MainThreadLanguageFeaturesShape extends IDisposable { $unregister(handle: number): void; $registerDocumentSymbolProvider(handle: number, selector: IDocumentFilterDto[], label: string): void; @@ -397,9 +401,10 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable { $emitDocumentSemanticTokensEvent(eventHandle: number): void; $registerDocumentRangeSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: modes.SemanticTokensLegend): void; $registerSuggestSupport(handle: number, selector: IDocumentFilterDto[], triggerCharacters: string[], supportsResolveDetails: boolean, displayName: string): void; + $registerInlineCompletionsSupport(handle: number, selector: IDocumentFilterDto[]): void; $registerSignatureHelpProvider(handle: number, selector: IDocumentFilterDto[], metadata: ISignatureHelpProviderMetadataDto): void; - $registerInlineHintsProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void; - $emitInlineHintsEvent(eventHandle: number, event?: any): void; + $registerInlayHintsProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void; + $emitInlayHintsEvent(eventHandle: number, event?: any): void; $registerDocumentLinkProvider(handle: number, selector: IDocumentFilterDto[], supportsResolve: boolean): void; $registerDocumentColorProvider(handle: number, selector: IDocumentFilterDto[]): void; $registerFoldingRangeProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void; @@ -458,7 +463,7 @@ export interface TerminalLaunchConfig { shellArgs?: string[] | string; cwd?: string | UriComponents; env?: ITerminalEnvironment; - icon?: string; + icon?: URI | { light: URI; dark: URI } | ThemeIcon; initialText?: string; waitOnExit?: boolean; strictEnv?: boolean; @@ -466,6 +471,8 @@ export interface TerminalLaunchConfig { isExtensionCustomPtyTerminal?: boolean; isFeatureTerminal?: boolean; isExtensionOwnedTerminal?: boolean; + useShellEnvironment?: boolean; + isSplitTerminal?: boolean; } export interface MainThreadTerminalServiceShape extends IDisposable { @@ -479,6 +486,8 @@ export interface MainThreadTerminalServiceShape extends IDisposable { $startLinkProvider(): void; $stopLinkProvider(): void; $registerProcessSupport(isSupported: boolean): void; + $registerProfileProvider(id: string): void; + $unregisterProfileProvider(id: string): void; $setEnvironmentVariableCollection(extensionIdentifier: string, persistent: boolean, collection: ISerializableEnvironmentVariableCollection | undefined): void; // Process @@ -623,7 +632,8 @@ export interface MainThreadEditorTabsShape extends IDisposable { export interface IEditorTabDto { group: number; name: string; - resource: UriComponents + resource: UriComponents; + isActive: boolean; } export interface IExtHostEditorTabsShape { @@ -647,7 +657,6 @@ export interface WebviewExtensionDescription { export interface NotebookExtensionDescription { readonly id: ExtensionIdentifier; readonly location: UriComponents; - readonly description?: string; } export enum WebviewEditorCapabilities { @@ -708,7 +717,7 @@ export interface WebviewMessageArrayBufferReference { export interface MainThreadWebviewsShape extends IDisposable { $setHtml(handle: WebviewHandle, value: string): void; $setOptions(handle: WebviewHandle, options: IWebviewOptions): void; - $postMessage(handle: WebviewHandle, value: any, ...buffers: VSBuffer[]): Promise + $postMessage(handle: WebviewHandle, value: string, ...buffers: VSBuffer[]): Promise } export interface MainThreadWebviewPanelsShape extends IDisposable { @@ -818,11 +827,6 @@ export interface ExtHostWebviewViewsShape { $disposeWebviewView(webviewHandle: WebviewHandle): void; } -export enum CellKind { - Markdown = 1, - Code = 2 -} - export enum CellOutputKind { Text = 1, Error = 2, @@ -873,19 +877,14 @@ export interface INotebookCellStatusBarListDto { } export interface MainThreadNotebookShape extends IDisposable { - $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: { - transientOutputs: boolean; - transientCellMetadata: TransientCellMetadata; - transientDocumentMetadata: TransientDocumentMetadata; - viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; }; - }): Promise; + $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: TransientOptions, registration: INotebookContributionData | undefined): Promise; $updateNotebookProviderOptions(viewType: string, options?: { transientOutputs: boolean; transientCellMetadata: TransientCellMetadata; transientDocumentMetadata: TransientDocumentMetadata; }): Promise; $unregisterNotebookProvider(viewType: string): Promise; - $registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions): void; + $registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions, registration: INotebookContributionData | undefined): void; $unregisterNotebookSerializer(handle: number): void; - $registerNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined, selector: NotebookSelector): Promise; + $registerNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined, viewType: string): Promise; $unregisterNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined): Promise; $emitCellStatusBarEvent(eventHandle: number): void; } @@ -900,14 +899,15 @@ export interface MainThreadNotebookEditorsShape extends IDisposable { } export interface MainThreadNotebookDocumentsShape extends IDisposable { - $tryOpenDocument(uriComponents: UriComponents): Promise; - $trySaveDocument(uri: UriComponents): Promise; + $tryCreateNotebook(options: { viewType: string, content?: NotebookDataDto }): Promise; + $tryOpenNotebook(uriComponents: UriComponents): Promise; + $trySaveNotebook(uri: UriComponents): Promise; $applyEdits(resource: UriComponents, edits: IImmediateCellEditOperation[], computeUndoRedo?: boolean): Promise; } export interface INotebookKernelDto2 { id: string; - viewType: string; + notebookType: string; extensionId: ExtensionIdentifier; extensionLocation: UriComponents; label: string; @@ -915,7 +915,7 @@ export interface INotebookKernelDto2 { description?: string; supportedLanguages?: string[]; supportsInterrupt?: boolean; - hasExecutionOrder?: boolean; + supportsExecutionOrder?: boolean; preloads?: { uri: UriComponents; provides: string[] }[]; } @@ -927,6 +927,10 @@ export interface MainThreadNotebookKernelsShape extends IDisposable { $updateNotebookPriority(handle: number, uri: UriComponents, value: number | undefined): void; } +export interface MainThreadNotebookRenderersShape extends IDisposable { + $postMessage(editorId: string, rendererId: string, message: unknown): void; +} + export interface MainThreadUrlsShape extends IDisposable { $registerUriHandler(handle: number, extensionId: ExtensionIdentifier): Promise; $unregisterUriHandler(handle: number): Promise; @@ -1229,6 +1233,7 @@ export interface ExtHostDocumentsAndEditorsShape { export interface ExtHostTreeViewsShape { $getChildren(treeViewId: string, treeItemHandle?: string): Promise; + $onDrop(treeViewId: string, treeItemHandle: string[], newParentTreeItemHandle: string): Promise; $setExpanded(treeViewId: string, treeItemHandle: string, expanded: boolean): void; $setSelection(treeViewId: string, treeItemHandles: string[]): void; $setVisible(treeViewId: string, visible: boolean): void; @@ -1305,6 +1310,7 @@ export type IResolveAuthorityResult = IResolveAuthorityErrorResult | IResolveAut export interface ExtHostExtensionServiceShape { $resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise; + $getCanonicalURI(remoteAuthority: string, uri: UriComponents): Promise; $startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise; $extensionTestsExecute(): Promise; $extensionTestsExit(code: number): Promise; @@ -1443,17 +1449,16 @@ export interface ISignatureHelpContextDto { readonly activeSignatureHelp?: ISignatureHelpDto; } -export interface IInlineHintDto { +export interface IInlayHintDto { text: string; - range: IRange; - kind: modes.InlineHintKind; + position: IPosition; + kind: modes.InlayHintKind; whitespaceBefore?: boolean; whitespaceAfter?: boolean; - hoverMessage?: string; } -export interface IInlineHintsDto { - hints: IInlineHintDto[] +export interface IInlayHintsDto { + hints: IInlayHintDto[] } export interface ILocationDto { @@ -1646,9 +1651,12 @@ export interface ExtHostLanguageFeaturesShape { $provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise; $resolveCompletionItem(handle: number, id: ChainedCacheId, token: CancellationToken): Promise; $releaseCompletionItems(handle: number, id: number): void; + $provideInlineCompletions(handle: number, resource: UriComponents, position: IPosition, context: modes.InlineCompletionContext, token: CancellationToken): Promise; + $handleInlineCompletionDidShow(handle: number, pid: number, idx: number): void; + $freeInlineCompletionsList(handle: number, pid: number): void; $provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Promise; $releaseSignatureHelp(handle: number, id: number): void; - $provideInlineHints(handle: number, resource: UriComponents, range: IRange, token: CancellationToken): Promise + $provideInlayHints(handle: number, resource: UriComponents, range: IRange, token: CancellationToken): Promise $provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise; $resolveDocumentLink(handle: number, id: ChainedCacheId, token: CancellationToken): Promise; $releaseDocumentLinks(handle: number, id: number): void; @@ -1679,11 +1687,6 @@ export interface ExtHostTelemetryShape { $onDidChangeTelemetryEnabled(enabled: boolean): void; } -export interface IShellAndArgsDto { - shell: string; - args: string[] | string | undefined; -} - export interface ITerminalLinkDto { /** The ID of the link to enable activation and disposal. */ id: number; @@ -1717,11 +1720,11 @@ export interface ExtHostTerminalServiceShape { $acceptProcessRequestInitialCwd(id: number): void; $acceptProcessRequestCwd(id: number): void; $acceptProcessRequestLatency(id: number): number; - $getAvailableProfiles(configuredProfilesOnly: boolean): Promise; - $getDefaultShellAndArgs(useAutomationShell: boolean): Promise; $provideLinks(id: number, line: string): Promise; $activateLink(id: number, linkId: number): void; $initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void; + $acceptDefaultProfile(profile: ITerminalProfile, automationProfile: ITerminalProfile): void; + $createContributedProfileTerminal(id: string, isSplitTerminal: boolean): Promise; } export interface ExtHostSCMShape { @@ -1740,7 +1743,6 @@ export interface ExtHostTaskShape { $onDidEndTaskProcess(value: tasks.TaskProcessEndedDTO): void; $OnDidEndTask(execution: tasks.TaskExecutionDTO): void; $resolveVariables(workspaceFolder: UriComponents, toResolve: { process?: { name: string; cwd?: string; }, variables: string[]; }): Promise<{ process?: string; variables: { [key: string]: string; }; }>; - $getDefaultShellAndArgs(): Thenable<{ shell: string, args: string[] | string | undefined; }>; $jsonTasksSupported(): Thenable; $findExecutable(command: string, cwd?: string, paths?: string[]): Promise; } @@ -1799,6 +1801,7 @@ export interface IDebugSessionFullDto { id: DebugSessionUUID; type: string; name: string; + parent: DebugSessionUUID | undefined; folderUri: UriComponents | undefined; configuration: IConfig; } @@ -1934,6 +1937,10 @@ export interface ExtHostNotebookShape extends ExtHostNotebookDocumentsAndEditors $notebookToData(handle: number, data: NotebookDataDto, token: CancellationToken): Promise; } +export interface ExtHostNotebookRenderersShape { + $postRendererMessage(editorId: string, rendererId: string, message: unknown): void; +} + export interface ExtHostNotebookDocumentsAndEditorsShape { $acceptDocumentAndEditorsDelta(delta: INotebookDocumentsAndEditorsDelta): void; } @@ -1953,10 +1960,10 @@ export interface ExtHostNotebookEditorsShape { } export interface ExtHostNotebookKernelsShape { - $acceptSelection(handle: number, uri: UriComponents, value: boolean): void; + $acceptNotebookAssociation(handle: number, uri: UriComponents, value: boolean): void; $executeCells(handle: number, uri: UriComponents, handles: number[]): Promise; $cancelCells(handle: number, uri: UriComponents, handles: number[]): Promise; - $acceptRendererMessage(handle: number, editorId: string, message: any): void; + $acceptKernelMessageFromRenderer(handle: number, editorId: string, message: any): void; } export interface ExtHostStorageShape { @@ -2087,6 +2094,7 @@ export const MainContext = { MainThreadNotebookDocuments: createMainId('MainThreadNotebookDocumentsShape'), MainThreadNotebookEditors: createMainId('MainThreadNotebookEditorsShape'), MainThreadNotebookKernels: createMainId('MainThreadNotebookKernels'), + MainThreadNotebookRenderers: createMainId('MainThreadNotebookRenderers'), MainThreadTheming: createMainId('MainThreadTheming'), MainThreadTunnelService: createMainId('MainThreadTunnelService'), MainThreadTimeline: createMainId('MainThreadTimeline'), @@ -2134,6 +2142,7 @@ export const ExtHostContext = { ExtHosLabelService: createMainId('ExtHostLabelService'), ExtHostNotebook: createMainId('ExtHostNotebook'), ExtHostNotebookKernels: createMainId('ExtHostNotebookKernels'), + ExtHostNotebookRenderers: createMainId('ExtHostNotebookRenderers'), ExtHostTheming: createMainId('ExtHostTheming'), ExtHostTunnelService: createMainId('ExtHostTunnelService'), ExtHostAuthentication: createMainId('ExtHostAuthentication'), diff --git a/lib/vscode/src/vs/workbench/api/common/extHostApiCommands.ts b/src/vs/workbench/api/common/extHostApiCommands.ts similarity index 90% rename from lib/vscode/src/vs/workbench/api/common/extHostApiCommands.ts rename to src/vs/workbench/api/common/extHostApiCommands.ts index f088f4ded9db..4fe87e99ca2a 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostApiCommands.ts +++ b/src/vs/workbench/api/common/extHostApiCommands.ts @@ -4,17 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { DisposableStore } from 'vs/base/common/lifecycle'; import type * as vscode from 'vscode'; import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import * as types from 'vs/workbench/api/common/extHostTypes'; import { IRawColorInfo, IWorkspaceEditDto, ICallHierarchyItemDto, IIncomingCallDto, IOutgoingCallDto } from 'vs/workbench/api/common/extHost.protocol'; import * as modes from 'vs/editor/common/modes'; import * as search from 'vs/workbench/contrib/search/common/search'; -import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; import { ApiCommand, ApiCommandArgument, ApiCommandResult, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; import { CustomCodeAction } from 'vs/workbench/api/common/extHostLanguageFeatures'; -import { ICommandsExecutor, RemoveFromRecentlyOpenedAPICommand, OpenIssueReporter, OpenIssueReporterArgs } from './apiCommands'; import { isFalsyOrEmpty } from 'vs/base/common/arrays'; import { IRange } from 'vs/editor/common/core/range'; import { IPosition } from 'vs/editor/common/core/position'; @@ -326,10 +323,10 @@ const newCommands: ApiCommand[] = [ ), // --- inline hints new ApiCommand( - 'vscode.executeInlineHintProvider', '_executeInlineHintProvider', 'Execute inline hints provider', + 'vscode.executeInlayHintProvider', '_executeInlayHintProvider', 'Execute inline hints provider', [ApiCommandArgument.Uri, ApiCommandArgument.Range], - new ApiCommandResult('A promise that resolves to an array of InlineHint objects', result => { - return result.map(typeConverters.InlineHint.to); + new ApiCommandResult('A promise that resolves to an array of Inlay objects', result => { + return result.map(typeConverters.InlayHint.to); }) ), // --- notebooks @@ -420,63 +417,8 @@ export class ExtHostApiCommands { static register(commands: ExtHostCommands) { newCommands.forEach(commands.registerApiCommand, commands); - return new ExtHostApiCommands(commands).registerCommands(); } - private _commands: ExtHostCommands; - private readonly _disposables = new DisposableStore(); - - private constructor(commands: ExtHostCommands) { - this._commands = commands; - } - - registerCommands() { - - - - - - // ----------------------------------------------------------------- - // The following commands are registered on both sides separately. - // - // We are trying to maintain backwards compatibility for cases where - // API commands are encoded as markdown links, for example. - // ----------------------------------------------------------------- - - type ICommandHandler = (...args: any[]) => any; - const adjustHandler = (handler: (executor: ICommandsExecutor, ...args: any[]) => any): ICommandHandler => { - return (...args: any[]) => { - return handler(this._commands, ...args); - }; - }; - - this._register(RemoveFromRecentlyOpenedAPICommand.ID, adjustHandler(RemoveFromRecentlyOpenedAPICommand.execute), { - description: 'Removes an entry with the given path from the recently opened list.', - args: [ - { name: 'path', description: 'Path to remove from recently opened.', constraint: (value: any) => typeof value === 'string' } - ] - }); - - this._register(OpenIssueReporter.ID, adjustHandler(OpenIssueReporter.execute), { - description: 'Opens the issue reporter with the provided extension id as the selected source', - args: [ - { name: 'extensionId', description: 'extensionId to report an issue on', constraint: (value: unknown) => typeof value === 'string' || (typeof value === 'object' && typeof (value as OpenIssueReporterArgs).extensionId === 'string') } - ] - }); - } - - // --- command impl - - /** - * @deprecated use the ApiCommand instead - */ - private _register(id: string, handler: (...args: any[]) => any, description?: ICommandHandlerDescription): void { - const disposable = this._commands.registerCommand(false, id, handler, this, description); - this._disposables.add(disposable); - } - - - } function tryMapWith(f: (x: T) => R) { diff --git a/lib/vscode/src/vs/workbench/api/common/extHostApiDeprecationService.ts b/src/vs/workbench/api/common/extHostApiDeprecationService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostApiDeprecationService.ts rename to src/vs/workbench/api/common/extHostApiDeprecationService.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostAuthentication.ts b/src/vs/workbench/api/common/extHostAuthentication.ts similarity index 92% rename from lib/vscode/src/vs/workbench/api/common/extHostAuthentication.ts rename to src/vs/workbench/api/common/extHostAuthentication.ts index be7640ce1d9a..c134a357403f 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostAuthentication.ts +++ b/src/vs/workbench/api/common/extHostAuthentication.ts @@ -48,11 +48,11 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape { return Object.freeze(this._providers.slice()); } - async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: string[], options: vscode.AuthenticationGetSessionOptions & { createIfNone: true }): Promise; - async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: string[], options: vscode.AuthenticationGetSessionOptions = {}): Promise { + async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: readonly string[], options: vscode.AuthenticationGetSessionOptions & { createIfNone: true }): Promise; + async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: readonly string[], options: vscode.AuthenticationGetSessionOptions = {}): Promise { const extensionId = ExtensionIdentifier.toKey(requestingExtension.identifier); const inFlightRequests = this._inFlightRequests.get(extensionId) || []; - const sortedScopes = scopes.sort().join(' '); + const sortedScopes = [...scopes].sort().join(' '); let inFlightRequest: GetSessionsRequest | undefined = inFlightRequests.find(request => request.scopes === sortedScopes); if (inFlightRequest) { @@ -81,7 +81,7 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape { } } - private async _getSession(requestingExtension: IExtensionDescription, extensionId: string, providerId: string, scopes: string[], options: vscode.AuthenticationGetSessionOptions = {}): Promise { + private async _getSession(requestingExtension: IExtensionDescription, extensionId: string, providerId: string, scopes: readonly string[], options: vscode.AuthenticationGetSessionOptions = {}): Promise { await this._proxy.$ensureProvider(providerId); const extensionName = requestingExtension.displayName || requestingExtension.name; return this._proxy.$getSession(providerId, scopes, extensionId, extensionName, options); diff --git a/lib/vscode/src/vs/workbench/api/common/extHostBulkEdits.ts b/src/vs/workbench/api/common/extHostBulkEdits.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostBulkEdits.ts rename to src/vs/workbench/api/common/extHostBulkEdits.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostClipboard.ts b/src/vs/workbench/api/common/extHostClipboard.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostClipboard.ts rename to src/vs/workbench/api/common/extHostClipboard.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostCodeInsets.ts b/src/vs/workbench/api/common/extHostCodeInsets.ts similarity index 93% rename from lib/vscode/src/vs/workbench/api/common/extHostCodeInsets.ts rename to src/vs/workbench/api/common/extHostCodeInsets.ts index 7db034cd81f9..fd7e9e715e53 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostCodeInsets.ts +++ b/src/vs/workbench/api/common/extHostCodeInsets.ts @@ -8,10 +8,9 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ExtHostTextEditor } from 'vs/workbench/api/common/extHostTextEditor'; import { ExtHostEditors } from 'vs/workbench/api/common/extHostTextEditors'; +import { asWebviewUri, webviewGenericCspSource, WebviewInitData } from 'vs/workbench/api/common/shared/webview'; import type * as vscode from 'vscode'; import { ExtHostEditorInsetsShape, MainThreadEditorInsetsShape } from './extHost.protocol'; -import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview'; -import { generateUuid } from 'vs/base/common/uuid'; export class ExtHostEditorInsets implements ExtHostEditorInsetsShape { @@ -61,16 +60,15 @@ export class ExtHostEditorInsets implements ExtHostEditorInsetsShape { const webview = new class implements vscode.Webview { - private readonly _uuid = generateUuid(); private _html: string = ''; private _options: vscode.WebviewOptions = Object.create(null); asWebviewUri(resource: vscode.Uri): vscode.Uri { - return asWebviewUri(that._initData, this._uuid, resource); + return asWebviewUri(resource, that._initData.remote); } get cspSource(): string { - return that._initData.webviewCspSource; + return webviewGenericCspSource; } set options(value: vscode.WebviewOptions) { diff --git a/lib/vscode/src/vs/workbench/api/common/extHostCommands.ts b/src/vs/workbench/api/common/extHostCommands.ts similarity index 98% rename from lib/vscode/src/vs/workbench/api/common/extHostCommands.ts rename to src/vs/workbench/api/common/extHostCommands.ts index 6d641f81fd22..14cb48998240 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostCommands.ts +++ b/src/vs/workbench/api/common/extHostCommands.ts @@ -166,12 +166,12 @@ export class ExtHostCommands implements ExtHostCommandsShape { const toArgs = cloneAndChange(args, function (value) { if (value instanceof extHostTypes.Position) { return extHostTypeConverter.Position.from(value); - } - if (value instanceof extHostTypes.Range) { + } else if (value instanceof extHostTypes.Range) { return extHostTypeConverter.Range.from(value); - } - if (value instanceof extHostTypes.Location) { + } else if (value instanceof extHostTypes.Location) { return extHostTypeConverter.location.from(value); + } else if (extHostTypes.NotebookRange.isNotebookRange(value)) { + return extHostTypeConverter.NotebookRange.from(value); } if (!Array.isArray(value)) { return value; diff --git a/lib/vscode/src/vs/workbench/api/common/extHostComments.ts b/src/vs/workbench/api/common/extHostComments.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostComments.ts rename to src/vs/workbench/api/common/extHostComments.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostConfiguration.ts b/src/vs/workbench/api/common/extHostConfiguration.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostConfiguration.ts rename to src/vs/workbench/api/common/extHostConfiguration.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostCustomEditors.ts b/src/vs/workbench/api/common/extHostCustomEditors.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostCustomEditors.ts rename to src/vs/workbench/api/common/extHostCustomEditors.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostCustomers.ts b/src/vs/workbench/api/common/extHostCustomers.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostCustomers.ts rename to src/vs/workbench/api/common/extHostCustomers.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostDebugService.ts b/src/vs/workbench/api/common/extHostDebugService.ts similarity index 96% rename from lib/vscode/src/vs/workbench/api/common/extHostDebugService.ts rename to src/vs/workbench/api/common/extHostDebugService.ts index 67477c58c5ca..406992259f6b 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostDebugService.ts +++ b/src/vs/workbench/api/common/extHostDebugService.ts @@ -31,6 +31,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions' import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { withNullAsUndefined } from 'vs/base/common/types'; import * as process from 'vs/base/common/process'; +import { IExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs'; export const IExtHostDebugService = createDecorator('IExtHostDebugService'); @@ -47,8 +48,8 @@ export interface IExtHostDebugService extends ExtHostDebugServiceShape { onDidChangeBreakpoints: Event; breakpoints: vscode.Breakpoint[]; - addBreakpoints(breakpoints0: vscode.Breakpoint[]): Promise; - removeBreakpoints(breakpoints0: vscode.Breakpoint[]): Promise; + addBreakpoints(breakpoints0: readonly vscode.Breakpoint[]): Promise; + removeBreakpoints(breakpoints0: readonly vscode.Breakpoint[]): Promise; startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration, options: vscode.DebugSessionOptions): Promise; stopDebugging(session?: vscode.DebugSession): Promise; registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider, trigger: vscode.DebugConfigurationProviderTriggerKind): vscode.Disposable; @@ -109,6 +110,7 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E @IExtHostExtensionService private _extensionService: IExtHostExtensionService, @IExtHostDocumentsAndEditors private _editorsService: IExtHostDocumentsAndEditors, @IExtHostConfiguration protected _configurationService: IExtHostConfiguration, + @IExtHostEditorTabs protected _editorTabs: IExtHostEditorTabs ) { this._configProviderHandleCounter = 0; this._configProviders = []; @@ -843,7 +845,8 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E let ds = this._debugSessions.get(dto.id); if (!ds) { const folder = await this.getFolder(dto.folderUri); - ds = new ExtHostDebugSession(this._debugServiceProxy, dto.id, dto.type, dto.name, folder, dto.configuration); + const parent = dto.parent ? this._debugSessions.get(dto.parent) : undefined; + ds = new ExtHostDebugSession(this._debugServiceProxy, dto.id, dto.type, dto.name, folder, dto.configuration, parent); this._debugSessions.set(ds.id, ds); this._debugServiceProxy.$sessionCached(ds.id); } @@ -870,7 +873,8 @@ export class ExtHostDebugSession implements vscode.DebugSession { private _type: string, private _name: string, private _workspaceFolder: vscode.WorkspaceFolder | undefined, - private _configuration: vscode.DebugConfiguration) { + private _configuration: vscode.DebugConfiguration, + private _parentSession: vscode.DebugSession | undefined) { } public get id(): string { @@ -884,12 +888,15 @@ export class ExtHostDebugSession implements vscode.DebugSession { public get name(): string { return this._name; } - public set name(name: string) { this._name = name; this._debugServiceProxy.$setDebugSessionName(this._id, name); } + public get parentSession(): vscode.DebugSession | undefined { + return this._parentSession; + } + _acceptNameChanged(name: string) { this._name = name; } @@ -930,7 +937,21 @@ export class ExtHostDebugConsole { export class ExtHostVariableResolverService extends AbstractVariableResolverService { - constructor(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors | undefined, configurationService: ExtHostConfigProvider, workspaceService?: IExtHostWorkspace) { + constructor(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors | undefined, configurationService: ExtHostConfigProvider, editorTabs: IExtHostEditorTabs, workspaceService?: IExtHostWorkspace) { + function getActiveUri(): URI | undefined { + if (editorService) { + const activeEditor = editorService.activeEditor(); + if (activeEditor) { + return activeEditor.document.uri; + } + const tabs = editorTabs.tabs.filter(tab => tab.isActive); + if (tabs.length > 0) { + return tabs[0].resource; + } + } + return undefined; + } + super({ getFolderUri: (folderName: string): URI | undefined => { const found = folders.filter(f => f.name === folderName); @@ -952,19 +973,17 @@ export class ExtHostVariableResolverService extends AbstractVariableResolverServ return process.env['VSCODE_EXEC_PATH']; }, getFilePath: (): string | undefined => { - if (editorService) { - const activeEditor = editorService.activeEditor(); - if (activeEditor) { - return path.normalize(activeEditor.document.uri.fsPath); - } + const activeUri = getActiveUri(); + if (activeUri) { + return path.normalize(activeUri.fsPath); } return undefined; }, getWorkspaceFolderPathForFile: (): string | undefined => { - if (editorService && workspaceService) { - const activeEditor = editorService.activeEditor(); - if (activeEditor) { - const ws = workspaceService.getWorkspaceFolder(activeEditor.document.uri); + if (workspaceService) { + const activeUri = getActiveUri(); + if (activeUri) { + const ws = workspaceService.getWorkspaceFolder(activeUri); if (ws) { return path.normalize(ws.uri.fsPath); } @@ -1076,12 +1095,13 @@ export class WorkerExtHostDebugService extends ExtHostDebugServiceBase { @IExtHostWorkspace workspaceService: IExtHostWorkspace, @IExtHostExtensionService extensionService: IExtHostExtensionService, @IExtHostDocumentsAndEditors editorsService: IExtHostDocumentsAndEditors, - @IExtHostConfiguration configurationService: IExtHostConfiguration + @IExtHostConfiguration configurationService: IExtHostConfiguration, + @IExtHostEditorTabs editorTabs: IExtHostEditorTabs ) { - super(extHostRpcService, workspaceService, extensionService, editorsService, configurationService); + super(extHostRpcService, workspaceService, extensionService, editorsService, configurationService, editorTabs); } protected createVariableResolver(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfigProvider): AbstractVariableResolverService { - return new ExtHostVariableResolverService(folders, editorService, configurationService); + return new ExtHostVariableResolverService(folders, editorService, configurationService, this._editorTabs); } } diff --git a/lib/vscode/src/vs/workbench/api/common/extHostDecorations.ts b/src/vs/workbench/api/common/extHostDecorations.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostDecorations.ts rename to src/vs/workbench/api/common/extHostDecorations.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostDiagnostics.ts b/src/vs/workbench/api/common/extHostDiagnostics.ts similarity index 95% rename from lib/vscode/src/vs/workbench/api/common/extHostDiagnostics.ts rename to src/vs/workbench/api/common/extHostDiagnostics.ts index 1114e309d858..39f05e7db201 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostDiagnostics.ts +++ b/src/vs/workbench/api/common/extHostDiagnostics.ts @@ -217,7 +217,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape { private readonly _collections = new Map(); private readonly _onDidChangeDiagnostics = new Emitter(); - static _debouncer(last: (vscode.Uri | string)[] | undefined, current: (vscode.Uri | string)[]): (vscode.Uri | string)[] { + static _debouncer(last: vscode.Uri[] | undefined, current: vscode.Uri[]): vscode.Uri[] { if (!last) { return current; } else { @@ -225,24 +225,12 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape { } } - static _mapper(last: (vscode.Uri | string)[]): { uris: vscode.Uri[] } { - const uris: vscode.Uri[] = []; - const map = new Set(); + static _mapper(last: vscode.Uri[]): { uris: readonly vscode.Uri[] } { + const map = new ResourceMap(); for (const uri of last) { - if (typeof uri === 'string') { - if (!map.has(uri)) { - map.add(uri); - uris.push(URI.parse(uri)); - } - } else { - if (!map.has(uri.toString())) { - map.add(uri.toString()); - uris.push(uri); - } - } + map.set(uri, uri); } - Object.freeze(uris); - return { uris }; + return { uris: Object.freeze(Array.from(map.values())) }; } readonly onDidChangeDiagnostics: Event = Event.map(Event.debounce(this._onDidChangeDiagnostics.event, ExtHostDiagnostics._debouncer, 50), ExtHostDiagnostics._mapper); diff --git a/lib/vscode/src/vs/workbench/api/common/extHostDialogs.ts b/src/vs/workbench/api/common/extHostDialogs.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostDialogs.ts rename to src/vs/workbench/api/common/extHostDialogs.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostDocumentContentProviders.ts b/src/vs/workbench/api/common/extHostDocumentContentProviders.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostDocumentContentProviders.ts rename to src/vs/workbench/api/common/extHostDocumentContentProviders.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostDocumentData.ts b/src/vs/workbench/api/common/extHostDocumentData.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostDocumentData.ts rename to src/vs/workbench/api/common/extHostDocumentData.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostDocumentSaveParticipant.ts b/src/vs/workbench/api/common/extHostDocumentSaveParticipant.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostDocumentSaveParticipant.ts rename to src/vs/workbench/api/common/extHostDocumentSaveParticipant.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostDocuments.ts b/src/vs/workbench/api/common/extHostDocuments.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostDocuments.ts rename to src/vs/workbench/api/common/extHostDocuments.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostDocumentsAndEditors.ts b/src/vs/workbench/api/common/extHostDocumentsAndEditors.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostDocumentsAndEditors.ts rename to src/vs/workbench/api/common/extHostDocumentsAndEditors.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostEditorTabs.ts b/src/vs/workbench/api/common/extHostEditorTabs.ts similarity index 67% rename from lib/vscode/src/vs/workbench/api/common/extHostEditorTabs.ts rename to src/vs/workbench/api/common/extHostEditorTabs.ts index 2d0f7b4c697f..1662754fd85e 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostEditorTabs.ts +++ b/src/vs/workbench/api/common/extHostEditorTabs.ts @@ -7,15 +7,25 @@ import type * as vscode from 'vscode'; import { IEditorTabDto, IExtHostEditorTabsShape } from 'vs/workbench/api/common/extHost.protocol'; import { URI } from 'vs/base/common/uri'; import { Emitter, Event } from 'vs/base/common/event'; - +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; export interface IEditorTab { name: string; group: number; resource: vscode.Uri + isActive: boolean +} + +export interface IExtHostEditorTabs extends IExtHostEditorTabsShape { + readonly _serviceBrand: undefined; + tabs: readonly IEditorTab[]; + onDidChangeTabs: Event; } -export class ExtHostEditorTabs implements IExtHostEditorTabsShape { +export const IExtHostEditorTabs = createDecorator('IExtHostEditorTabs'); + +export class ExtHostEditorTabs implements IExtHostEditorTabs { + readonly _serviceBrand: undefined; private readonly _onDidChangeTabs = new Emitter(); readonly onDidChangeTabs: Event = this._onDidChangeTabs.event; @@ -31,7 +41,8 @@ export class ExtHostEditorTabs implements IExtHostEditorTabsShape { return { name: dto.name, group: dto.group, - resource: URI.revive(dto.resource) + resource: URI.revive(dto.resource), + isActive: dto.isActive }; }); this._onDidChangeTabs.fire(); diff --git a/lib/vscode/src/vs/workbench/api/common/extHostExtensionActivator.ts b/src/vs/workbench/api/common/extHostExtensionActivator.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostExtensionActivator.ts rename to src/vs/workbench/api/common/extHostExtensionActivator.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts similarity index 96% rename from lib/vscode/src/vs/workbench/api/common/extHostExtensionService.ts rename to src/vs/workbench/api/common/extHostExtensionService.ts index d7c4c6a4e6f4..abb761d9dbee 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostExtensionService.ts +++ b/src/vs/workbench/api/common/extHostExtensionService.ts @@ -7,10 +7,10 @@ import * as nls from 'vs/nls'; import * as path from 'vs/base/common/path'; import * as performance from 'vs/base/common/performance'; import { originalFSPath, joinPath } from 'vs/base/common/resources'; -import { Barrier, timeout } from 'vs/base/common/async'; +import { asPromise, Barrier, timeout } from 'vs/base/common/async'; import { dispose, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; import { TernarySearchTree } from 'vs/base/common/map'; -import { URI } from 'vs/base/common/uri'; +import { URI, UriComponents } from 'vs/base/common/uri'; import { ILogService } from 'vs/platform/log/common/log'; import { ExtHostExtensionServiceShape, IInitData, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape, IResolveAuthorityResult } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostConfiguration, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration'; @@ -292,19 +292,19 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme try { if (typeof extension.module.deactivate === 'function') { result = Promise.resolve(extension.module.deactivate()).then(undefined, (err) => { - // TODO: Do something with err if this is not the shutdown case + this._logService.error(err); return Promise.resolve(undefined); }); } } catch (err) { - // TODO: Do something with err if this is not the shutdown case + this._logService.error(err); } // clean up subscriptions try { dispose(extension.subscriptions); } catch (err) { - // TODO: Do something with err if this is not the shutdown case + this._logService.error(err); } return result; @@ -631,7 +631,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme // -- called by main thread - public async $resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise { + private async _activateAndGetResolver(remoteAuthority: string): Promise<{ authorityPrefix: string; resolver: vscode.RemoteAuthorityResolver | undefined; }> { const authorityPlusIndex = remoteAuthority.indexOf('+'); if (authorityPlusIndex === -1) { throw new Error(`Not an authority that can be resolved!`); @@ -641,7 +641,12 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme await this._almostReadyToRunExtensions.wait(); await this._activateByEvent(`onResolveRemoteAuthority:${authorityPrefix}`, false); - const resolver = this._resolvers[authorityPrefix]; + return { authorityPrefix, resolver: this._resolvers[authorityPrefix] }; + } + + public async $resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise { + + const { authorityPrefix, resolver } = await this._activateAndGetResolver(remoteAuthority); if (!resolver) { return { type: 'error', @@ -668,7 +673,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme }; const options: ResolvedOptions = { extensionHostEnv: result.extensionHostEnv, - trust: result.trust + isTrusted: result.isTrusted }; return { @@ -695,6 +700,28 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme } } + public async $getCanonicalURI(remoteAuthority: string, uriComponents: UriComponents): Promise { + + const { authorityPrefix, resolver } = await this._activateAndGetResolver(remoteAuthority); + if (!resolver) { + throw new Error(`Cannot get canonical URI because no remote extension is installed to resolve ${authorityPrefix}`); + } + + const uri = URI.revive(uriComponents); + + if (typeof resolver.getCanonicalURI === 'undefined') { + // resolver cannot compute canonical URI + return uri; + } + + const result = await asPromise(() => resolver.getCanonicalURI!(uri)); + if (!result) { + return uri; + } + + return result; + } + public $startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise { this._registry.keepOnly(enabledExtensionIds); return this._startExtensionHost(); diff --git a/lib/vscode/src/vs/workbench/api/common/extHostFileSystem.ts b/src/vs/workbench/api/common/extHostFileSystem.ts similarity index 94% rename from lib/vscode/src/vs/workbench/api/common/extHostFileSystem.ts rename to src/vs/workbench/api/common/extHostFileSystem.ts index 462f181ba5b5..c3522c3f7900 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostFileSystem.ts +++ b/src/vs/workbench/api/common/extHostFileSystem.ts @@ -115,6 +115,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { private readonly _fsProvider = new Map(); private readonly _registeredSchemes = new Set(); private readonly _watches = new Map(); + private readonly _enableProposedApi = new Map(); private _linkProviderRegistration?: IDisposable; private _handlePool: number = 0; @@ -133,7 +134,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { } } - registerFileSystemProvider(extension: ExtensionIdentifier, scheme: string, provider: vscode.FileSystemProvider, options: { isCaseSensitive?: boolean, isReadonly?: boolean } = {}) { + registerFileSystemProvider(extension: ExtensionIdentifier, scheme: string, provider: vscode.FileSystemProvider, options: { isCaseSensitive?: boolean, isReadonly?: boolean } = {}, enableProposedApi?: boolean) { if (this._registeredSchemes.has(scheme)) { throw new Error(`a provider for the scheme '${scheme}' is already registered`); @@ -146,6 +147,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { this._linkProvider.add(scheme); this._registeredSchemes.add(scheme); this._fsProvider.set(handle, provider); + this._enableProposedApi.set(handle, enableProposedApi ?? false); let capabilities = files.FileSystemProviderCapabilities.FileReadWrite; if (options.isCaseSensitive) { @@ -200,17 +202,22 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape { this._linkProvider.delete(scheme); this._registeredSchemes.delete(scheme); this._fsProvider.delete(handle); + this._enableProposedApi.delete(handle); this._proxy.$unregisterProvider(handle); }); } - private static _asIStat(stat: vscode.FileStat): files.IStat { - const { type, ctime, mtime, size } = stat; - return { type, ctime, mtime, size }; + private static _asIStat(stat: vscode.FileStat, enableProposedApi: boolean): files.IStat { + const { type, ctime, mtime, size, permissions } = stat; + if (enableProposedApi) { + return { type, ctime, mtime, size, permissions }; + } else { + return { type, ctime, mtime, size }; + } } $stat(handle: number, resource: UriComponents): Promise { - return Promise.resolve(this._getFsProvider(handle).stat(URI.revive(resource))).then(ExtHostFileSystem._asIStat); + return Promise.resolve(this._getFsProvider(handle).stat(URI.revive(resource))).then(stat => ExtHostFileSystem._asIStat(stat, this._enableProposedApi.get(handle) ?? false)); } $readdir(handle: number, resource: UriComponents): Promise<[string, files.FileType][]> { diff --git a/lib/vscode/src/vs/workbench/api/common/extHostFileSystemConsumer.ts b/src/vs/workbench/api/common/extHostFileSystemConsumer.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostFileSystemConsumer.ts rename to src/vs/workbench/api/common/extHostFileSystemConsumer.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostFileSystemEventService.ts b/src/vs/workbench/api/common/extHostFileSystemEventService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostFileSystemEventService.ts rename to src/vs/workbench/api/common/extHostFileSystemEventService.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostFileSystemInfo.ts b/src/vs/workbench/api/common/extHostFileSystemInfo.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostFileSystemInfo.ts rename to src/vs/workbench/api/common/extHostFileSystemInfo.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostInitDataService.ts b/src/vs/workbench/api/common/extHostInitDataService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostInitDataService.ts rename to src/vs/workbench/api/common/extHostInitDataService.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostLabelService.ts b/src/vs/workbench/api/common/extHostLabelService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostLabelService.ts rename to src/vs/workbench/api/common/extHostLabelService.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts similarity index 93% rename from lib/vscode/src/vs/workbench/api/common/extHostLanguageFeatures.ts rename to src/vs/workbench/api/common/extHostLanguageFeatures.ts index 7fc9363feb79..05ab94c722c5 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -19,7 +19,7 @@ import { regExpLeadsToEndlessLoop, regExpFlags } from 'vs/base/common/strings'; import { IPosition } from 'vs/editor/common/core/position'; import { IRange, Range as EditorRange } from 'vs/editor/common/core/range'; import { isFalsyOrEmpty, isNonEmptyArray, coalesce, asArray } from 'vs/base/common/arrays'; -import { isObject } from 'vs/base/common/types'; +import { isArray, isObject } from 'vs/base/common/types'; import { ISelection, Selection } from 'vs/editor/common/core/selection'; import { ILogService } from 'vs/platform/log/common/log'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -33,6 +33,7 @@ import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostAp import { Cache } from './cache'; import { StopWatch } from 'vs/base/common/stopwatch'; import { CancellationError } from 'vs/base/common/errors'; +import { Emitter } from 'vs/base/common/event'; // --- adapter @@ -1038,6 +1039,99 @@ class SuggestAdapter { } } +class InlineCompletionAdapter { + private readonly _cache = new Cache('InlineCompletionItem'); + private readonly _disposables = new Map(); + + constructor( + private readonly _documents: ExtHostDocuments, + private readonly _provider: vscode.InlineCompletionItemProvider, + private readonly _commands: CommandsConverter, + ) { } + + public async provideInlineCompletions(resource: URI, position: IPosition, context: vscode.InlineCompletionContext, token: CancellationToken): Promise { + const doc = this._documents.getDocument(resource); + const pos = typeConvert.Position.to(position); + + const result = await asPromise(() => this._provider.provideInlineCompletionItems(doc, pos, context, token)); + + if (!result) { + // undefined and null are valid results + return undefined; + } + + if (token.isCancellationRequested) { + // cancelled -> return without further ado, esp no caching + // of results as they will leak + return undefined; + } + + const normalizedResult: vscode.InlineCompletionList = isArray(result) ? { items: result } : result; + + const pid = this._cache.add(normalizedResult.items); + let disposableStore: DisposableStore | undefined = undefined; + + return { + pid, + items: normalizedResult.items.map((item, idx) => { + let command: modes.Command | undefined = undefined; + if (item.command) { + if (!disposableStore) { + disposableStore = new DisposableStore(); + this._disposables.set(pid, disposableStore); + } + command = this._commands.toInternal(item.command, disposableStore); + } + + return ({ + text: item.text, + range: item.range ? typeConvert.Range.from(item.range) : undefined, + command, + idx: idx, + }); + }), + }; + } + + public disposeCompletions(pid: number) { + this._cache.delete(pid); + const d = this._disposables.get(pid); + if (d) { + d.clear(); + } + this._disposables.delete(pid); + } + + public handleDidShowCompletionItem(pid: number, idx: number): void { + const completionItem = this._cache.get(pid, idx); + if (completionItem) { + InlineCompletionController.get(this._provider).fireOnDidShowCompletionItem({ + completionItem + }); + } + } +} + +export class InlineCompletionController implements vscode.InlineCompletionController { + private static readonly map = new WeakMap, InlineCompletionController>(); + + public static get(provider: vscode.InlineCompletionItemProvider): InlineCompletionController { + let existing = InlineCompletionController.map.get(provider); + if (!existing) { + existing = new InlineCompletionController(); + InlineCompletionController.map.set(provider, existing); + } + return existing; + } + + private readonly _onDidShowCompletionItemEmitter = new Emitter>(); + public readonly onDidShowCompletionItem: vscode.Event> = this._onDidShowCompletionItemEmitter.event; + + public fireOnDidShowCompletionItem(event: vscode.InlineCompletionItemDidShowEvent): void { + this._onDidShowCompletionItemEmitter.fire(event); + } +} + class SignatureHelpAdapter { private readonly _cache = new Cache('SignatureHelp'); @@ -1082,16 +1176,16 @@ class SignatureHelpAdapter { } } -class InlineHintsAdapter { +class InlayHintsAdapter { constructor( private readonly _documents: ExtHostDocuments, - private readonly _provider: vscode.InlineHintsProvider, + private readonly _provider: vscode.InlayHintsProvider, ) { } - provideInlineHints(resource: URI, range: IRange, token: CancellationToken): Promise { + provideInlayHints(resource: URI, range: IRange, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); - return asPromise(() => this._provider.provideInlineHints(doc, typeConvert.Range.to(range), token)).then(value => { - return value ? { hints: value.map(typeConvert.InlineHint.from) } : undefined; + return asPromise(() => this._provider.provideInlayHints(doc, typeConvert.Range.to(range), token)).then(value => { + return value ? { hints: value.map(typeConvert.InlayHint.from) } : undefined; }); } } @@ -1355,7 +1449,7 @@ type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | Hov | TypeDefinitionAdapter | ColorProviderAdapter | FoldingProviderAdapter | DeclarationAdapter | SelectionRangeAdapter | CallHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter | EvaluatableExpressionAdapter | InlineValuesAdapter - | LinkedEditingRangeAdapter | InlineHintsAdapter; + | LinkedEditingRangeAdapter | InlayHintsAdapter | InlineCompletionAdapter; class AdapterData { constructor( @@ -1809,6 +1903,28 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF this._withAdapter(handle, SuggestAdapter, adapter => adapter.releaseCompletionItems(id), undefined); } + // --- ghost test + + registerInlineCompletionsProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.InlineCompletionItemProvider): vscode.Disposable { + const handle = this._addNewAdapter(new InlineCompletionAdapter(this._documents, provider, this._commands.converter), extension); + this._proxy.$registerInlineCompletionsSupport(handle, this._transformDocumentSelector(selector)); + return this._createDisposable(handle); + } + + $provideInlineCompletions(handle: number, resource: UriComponents, position: IPosition, context: modes.InlineCompletionContext, token: CancellationToken): Promise { + return this._withAdapter(handle, InlineCompletionAdapter, adapter => adapter.provideInlineCompletions(URI.revive(resource), position, context, token), undefined); + } + + $handleInlineCompletionDidShow(handle: number, pid: number, idx: number): void { + this._withAdapter(handle, InlineCompletionAdapter, async adapter => { + adapter.handleDidShowCompletionItem(pid, idx); + }, undefined); + } + + $freeInlineCompletionsList(handle: number, pid: number): void { + this._withAdapter(handle, InlineCompletionAdapter, async adapter => { adapter.disposeCompletions(pid); }, undefined); + } + // --- parameter hints registerSignatureHelpProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, metadataOrTriggerChars: string[] | vscode.SignatureHelpProviderMetadata): vscode.Disposable { @@ -1831,23 +1947,23 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF // --- inline hints - registerInlineHintsProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.InlineHintsProvider): vscode.Disposable { + registerInlayHintsProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.InlayHintsProvider): vscode.Disposable { - const eventHandle = typeof provider.onDidChangeInlineHints === 'function' ? this._nextHandle() : undefined; - const handle = this._addNewAdapter(new InlineHintsAdapter(this._documents, provider), extension); + const eventHandle = typeof provider.onDidChangeInlayHints === 'function' ? this._nextHandle() : undefined; + const handle = this._addNewAdapter(new InlayHintsAdapter(this._documents, provider), extension); - this._proxy.$registerInlineHintsProvider(handle, this._transformDocumentSelector(selector), eventHandle); + this._proxy.$registerInlayHintsProvider(handle, this._transformDocumentSelector(selector), eventHandle); let result = this._createDisposable(handle); if (eventHandle !== undefined) { - const subscription = provider.onDidChangeInlineHints!(_ => this._proxy.$emitInlineHintsEvent(eventHandle)); + const subscription = provider.onDidChangeInlayHints!(_ => this._proxy.$emitInlayHintsEvent(eventHandle)); result = Disposable.from(result, subscription); } return result; } - $provideInlineHints(handle: number, resource: UriComponents, range: IRange, token: CancellationToken): Promise { - return this._withAdapter(handle, InlineHintsAdapter, adapter => adapter.provideInlineHints(URI.revive(resource), range, token), undefined); + $provideInlayHints(handle: number, resource: UriComponents, range: IRange, token: CancellationToken): Promise { + return this._withAdapter(handle, InlayHintsAdapter, adapter => adapter.provideInlayHints(URI.revive(resource), range, token), undefined); } // --- links diff --git a/lib/vscode/src/vs/workbench/api/common/extHostLanguages.ts b/src/vs/workbench/api/common/extHostLanguages.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostLanguages.ts rename to src/vs/workbench/api/common/extHostLanguages.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostMemento.ts b/src/vs/workbench/api/common/extHostMemento.ts similarity index 92% rename from lib/vscode/src/vs/workbench/api/common/extHostMemento.ts rename to src/vs/workbench/api/common/extHostMemento.ts index 31c1676e6963..e4f029c0b126 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostMemento.ts +++ b/src/vs/workbench/api/common/extHostMemento.ts @@ -56,6 +56,11 @@ export class ExtensionMemento implements vscode.Memento { }, 0); } + get keys(): readonly string[] { + // Filter out `undefined` values, as they can stick around in the `_value` until the `onDidChangeStorage` event runs + return Object.entries(this._value ?? {}).filter(([, value]) => value !== undefined).map(([key]) => key); + } + get whenReady(): Promise { return this._init; } diff --git a/lib/vscode/src/vs/workbench/api/common/extHostMessageService.ts b/src/vs/workbench/api/common/extHostMessageService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostMessageService.ts rename to src/vs/workbench/api/common/extHostMessageService.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts similarity index 67% rename from lib/vscode/src/vs/workbench/api/common/extHostNotebook.ts rename to src/vs/workbench/api/common/extHostNotebook.ts index 116b80d14c0e..e220a0d6f00e 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -3,14 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { timeout } from 'vs/base/common/async'; import { VSBuffer } from 'vs/base/common/buffer'; -import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; +import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter, Event } from 'vs/base/common/event'; import { IRelativePattern } from 'vs/base/common/glob'; import { hash } from 'vs/base/common/hash'; import { IdGenerator } from 'vs/base/common/idGenerator'; -import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ResourceMap } from 'vs/base/common/map'; import { isFalsyOrWhitespace } from 'vs/base/common/strings'; import { assertIsDefined } from 'vs/base/common/types'; @@ -25,7 +24,7 @@ import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocum import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths'; import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import * as extHostTypes from 'vs/workbench/api/common/extHostTypes'; -import { CellEditType, IImmediateCellEditOperation, INotebookExclusiveDocumentFilter, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookDataDto, NullablePartialNotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookExclusiveDocumentFilter, INotebookContributionData, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookDataDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import type * as vscode from 'vscode'; import { ExtHostCell, ExtHostNotebookDocument } from './extHostNotebookDocument'; import { ExtHostNotebookEditor } from './extHostNotebookEditor'; @@ -103,8 +102,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { private _onDidChangeVisibleNotebookEditors = new Emitter(); onDidChangeVisibleNotebookEditors = this._onDidChangeVisibleNotebookEditors.event; - private _activeExecutions = new ResourceMap(); - private _statusBarCache = new Cache('NotebookCellStatusBarCache'); constructor( @@ -155,13 +152,11 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { return [...this._documents.values()]; } - lookupNotebookDocument(uri: URI): ExtHostNotebookDocument | undefined { - return this._documents.get(uri); - } - - private _getNotebookDocument(uri: URI): ExtHostNotebookDocument { + getNotebookDocument(uri: URI, relaxed: true): ExtHostNotebookDocument | undefined; + getNotebookDocument(uri: URI): ExtHostNotebookDocument; + getNotebookDocument(uri: URI, relaxed?: true): ExtHostNotebookDocument | undefined { const result = this._documents.get(uri); - if (!result) { + if (!result && !relaxed) { throw new Error(`NO notebook document for '${uri}'`); } return result; @@ -179,13 +174,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { extension: IExtensionDescription, viewType: string, provider: vscode.NotebookContentProvider, - options?: vscode.NotebookDocumentContentOptions & { - viewOptions?: { - displayName: string; - filenamePattern: (vscode.GlobPattern | { include: vscode.GlobPattern; exclude: vscode.GlobPattern })[]; - exclusive?: boolean; - }; - } + options?: vscode.NotebookDocumentContentOptions, + registration?: vscode.NotebookRegistrationData ): vscode.Disposable { if (isFalsyOrWhitespace(viewType)) { throw new Error(`viewType cannot be empty or just whitespace`); @@ -196,7 +186,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { this._notebookContentProviders.set(viewType, { extension, provider }); - let listener: IDisposable | undefined; if (provider.onDidChangeNotebookContentOptions) { listener = provider.onDidChangeNotebookContentOptions(() => { @@ -205,21 +194,12 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { }); } - const viewOptionsFilenamePattern = options?.viewOptions?.filenamePattern - .map(pattern => typeConverters.NotebookExclusiveDocumentPattern.from(pattern)) - .filter(pattern => pattern !== undefined) as (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; - - if (options?.viewOptions?.filenamePattern && !viewOptionsFilenamePattern) { - console.warn(`Notebook content provider view options file name pattern is invalid ${options?.viewOptions?.filenamePattern}`); - } - - const internalOptions = typeConverters.NotebookDocumentContentOptions.from(options); - this._notebookProxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, viewType, { - transientOutputs: internalOptions.transientOutputs, - transientCellMetadata: internalOptions.transientCellMetadata, - transientDocumentMetadata: internalOptions.transientDocumentMetadata, - viewOptions: options?.viewOptions && viewOptionsFilenamePattern ? { displayName: options.viewOptions.displayName, filenamePattern: viewOptionsFilenamePattern, exclusive: options.viewOptions.exclusive || false } : undefined - }); + this._notebookProxy.$registerNotebookProvider( + { id: extension.identifier, location: extension.extensionLocation }, + viewType, + typeConverters.NotebookDocumentContentOptions.from(options), + ExtHostNotebookController._convertNotebookRegistrationData(extension, registration) + ); return new extHostTypes.Disposable(() => { listener?.dispose(); @@ -228,13 +208,33 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { }); } - registerNotebookCellStatusBarItemProvider(extension: IExtensionDescription, selector: vscode.NotebookSelector, provider: vscode.NotebookCellStatusBarItemProvider) { + private static _convertNotebookRegistrationData(extension: IExtensionDescription, registration: vscode.NotebookRegistrationData | undefined): INotebookContributionData | undefined { + if (!registration) { + return; + } + const viewOptionsFilenamePattern = registration.filenamePattern + .map(pattern => typeConverters.NotebookExclusiveDocumentPattern.from(pattern)) + .filter(pattern => pattern !== undefined) as (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; + if (registration.filenamePattern && !viewOptionsFilenamePattern) { + console.warn(`Notebook content provider view options file name pattern is invalid ${registration.filenamePattern}`); + return undefined; + } + return { + extension: extension.identifier, + providerDisplayName: extension.displayName || extension.name, + displayName: registration.displayName, + filenamePattern: viewOptionsFilenamePattern, + exclusive: registration.exclusive || false + }; + } + + registerNotebookCellStatusBarItemProvider(extension: IExtensionDescription, notebookType: string, provider: vscode.NotebookCellStatusBarItemProvider) { const handle = ExtHostNotebookController._notebookStatusBarItemProviderHandlePool++; const eventHandle = typeof provider.onDidChangeCellStatusBarItems === 'function' ? ExtHostNotebookController._notebookStatusBarItemProviderHandlePool++ : undefined; this._notebookStatusBarItemProviders.set(handle, provider); - this._notebookProxy.$registerNotebookCellStatusBarItemProvider(handle, eventHandle, selector); + this._notebookProxy.$registerNotebookCellStatusBarItemProvider(handle, eventHandle, notebookType); let subscription: vscode.Disposable | undefined; if (eventHandle !== undefined) { @@ -254,12 +254,20 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { return new NotebookEditorDecorationType(this._notebookEditorsProxy, options).value; } + async createNotebookDocument(options: { viewType: string, content?: vscode.NotebookData }): Promise { + const canonicalUri = await this._notebookDocumentsProxy.$tryCreateNotebook({ + viewType: options.viewType, + content: options.content && typeConverters.NotebookData.from(options.content) + }); + return URI.revive(canonicalUri); + } + async openNotebookDocument(uri: URI): Promise { const cached = this._documents.get(uri); if (cached) { return cached.apiNotebook; } - const canonicalUri = await this._notebookDocumentsProxy.$tryOpenDocument(uri); + const canonicalUri = await this._notebookDocumentsProxy.$tryOpenNotebook(uri); const document = this._documents.get(URI.revive(canonicalUri)); return assertIsDefined(document?.apiNotebook); } @@ -285,7 +293,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { }; } - const editorId = await this._notebookEditorsProxy.$tryShowNotebookDocument(notebookOrUri.uri, notebookOrUri.viewType, resolvedOptions); + const editorId = await this._notebookEditorsProxy.$tryShowNotebookDocument(notebookOrUri.uri, notebookOrUri.notebookType, resolvedOptions); const editor = editorId && this._editors.get(editorId)?.apiEditor; if (editor) { @@ -293,9 +301,9 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { } if (editorId) { - throw new Error(`Could NOT open editor for "${notebookOrUri.toString()}" because another editor opened in the meantime.`); + throw new Error(`Could NOT open editor for "${notebookOrUri.uri.toString()}" because another editor opened in the meantime.`); } else { - throw new Error(`Could NOT open editor for "${notebookOrUri.toString()}".`); + throw new Error(`Could NOT open editor for "${notebookOrUri.uri.toString()}".`); } } @@ -319,7 +327,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { const disposables = new DisposableStore(); const cacheId = this._statusBarCache.add([disposables]); - const items = (result && result.map(item => typeConverters.NotebookStatusBarItem.from(item, this._commandsConverter, disposables))) ?? undefined; + const resultArr = Array.isArray(result) ? result : [result]; + const items = resultArr.map(item => typeConverters.NotebookStatusBarItem.from(item, this._commandsConverter, disposables)); return { cacheId, items @@ -335,18 +344,18 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { private _handlePool = 0; private readonly _notebookSerializer = new Map(); - registerNotebookSerializer(extension: IExtensionDescription, viewType: string, serializer: vscode.NotebookSerializer, options?: vscode.NotebookDocumentContentOptions): vscode.Disposable { + registerNotebookSerializer(extension: IExtensionDescription, viewType: string, serializer: vscode.NotebookSerializer, options?: vscode.NotebookDocumentContentOptions, registration?: vscode.NotebookRegistrationData): vscode.Disposable { if (isFalsyOrWhitespace(viewType)) { throw new Error(`viewType cannot be empty or just whitespace`); } const handle = this._handlePool++; this._notebookSerializer.set(handle, serializer); - const internalOptions = typeConverters.NotebookDocumentContentOptions.from(options); this._notebookProxy.$registerNotebookSerializer( handle, - { id: extension.identifier, location: extension.extensionLocation, description: extension.description }, + { id: extension.identifier, location: extension.extensionLocation }, viewType, - internalOptions + typeConverters.NotebookDocumentContentOptions.from(options), + ExtHostNotebookController._convertNotebookRegistrationData(extension, registration) ); return toDisposable(() => { this._notebookProxy.$unregisterNotebookSerializer(handle); @@ -359,10 +368,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { throw new Error('NO serializer found'); } const data = await serializer.deserializeNotebook(bytes.buffer, token); - return { - metadata: typeConverters.NotebookDocumentMetadata.from(data.metadata), - cells: data.cells.map(typeConverters.NotebookCellData.from), - }; + return typeConverters.NotebookData.from(data); } async $notebookToData(handle: number, data: NotebookDataDto, token: CancellationToken): Promise { @@ -370,38 +376,30 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { if (!serializer) { throw new Error('NO serializer found'); } - const bytes = await serializer.serializeNotebook({ - metadata: typeConverters.NotebookDocumentMetadata.to(data.metadata), - cells: data.cells.map(typeConverters.NotebookCellData.to) - }, token); + const bytes = await serializer.serializeNotebook(typeConverters.NotebookData.to(data), token); return VSBuffer.wrap(bytes); } - cancelOneNotebookCellExecution(cell: ExtHostCell): void { - const execution = this._activeExecutions.get(cell.uri); - execution?.cancel(); - } - // --- open, save, saveAs, backup async $openNotebook(viewType: string, uri: UriComponents, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken): Promise { const { provider } = this._getProviderData(viewType); const data = await provider.openNotebook(URI.revive(uri), { backupId, untitledDocumentData: untitledDocumentData?.buffer }, token); return { - metadata: typeConverters.NotebookDocumentMetadata.from(data.metadata), + metadata: data.metadata ?? Object.create(null), cells: data.cells.map(typeConverters.NotebookCellData.from), }; } async $saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise { - const document = this._getNotebookDocument(URI.revive(uri)); + const document = this.getNotebookDocument(URI.revive(uri)); const { provider } = this._getProviderData(viewType); await provider.saveNotebook(document.apiNotebook, token); return true; } async $saveNotebookAs(viewType: string, uri: UriComponents, target: UriComponents, token: CancellationToken): Promise { - const document = this._getNotebookDocument(URI.revive(uri)); + const document = this.getNotebookDocument(URI.revive(uri)); const { provider } = this._getProviderData(viewType); await provider.saveNotebookAs(URI.revive(target), document.apiNotebook, token); return true; @@ -410,7 +408,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { private _backupIdPool: number = 0; async $backupNotebook(viewType: string, uri: UriComponents, cancellation: CancellationToken): Promise { - const document = this._getNotebookDocument(URI.revive(uri)); + const document = this.getNotebookDocument(URI.revive(uri)); const provider = this._getProviderData(viewType); const storagePath = this._extensionStoragePaths.workspaceValue(provider.extension) ?? this._extensionStoragePaths.globalValue(provider.extension); @@ -423,17 +421,17 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { } $acceptModelChanged(uri: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void { - const document = this._getNotebookDocument(URI.revive(uri)); + const document = this.getNotebookDocument(URI.revive(uri)); document.acceptModelChanged(event, isDirty); } $acceptDirtyStateChanged(uri: UriComponents, isDirty: boolean): void { - const document = this._getNotebookDocument(URI.revive(uri)); + const document = this.getNotebookDocument(URI.revive(uri)); document.acceptModelChanged({ rawEvents: [], versionId: document.apiNotebook.version }, isDirty); } $acceptModelSaved(uri: UriComponents): void { - const document = this._getNotebookDocument(URI.revive(uri)); + const document = this.getNotebookDocument(URI.revive(uri)); this._onDidSaveNotebookDocument.fire(document.apiNotebook); } @@ -480,7 +478,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { $acceptDocumentPropertiesChanged(uri: UriComponents, data: INotebookDocumentPropertiesChangeData): void { this.logService.debug('ExtHostNotebook#$acceptDocumentPropertiesChanged', uri.path, data); - const document = this._getNotebookDocument(URI.revive(uri)); + const document = this.getNotebookDocument(URI.revive(uri)); document.acceptDocumentPropertiesChanged(data); if (data.metadata) { this._onDidChangeNotebookDocumentMetadata.fire({ document: document.apiNotebook }); @@ -559,7 +557,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { } }, viewType, - modelData.metadata ? typeConverters.NotebookDocumentMetadata.to(modelData.metadata) : new extHostTypes.NotebookDocumentMetadata(), + modelData.metadata ?? Object.create({}), uri, ); @@ -639,213 +637,4 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { this._onDidChangeActiveNotebookEditor.fire(this._activeNotebookEditor?.apiEditor); } } - createNotebookCellExecution(docUri: vscode.Uri, index: number, kernelId: string): vscode.NotebookCellExecutionTask | undefined { - const document = this.lookupNotebookDocument(docUri); - if (!document) { - throw new Error(`Invalid uri: ${docUri} `); - } - - const cell = document.getCellFromIndex(index); - if (!cell) { - throw new Error(`Invalid cell index: ${docUri}, ${index} `); - } - - // TODO@roblou also validate kernelId, once kernel has moved from editor to document - if (this._activeExecutions.has(cell.uri)) { - throw new Error(`duplicate execution for ${cell.uri}`); - } - - const execution = new NotebookCellExecutionTask(docUri, document, cell, this._notebookDocumentsProxy); - this._activeExecutions.set(cell.uri, execution); - const listener = execution.onDidChangeState(() => { - if (execution.state === NotebookCellExecutionTaskState.Resolved) { - execution.dispose(); - listener.dispose(); - this._activeExecutions.delete(cell.uri); - } - }); - - return execution.asApiObject(); - } -} - -enum NotebookCellExecutionTaskState { - Init, - Started, - Resolved -} - -class NotebookCellExecutionTask extends Disposable { - private _onDidChangeState = new Emitter(); - readonly onDidChangeState = this._onDidChangeState.event; - - private _state = NotebookCellExecutionTaskState.Init; - get state(): NotebookCellExecutionTaskState { return this._state; } - - private readonly _tokenSource = this._register(new CancellationTokenSource()); - - private readonly _collector: TimeoutBasedCollector; - - private _executionOrder: number | undefined; - - constructor( - private readonly _uri: vscode.Uri, - private readonly _document: ExtHostNotebookDocument, - private readonly _cell: ExtHostCell, - private readonly _proxy: MainThreadNotebookDocumentsShape) { - super(); - - this._collector = new TimeoutBasedCollector(10, edits => this.applyEdits(edits)); - - this._executionOrder = _cell.internalMetadata.executionOrder; - this.mixinMetadata({ - runState: extHostTypes.NotebookCellExecutionState.Pending, - executionOrder: null - }); - } - - cancel(): void { - this._tokenSource.cancel(); - } - - private async applyEditSoon(edit: IImmediateCellEditOperation): Promise { - await this._collector.addItem(edit); - } - - private async applyEdits(edits: IImmediateCellEditOperation[]): Promise { - return this._proxy.$applyEdits(this._uri, edits, false); - } - - private verifyStateForOutput() { - if (this._state === NotebookCellExecutionTaskState.Init) { - throw new Error('Must call start before modifying cell output'); - } - - if (this._state === NotebookCellExecutionTaskState.Resolved) { - throw new Error('Cannot modify cell output after calling resolve'); - } - } - - private mixinMetadata(mixinMetadata: NullablePartialNotebookCellMetadata) { - const edit: IImmediateCellEditOperation = { editType: CellEditType.PartialMetadata, handle: this._cell.handle, metadata: mixinMetadata }; - this.applyEdits([edit]); - } - - private cellIndexToHandle(cellIndex: number | undefined): number | undefined { - const cell = typeof cellIndex === 'number' ? this._document.getCellFromIndex(cellIndex) : this._cell; - if (!cell) { - return; - } - - return cell.handle; - } - - asApiObject(): vscode.NotebookCellExecutionTask { - const that = this; - return Object.freeze({ - get document() { return that._document.apiNotebook; }, - get cell() { return that._cell.apiCell; }, - - get executionOrder() { return that._executionOrder; }, - set executionOrder(v: number | undefined) { - that._executionOrder = v; - that.mixinMetadata({ - executionOrder: v - }); - }, - - start(context?: vscode.NotebookCellExecuteStartContext): void { - if (that._state === NotebookCellExecutionTaskState.Resolved || that._state === NotebookCellExecutionTaskState.Started) { - throw new Error('Cannot call start again'); - } - - that._state = NotebookCellExecutionTaskState.Started; - that._onDidChangeState.fire(); - - that.mixinMetadata({ - runState: extHostTypes.NotebookCellExecutionState.Executing, - runStartTime: context?.startTime ?? null - }); - }, - - end(result?: vscode.NotebookCellExecuteEndContext): void { - if (that._state === NotebookCellExecutionTaskState.Resolved) { - throw new Error('Cannot call resolve twice'); - } - - that._state = NotebookCellExecutionTaskState.Resolved; - that._onDidChangeState.fire(); - - that.mixinMetadata({ - runState: extHostTypes.NotebookCellExecutionState.Idle, - lastRunSuccess: result?.success ?? null, - runEndTime: result?.endTime ?? null, - }); - }, - - clearOutput(cellIndex?: number): Thenable { - that.verifyStateForOutput(); - return this.replaceOutput([], cellIndex); - }, - - async appendOutput(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cellIndex?: number): Promise { - that.verifyStateForOutput(); - const handle = that.cellIndexToHandle(cellIndex); - if (typeof handle !== 'number') { - return; - } - - outputs = Array.isArray(outputs) ? outputs : [outputs]; - return that.applyEditSoon({ editType: CellEditType.Output, handle, append: true, outputs: outputs.map(typeConverters.NotebookCellOutput.from) }); - }, - - async replaceOutput(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cellIndex?: number): Promise { - that.verifyStateForOutput(); - const handle = that.cellIndexToHandle(cellIndex); - if (typeof handle !== 'number') { - return; - } - - outputs = Array.isArray(outputs) ? outputs : [outputs]; - return that.applyEditSoon({ editType: CellEditType.Output, handle, outputs: outputs.map(typeConverters.NotebookCellOutput.from) }); - }, - - async appendOutputItems(items: vscode.NotebookCellOutputItem | vscode.NotebookCellOutputItem[], outputId: string): Promise { - that.verifyStateForOutput(); - items = Array.isArray(items) ? items : [items]; - return that.applyEditSoon({ editType: CellEditType.OutputItems, append: true, items: items.map(typeConverters.NotebookCellOutputItem.from), outputId }); - }, - - async replaceOutputItems(items: vscode.NotebookCellOutputItem | vscode.NotebookCellOutputItem[], outputId: string): Promise { - that.verifyStateForOutput(); - items = Array.isArray(items) ? items : [items]; - return that.applyEditSoon({ editType: CellEditType.OutputItems, items: items.map(typeConverters.NotebookCellOutputItem.from), outputId }); - }, - - token: that._tokenSource.token - }); - } -} - -class TimeoutBasedCollector { - private batch: T[] = []; - private waitPromise: Promise | undefined; - - constructor( - private readonly delay: number, - private readonly callback: (items: T[]) => Promise) { } - - addItem(item: T): Promise { - this.batch.push(item); - if (!this.waitPromise) { - this.waitPromise = timeout(this.delay).then(() => { - this.waitPromise = undefined; - const batch = this.batch; - this.batch = []; - return this.callback(batch); - }); - } - - return this.waitPromise; - } } diff --git a/lib/vscode/src/vs/workbench/api/common/extHostNotebookConcatDocument.ts b/src/vs/workbench/api/common/extHostNotebookConcatDocument.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostNotebookConcatDocument.ts rename to src/vs/workbench/api/common/extHostNotebookConcatDocument.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostNotebookDocument.ts b/src/vs/workbench/api/common/extHostNotebookDocument.ts similarity index 79% rename from lib/vscode/src/vs/workbench/api/common/extHostNotebookDocument.ts rename to src/vs/workbench/api/common/extHostNotebookDocument.ts index 4e46c5819461..55c2669a3d73 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostNotebookDocument.ts +++ b/src/vs/workbench/api/common/extHostNotebookDocument.ts @@ -6,12 +6,12 @@ import { Schemas } from 'vs/base/common/network'; import { deepFreeze, equals } from 'vs/base/common/objects'; import { URI } from 'vs/base/common/uri'; -import { CellKind, INotebookDocumentPropertiesChangeData, MainThreadNotebookDocumentsShape } from 'vs/workbench/api/common/extHost.protocol'; +import { INotebookDocumentPropertiesChangeData, MainThreadNotebookDocumentsShape } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; import { ExtHostDocumentsAndEditors, IExtHostModelAddedData } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import * as extHostTypes from 'vs/workbench/api/common/extHostTypes'; -import { IMainCellDto, IOutputDto, IOutputItemDto, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2 } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, IMainCellDto, IOutputDto, IOutputItemDto, NotebookCellInternalMetadata, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2 } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import * as vscode from 'vscode'; class RawContentChangeEvent { @@ -44,19 +44,19 @@ export class ExtHostCell { }; } - private _outputs: extHostTypes.NotebookCellOutput[]; - private _metadata: extHostTypes.NotebookCellMetadata; + private _outputs: vscode.NotebookCellOutput[]; + private _metadata: NotebookCellMetadata; private _previousResult: vscode.NotebookCellExecutionSummary | undefined; - private _internalMetadata: NotebookCellMetadata; + private _internalMetadata: NotebookCellInternalMetadata; readonly handle: number; readonly uri: URI; readonly cellKind: CellKind; - private _cell: vscode.NotebookCell | undefined; + private _apiCell: vscode.NotebookCell | undefined; constructor( - private readonly _notebook: ExtHostNotebookDocument, + readonly notebook: ExtHostNotebookDocument, private readonly _extHostDocument: ExtHostDocumentsAndEditors, private readonly _cellData: IMainCellDto, ) { @@ -64,33 +64,33 @@ export class ExtHostCell { this.uri = URI.revive(_cellData.uri); this.cellKind = _cellData.cellKind; this._outputs = _cellData.outputs.map(extHostTypeConverters.NotebookCellOutput.to); - this._internalMetadata = _cellData.metadata ?? {}; - this._metadata = extHostTypeConverters.NotebookCellMetadata.to(this._internalMetadata); - this._previousResult = extHostTypeConverters.NotebookCellPreviousExecutionResult.to(this._internalMetadata); + this._internalMetadata = _cellData.internalMetadata ?? {}; + this._metadata = _cellData.metadata ?? {}; + this._previousResult = extHostTypeConverters.NotebookCellExecutionSummary.to(_cellData.internalMetadata ?? {}); } - get internalMetadata(): NotebookCellMetadata { + get internalMetadata(): NotebookCellInternalMetadata { return this._internalMetadata; } get apiCell(): vscode.NotebookCell { - if (!this._cell) { + if (!this._apiCell) { const that = this; const data = this._extHostDocument.getDocument(this.uri); if (!data) { throw new Error(`MISSING extHostDocument for notebook cell: ${this.uri}`); } - this._cell = Object.freeze({ - get index() { return that._notebook.getCellIndex(that); }, - notebook: that._notebook.apiNotebook, + this._apiCell = Object.freeze({ + get index() { return that.notebook.getCellIndex(that); }, + notebook: that.notebook.apiNotebook, kind: extHostTypeConverters.NotebookCellKind.to(this._cellData.cellKind), document: data.document, get outputs() { return that._outputs.slice(0); }, get metadata() { return that._metadata; }, - get latestExecutionSummary() { return that._previousResult; } + get executionSummary() { return that._previousResult; } }); } - return this._cell; + return this._apiCell; } setOutputs(newOutputs: IOutputDto[]): void { @@ -102,16 +102,19 @@ export class ExtHostCell { const output = this._outputs.find(op => op.id === outputId); if (output) { if (!append) { - output.outputs.length = 0; + output.items.length = 0; } - output.outputs.push(...newItems); + output.items.push(...newItems); } } setMetadata(newMetadata: NotebookCellMetadata): void { - this._internalMetadata = newMetadata; - this._metadata = extHostTypeConverters.NotebookCellMetadata.to(newMetadata); - this._previousResult = extHostTypeConverters.NotebookCellPreviousExecutionResult.to(newMetadata); + this._metadata = newMetadata; + } + + setInternalMetadata(newInternalMetadata: NotebookCellInternalMetadata): void { + this._internalMetadata = newInternalMetadata; + this._previousResult = extHostTypeConverters.NotebookCellExecutionSummary.to(newInternalMetadata); } } @@ -141,8 +144,8 @@ export class ExtHostNotebookDocument { private readonly _textDocumentsAndEditors: ExtHostDocumentsAndEditors, private readonly _textDocuments: ExtHostDocuments, private readonly _emitter: INotebookEventEmitter, - private readonly _viewType: string, - private _metadata: extHostTypes.NotebookDocumentMetadata, + private readonly _notebookType: string, + private _metadata: Record, readonly uri: URI, ) { } @@ -156,7 +159,7 @@ export class ExtHostNotebookDocument { this._notebook = { get uri() { return that.uri; }, get version() { return that._versionId; }, - get viewType() { return that._viewType; }, + get notebookType() { return that._notebookType; }, get isDirty() { return that._isDirty; }, get isUntitled() { return that.uri.scheme === Schemas.untitled; }, get isClosed() { return that._disposed; }, @@ -190,7 +193,7 @@ export class ExtHostNotebookDocument { acceptDocumentPropertiesChanged(data: INotebookDocumentPropertiesChangeData) { if (data.metadata) { - this._metadata = this._metadata.with(data.metadata); + this._metadata = { ...this._metadata, ...data.metadata }; } } @@ -213,11 +216,14 @@ export class ExtHostNotebookDocument { this._changeCellLanguage(rawEvent.index, rawEvent.language); } else if (rawEvent.kind === NotebookCellsChangeType.ChangeCellMetadata) { this._changeCellMetadata(rawEvent.index, rawEvent.metadata); + } else if (rawEvent.kind === NotebookCellsChangeType.ChangeCellInternalMetadata) { + this._changeCellInternalMetadata(rawEvent.index, rawEvent.internalMetadata); } } } private _validateIndex(index: number): number { + index = index | 0; if (index < 0) { return 0; } else if (index >= this._cells.length) { @@ -228,13 +234,15 @@ export class ExtHostNotebookDocument { } private _validateRange(range: vscode.NotebookRange): vscode.NotebookRange { - if (range.start < 0) { - range = range.with({ start: 0 }); + let start = range.start | 0; + let end = range.end | 0; + if (start < 0) { + start = 0; } - if (range.end > this._cells.length) { - range = range.with({ end: this._cells.length }); + if (end > this._cells.length) { + end = this._cells.length; } - return range; + return range.with({ start, end }); } private _getCells(range: vscode.NotebookRange): ExtHostCell[] { @@ -250,7 +258,7 @@ export class ExtHostNotebookDocument { if (this._disposed) { return Promise.reject(new Error('Notebook has been closed')); } - return this._proxy.$trySaveDocument(this.uri); + return this._proxy.$trySaveNotebook(this.uri); } private _spliceNotebookCells(splices: NotebookCellsSplice2[], initialization: boolean): void { @@ -275,7 +283,7 @@ export class ExtHostNotebookDocument { const changeEvent = new RawContentChangeEvent(splice[0], splice[1], [], newCells); const deletedItems = this._cells.splice(splice[0], splice[1], ...newCells); - for (let cell of deletedItems) { + for (const cell of deletedItems) { removedCellDocuments.push(cell.uri); changeEvent.deletedItems.push(cell.apiCell); } @@ -331,7 +339,6 @@ export class ExtHostNotebookDocument { private _changeCellMetadata(index: number, newMetadata: NotebookCellMetadata): void { const cell = this._cells[index]; - const originalInternalMetadata = cell.internalMetadata; const originalExtMetadata = cell.apiCell.metadata; cell.setMetadata(newMetadata); const newExtMetadata = cell.apiCell.metadata; @@ -339,13 +346,24 @@ export class ExtHostNotebookDocument { if (!equals(originalExtMetadata, newExtMetadata)) { this._emitter.emitCellMetadataChange(deepFreeze({ document: this.apiNotebook, cell: cell.apiCell })); } + } + + private _changeCellInternalMetadata(index: number, newInternalMetadata: NotebookCellInternalMetadata): void { + const cell = this._cells[index]; + + const originalInternalMetadata = cell.internalMetadata; + cell.setInternalMetadata(newInternalMetadata); - if (originalInternalMetadata.runState !== newMetadata.runState) { - const executionState = newMetadata.runState ?? extHostTypes.NotebookCellExecutionState.Idle; - this._emitter.emitCellExecutionStateChange(deepFreeze({ document: this.apiNotebook, cell: cell.apiCell, executionState })); + if (originalInternalMetadata.runState !== newInternalMetadata.runState) { + const executionState = newInternalMetadata.runState ?? extHostTypes.NotebookCellExecutionState.Idle; + this._emitter.emitCellExecutionStateChange(deepFreeze({ document: this.apiNotebook, cell: cell.apiCell, state: executionState })); } } + getCellFromApiCell(apiCell: vscode.NotebookCell): ExtHostCell | undefined { + return this._cells.find(cell => cell.apiCell === apiCell); + } + getCellFromIndex(index: number): ExtHostCell | undefined { return this._cells[index]; } diff --git a/lib/vscode/src/vs/workbench/api/common/extHostNotebookEditor.ts b/src/vs/workbench/api/common/extHostNotebookEditor.ts similarity index 94% rename from lib/vscode/src/vs/workbench/api/common/extHostNotebookEditor.ts rename to src/vs/workbench/api/common/extHostNotebookEditor.ts index 30f8c6d52e43..a3b7fabf34fe 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostNotebookEditor.ts +++ b/src/vs/workbench/api/common/extHostNotebookEditor.ts @@ -40,7 +40,7 @@ class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit { } } - replaceMetadata(value: vscode.NotebookDocumentMetadata): void { + replaceMetadata(value: { [key: string]: any }): void { this._throwIfFinalized(); this._collectedEdits.push({ editType: CellEditType.DocumentMetadata, @@ -48,7 +48,7 @@ class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit { }); } - replaceCellMetadata(index: number, metadata: vscode.NotebookCellMetadata): void { + replaceCellMetadata(index: number, metadata: Record): void { this._throwIfFinalized(); this._collectedEdits.push({ editType: CellEditType.Metadata, @@ -73,6 +73,8 @@ class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit { export class ExtHostNotebookEditor { + public static readonly apiEditorsToExtHost = new WeakMap(); + private _selections: vscode.NotebookRange[] = []; private _visibleRanges: vscode.NotebookRange[] = []; private _viewColumn?: vscode.ViewColumn; @@ -127,6 +129,8 @@ export class ExtHostNotebookEditor { return that.setDecorations(decorationType, range); } }; + + ExtHostNotebookEditor.apiEditorsToExtHost.set(this._editor, this); } return this._editor; } diff --git a/src/vs/workbench/api/common/extHostNotebookKernels.ts b/src/vs/workbench/api/common/extHostNotebookKernels.ts new file mode 100644 index 000000000000..626520ce8bda --- /dev/null +++ b/src/vs/workbench/api/common/extHostNotebookKernels.ts @@ -0,0 +1,521 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Emitter } from 'vs/base/common/event'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { ExtHostNotebookKernelsShape, IMainContext, INotebookKernelDto2, MainContext, MainThreadNotebookDocumentsShape, MainThreadNotebookKernelsShape } from 'vs/workbench/api/common/extHost.protocol'; +import * as vscode from 'vscode'; +import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook'; +import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { URI, UriComponents } from 'vs/base/common/uri'; +import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters'; +import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; +import { asWebviewUri } from 'vs/workbench/api/common/shared/webview'; +import { ResourceMap } from 'vs/base/common/map'; +import { timeout } from 'vs/base/common/async'; +import { ExtHostCell, ExtHostNotebookDocument } from 'vs/workbench/api/common/extHostNotebookDocument'; +import { CellEditType, IImmediateCellEditOperation, IOutputDto, NotebookCellExecutionState, NullablePartialNotebookCellInternalMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CancellationTokenSource } from 'vs/base/common/cancellation'; +import { asArray } from 'vs/base/common/arrays'; +import { ILogService } from 'vs/platform/log/common/log'; +import { NotebookCellOutput } from 'vs/workbench/api/common/extHostTypes'; +import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; + +interface IKernelData { + extensionId: ExtensionIdentifier, + controller: vscode.NotebookController; + onDidChangeSelection: Emitter<{ selected: boolean; notebook: vscode.NotebookDocument; }>; + onDidReceiveMessage: Emitter<{ editor: vscode.NotebookEditor, message: any; }>; + associatedNotebooks: ResourceMap; +} + +export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape { + + private readonly _proxy: MainThreadNotebookKernelsShape; + private readonly _activeExecutions = new ResourceMap(); + + private readonly _kernelData = new Map(); + private _handlePool: number = 0; + + constructor( + private readonly _mainContext: IMainContext, + private readonly _initData: IExtHostInitDataService, + private readonly _extHostNotebook: ExtHostNotebookController, + @ILogService private readonly _logService: ILogService, + ) { + this._proxy = _mainContext.getProxy(MainContext.MainThreadNotebookKernels); + } + + createNotebookController(extension: IExtensionDescription, id: string, viewType: string, label: string, handler?: (cells: vscode.NotebookCell[], notebook: vscode.NotebookDocument, controller: vscode.NotebookController) => void | Thenable, preloads?: vscode.NotebookRendererScript[]): vscode.NotebookController { + + for (let data of this._kernelData.values()) { + if (data.controller.id === id && ExtensionIdentifier.equals(extension.identifier, data.extensionId)) { + throw new Error(`notebook controller with id '${id}' ALREADY exist`); + } + } + + + const handle = this._handlePool++; + const that = this; + + this._logService.trace(`NotebookController[${handle}], CREATED by ${extension.identifier.value}, ${id}`); + + const _defaultExecutHandler = () => console.warn(`NO execute handler from notebook controller '${data.id}' of extension: '${extension.identifier}'`); + + let isDisposed = false; + const commandDisposables = new DisposableStore(); + + const onDidChangeSelection = new Emitter<{ selected: boolean, notebook: vscode.NotebookDocument; }>(); + const onDidReceiveMessage = new Emitter<{ editor: vscode.NotebookEditor, message: any; }>(); + + const data: INotebookKernelDto2 = { + id: `${extension.identifier.value}/${id}`, + notebookType: viewType, + extensionId: extension.identifier, + extensionLocation: extension.extensionLocation, + label: label || extension.identifier.value, + preloads: preloads ? preloads.map(extHostTypeConverters.NotebookRendererScript.from) : [] + }; + + // + let _executeHandler = handler ?? _defaultExecutHandler; + let _interruptHandler: ((this: vscode.NotebookController, notebook: vscode.NotebookDocument) => void | Thenable) | undefined; + + // todo@jrieken the selector needs to be massaged + this._proxy.$addKernel(handle, data).catch(err => { + // this can happen when a kernel with that ID is already registered + console.log(err); + isDisposed = true; + }); + + // update: all setters write directly into the dto object + // and trigger an update. the actual update will only happen + // once per event loop execution + let tokenPool = 0; + const _update = () => { + if (isDisposed) { + return; + } + const myToken = ++tokenPool; + Promise.resolve().then(() => { + if (myToken === tokenPool) { + this._proxy.$updateKernel(handle, data); + } + }); + }; + + // notebook documents that are associated to this controller + const associatedNotebooks = new ResourceMap(); + + const controller: vscode.NotebookController = { + get id() { return id; }, + get notebookType() { return data.notebookType; }, + onDidChangeSelectedNotebooks: onDidChangeSelection.event, + get label() { + return data.label; + }, + set label(value) { + data.label = value ?? extension.displayName ?? extension.name; + _update(); + }, + get detail() { + return data.detail ?? ''; + }, + set detail(value) { + data.detail = value; + _update(); + }, + get description() { + return data.description ?? ''; + }, + set description(value) { + data.description = value; + _update(); + }, + get supportedLanguages() { + return data.supportedLanguages; + }, + set supportedLanguages(value) { + data.supportedLanguages = value; + _update(); + }, + get supportsExecutionOrder() { + return data.supportsExecutionOrder ?? false; + }, + set supportsExecutionOrder(value) { + data.supportsExecutionOrder = value; + _update(); + }, + get rendererScripts() { + return data.preloads ? data.preloads.map(extHostTypeConverters.NotebookRendererScript.to) : []; + }, + get executeHandler() { + return _executeHandler; + }, + set executeHandler(value) { + _executeHandler = value ?? _defaultExecutHandler; + }, + get interruptHandler() { + return _interruptHandler; + }, + set interruptHandler(value) { + _interruptHandler = value; + data.supportsInterrupt = Boolean(value); + _update(); + }, + createNotebookCellExecution(cell) { + if (isDisposed) { + throw new Error('notebook controller is DISPOSED'); + } + if (!associatedNotebooks.has(cell.notebook.uri)) { + that._logService.trace(`NotebookController[${handle}] NOT associated to notebook, associated to THESE notebooks:`, Array.from(associatedNotebooks.keys()).map(u => u.toString())); + throw new Error(`notebook controller is NOT associated to notebook: ${cell.notebook.uri.toString()}`); + } + return that._createNotebookCellExecution(cell); + }, + dispose: () => { + if (!isDisposed) { + this._logService.trace(`NotebookController[${handle}], DISPOSED`); + isDisposed = true; + this._kernelData.delete(handle); + commandDisposables.dispose(); + onDidChangeSelection.dispose(); + onDidReceiveMessage.dispose(); + this._proxy.$removeKernel(handle); + } + }, + // --- priority + updateNotebookAffinity(notebook, priority) { + that._proxy.$updateNotebookPriority(handle, notebook.uri, priority); + }, + // --- ipc + onDidReceiveMessage: onDidReceiveMessage.event, + postMessage(message, editor) { + checkProposedApiEnabled(extension); + return that._proxy.$postMessage(handle, editor && that._extHostNotebook.getIdByEditor(editor), message); + }, + asWebviewUri(uri: URI) { + checkProposedApiEnabled(extension); + return asWebviewUri(uri, that._initData.remote); + }, + }; + + this._kernelData.set(handle, { + extensionId: extension.identifier, + controller, + onDidReceiveMessage, + onDidChangeSelection, + associatedNotebooks + }); + return controller; + } + + $acceptNotebookAssociation(handle: number, uri: UriComponents, value: boolean): void { + const obj = this._kernelData.get(handle); + if (obj) { + // update data structure + const notebook = this._extHostNotebook.getNotebookDocument(URI.revive(uri))!; + if (value) { + obj.associatedNotebooks.set(notebook.uri, true); + } else { + obj.associatedNotebooks.delete(notebook.uri); + } + this._logService.trace(`NotebookController[${handle}] ASSOCIATE notebook`, notebook.uri.toString(), value); + // send event + obj.onDidChangeSelection.fire({ + selected: value, + notebook: notebook.apiNotebook + }); + } + } + + async $executeCells(handle: number, uri: UriComponents, handles: number[]): Promise { + const obj = this._kernelData.get(handle); + if (!obj) { + // extension can dispose kernels in the meantime + return; + } + const document = this._extHostNotebook.getNotebookDocument(URI.revive(uri)); + const cells: vscode.NotebookCell[] = []; + for (let cellHandle of handles) { + const cell = document.getCell(cellHandle); + if (cell) { + cells.push(cell.apiCell); + } + } + + try { + this._logService.trace(`NotebookController[${handle}] EXECUTE cells`, document.uri.toString(), cells.length); + await obj.controller.executeHandler.call(obj.controller, cells, document.apiNotebook, obj.controller); + } catch (err) { + // + this._logService.error(`NotebookController[${handle}] execute cells FAILED`, err); + console.error(err); + } + } + + async $cancelCells(handle: number, uri: UriComponents, handles: number[]): Promise { + const obj = this._kernelData.get(handle); + if (!obj) { + // extension can dispose kernels in the meantime + return; + } + + // cancel or interrupt depends on the controller. When an interrupt handler is used we + // don't trigger the cancelation token of executions. + const document = this._extHostNotebook.getNotebookDocument(URI.revive(uri)); + if (obj.controller.interruptHandler) { + await obj.controller.interruptHandler.call(obj.controller, document.apiNotebook); + + } else { + for (let cellHandle of handles) { + const cell = document.getCell(cellHandle); + if (cell) { + this._activeExecutions.get(cell.uri)?.cancel(); + } + } + } + } + + $acceptKernelMessageFromRenderer(handle: number, editorId: string, message: any): void { + const obj = this._kernelData.get(handle); + if (!obj) { + // extension can dispose kernels in the meantime + return; + } + + const editor = this._extHostNotebook.getEditorById(editorId); + if (!editor) { + throw new Error(`send message for UNKNOWN editor: ${editorId}`); + } + + obj.onDidReceiveMessage.fire(Object.freeze({ editor: editor.apiEditor, message })); + } + + // --- + + _createNotebookCellExecution(cell: vscode.NotebookCell): vscode.NotebookCellExecution { + if (cell.index < 0) { + throw new Error('CANNOT execute cell that has been REMOVED from notebook'); + } + const notebook = this._extHostNotebook.getNotebookDocument(cell.notebook.uri); + const cellObj = notebook.getCellFromApiCell(cell); + if (!cellObj) { + throw new Error('invalid cell'); + } + if (this._activeExecutions.has(cellObj.uri)) { + throw new Error(`duplicate execution for ${cellObj.uri}`); + } + const execution = new NotebookCellExecutionTask(cellObj.notebook, cellObj, this._mainContext.getProxy(MainContext.MainThreadNotebookDocuments)); + this._activeExecutions.set(cellObj.uri, execution); + const listener = execution.onDidChangeState(() => { + if (execution.state === NotebookCellExecutionTaskState.Resolved) { + execution.dispose(); + listener.dispose(); + this._activeExecutions.delete(cellObj.uri); + } + }); + return execution.asApiObject(); + } +} + + +enum NotebookCellExecutionTaskState { + Init, + Started, + Resolved +} + +class NotebookCellExecutionTask extends Disposable { + private _onDidChangeState = new Emitter(); + readonly onDidChangeState = this._onDidChangeState.event; + + private _state = NotebookCellExecutionTaskState.Init; + get state(): NotebookCellExecutionTaskState { return this._state; } + + private readonly _tokenSource = this._register(new CancellationTokenSource()); + + private readonly _collector: TimeoutBasedCollector; + + private _executionOrder: number | undefined; + + constructor( + private readonly _document: ExtHostNotebookDocument, + private readonly _cell: ExtHostCell, + private readonly _proxy: MainThreadNotebookDocumentsShape + ) { + super(); + + this._collector = new TimeoutBasedCollector(10, edits => this.applyEdits(edits)); + + this._executionOrder = _cell.internalMetadata.executionOrder; + this.mixinMetadata({ + runState: NotebookCellExecutionState.Pending, + executionOrder: null + }); + } + + cancel(): void { + this._tokenSource.cancel(); + } + + private async applyEditSoon(edit: IImmediateCellEditOperation): Promise { + await this._collector.addItem(edit); + } + + private async applyEdits(edits: IImmediateCellEditOperation[]): Promise { + return this._proxy.$applyEdits(this._document.uri, edits, false); + } + + private verifyStateForOutput() { + if (this._state === NotebookCellExecutionTaskState.Init) { + throw new Error('Must call start before modifying cell output'); + } + + if (this._state === NotebookCellExecutionTaskState.Resolved) { + throw new Error('Cannot modify cell output after calling resolve'); + } + } + + private mixinMetadata(mixinMetadata: NullablePartialNotebookCellInternalMetadata) { + const edit: IImmediateCellEditOperation = { editType: CellEditType.PartialInternalMetadata, handle: this._cell.handle, internalMetadata: mixinMetadata }; + this.applyEdits([edit]); + } + + private cellIndexToHandle(cellOrCellIndex: vscode.NotebookCell | number | undefined): number { + let cell: ExtHostCell | undefined = this._cell; + if (typeof cellOrCellIndex === 'number') { + // todo@jrieken remove support for number shortly + cell = this._document.getCellFromIndex(cellOrCellIndex); + } else if (cellOrCellIndex) { + cell = this._document.getCellFromApiCell(cellOrCellIndex); + } + if (!cell) { + throw new Error('INVALID cell'); + } + return cell.handle; + } + + private validateAndConvertOutputs(items: vscode.NotebookCellOutput[]): IOutputDto[] { + return items.map(output => { + const newOutput = NotebookCellOutput.ensureUniqueMimeTypes(output.items, true); + if (newOutput === output.items) { + return extHostTypeConverters.NotebookCellOutput.from(output); + } + return extHostTypeConverters.NotebookCellOutput.from({ + items: newOutput, + id: output.id, + metadata: output.metadata + }); + }); + } + + private async updateOutputs(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cell: vscode.NotebookCell | number | undefined, append: boolean): Promise { + const handle = this.cellIndexToHandle(cell); + const outputDtos = this.validateAndConvertOutputs(asArray(outputs)); + return this.applyEditSoon({ editType: CellEditType.Output, handle, append, outputs: outputDtos }); + } + + private async updateOutputItems(items: vscode.NotebookCellOutputItem | vscode.NotebookCellOutputItem[], outputOrOutputId: vscode.NotebookCellOutput | string, append: boolean): Promise { + if (NotebookCellOutput.isNotebookCellOutput(outputOrOutputId)) { + outputOrOutputId = outputOrOutputId.id; + } + items = NotebookCellOutput.ensureUniqueMimeTypes(asArray(items), true); + return this.applyEditSoon({ editType: CellEditType.OutputItems, items: items.map(extHostTypeConverters.NotebookCellOutputItem.from), outputId: outputOrOutputId, append }); + } + + asApiObject(): vscode.NotebookCellExecution { + const that = this; + const result: vscode.NotebookCellExecution = { + get token() { return that._tokenSource.token; }, + get cell() { return that._cell.apiCell; }, + get executionOrder() { return that._executionOrder; }, + set executionOrder(v: number | undefined) { + that._executionOrder = v; + that.mixinMetadata({ + executionOrder: v + }); + }, + + start(startTime?: number): void { + if (that._state === NotebookCellExecutionTaskState.Resolved || that._state === NotebookCellExecutionTaskState.Started) { + throw new Error('Cannot call start again'); + } + + that._state = NotebookCellExecutionTaskState.Started; + that._onDidChangeState.fire(); + + that.mixinMetadata({ + runState: NotebookCellExecutionState.Executing, + runStartTime: startTime ?? null + }); + }, + + end(success: boolean | undefined, endTime?: number): void { + if (that._state === NotebookCellExecutionTaskState.Resolved) { + throw new Error('Cannot call resolve twice'); + } + + that._state = NotebookCellExecutionTaskState.Resolved; + that._onDidChangeState.fire(); + + that.mixinMetadata({ + runState: null, + lastRunSuccess: success ?? null, + runEndTime: endTime ?? null, + }); + }, + + clearOutput(cell?: vscode.NotebookCell | number): Thenable { + that.verifyStateForOutput(); + return that.updateOutputs([], cell, false); + }, + + appendOutput(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cell?: vscode.NotebookCell | number): Promise { + that.verifyStateForOutput(); + return that.updateOutputs(outputs, cell, true); + }, + + replaceOutput(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cell?: vscode.NotebookCell | number): Promise { + that.verifyStateForOutput(); + return that.updateOutputs(outputs, cell, false); + }, + + appendOutputItems(items: vscode.NotebookCellOutputItem | vscode.NotebookCellOutputItem[], output: vscode.NotebookCellOutput | string): Promise { + that.verifyStateForOutput(); + return that.updateOutputItems(items, output, true); + }, + + replaceOutputItems(items: vscode.NotebookCellOutputItem | vscode.NotebookCellOutputItem[], output: vscode.NotebookCellOutput | string): Promise { + that.verifyStateForOutput(); + return that.updateOutputItems(items, output, false); + } + }; + return Object.freeze(result); + } +} + +class TimeoutBasedCollector { + private batch: T[] = []; + private waitPromise: Promise | undefined; + + constructor( + private readonly delay: number, + private readonly callback: (items: T[]) => Promise) { } + + addItem(item: T): Promise { + this.batch.push(item); + if (!this.waitPromise) { + this.waitPromise = timeout(this.delay).then(() => { + this.waitPromise = undefined; + const batch = this.batch; + this.batch = []; + return this.callback(batch); + }); + } + + return this.waitPromise; + } +} diff --git a/src/vs/workbench/api/common/extHostNotebookRenderers.ts b/src/vs/workbench/api/common/extHostNotebookRenderers.ts new file mode 100644 index 000000000000..fcf5eb9cfd51 --- /dev/null +++ b/src/vs/workbench/api/common/extHostNotebookRenderers.ts @@ -0,0 +1,63 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Emitter } from 'vs/base/common/event'; +import { ExtHostNotebookRenderersShape, IMainContext, MainContext, MainThreadNotebookRenderersShape } from 'vs/workbench/api/common/extHost.protocol'; +import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook'; +import { ExtHostNotebookEditor } from 'vs/workbench/api/common/extHostNotebookEditor'; +import * as vscode from 'vscode'; + +export class ExtHostNotebookRenderers implements ExtHostNotebookRenderersShape { + private readonly _rendererMessageEmitters = new Map>>(); + private readonly proxy: MainThreadNotebookRenderersShape; + + constructor(mainContext: IMainContext, private readonly _extHostNotebook: ExtHostNotebookController) { + this.proxy = mainContext.getProxy(MainContext.MainThreadNotebookRenderers); + } + + public $postRendererMessage(editorId: string, rendererId: string, message: unknown): void { + const editor = this._extHostNotebook.getEditorById(editorId); + if (!editor) { + return; + } + + this._rendererMessageEmitters.get(rendererId)?.fire({ editor: editor.apiEditor, message }); + } + + public createRendererMessaging(rendererId: string): vscode.NotebookRendererMessaging { + const messaging: vscode.NotebookRendererMessaging = { + onDidReceiveMessage: (...args) => + this.getOrCreateEmitterFor(rendererId).event(...args), + postMessage: (editor, message) => { + const extHostEditor = ExtHostNotebookEditor.apiEditorsToExtHost.get(editor); + if (!extHostEditor) { + throw new Error(`The first argument to postMessage() must be a NotebookEditor`); + } + + this.proxy.$postMessage(extHostEditor.id, rendererId, message); + }, + }; + + return messaging; + } + + private getOrCreateEmitterFor(rendererId: string) { + let emitter = this._rendererMessageEmitters.get(rendererId); + if (emitter) { + return emitter; + } + + emitter = new Emitter({ + onLastListenerRemove: () => { + emitter?.dispose(); + this._rendererMessageEmitters.delete(rendererId); + } + }); + + this._rendererMessageEmitters.set(rendererId, emitter); + + return emitter; + } +} diff --git a/lib/vscode/src/vs/workbench/api/common/extHostOutput.ts b/src/vs/workbench/api/common/extHostOutput.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostOutput.ts rename to src/vs/workbench/api/common/extHostOutput.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostProgress.ts b/src/vs/workbench/api/common/extHostProgress.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostProgress.ts rename to src/vs/workbench/api/common/extHostProgress.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostQuickOpen.ts b/src/vs/workbench/api/common/extHostQuickOpen.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostQuickOpen.ts rename to src/vs/workbench/api/common/extHostQuickOpen.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostRequireInterceptor.ts b/src/vs/workbench/api/common/extHostRequireInterceptor.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostRequireInterceptor.ts rename to src/vs/workbench/api/common/extHostRequireInterceptor.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostRpcService.ts b/src/vs/workbench/api/common/extHostRpcService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostRpcService.ts rename to src/vs/workbench/api/common/extHostRpcService.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostSCM.ts b/src/vs/workbench/api/common/extHostSCM.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostSCM.ts rename to src/vs/workbench/api/common/extHostSCM.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostSearch.ts b/src/vs/workbench/api/common/extHostSearch.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostSearch.ts rename to src/vs/workbench/api/common/extHostSearch.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostSecrets.ts b/src/vs/workbench/api/common/extHostSecrets.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostSecrets.ts rename to src/vs/workbench/api/common/extHostSecrets.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostStatusBar.ts b/src/vs/workbench/api/common/extHostStatusBar.ts similarity index 71% rename from lib/vscode/src/vs/workbench/api/common/extHostStatusBar.ts rename to src/vs/workbench/api/common/extHostStatusBar.ts index ba9c5b184ae8..f85f182011ed 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostStatusBar.ts +++ b/src/vs/workbench/api/common/extHostStatusBar.ts @@ -10,8 +10,10 @@ import { MainContext, MainThreadStatusBarShape, IMainContext, ICommandDto } from import { localize } from 'vs/nls'; import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands'; import { DisposableStore } from 'vs/base/common/lifecycle'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; export class ExtHostStatusBarEntry implements vscode.StatusBarItem { + private static ID_GEN = 0; private static ALLOWED_BACKGROUND_COLORS = new Map( @@ -21,17 +23,20 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem { #proxy: MainThreadStatusBarShape; #commands: CommandsConverter; - private _id: number; + private _entryId: number; + + private _extension?: IExtensionDescription; + + private _id?: string; private _alignment: number; private _priority?: number; + private _disposed: boolean = false; private _visible: boolean = false; - private _statusId: string; - private _statusName: string; - private _text: string = ''; private _tooltip?: string; + private _name?: string; private _color?: string | ThemeColor; private _backgroundColor?: ThemeColor; private readonly _internalCommandRegistration = new DisposableStore(); @@ -43,20 +48,23 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem { private _timeoutHandle: any; private _accessibilityInformation?: vscode.AccessibilityInformation; - constructor(proxy: MainThreadStatusBarShape, commands: CommandsConverter, id: string, name: string, alignment: ExtHostStatusBarAlignment = ExtHostStatusBarAlignment.Left, priority?: number, accessibilityInformation?: vscode.AccessibilityInformation) { + constructor(proxy: MainThreadStatusBarShape, commands: CommandsConverter, extension: IExtensionDescription, id?: string, alignment?: ExtHostStatusBarAlignment, priority?: number); + constructor(proxy: MainThreadStatusBarShape, commands: CommandsConverter, extension: IExtensionDescription | undefined, id: string, alignment?: ExtHostStatusBarAlignment, priority?: number); + constructor(proxy: MainThreadStatusBarShape, commands: CommandsConverter, extension?: IExtensionDescription, id?: string, alignment: ExtHostStatusBarAlignment = ExtHostStatusBarAlignment.Left, priority?: number) { this.#proxy = proxy; this.#commands = commands; - this._id = ExtHostStatusBarEntry.ID_GEN++; - this._statusId = id; - this._statusName = name; + this._entryId = ExtHostStatusBarEntry.ID_GEN++; + + this._extension = extension; + + this._id = id; this._alignment = alignment; this._priority = priority; - this._accessibilityInformation = accessibilityInformation; } - public get id(): number { - return this._id; + public get id(): string { + return this._id ?? this._extension!.identifier.value; } public get alignment(): vscode.StatusBarAlignment { @@ -71,6 +79,10 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem { return this._text; } + public get name(): string | undefined { + return this._name; + } + public get tooltip(): string | undefined { return this._tooltip; } @@ -96,6 +108,11 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem { this.update(); } + public set name(name: string | undefined) { + this._name = name; + this.update(); + } + public set tooltip(tooltip: string | undefined) { this._tooltip = tooltip; this.update(); @@ -150,7 +167,7 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem { public hide(): void { clearTimeout(this._timeoutHandle); this._visible = false; - this.#proxy.$dispose(this.id); + this.#proxy.$dispose(this._entryId); } private update(): void { @@ -164,6 +181,28 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem { this._timeoutHandle = setTimeout(() => { this._timeoutHandle = undefined; + // If the id is not set, derive it from the extension identifier, + // otherwise make sure to prefix it with the extension identifier + // to get a more unique value across extensions. + let id: string; + if (this._extension) { + if (this._id) { + id = `${this._extension.identifier.value}.${this._id}`; + } else { + id = this._extension.identifier.value; + } + } else { + id = this._id!; + } + + // If the name is not set, derive it from the extension descriptor + let name: string; + if (this._name) { + name = this._name; + } else { + name = localize('extensionLabel', "{0} (Extension)", this._extension!.displayName || this._extension!.name); + } + // If a background color is set, the foreground is determined let color = this._color; if (this._backgroundColor) { @@ -171,7 +210,7 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem { } // Set to status bar - this.#proxy.$setEntry(this.id, this._statusId, this._statusName, this._text, this._tooltip, this._command?.internal, color, + this.#proxy.$setEntry(this._entryId, id, name, this._text, this._tooltip, this._command?.internal, color, this._backgroundColor, this._alignment === ExtHostStatusBarAlignment.Left ? MainThreadStatusBarAlignment.LEFT : MainThreadStatusBarAlignment.RIGHT, this._priority, this._accessibilityInformation); }, 0); @@ -189,7 +228,8 @@ class StatusBarMessage { private _messages: { message: string }[] = []; constructor(statusBar: ExtHostStatusBar) { - this._item = statusBar.createStatusBarEntry('status.extensionMessage', localize('status.extensionMessage', "Extension Status"), ExtHostStatusBarAlignment.Left, Number.MIN_VALUE); + this._item = statusBar.createStatusBarEntry(undefined, 'status.extensionMessage', ExtHostStatusBarAlignment.Left, Number.MIN_VALUE); + this._item.name = localize('status.extensionMessage', "Extension Status"); } dispose() { @@ -233,12 +273,13 @@ export class ExtHostStatusBar { this._statusMessage = new StatusBarMessage(this); } - createStatusBarEntry(id: string, name: string, alignment?: ExtHostStatusBarAlignment, priority?: number, accessibilityInformation?: vscode.AccessibilityInformation): vscode.StatusBarItem { - return new ExtHostStatusBarEntry(this._proxy, this._commands, id, name, alignment, priority, accessibilityInformation); + createStatusBarEntry(extension: IExtensionDescription | undefined, id: string, alignment?: ExtHostStatusBarAlignment, priority?: number): vscode.StatusBarItem; + createStatusBarEntry(extension: IExtensionDescription, id?: string, alignment?: ExtHostStatusBarAlignment, priority?: number): vscode.StatusBarItem; + createStatusBarEntry(extension: IExtensionDescription, id: string, alignment?: ExtHostStatusBarAlignment, priority?: number): vscode.StatusBarItem { + return new ExtHostStatusBarEntry(this._proxy, this._commands, extension, id, alignment, priority); } setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable): Disposable { - const d = this._statusMessage.setMessage(text); let handle: any; diff --git a/lib/vscode/src/vs/workbench/api/common/extHostStorage.ts b/src/vs/workbench/api/common/extHostStorage.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostStorage.ts rename to src/vs/workbench/api/common/extHostStorage.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostStoragePaths.ts b/src/vs/workbench/api/common/extHostStoragePaths.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostStoragePaths.ts rename to src/vs/workbench/api/common/extHostStoragePaths.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostTask.ts b/src/vs/workbench/api/common/extHostTask.ts similarity index 99% rename from lib/vscode/src/vs/workbench/api/common/extHostTask.ts rename to src/vs/workbench/api/common/extHostTask.ts index 35e824bad1dd..8f5d4a159774 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostTask.ts +++ b/src/vs/workbench/api/common/extHostTask.ts @@ -605,8 +605,6 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape, IExtHostTask public abstract $resolveVariables(uriComponents: UriComponents, toResolve: { process?: { name: string; cwd?: string; path?: string }, variables: string[] }): Promise<{ process?: string, variables: { [key: string]: string; } }>; - public abstract $getDefaultShellAndArgs(): Promise<{ shell: string, args: string[] | string | undefined }>; - private nextHandle(): number { return this._handleCounter++; } @@ -775,10 +773,6 @@ export class WorkerExtHostTask extends ExtHostTaskBase { return result; } - public $getDefaultShellAndArgs(): Promise<{ shell: string, args: string[] | string | undefined }> { - throw new Error('Not implemented'); - } - public async $jsonTasksSupported(): Promise { return false; } diff --git a/lib/vscode/src/vs/workbench/api/common/extHostTelemetry.ts b/src/vs/workbench/api/common/extHostTelemetry.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostTelemetry.ts rename to src/vs/workbench/api/common/extHostTelemetry.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostTerminalService.ts b/src/vs/workbench/api/common/extHostTerminalService.ts similarity index 84% rename from lib/vscode/src/vs/workbench/api/common/extHostTerminalService.ts rename to src/vs/workbench/api/common/extHostTerminalService.ts index a10d6b973b4d..23b91c7f5058 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostTerminalService.ts +++ b/src/vs/workbench/api/common/extHostTerminalService.ts @@ -5,13 +5,12 @@ import type * as vscode from 'vscode'; import { Event, Emitter } from 'vs/base/common/event'; -import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellAndArgsDto, ITerminalDimensionsDto, ITerminalLinkDto, TerminalIdentifier } from 'vs/workbench/api/common/extHost.protocol'; -import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration'; +import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, ITerminalDimensionsDto, ITerminalLinkDto, TerminalIdentifier } from 'vs/workbench/api/common/extHost.protocol'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { URI } from 'vs/base/common/uri'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; -import { Disposable as VSCodeDisposable, EnvironmentVariableMutatorType } from './extHostTypes'; +import { Disposable as VSCodeDisposable, EnvironmentVariableMutatorType, ThemeColor } from './extHostTypes'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { localize } from 'vs/nls'; import { NotSupportedError } from 'vs/base/common/errors'; @@ -19,9 +18,10 @@ import { serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/ter import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { generateUuid } from 'vs/base/common/uuid'; import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable'; -import { IShellLaunchConfigDto, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalEnvironment, ITerminalLaunchError, TerminalShellType } from 'vs/platform/terminal/common/terminal'; +import { IProcessReadyEvent, IShellLaunchConfigDto, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalLaunchError, ITerminalProfile, TerminalIcon, TerminalShellType } from 'vs/platform/terminal/common/terminal'; import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering'; -import { ITerminalProfile } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { withNullAsUndefined } from 'vs/base/common/types'; export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, IDisposable { @@ -37,15 +37,22 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, ID onDidWriteTerminalData: Event; createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal; - createTerminalFromOptions(options: vscode.TerminalOptions, isFeatureTerminal?: boolean): vscode.Terminal; + createTerminalFromOptions(options: vscode.TerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal; createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal; attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void; - getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string; - getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string; + getDefaultShell(useAutomationShell: boolean): string; + getDefaultShellArgs(useAutomationShell: boolean): string[] | string; registerLinkProvider(provider: vscode.TerminalLinkProvider): vscode.Disposable; + registerProfileProvider(id: string, provider: vscode.TerminalProfileProvider): vscode.Disposable; getEnvironmentVariableCollection(extension: IExtensionDescription, persistent?: boolean): vscode.EnvironmentVariableCollection; } +export interface ITerminalInternalOptions { + isFeatureTerminal?: boolean; + useShellEnvironment?: boolean; + isSplitTerminal?: boolean; +} + export const IExtHostTerminalService = createDecorator('IExtHostTerminalService'); export class ExtHostTerminal { @@ -114,29 +121,39 @@ export class ExtHostTerminal { } public async create( - shellPath?: string, - shellArgs?: string[] | string, - cwd?: string | URI, - env?: ITerminalEnvironment, - icon?: string, - initialText?: string, - waitOnExit?: boolean, - strictEnv?: boolean, - hideFromUser?: boolean, - isFeatureTerminal?: boolean, - isExtensionOwnedTerminal?: boolean + options: vscode.TerminalOptions, + internalOptions?: ITerminalInternalOptions, ): Promise { if (typeof this._id !== 'string') { throw new Error('Terminal has already been created'); } - await this._proxy.$createTerminal(this._id, { name: this._name, shellPath, shellArgs, cwd, env, icon, initialText, waitOnExit, strictEnv, hideFromUser, isFeatureTerminal, isExtensionOwnedTerminal }); + await this._proxy.$createTerminal(this._id, { + name: options.name, + shellPath: withNullAsUndefined(options.shellPath), + shellArgs: withNullAsUndefined(options.shellArgs), + cwd: withNullAsUndefined(options.cwd), + env: withNullAsUndefined(options.env), + icon: withNullAsUndefined(asTerminalIcon(options.iconPath)), + initialText: withNullAsUndefined(options.message), + strictEnv: withNullAsUndefined(options.strictEnv), + hideFromUser: withNullAsUndefined(options.hideFromUser), + isFeatureTerminal: withNullAsUndefined(internalOptions?.isFeatureTerminal), + isExtensionOwnedTerminal: true, + useShellEnvironment: withNullAsUndefined(internalOptions?.useShellEnvironment), + isSplitTerminal: withNullAsUndefined(internalOptions?.isSplitTerminal) + }); } - public async createExtensionTerminal(): Promise { + public async createExtensionTerminal(isSplitTerminal?: boolean, iconPath?: URI | { light: URI; dark: URI } | ThemeIcon): Promise { if (typeof this._id !== 'string') { throw new Error('Terminal has already been created'); } - await this._proxy.$createTerminal(this._id, { name: this._name, isExtensionCustomPtyTerminal: true }); + await this._proxy.$createTerminal(this._id, { + name: this._name, + isExtensionCustomPtyTerminal: true, + icon: iconPath, + isSplitTerminal + }); // At this point, the id has been set via `$acceptTerminalOpened` if (typeof this._id === 'string') { throw new Error('Terminal creation failed'); @@ -195,8 +212,8 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess { public readonly onProcessData: Event = this._onProcessData.event; private readonly _onProcessExit = new Emitter(); public readonly onProcessExit: Event = this._onProcessExit.event; - private readonly _onProcessReady = new Emitter<{ pid: number, cwd: string }>(); - public get onProcessReady(): Event<{ pid: number, cwd: string }> { return this._onProcessReady.event; } + private readonly _onProcessReady = new Emitter(); + public get onProcessReady(): Event { return this._onProcessReady.event; } private readonly _onProcessTitleChanged = new Emitter(); public readonly onProcessTitleChanged: Event = this._onProcessTitleChanged.event; private readonly _onProcessOverrideDimensions = new Emitter(); @@ -259,6 +276,9 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess { if (this._pty.onDidOverrideDimensions) { this._pty.onDidOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e ? { cols: e.columns, rows: e.rows } : e)); } + if (this._pty.onDidChangeName) { + this._pty.onDidChangeName(title => this._onProcessTitleChanged.fire(title)); + } this._pty.open(initialDimensions ? initialDimensions : undefined); @@ -289,9 +309,12 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I protected _extensionTerminalAwaitingStart: { [id: number]: { initialDimensions: ITerminalDimensionsDto | undefined } | undefined } = {}; protected _getTerminalPromises: { [id: number]: Promise } = {}; protected _environmentVariableCollections: Map = new Map(); + private _defaultProfile: ITerminalProfile | undefined; + private _defaultAutomationProfile: ITerminalProfile | undefined; private readonly _bufferer: TerminalDataBufferer; private readonly _linkProviders: Set = new Set(); + private readonly _profileProviders: Map = new Map(); private readonly _terminalLinkCache: Map> = new Map(); private readonly _terminalLinkCancellationSource: Map = new Map(); @@ -331,16 +354,22 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I } public abstract createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal; - public abstract createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal; - public abstract getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string; - public abstract getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string; - public abstract $getAvailableProfiles(configuredProfilesOnly: boolean): Promise; - public abstract $getDefaultShellAndArgs(useAutomationShell: boolean): Promise; + public abstract createTerminalFromOptions(options: vscode.TerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal; + + public getDefaultShell(useAutomationShell: boolean): string { + const profile = useAutomationShell ? this._defaultAutomationProfile : this._defaultProfile; + return profile?.path || ''; + } + + public getDefaultShellArgs(useAutomationShell: boolean): string[] | string { + const profile = useAutomationShell ? this._defaultAutomationProfile : this._defaultProfile; + return profile?.args || []; + } - public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal { + public createExtensionTerminal(options: vscode.ExtensionTerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal { const terminal = new ExtHostTerminal(this._proxy, generateUuid(), options, options.name); const p = new ExtHostPseudoterminal(options.pty); - terminal.createExtensionTerminal().then(id => { + terminal.createExtensionTerminal(internalOptions?.isSplitTerminal, asTerminalIcon(options.iconPath)).then(id => { const disposable = this._setupExtHostProcessListeners(id, p); this._terminalProcessDisposables[id] = disposable; }); @@ -555,6 +584,34 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I }); } + public registerProfileProvider(id: string, provider: vscode.TerminalProfileProvider): vscode.Disposable { + if (this._profileProviders.has(id)) { + throw new Error(`Terminal profile provider "${id}" already registered`); + } + this._profileProviders.set(id, provider); + this._proxy.$registerProfileProvider(id); + return new VSCodeDisposable(() => { + this._profileProviders.delete(id); + this._proxy.$unregisterProfileProvider(id); + }); + } + + public async $createContributedProfileTerminal(id: string, isSplitTerminal: boolean): Promise { + const token = new CancellationTokenSource().token; + const options = await this._profileProviders.get(id)?.provideProfileOptions(token); + if (token.isCancellationRequested) { + return; + } + if (!options) { + throw new Error(`No terminal profile options provided for id "${id}"`); + } + if ('pty' in options) { + this.createExtensionTerminal(options, { isSplitTerminal }); + return; + } + this.createTerminalFromOptions(options, { isSplitTerminal }); + } + public async $provideLinks(terminalId: number, line: string): Promise { const terminal = this._getTerminalById(terminalId); if (!terminal) { @@ -686,6 +743,11 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I }); } + public $acceptDefaultProfile(profile: ITerminalProfile, automationProfile: ITerminalProfile): void { + this._defaultProfile = profile; + this._defaultAutomationProfile = automationProfile; + } + private _setEnvironmentVariableCollection(extensionIdentifier: string, collection: EnvironmentVariableCollection): void { this._environmentVariableCollections.set(extensionIdentifier, collection); collection.onDidChangeCollection(() => { @@ -771,23 +833,20 @@ export class WorkerExtHostTerminalService extends BaseExtHostTerminalService { throw new NotSupportedError(); } - public createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal { - throw new NotSupportedError(); - } - - public getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string { - throw new NotSupportedError(); - } - - public getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string { + public createTerminalFromOptions(options: vscode.TerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal { throw new NotSupportedError(); } +} - public $getAvailableProfiles(configuredProfilesOnly: boolean): Promise { - throw new NotSupportedError(); +function asTerminalIcon(iconPath?: vscode.Uri | { light: vscode.Uri; dark: vscode.Uri } | vscode.ThemeIcon): TerminalIcon | undefined { + if (!iconPath) { + return undefined; } - - public async $getDefaultShellAndArgs(useAutomationShell: boolean): Promise { - throw new NotSupportedError(); + if (!('id' in iconPath)) { + return iconPath; } + return { + id: iconPath.id, + color: iconPath.color as ThemeColor + }; } diff --git a/lib/vscode/src/vs/workbench/api/common/extHostTesting.ts b/src/vs/workbench/api/common/extHostTesting.ts similarity index 99% rename from lib/vscode/src/vs/workbench/api/common/extHostTesting.ts rename to src/vs/workbench/api/common/extHostTesting.ts index 7afd44dfc346..46f08ad1d9f0 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostTesting.ts +++ b/src/vs/workbench/api/common/extHostTesting.ts @@ -666,7 +666,7 @@ export class TestItemFilteredWrapper extends TestItemImpl { } } - const nowMatches = this.children.size > 0 || this.actual.uri.toString() === this.filterDocument.uri.toString(); + const nowMatches = this.children.size > 0 || this.actual.uri?.toString() === this.filterDocument.uri.toString(); this._cachedMatchesFilter = nowMatches; if (nowMatches !== didMatch) { diff --git a/lib/vscode/src/vs/workbench/api/common/extHostTestingPrivateApi.ts b/src/vs/workbench/api/common/extHostTestingPrivateApi.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostTestingPrivateApi.ts rename to src/vs/workbench/api/common/extHostTestingPrivateApi.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostTextEditor.ts b/src/vs/workbench/api/common/extHostTextEditor.ts similarity index 98% rename from lib/vscode/src/vs/workbench/api/common/extHostTextEditor.ts rename to src/vs/workbench/api/common/extHostTextEditor.ts index f3dff81c5444..88a6ca5f7034 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostTextEditor.ts +++ b/src/vs/workbench/api/common/extHostTextEditor.ts @@ -15,6 +15,7 @@ import { EndOfLine, Position, Range, Selection, SnippetString, TextEditorLineNum import type * as vscode from 'vscode'; import { ILogService } from 'vs/platform/log/common/log'; import { Lazy } from 'vs/base/common/lazy'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; export class TextEditorDecorationType { @@ -22,9 +23,9 @@ export class TextEditorDecorationType { readonly value: vscode.TextEditorDecorationType; - constructor(proxy: MainThreadTextEditorsShape, options: vscode.DecorationRenderOptions) { + constructor(proxy: MainThreadTextEditorsShape, extension: IExtensionDescription, options: vscode.DecorationRenderOptions) { const key = TextEditorDecorationType._Keys.nextId(); - proxy.$registerTextEditorDecorationType(key, TypeConverters.DecorationRenderOptions.from(options)); + proxy.$registerTextEditorDecorationType(extension.identifier, key, TypeConverters.DecorationRenderOptions.from(options)); this.value = Object.freeze({ key, dispose() { diff --git a/lib/vscode/src/vs/workbench/api/common/extHostTextEditors.ts b/src/vs/workbench/api/common/extHostTextEditors.ts similarity index 96% rename from lib/vscode/src/vs/workbench/api/common/extHostTextEditors.ts rename to src/vs/workbench/api/common/extHostTextEditors.ts index dc8bd7bd9108..555b638a1158 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostTextEditors.ts +++ b/src/vs/workbench/api/common/extHostTextEditors.ts @@ -11,6 +11,7 @@ import { ExtHostTextEditor, TextEditorDecorationType } from 'vs/workbench/api/co import * as TypeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import { TextEditorSelectionChangeKind } from 'vs/workbench/api/common/extHostTypes'; import type * as vscode from 'vscode'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; export class ExtHostEditors implements ExtHostEditorsShape { @@ -91,8 +92,8 @@ export class ExtHostEditors implements ExtHostEditorsShape { } } - createTextEditorDecorationType(options: vscode.DecorationRenderOptions): vscode.TextEditorDecorationType { - return new TextEditorDecorationType(this._proxy, options).value; + createTextEditorDecorationType(extension: IExtensionDescription, options: vscode.DecorationRenderOptions): vscode.TextEditorDecorationType { + return new TextEditorDecorationType(this._proxy, extension, options).value; } // --- called from main thread diff --git a/lib/vscode/src/vs/workbench/api/common/extHostTheming.ts b/src/vs/workbench/api/common/extHostTheming.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostTheming.ts rename to src/vs/workbench/api/common/extHostTheming.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostTimeline.ts b/src/vs/workbench/api/common/extHostTimeline.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostTimeline.ts rename to src/vs/workbench/api/common/extHostTimeline.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostTreeViews.ts b/src/vs/workbench/api/common/extHostTreeViews.ts similarity index 96% rename from lib/vscode/src/vs/workbench/api/common/extHostTreeViews.ts rename to src/vs/workbench/api/common/extHostTreeViews.ts index bf2801705cfb..8b02f4ab8ea2 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostTreeViews.ts +++ b/src/vs/workbench/api/common/extHostTreeViews.ts @@ -84,7 +84,8 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape { if (!options || !options.treeDataProvider) { throw new Error('Options with treeDataProvider is mandatory'); } - const registerPromise = this._proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany }); + const canDragAndDrop = options.dragAndDropController !== undefined; + const registerPromise = this._proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany, canDragAndDrop: canDragAndDrop }); const treeView = this.createExtHostTreeView(viewId, options, extension); return { get onDidCollapseElement() { return treeView.onDidCollapseElement; }, @@ -127,6 +128,14 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape { return treeView.getChildren(treeItemHandle); } + $onDrop(treeViewId: string, treeItemHandles: string[], newParentItemHandle: string): Promise { + const treeView = this.treeViews.get(treeViewId); + if (!treeView) { + return Promise.reject(new Error(localize('treeView.notRegistered', 'No tree view with id \'{0}\' registered.', treeViewId))); + } + return treeView.onDrop(treeItemHandles, newParentItemHandle); + } + async $hasResolve(treeViewId: string): Promise { const treeView = this.treeViews.get(treeViewId); if (!treeView) { @@ -196,6 +205,7 @@ class ExtHostTreeView extends Disposable { private static readonly ID_HANDLE_PREFIX = '1'; private readonly dataProvider: vscode.TreeDataProvider; + private readonly dndController: vscode.DragAndDropController | undefined; private roots: TreeNode[] | null = null; private elements: Map = new Map(); @@ -242,6 +252,7 @@ class ExtHostTreeView extends Disposable { } } this.dataProvider = options.treeDataProvider; + this.dndController = options.dragAndDropController; if (this.dataProvider.onDidChangeTreeData) { this._register(this.dataProvider.onDidChangeTreeData(element => this._onDidChangeData.fire({ message: false, element }))); } @@ -369,6 +380,15 @@ class ExtHostTreeView extends Disposable { } } + onDrop(treeItemHandleOrNodes: TreeItemHandle[], targetHandleOrNode: TreeItemHandle): Promise { + const elements = treeItemHandleOrNodes.map(item => this.getExtensionElement(item)).filter(element => !isUndefinedOrNull(element)); + const target = this.getExtensionElement(targetHandleOrNode); + if (elements && target) { + return asPromise(() => this.dndController?.onDrop(elements, target)); + } + return Promise.resolve(undefined); + } + get hasResolve(): boolean { return !!this.dataProvider.resolveTreeItem; } diff --git a/lib/vscode/src/vs/workbench/api/common/extHostTunnelService.ts b/src/vs/workbench/api/common/extHostTunnelService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostTunnelService.ts rename to src/vs/workbench/api/common/extHostTunnelService.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts similarity index 94% rename from lib/vscode/src/vs/workbench/api/common/extHostTypeConverters.ts rename to src/vs/workbench/api/common/extHostTypeConverters.ts index df14612813d4..9dc02f2235ab 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -9,7 +9,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import * as marked from 'vs/base/common/marked/marked'; import { parse } from 'vs/base/common/marshalling'; import { cloneAndChange } from 'vs/base/common/objects'; -import { isDefined, isNumber, isString } from 'vs/base/common/types'; +import { isDefined, isEmptyObject, isNumber, isString } from 'vs/base/common/types'; import { URI, UriComponents } from 'vs/base/common/uri'; import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions'; import { IPosition } from 'vs/editor/common/core/position'; @@ -545,7 +545,7 @@ export namespace WorkspaceEdit { resource: entry.uri, edit: entry.edit, notebookMetadata: entry.notebookMetadata, - notebookVersionId: extHostNotebooks?.lookupNotebookDocument(entry.uri)?.apiNotebook.version + notebookVersionId: extHostNotebooks?.getNotebookDocument(entry.uri, true)?.apiNotebook.version }); } else if (entry._type === types.FileEditType.CellOutput) { @@ -580,7 +580,7 @@ export namespace WorkspaceEdit { _type: extHostProtocol.WorkspaceEditType.Cell, metadata: entry.metadata, resource: entry.uri, - notebookVersionId: extHostNotebooks?.lookupNotebookDocument(entry.uri)?.apiNotebook.version, + notebookVersionId: extHostNotebooks?.getNotebookDocument(entry.uri, true)?.apiNotebook.version, edit: { editType: notebooks.CellEditType.Replace, index: entry.index, @@ -1130,37 +1130,35 @@ export namespace SignatureHelp { } } -export namespace InlineHint { +export namespace InlayHint { - export function from(hint: vscode.InlineHint): modes.InlineHint { + export function from(hint: vscode.InlayHint): modes.InlayHint { return { text: hint.text, - range: Range.from(hint.range), - kind: InlineHintKind.from(hint.kind ?? types.InlineHintKind.Other), - description: hint.description && MarkdownString.fromStrict(hint.description), + position: Position.from(hint.position), + kind: InlayHintKind.from(hint.kind ?? types.InlayHintKind.Other), whitespaceBefore: hint.whitespaceBefore, whitespaceAfter: hint.whitespaceAfter }; } - export function to(hint: modes.InlineHint): vscode.InlineHint { - const res = new types.InlineHint( + export function to(hint: modes.InlayHint): vscode.InlayHint { + const res = new types.InlayHint( hint.text, - Range.to(hint.range), - InlineHintKind.to(hint.kind) + Position.to(hint.position), + InlayHintKind.to(hint.kind) ); res.whitespaceAfter = hint.whitespaceAfter; res.whitespaceBefore = hint.whitespaceBefore; - res.description = htmlContent.isMarkdownString(hint.description) ? MarkdownString.to(hint.description) : hint.description; return res; } } -export namespace InlineHintKind { - export function from(kind: vscode.InlineHintKind): modes.InlineHintKind { +export namespace InlayHintKind { + export function from(kind: vscode.InlayHintKind): modes.InlayHintKind { return kind; } - export function to(kind: modes.InlineHintKind): vscode.InlineHintKind { + export function to(kind: modes.InlayHintKind): vscode.InlayHintKind { return kind; } } @@ -1417,49 +1415,20 @@ export namespace NotebookRange { } } -export namespace NotebookCellMetadata { - - export function to(data: notebooks.NotebookCellMetadata): types.NotebookCellMetadata { - return new types.NotebookCellMetadata().with({ - ...data, - ...{ - executionOrder: null, - lastRunSuccess: null, - runState: null, - runStartTime: null, - runStartTimeAdjustment: null, - runEndTime: null - } - }); - } -} - -export namespace NotebookDocumentMetadata { - - export function from(data: types.NotebookDocumentMetadata): notebooks.NotebookDocumentMetadata { - return data; - } - - export function to(data: notebooks.NotebookDocumentMetadata): types.NotebookDocumentMetadata { - return new types.NotebookDocumentMetadata().with(data); - } -} - -export namespace NotebookCellPreviousExecutionResult { - export function to(data: notebooks.NotebookCellMetadata): vscode.NotebookCellExecutionSummary { +export namespace NotebookCellExecutionSummary { + export function to(data: notebooks.NotebookCellInternalMetadata): vscode.NotebookCellExecutionSummary { return { - startTime: data.runStartTime, - endTime: data.runEndTime, + timing: typeof data.runStartTime === 'number' && typeof data.runEndTime === 'number' ? { startTime: data.runStartTime, endTime: data.runEndTime } : undefined, executionOrder: data.executionOrder, success: data.lastRunSuccess }; } - export function from(data: vscode.NotebookCellExecutionSummary): Partial { + export function from(data: vscode.NotebookCellExecutionSummary): Partial { return { lastRunSuccess: data.success, - runStartTime: data.startTime, - runEndTime: data.endTime, + runStartTime: data.timing?.startTime, + runEndTime: data.timing?.endTime, executionOrder: data.executionOrder }; } @@ -1468,8 +1437,8 @@ export namespace NotebookCellPreviousExecutionResult { export namespace NotebookCellKind { export function from(data: vscode.NotebookCellKind): notebooks.CellKind { switch (data) { - case types.NotebookCellKind.Markdown: - return notebooks.CellKind.Markdown; + case types.NotebookCellKind.Markup: + return notebooks.CellKind.Markup; case types.NotebookCellKind.Code: default: return notebooks.CellKind.Code; @@ -1478,8 +1447,8 @@ export namespace NotebookCellKind { export function to(data: notebooks.CellKind): vscode.NotebookCellKind { switch (data) { - case notebooks.CellKind.Markdown: - return types.NotebookCellKind.Markdown; + case notebooks.CellKind.Markup: + return types.NotebookCellKind.Markup; case notebooks.CellKind.Code: default: return types.NotebookCellKind.Code; @@ -1487,17 +1456,40 @@ export namespace NotebookCellKind { } } +export namespace NotebookData { + + export function from(data: vscode.NotebookData): notebooks.NotebookDataDto { + const res: notebooks.NotebookDataDto = { + metadata: Object.create(null), + cells: [], + }; + for (let cell of data.cells) { + types.NotebookCellData.validate(cell); + res.cells.push(NotebookCellData.from(cell)); + } + return res; + } + + export function to(data: notebooks.NotebookDataDto): vscode.NotebookData { + const res = new types.NotebookData( + data.cells.map(NotebookCellData.to), + ); + if (!isEmptyObject(data.metadata)) { + res.metadata = data.metadata; + } + return res; + } +} + export namespace NotebookCellData { export function from(data: vscode.NotebookCellData): notebooks.ICellDto2 { return { cellKind: NotebookCellKind.from(data.kind), - language: data.language, - source: data.source, - metadata: { - ...data.metadata, - ...NotebookCellPreviousExecutionResult.from(data.latestExecutionSummary ?? {}) - }, + language: data.languageId, + source: data.value, + metadata: data.metadata, + internalMetadata: NotebookCellExecutionSummary.from(data.executionSummary ?? {}), outputs: data.outputs ? data.outputs.map(NotebookCellOutput.from) : [] }; } @@ -1508,7 +1500,8 @@ export namespace NotebookCellData { data.source, data.language, data.outputs ? data.outputs.map(NotebookCellOutput.to) : undefined, - data.metadata ? NotebookCellMetadata.to(data.metadata) : undefined, + data.metadata, + data.internalMetadata ? NotebookCellExecutionSummary.to(data.internalMetadata) : undefined ); } } @@ -1517,21 +1510,20 @@ export namespace NotebookCellOutputItem { export function from(item: types.NotebookCellOutputItem): notebooks.IOutputItemDto { return { mime: item.mime, - value: item.value, - metadata: item.metadata + valueBytes: Array.from(item.data), //todo@jrieken this HACKY and SLOW... hoist VSBuffer instead }; } export function to(item: notebooks.IOutputItemDto): types.NotebookCellOutputItem { - return new types.NotebookCellOutputItem(item.mime, item.value, item.metadata); + return new types.NotebookCellOutputItem(new Uint8Array(item.valueBytes), item.mime); } } export namespace NotebookCellOutput { - export function from(output: types.NotebookCellOutput): notebooks.IOutputDto { + export function from(output: vscode.NotebookCellOutput): notebooks.IOutputDto { return { outputId: output.id, - outputs: output.outputs.map(NotebookCellOutputItem.from), + outputs: output.items.map(NotebookCellOutputItem.from), metadata: output.metadata }; } @@ -1644,35 +1636,22 @@ export namespace NotebookDocumentContentOptions { export function from(options: vscode.NotebookDocumentContentOptions | undefined): notebooks.TransientOptions { return { transientOutputs: options?.transientOutputs ?? false, - transientCellMetadata: { - ...options?.transientCellMetadata, - executionOrder: true, - runState: true, - runStartTime: true, - runStartTimeAdjustment: true, - runEndTime: true, - lastRunSuccess: true - }, + transientCellMetadata: options?.transientCellMetadata ?? {}, transientDocumentMetadata: options?.transientDocumentMetadata ?? {} }; } } -export namespace NotebookKernelPreload { - export function from(preload: vscode.NotebookKernelPreload): { uri: UriComponents; provides: string[] } { +export namespace NotebookRendererScript { + export function from(preload: vscode.NotebookRendererScript): { uri: UriComponents; provides: string[] } { return { uri: preload.uri, - provides: typeof preload.provides === 'string' - ? [preload.provides] - : preload.provides ?? [] - }; - } - export function to(preload: { uri: UriComponents; provides: string[] }): vscode.NotebookKernelPreload { - return { - uri: URI.revive(preload.uri), provides: preload.provides }; } + export function to(preload: { uri: UriComponents; provides: string[] }): vscode.NotebookRendererScript { + return new types.NotebookRendererScript(URI.revive(preload.uri), preload.provides); + } } export namespace TestMessage { diff --git a/lib/vscode/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts similarity index 93% rename from lib/vscode/src/vs/workbench/api/common/extHostTypes.ts rename to src/vs/workbench/api/common/extHostTypes.ts index 85e8d64cc59c..ed30c969a705 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -3,13 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { coalesceInPlace, equals } from 'vs/base/common/arrays'; +import { asArray, coalesceInPlace, equals } from 'vs/base/common/arrays'; import { illegalArgument } from 'vs/base/common/errors'; import { IRelativePattern } from 'vs/base/common/glob'; import { isMarkdownString, MarkdownString as BaseMarkdownString } from 'vs/base/common/htmlContent'; import { ReadonlyMapView, ResourceMap } from 'vs/base/common/map'; -import { isFalsyOrWhitespace } from 'vs/base/common/strings'; -import { isStringArray } from 'vs/base/common/types'; +import { normalizeMimeType } from 'vs/base/common/mime'; +import { isArray, isStringArray } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { FileSystemProviderErrorCode, markAsFileSystemProviderError } from 'vs/platform/files/common/files'; @@ -612,7 +612,7 @@ export interface IFileCellEdit { _type: FileEditType.Cell; uri: URI; edit?: ICellEditOperation; - notebookMetadata?: vscode.NotebookDocumentMetadata; + notebookMetadata?: Record; metadata?: vscode.WorkspaceEditEntryMetadata; } @@ -631,7 +631,7 @@ export interface ICellOutputEdit { index: number; append: boolean; newOutputs?: NotebookCellOutput[]; - newMetadata?: vscode.NotebookCellMetadata; + newMetadata?: Record; metadata?: vscode.WorkspaceEditEntryMetadata; } @@ -674,7 +674,7 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit { // --- notebook - replaceNotebookMetadata(uri: URI, value: vscode.NotebookDocumentMetadata, metadata?: vscode.WorkspaceEditEntryMetadata): void { + replaceNotebookMetadata(uri: URI, value: Record, metadata?: vscode.WorkspaceEditEntryMetadata): void { this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.DocumentMetadata, metadata: value }, notebookMetadata: value }); } @@ -707,7 +707,7 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit { } } - replaceNotebookCellMetadata(uri: URI, index: number, cellMetadata: vscode.NotebookCellMetadata, metadata?: vscode.WorkspaceEditEntryMetadata): void { + replaceNotebookCellMetadata(uri: URI, index: number, cellMetadata: Record, metadata?: vscode.WorkspaceEditEntryMetadata): void { this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.PartialMetadata, index, metadata: cellMetadata } }); } @@ -1420,24 +1420,23 @@ export enum SignatureHelpTriggerKind { } -export enum InlineHintKind { +export enum InlayHintKind { Other = 0, Type = 1, Parameter = 2, } @es5ClassCompat -export class InlineHint { +export class InlayHint { text: string; - range: Range; - kind?: vscode.InlineHintKind; - description?: string | vscode.MarkdownString; + position: Position; + kind?: vscode.InlayHintKind; whitespaceBefore?: boolean; whitespaceAfter?: boolean; - constructor(text: string, range: Range, kind?: vscode.InlineHintKind) { + constructor(text: string, position: Position, kind?: vscode.InlayHintKind) { this.text = text; - this.range = range; + this.position = position; this.kind = kind; } } @@ -1548,6 +1547,29 @@ export class CompletionList { } } +@es5ClassCompat +export class InlineSuggestion implements vscode.InlineCompletionItem { + + text: string; + range?: Range; + command?: vscode.Command; + + constructor(text: string, range?: Range, command?: vscode.Command) { + this.text = text; + this.range = range; + this.command = command; + } +} + +@es5ClassCompat +export class InlineSuggestions implements vscode.InlineCompletionList { + items: vscode.InlineCompletionItem[]; + + constructor(items: vscode.InlineCompletionItem[]) { + this.items = items; + } +} + export enum ViewColumn { Active = -1, Beside = -2, @@ -2439,6 +2461,11 @@ export class EvaluatableExpression implements vscode.EvaluatableExpression { } } +export enum InlineCompletionTriggerKind { + Automatic = 0, + Explicit = 1, +} + @es5ClassCompat export class InlineValueText implements vscode.InlineValueText { readonly range: Range; @@ -2956,102 +2983,19 @@ export class NotebookRange { } } -export class NotebookCellMetadata { - readonly inputCollapsed?: boolean; - readonly outputCollapsed?: boolean; - readonly [key: string]: any; - - constructor(inputCollapsed?: boolean, outputCollapsed?: boolean); - constructor(data: Record); - constructor(inputCollapsedOrData: (boolean | undefined) | Record, outputCollapsed?: boolean) { - if (typeof inputCollapsedOrData === 'object') { - Object.assign(this, inputCollapsedOrData); - } else { - this.inputCollapsed = inputCollapsedOrData; - this.outputCollapsed = outputCollapsed; - } - } - - with(change: { - inputCollapsed?: boolean | null, - outputCollapsed?: boolean | null, - [key: string]: any - }): NotebookCellMetadata { - - let { inputCollapsed, outputCollapsed, ...remaining } = change; - - if (inputCollapsed === undefined) { - inputCollapsed = this.inputCollapsed; - } else if (inputCollapsed === null) { - inputCollapsed = undefined; - } - if (outputCollapsed === undefined) { - outputCollapsed = this.outputCollapsed; - } else if (outputCollapsed === null) { - outputCollapsed = undefined; - } - - if (inputCollapsed === this.inputCollapsed && - outputCollapsed === this.outputCollapsed && - Object.keys(remaining).length === 0 - ) { - return this; - } - - return new NotebookCellMetadata( - { - inputCollapsed, - outputCollapsed, - ...remaining - } - ); - } -} - -export class NotebookDocumentMetadata { - readonly trusted: boolean; - readonly [key: string]: any; +export class NotebookCellData { - constructor(trusted?: boolean); - constructor(data: Record); - constructor(trustedOrData: boolean | Record = true) { - if (typeof trustedOrData === 'object') { - Object.assign(this, trustedOrData); - this.trusted = trustedOrData.trusted ?? true; - } else { - this.trusted = trustedOrData; + static validate(data: NotebookCellData): void { + if (typeof data.kind !== 'number') { + throw new Error('NotebookCellData MUST have \'kind\' property'); } - } - - with(change: { - trusted?: boolean | null, - [key: string]: any - }): NotebookDocumentMetadata { - - let { trusted, ...remaining } = change; - - if (trusted === undefined) { - trusted = this.trusted; - } else if (trusted === null) { - trusted = undefined; + if (typeof data.value !== 'string') { + throw new Error('NotebookCellData MUST have \'value\' property'); } - - if (trusted === this.trusted && - Object.keys(remaining).length === 0 - ) { - return this; + if (typeof data.languageId !== 'string') { + throw new Error('NotebookCellData MUST have \'languageId\' property'); } - - return new NotebookDocumentMetadata( - { - trusted, - ...remaining - } - ); } -} - -export class NotebookCellData { static isNotebookCellDataArray(value: unknown): value is vscode.NotebookCellData[] { return Array.isArray(value) && (value).every(elem => NotebookCellData.isNotebookCellData(elem)); @@ -3063,30 +3007,31 @@ export class NotebookCellData { } kind: NotebookCellKind; - source: string; - language: string; - outputs?: NotebookCellOutput[]; - metadata?: NotebookCellMetadata; - latestExecutionSummary?: vscode.NotebookCellExecutionSummary; + value: string; + languageId: string; + outputs?: vscode.NotebookCellOutput[]; + metadata?: Record; + executionSummary?: vscode.NotebookCellExecutionSummary; - constructor(kind: NotebookCellKind, source: string, language: string, outputs?: NotebookCellOutput[], metadata?: NotebookCellMetadata, latestExecutionSummary?: vscode.NotebookCellExecutionSummary) { + constructor(kind: NotebookCellKind, value: string, languageId: string, outputs?: vscode.NotebookCellOutput[], metadata?: Record, executionSummary?: vscode.NotebookCellExecutionSummary) { this.kind = kind; - this.source = source; - this.language = language; + this.value = value; + this.languageId = languageId; this.outputs = outputs ?? []; this.metadata = metadata; - this.latestExecutionSummary = latestExecutionSummary; + this.executionSummary = executionSummary; + + NotebookCellData.validate(this); } } export class NotebookData { cells: NotebookCellData[]; - metadata: NotebookDocumentMetadata; + metadata?: { [key: string]: any }; - constructor(cells: NotebookCellData[], metadata?: NotebookDocumentMetadata) { + constructor(cells: NotebookCellData[]) { this.cells = cells; - this.metadata = metadata ?? new NotebookDocumentMetadata(); } } @@ -3094,32 +3039,105 @@ export class NotebookData { export class NotebookCellOutputItem { static isNotebookCellOutputItem(obj: unknown): obj is vscode.NotebookCellOutputItem { - return obj instanceof NotebookCellOutputItem; + if (obj instanceof NotebookCellOutputItem) { + return true; + } + if (!obj) { + return false; + } + return typeof (obj).mime === 'string' + && (obj).data instanceof Uint8Array; + } + + static error(err: Error | { name: string, message?: string, stack?: string }): NotebookCellOutputItem { + const obj = { + name: err.name, + message: err.message, + stack: err.stack + }; + return NotebookCellOutputItem.json(obj, 'application/vnd.code.notebook.error'); + } + + static stdout(value: string): NotebookCellOutputItem { + return NotebookCellOutputItem.text(value, 'application/vnd.code.notebook.stdout'); + } + + static stderr(value: string): NotebookCellOutputItem { + return NotebookCellOutputItem.text(value, 'application/vnd.code.notebook.stderr'); + } + + static bytes(value: Uint8Array, mime: string = 'application/octet-stream'): NotebookCellOutputItem { + return new NotebookCellOutputItem(value, mime); + } + + static #encoder = new TextEncoder(); + + static text(value: string, mime: string = 'text/plain'): NotebookCellOutputItem { + const bytes = NotebookCellOutputItem.#encoder.encode(String(value)); + return new NotebookCellOutputItem(bytes, mime); + } + + static json(value: any, mime: string = 'application/json'): NotebookCellOutputItem { + const rawStr = JSON.stringify(value, undefined, '\t'); + return NotebookCellOutputItem.text(rawStr, mime); } constructor( + public data: Uint8Array, public mime: string, - public value: unknown, // JSON'able - public metadata?: Record ) { - if (isFalsyOrWhitespace(this.mime)) { - throw new Error('INVALID mime type, must not be empty or falsy'); + const mimeNormalized = normalizeMimeType(mime, true); + if (!mimeNormalized) { + throw new Error('INVALID mime type, must not be empty or falsy: ' + mime); } + this.mime = mimeNormalized; } } export class NotebookCellOutput { + static isNotebookCellOutput(candidate: any): candidate is vscode.NotebookCellOutput { + if (candidate instanceof NotebookCellOutput) { + return true; + } + if (!candidate || typeof candidate !== 'object') { + return false; + } + return typeof (candidate).id === 'string' && isArray((candidate).items); + } + + static ensureUniqueMimeTypes(items: NotebookCellOutputItem[], warn: boolean = false): NotebookCellOutputItem[] { + const seen = new Set(); + const removeIdx = new Set(); + for (let i = 0; i < items.length; i++) { + const item = items[i]; + const normalMime = normalizeMimeType(item.mime); + if (!seen.has(normalMime)) { + seen.add(normalMime); + continue; + } + // duplicated mime types... first has won + removeIdx.add(i); + if (warn) { + console.warn(`DUPLICATED mime type '${item.mime}' will be dropped`); + } + } + if (removeIdx.size === 0) { + return items; + } + return items.filter((_item, index) => !removeIdx.has(index)); + } + id: string; - outputs: NotebookCellOutputItem[]; + items: NotebookCellOutputItem[]; metadata?: Record; constructor( - outputs: NotebookCellOutputItem[], + items: NotebookCellOutputItem[], idOrMetadata?: string | Record, metadata?: Record ) { - this.outputs = outputs; + this.items = NotebookCellOutput.ensureUniqueMimeTypes(items, true); if (typeof idOrMetadata === 'string') { this.id = idOrMetadata; this.metadata = metadata; @@ -3131,7 +3149,7 @@ export class NotebookCellOutput { } export enum NotebookCellKind { - Markdown = 1, + Markup = 1, Code = 2 } @@ -3156,11 +3174,7 @@ export enum NotebookEditorRevealType { export class NotebookCellStatusBarItem { constructor( public text: string, - public alignment: NotebookCellStatusBarAlignment, - public command?: string | vscode.Command, - public tooltip?: string, - public priority?: number, - public accessibilityInformation?: vscode.AccessibilityInformation) { } + public alignment: NotebookCellStatusBarAlignment) { } } @@ -3169,6 +3183,18 @@ export enum NotebookControllerAffinity { Preferred = 2 } +export class NotebookRendererScript { + + public provides: string[]; + + constructor( + public uri: vscode.Uri, + provides: string | string[] = [] + ) { + this.provides = asArray(provides); + } +} + //#endregion //#region Timeline @@ -3228,6 +3254,25 @@ export class LinkedEditingRanges { } } +//#region ports +export class PortAttributes { + private _port: number; + private _autoForwardAction: PortAutoForwardAction; + constructor(port: number, autoForwardAction: PortAutoForwardAction) { + this._port = port; + this._autoForwardAction = autoForwardAction; + } + + get port(): number { + return this._port; + } + + get autoForwardAction(): PortAutoForwardAction { + return this._autoForwardAction; + } +} +//#endregion ports + //#region Testing export enum TestResultState { Unset = 0, @@ -3282,7 +3327,7 @@ const rangeComparator = (a: vscode.Range | undefined, b: vscode.Range | undefine export class TestItemImpl implements vscode.TestItem { public readonly id!: string; - public readonly uri!: vscode.Uri; + public readonly uri!: vscode.Uri | undefined; public readonly children!: ReadonlyMap; public readonly parent!: TestItemImpl | undefined; @@ -3296,7 +3341,7 @@ export class TestItemImpl implements vscode.TestItem { /** Extension-owned resolve handler */ public resolveHandler?: (token: vscode.CancellationToken) => void; - constructor(id: string, public label: string, uri: vscode.Uri, public data: unknown) { + constructor(id: string, public label: string, uri: vscode.Uri | undefined, public data: unknown) { const api = getPrivateApiFor(this); Object.defineProperties(this, { @@ -3322,7 +3367,7 @@ export class TestItemImpl implements vscode.TestItem { range: testItemPropAccessor(api, 'range', undefined, rangeComparator), description: testItemPropAccessor(api, 'description', undefined, strictEqualComparator), runnable: testItemPropAccessor(api, 'runnable', true, strictEqualComparator), - debuggable: testItemPropAccessor(api, 'debuggable', true, strictEqualComparator), + debuggable: testItemPropAccessor(api, 'debuggable', false, strictEqualComparator), status: testItemPropAccessor(api, 'status', TestItemStatus.Resolved, strictEqualComparator), error: testItemPropAccessor(api, 'error', undefined, strictEqualComparator), }); diff --git a/lib/vscode/src/vs/workbench/api/common/extHostUriOpener.ts b/src/vs/workbench/api/common/extHostUriOpener.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostUriOpener.ts rename to src/vs/workbench/api/common/extHostUriOpener.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostUriTransformerService.ts b/src/vs/workbench/api/common/extHostUriTransformerService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostUriTransformerService.ts rename to src/vs/workbench/api/common/extHostUriTransformerService.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostUrls.ts b/src/vs/workbench/api/common/extHostUrls.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostUrls.ts rename to src/vs/workbench/api/common/extHostUrls.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostWebview.ts b/src/vs/workbench/api/common/extHostWebview.ts similarity index 81% rename from lib/vscode/src/vs/workbench/api/common/extHostWebview.ts rename to src/vs/workbench/api/common/extHostWebview.ts index b4a280b116b4..9de76732f606 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostWebview.ts +++ b/src/vs/workbench/api/common/extHostWebview.ts @@ -10,9 +10,9 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions' import { normalizeVersion, parseVersion } from 'vs/platform/extensions/common/extensionValidator'; import { ILogService } from 'vs/platform/log/common/log'; import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService'; -import { deserializeWebviewMessage } from 'vs/workbench/api/common/extHostWebviewMessaging'; +import { serializeWebviewMessage, deserializeWebviewMessage } from 'vs/workbench/api/common/extHostWebviewMessaging'; import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; -import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview'; +import { asWebviewUri, webviewGenericCspSource, WebviewInitData } from 'vs/workbench/api/common/shared/webview'; import type * as vscode from 'vscode'; import * as extHostProtocol from './extHost.protocol'; @@ -69,12 +69,11 @@ export class ExtHostWebview implements vscode.Webview { public asWebviewUri(resource: vscode.Uri): vscode.Uri { this.#hasCalledAsWebviewUri = true; - return asWebviewUri(this.#initData, this.#handle, resource); + return asWebviewUri(resource, this.#initData.remote); } public get cspSource(): string { - return this.#initData.webviewCspSource - .replace('{{uuid}}', this.#handle); + return webviewGenericCspSource; } public get html(): string { @@ -110,7 +109,7 @@ export class ExtHostWebview implements vscode.Webview { if (this.#isDisposed) { return false; } - const serialized = serializeMessage(message, { serializeBuffersForPostMessage: this.#serializeBuffersForPostMessage }); + const serialized = serializeWebviewMessage(message, { serializeBuffersForPostMessage: this.#serializeBuffersForPostMessage }); return this.#proxy.$postMessage(this.#handle, serialized.message, ...serialized.buffers); } @@ -122,48 +121,14 @@ export class ExtHostWebview implements vscode.Webview { } export function shouldSerializeBuffersForPostMessage(extension: IExtensionDescription): boolean { - if (!extension.enableProposedApi) { - return false; - } - try { const version = normalizeVersion(parseVersion(extension.engines.vscode)); - return !!version && version.majorBase >= 1 && version.minorBase >= 56; + return !!version && version.majorBase >= 1 && version.minorBase >= 57; } catch { return false; } } -export function serializeMessage(message: any, options: { serializeBuffersForPostMessage?: boolean }): { message: string, buffers: VSBuffer[] } { - if (options.serializeBuffersForPostMessage) { - // Extract all ArrayBuffers from the message and replace them with references. - const vsBuffers: Array<{ original: ArrayBuffer, vsBuffer: VSBuffer }> = []; - - const replacer = (_key: string, value: any) => { - if (value && value instanceof ArrayBuffer) { - let index = vsBuffers.findIndex(x => x.original === value); - if (index === -1) { - const bytes = new Uint8Array(value); - const vsBuffer = VSBuffer.wrap(bytes); - index = vsBuffers.length; - vsBuffers.push({ original: value, vsBuffer }); - } - - return { - $$vscode_array_buffer_reference$$: true, - index, - }; - } - return value; - }; - - const serializedMessage = JSON.stringify(message, replacer); - return { message: serializedMessage, buffers: vsBuffers.map(x => x.vsBuffer) }; - } else { - return { message: JSON.stringify(message), buffers: [] }; - } -} - export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape { private readonly _webviewProxy: extHostProtocol.MainThreadWebviewsShape; diff --git a/lib/vscode/src/vs/workbench/api/common/extHostWebviewMessaging.ts b/src/vs/workbench/api/common/extHostWebviewMessaging.ts similarity index 98% rename from lib/vscode/src/vs/workbench/api/common/extHostWebviewMessaging.ts rename to src/vs/workbench/api/common/extHostWebviewMessaging.ts index 06e76ab5b5e0..bba4171c6f1b 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostWebviewMessaging.ts +++ b/src/vs/workbench/api/common/extHostWebviewMessaging.ts @@ -21,9 +21,9 @@ class ArrayBufferSet { export function serializeWebviewMessage( message: any, - transfer?: readonly ArrayBuffer[] + options: { serializeBuffersForPostMessage?: boolean } ): { message: string, buffers: VSBuffer[] } { - if (transfer) { + if (options.serializeBuffersForPostMessage) { // Extract all ArrayBuffers from the message and replace them with references. const arrayBuffers = new ArrayBufferSet(); diff --git a/lib/vscode/src/vs/workbench/api/common/extHostWebviewPanels.ts b/src/vs/workbench/api/common/extHostWebviewPanels.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostWebviewPanels.ts rename to src/vs/workbench/api/common/extHostWebviewPanels.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostWebviewView.ts b/src/vs/workbench/api/common/extHostWebviewView.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/extHostWebviewView.ts rename to src/vs/workbench/api/common/extHostWebviewView.ts diff --git a/lib/vscode/src/vs/workbench/api/common/extHostWindow.ts b/src/vs/workbench/api/common/extHostWindow.ts similarity index 95% rename from lib/vscode/src/vs/workbench/api/common/extHostWindow.ts rename to src/vs/workbench/api/common/extHostWindow.ts index a8c05964b01c..46e6191675f8 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostWindow.ts +++ b/src/vs/workbench/api/common/extHostWindow.ts @@ -61,8 +61,6 @@ export class ExtHostWindow implements ExtHostWindowShape { async asExternalUri(uri: URI, options: IOpenUriOptions): Promise { if (isFalsyOrWhitespace(uri.scheme)) { return Promise.reject('Invalid scheme - cannot be empty'); - } else if (!new Set([Schemas.http, Schemas.https]).has(uri.scheme)) { - return Promise.reject(`Invalid scheme '${uri.scheme}'`); } const result = await this._proxy.$asExternalUri(uri, options); diff --git a/lib/vscode/src/vs/workbench/api/common/extHostWorkspace.ts b/src/vs/workbench/api/common/extHostWorkspace.ts similarity index 99% rename from lib/vscode/src/vs/workbench/api/common/extHostWorkspace.ts rename to src/vs/workbench/api/common/extHostWorkspace.ts index 4e80bce81f91..b81eea794a6e 100644 --- a/lib/vscode/src/vs/workbench/api/common/extHostWorkspace.ts +++ b/src/vs/workbench/api/common/extHostWorkspace.ts @@ -563,8 +563,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac } requestWorkspaceTrust(options?: vscode.WorkspaceTrustRequestOptions): Promise { - const promise = this._proxy.$requestWorkspaceTrust(options); - return options?.modal ? promise : Promise.resolve(this._trusted); + return this._proxy.$requestWorkspaceTrust(options); } $onDidGrantWorkspaceTrust(): void { diff --git a/lib/vscode/src/vs/workbench/api/common/jsonValidationExtensionPoint.ts b/src/vs/workbench/api/common/jsonValidationExtensionPoint.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/jsonValidationExtensionPoint.ts rename to src/vs/workbench/api/common/jsonValidationExtensionPoint.ts diff --git a/lib/vscode/src/vs/workbench/api/common/menusExtensionPoint.ts b/src/vs/workbench/api/common/menusExtensionPoint.ts similarity index 95% rename from lib/vscode/src/vs/workbench/api/common/menusExtensionPoint.ts rename to src/vs/workbench/api/common/menusExtensionPoint.ts index 3046d981ff38..513eb79d4855 100644 --- a/lib/vscode/src/vs/workbench/api/common/menusExtensionPoint.ts +++ b/src/vs/workbench/api/common/menusExtensionPoint.ts @@ -23,6 +23,7 @@ interface IAPIMenu { readonly description: string; readonly proposed?: boolean; // defaults to false readonly supportsSubmenus?: boolean; // defaults to true + readonly deprecationMessage?: string; } const apiMenus: IAPIMenu[] = [ @@ -136,7 +137,8 @@ const apiMenus: IAPIMenu[] = [ id: MenuId.StatusBarWindowIndicatorMenu, description: localize('menus.statusBarWindowIndicator', "The window indicator menu in the status bar"), proposed: true, - supportsSubmenus: false + supportsSubmenus: false, + deprecationMessage: localize('menus.statusBarWindowIndicator.deprecated', "Use menu 'statusBar/remoteIndicator' instead."), }, { key: 'statusBar/remoteIndicator', @@ -182,6 +184,12 @@ const apiMenus: IAPIMenu[] = [ description: localize('notebook.toolbar', "The contributed notebook toolbar menu"), proposed: true }, + { + key: 'notebook/toolbar/right', + id: MenuId.NotebookRightToolbar, + description: localize('notebook.toolbar.right', "The contributed notebook right toolbar menu"), + proposed: true + }, { key: 'notebook/cell/title', id: MenuId.NotebookCellTitle, @@ -223,7 +231,14 @@ const apiMenus: IAPIMenu[] = [ key: 'ports/item/port/inline', id: MenuId.TunnelPortInline, description: localize('view.tunnelPortInline', "The Ports view item port inline menu") - } + }, + { + key: 'editor/inlineCompletions/actions', + id: MenuId.InlineCompletionsActions, + description: localize('inlineCompletions.actions', "The actions shown when hovering on an inline completion"), + supportsSubmenus: false, + proposed: true + }, ]; namespace schema { @@ -411,6 +426,7 @@ namespace schema { type: 'object', properties: index(apiMenus, menu => menu.key, menu => ({ description: menu.proposed ? `(${localize('proposed', "Proposed API")}) ${menu.description}` : menu.description, + deprecationMessage: menu.deprecationMessage, type: 'array', items: menu.supportsSubmenus === false ? menuItem : { oneOf: [menuItem, submenuItem] } })), @@ -432,6 +448,7 @@ namespace schema { export interface IUserFriendlyCommand { command: string; title: string | ILocalizedString; + shortTitle?: string | ILocalizedString; enablement?: string; category?: string | ILocalizedString; icon?: IUserFriendlyIcon; @@ -451,6 +468,9 @@ namespace schema { if (!isValidLocalizedString(command.title, collector, 'title')) { return false; } + if (command.shortTitle && !isValidLocalizedString(command.shortTitle, collector, 'shortTitle')) { + return false; + } if (command.enablement && typeof command.enablement !== 'string') { collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'precondition')); return false; @@ -504,6 +524,10 @@ namespace schema { description: localize('vscode.extension.contributes.commandType.title', 'Title by which the command is represented in the UI'), type: 'string' }, + shortTitle: { + description: localize('vscode.extension.contributes.commandType.shortTitle', 'Short title by which the command is represented in the UI'), + type: 'string' + }, category: { description: localize('vscode.extension.contributes.commandType.category', '(Optional) Category string by the command is grouped in the UI'), type: 'string' @@ -561,7 +585,7 @@ commandsExtensionPoint.setHandler(extensions => { return; } - const { icon, enablement, category, title, command } = userFriendlyCommand; + const { icon, enablement, category, title, shortTitle, command } = userFriendlyCommand; let absoluteIcon: { dark: URI; light?: URI; } | ThemeIcon | undefined; if (icon) { @@ -582,6 +606,7 @@ commandsExtensionPoint.setHandler(extensions => { bucket.push({ id: command, title, + shortTitle: extension.description.enableProposedApi ? shortTitle : undefined, category, precondition: ContextKeyExpr.deserialize(enablement), icon: absoluteIcon diff --git a/lib/vscode/src/vs/workbench/api/common/shared/tasks.ts b/src/vs/workbench/api/common/shared/tasks.ts similarity index 99% rename from lib/vscode/src/vs/workbench/api/common/shared/tasks.ts rename to src/vs/workbench/api/common/shared/tasks.ts index 4de859f671b3..066b22f90ea7 100644 --- a/lib/vscode/src/vs/workbench/api/common/shared/tasks.ts +++ b/src/vs/workbench/api/common/shared/tasks.ts @@ -19,6 +19,7 @@ export interface TaskPresentationOptionsDTO { showReuseMessage?: boolean; clear?: boolean; group?: string; + close?: boolean; } export interface RunOptionsDTO { diff --git a/src/vs/workbench/api/common/shared/webview.ts b/src/vs/workbench/api/common/shared/webview.ts new file mode 100644 index 000000000000..9c78a6bf9f1e --- /dev/null +++ b/src/vs/workbench/api/common/shared/webview.ts @@ -0,0 +1,65 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Schemas } from 'vs/base/common/network'; +import { URI } from 'vs/base/common/uri'; +import type * as vscode from 'vscode'; + +export interface WebviewInitData { + readonly remote: { + readonly isRemote: boolean; + readonly authority: string | undefined + }; +} + +/** + * Root from which resources in webviews are loaded. + * + * This is hardcoded because we never expect to actually hit it. Instead these requests + * should always go to a service worker. + */ +export const webviewResourceBaseHost = 'vscode-webview.net'; + +export const webviewRootResourceAuthority = `vscode-resource.${webviewResourceBaseHost}`; + +export const webviewGenericCspSource = `https://*.${webviewResourceBaseHost}`; + +/** + * Construct a uri that can load resources inside a webview + * + * We encode the resource component of the uri so that on the main thread + * we know where to load the resource from (remote or truly local): + * + * ```txt + * ${scheme}+${resource-authority}.vscode-resource.vscode-webview.net/${path} + * ``` + * + * @param resource Uri of the resource to load. + * @param remoteInfo Optional information about the remote that specifies where `resource` should be resolved from. + */ +export function asWebviewUri( + resource: vscode.Uri, + remoteInfo?: { authority: string | undefined, isRemote: boolean } +): vscode.Uri { + if (resource.scheme === Schemas.http || resource.scheme === Schemas.https) { + return resource; + } + + if (remoteInfo && remoteInfo.authority && remoteInfo.isRemote && resource.scheme === Schemas.file) { + resource = URI.from({ + scheme: Schemas.vscodeRemote, + authority: remoteInfo.authority, + path: resource.path, + }); + } + + return URI.from({ + scheme: Schemas.https, + authority: `${resource.scheme}+${resource.authority}.${webviewRootResourceAuthority}`, + path: resource.path, + fragment: resource.fragment, + query: resource.query, + }); +} diff --git a/lib/vscode/src/vs/workbench/api/common/shared/workspaceContains.ts b/src/vs/workbench/api/common/shared/workspaceContains.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/common/shared/workspaceContains.ts rename to src/vs/workbench/api/common/shared/workspaceContains.ts diff --git a/lib/vscode/src/vs/workbench/api/node/extHost.node.services.ts b/src/vs/workbench/api/node/extHost.node.services.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/node/extHost.node.services.ts rename to src/vs/workbench/api/node/extHost.node.services.ts diff --git a/lib/vscode/src/vs/workbench/api/node/extHostCLIServer.ts b/src/vs/workbench/api/node/extHostCLIServer.ts similarity index 95% rename from lib/vscode/src/vs/workbench/api/node/extHostCLIServer.ts rename to src/vs/workbench/api/node/extHostCLIServer.ts index d5bc09abd495..6177f03c80fd 100644 --- a/lib/vscode/src/vs/workbench/api/node/extHostCLIServer.ts +++ b/src/vs/workbench/api/node/extHostCLIServer.ts @@ -11,8 +11,6 @@ import { IWindowOpenable, IOpenWindowOptions } from 'vs/platform/windows/common/ import { URI } from 'vs/base/common/uri'; import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; import { ILogService } from 'vs/platform/log/common/log'; -import { join } from 'vs/base/common/path'; -import { tmpdir } from 'os'; export interface OpenCommandPipeArgs { type: 'open'; @@ -69,11 +67,6 @@ export class CLIServerBase { } private async setup(): Promise { - // NOTE@coder: Write this out so we can get the most recent path. - fs.promises.writeFile(join(tmpdir(), 'vscode-ipc'), this._ipcHandlePath).catch((error) => { - this.logService.error(error); - }); - try { this._server.listen(this.ipcHandlePath); this._server.on('error', err => this.logService.error(err)); diff --git a/lib/vscode/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts similarity index 95% rename from lib/vscode/src/vs/workbench/api/node/extHostDebugService.ts rename to src/vs/workbench/api/node/extHostDebugService.ts index 9ba96a894b50..193490ea7b0d 100644 --- a/lib/vscode/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -20,10 +20,11 @@ import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { ExtHostDebugServiceBase, ExtHostDebugSession, ExtHostVariableResolverService } from 'vs/workbench/api/common/extHostDebugService'; import { ISignService } from 'vs/platform/sign/common/sign'; import { SignService } from 'vs/platform/sign/node/signService'; -import { hasChildProcesses, prepareCommand, runInExternalTerminal } from 'vs/workbench/contrib/debug/node/terminals'; import { IDisposable } from 'vs/base/common/lifecycle'; import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver'; import { createCancelablePromise, firstParallel } from 'vs/base/common/async'; +import { hasChildProcesses, prepareCommand, runInExternalTerminal } from 'vs/workbench/contrib/debug/node/terminals'; +import { IExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs'; export class ExtHostDebugService extends ExtHostDebugServiceBase { @@ -38,9 +39,10 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase { @IExtHostExtensionService extensionService: IExtHostExtensionService, @IExtHostDocumentsAndEditors editorsService: IExtHostDocumentsAndEditors, @IExtHostConfiguration configurationService: IExtHostConfiguration, - @IExtHostTerminalService private _terminalService: IExtHostTerminalService + @IExtHostTerminalService private _terminalService: IExtHostTerminalService, + @IExtHostEditorTabs editorTabs: IExtHostEditorTabs ) { - super(extHostRpcService, workspaceService, extensionService, editorsService, configurationService); + super(extHostRpcService, workspaceService, extensionService, editorsService, configurationService, editorTabs); } protected override createDebugAdapter(adapter: IAdapterDescriptor, session: ExtHostDebugSession): AbstractDebugAdapter | undefined { @@ -79,8 +81,8 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase { } const configProvider = await this._configurationService.getConfigProvider(); - const shell = this._terminalService.getDefaultShell(true, configProvider); - const shellArgs = this._terminalService.getDefaultShellArgs(true, configProvider); + const shell = this._terminalService.getDefaultShell(true); + const shellArgs = this._terminalService.getDefaultShellArgs(true); const shellConfig = JSON.stringify({ shell, shellArgs }); let terminal = await this._integratedTerminalInstances.checkout(shellConfig); @@ -96,7 +98,10 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase { name: args.title || nls.localize('debug.terminal.title', "debuggee"), }; giveShellTimeToInitialize = true; - terminal = this._terminalService.createTerminalFromOptions(options, true); + terminal = this._terminalService.createTerminalFromOptions(options, { + isFeatureTerminal: true, + useShellEnvironment: true + }); this._integratedTerminalInstances.insert(terminal, shellConfig); } else { @@ -139,14 +144,13 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase { return shellProcessId; } else if (args.kind === 'external') { - return runInExternalTerminal(args, await this._configurationService.getConfigProvider()); } return super.$runInTerminal(args, sessionId); } protected createVariableResolver(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfigProvider): AbstractVariableResolverService { - return new ExtHostVariableResolverService(folders, editorService, configurationService, this._workspaceService); + return new ExtHostVariableResolverService(folders, editorService, configurationService, this._editorTabs, this._workspaceService); } } diff --git a/lib/vscode/src/vs/workbench/api/node/extHostDownloadService.ts b/src/vs/workbench/api/node/extHostDownloadService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/node/extHostDownloadService.ts rename to src/vs/workbench/api/node/extHostDownloadService.ts diff --git a/lib/vscode/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/node/extHostExtensionService.ts rename to src/vs/workbench/api/node/extHostExtensionService.ts diff --git a/lib/vscode/src/vs/workbench/api/node/extHostLogService.ts b/src/vs/workbench/api/node/extHostLogService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/node/extHostLogService.ts rename to src/vs/workbench/api/node/extHostLogService.ts diff --git a/lib/vscode/src/vs/workbench/api/node/extHostOutputService.ts b/src/vs/workbench/api/node/extHostOutputService.ts similarity index 85% rename from lib/vscode/src/vs/workbench/api/node/extHostOutputService.ts rename to src/vs/workbench/api/node/extHostOutputService.ts index 518c90b4b732..9935633b766e 100644 --- a/lib/vscode/src/vs/workbench/api/node/extHostOutputService.ts +++ b/src/vs/workbench/api/node/extHostOutputService.ts @@ -8,26 +8,27 @@ import type * as vscode from 'vscode'; import { URI } from 'vs/base/common/uri'; import { join } from 'vs/base/common/path'; import { toLocalISOString } from 'vs/base/common/date'; -import { SymlinkSupport } from 'vs/base/node/pfs'; -import { promises } from 'fs'; +import { Promises, SymlinkSupport } from 'vs/base/node/pfs'; import { AbstractExtHostOutputChannel, ExtHostPushOutputChannel, ExtHostOutputService, LazyOutputChannel } from 'vs/workbench/api/common/extHostOutput'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { MutableDisposable } from 'vs/base/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; import { createRotatingLogger } from 'vs/platform/log/node/spdlogLog'; -import { RotatingLogger } from 'spdlog'; +import { Logger } from 'spdlog'; import { ByteSize } from 'vs/platform/files/common/files'; class OutputAppender { - private appender: RotatingLogger; + static async create(name: string, file: string): Promise { + const appender = await createRotatingLogger(name, file, 30 * ByteSize.MB, 1); + appender.clearFormatters(); - constructor(name: string, readonly file: string) { - this.appender = createRotatingLogger(name, file, 30 * ByteSize.MB, 1); - this.appender.clearFormatters(); + return new OutputAppender(name, file, appender); } + private constructor(readonly name: string, readonly file: string, private readonly appender: Logger) { } + append(content: string): void { this.appender.critical(content); } @@ -38,7 +39,7 @@ class OutputAppender { } -export class ExtHostOutputChannelBackedByFile extends AbstractExtHostOutputChannel { +class ExtHostOutputChannelBackedByFile extends AbstractExtHostOutputChannel { private _appender: OutputAppender; @@ -109,11 +110,11 @@ export class ExtHostOutputService2 extends ExtHostOutputService { const outputDirPath = join(this._logsLocation.fsPath, `output_logging_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`); const exists = await SymlinkSupport.existsDirectory(outputDirPath); if (!exists) { - await promises.mkdir(outputDirPath, { recursive: true }); + await Promises.mkdir(outputDirPath, { recursive: true }); } const fileName = `${this._namePool++}-${name.replace(/[\\/:\*\?"<>\|]/g, '')}`; const file = URI.file(join(outputDirPath, `${fileName}.log`)); - const appender = new OutputAppender(fileName, file.fsPath); + const appender = await OutputAppender.create(fileName, file.fsPath); return new ExtHostOutputChannelBackedByFile(name, appender, this._proxy); } catch (error) { // Do not crash if logger cannot be created diff --git a/lib/vscode/src/vs/workbench/api/node/extHostSearch.ts b/src/vs/workbench/api/node/extHostSearch.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/node/extHostSearch.ts rename to src/vs/workbench/api/node/extHostSearch.ts diff --git a/lib/vscode/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts similarity index 96% rename from lib/vscode/src/vs/workbench/api/node/extHostTask.ts rename to src/vs/workbench/api/node/extHostTask.ts index dd250c83c291..98a5b1970225 100644 --- a/lib/vscode/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -23,6 +23,7 @@ import { ExtHostTaskBase, TaskHandleDTO, TaskDTO, CustomExecutionDTO, HandlerDat import { Schemas } from 'vs/base/common/network'; import { ILogService } from 'vs/platform/log/common/log'; import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService'; +import { IExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs'; export class ExtHostTask extends ExtHostTaskBase { private _variableResolver: ExtHostVariableResolverService | undefined; @@ -35,7 +36,8 @@ export class ExtHostTask extends ExtHostTaskBase { @IExtHostConfiguration configurationService: IExtHostConfiguration, @IExtHostTerminalService extHostTerminalService: IExtHostTerminalService, @ILogService logService: ILogService, - @IExtHostApiDeprecationService deprecationService: IExtHostApiDeprecationService + @IExtHostApiDeprecationService deprecationService: IExtHostApiDeprecationService, + @IExtHostEditorTabs private readonly editorTabs: IExtHostEditorTabs ) { super(extHostRpc, initData, workspaceService, editorService, configurationService, extHostTerminalService, logService, deprecationService); if (initData.remote.isRemote && initData.remote.authority) { @@ -127,7 +129,7 @@ export class ExtHostTask extends ExtHostTaskBase { private async getVariableResolver(workspaceFolders: vscode.WorkspaceFolder[]): Promise { if (this._variableResolver === undefined) { const configProvider = await this._configurationService.getConfigProvider(); - this._variableResolver = new ExtHostVariableResolverService(workspaceFolders, this._editorService, configProvider, this.workspaceService); + this._variableResolver = new ExtHostVariableResolverService(workspaceFolders, this._editorService, configProvider, this.editorTabs, this.workspaceService); } return this._variableResolver; } @@ -172,10 +174,6 @@ export class ExtHostTask extends ExtHostTaskBase { return result; } - public $getDefaultShellAndArgs(): Promise<{ shell: string, args: string[] | string | undefined }> { - return this._terminalService.$getDefaultShellAndArgs(true); - } - public async $jsonTasksSupported(): Promise { return true; } diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts new file mode 100644 index 000000000000..652223e1a45e --- /dev/null +++ b/src/vs/workbench/api/node/extHostTerminalService.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 { generateUuid } from 'vs/base/common/uuid'; +import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; +import { BaseExtHostTerminalService, ExtHostTerminal, ITerminalInternalOptions } from 'vs/workbench/api/common/extHostTerminalService'; +import type * as vscode from 'vscode'; + +export class ExtHostTerminalService extends BaseExtHostTerminalService { + + constructor( + @IExtHostRpcService extHostRpc: IExtHostRpcService + ) { + super(true, extHostRpc); + } + + public createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal { + return this.createTerminalFromOptions({ name, shellPath, shellArgs }); + } + + public createTerminalFromOptions(options: vscode.TerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal { + const terminal = new ExtHostTerminal(this._proxy, generateUuid(), options, options.name); + this._terminals.push(terminal); + terminal.create(options, internalOptions); + return terminal.value; + } +} diff --git a/lib/vscode/src/vs/workbench/api/node/extHostTunnelService.ts b/src/vs/workbench/api/node/extHostTunnelService.ts similarity index 97% rename from lib/vscode/src/vs/workbench/api/node/extHostTunnelService.ts rename to src/vs/workbench/api/node/extHostTunnelService.ts index a33f7851f347..caefe078c1ab 100644 --- a/lib/vscode/src/vs/workbench/api/node/extHostTunnelService.ts +++ b/src/vs/workbench/api/node/extHostTunnelService.ts @@ -11,7 +11,6 @@ import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitData import { URI } from 'vs/base/common/uri'; import { exec } from 'child_process'; import * as resources from 'vs/base/common/resources'; -import * as fs from 'fs'; import * as pfs from 'vs/base/node/pfs'; import * as types from 'vs/workbench/api/common/extHostTypes'; import { isLinux } from 'vs/base/common/platform'; @@ -365,8 +364,8 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe let tcp: string = ''; let tcp6: string = ''; try { - tcp = await fs.promises.readFile('/proc/net/tcp', 'utf8'); - tcp6 = await fs.promises.readFile('/proc/net/tcp6', 'utf8'); + tcp = await pfs.Promises.readFile('/proc/net/tcp', 'utf8'); + tcp6 = await pfs.Promises.readFile('/proc/net/tcp6', 'utf8'); } catch (e) { // File reading error. No additional handling needed. } @@ -387,10 +386,10 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe try { const pid: number = Number(childName); const childUri = resources.joinPath(URI.file('/proc'), childName); - const childStat = await fs.promises.stat(childUri.fsPath); + const childStat = await pfs.Promises.stat(childUri.fsPath); if (childStat.isDirectory() && !isNaN(pid)) { - const cwd = await fs.promises.readlink(resources.joinPath(childUri, 'cwd').fsPath); - const cmd = await fs.promises.readFile(resources.joinPath(childUri, 'cmdline').fsPath, 'utf8'); + const cwd = await pfs.Promises.readlink(resources.joinPath(childUri, 'cwd').fsPath); + const cmd = await pfs.Promises.readFile(resources.joinPath(childUri, 'cmdline').fsPath, 'utf8'); processes.push({ pid, cwd, cmd }); } } catch (e) { diff --git a/lib/vscode/src/vs/workbench/api/worker/extHost.worker.services.ts b/src/vs/workbench/api/worker/extHost.worker.services.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/worker/extHost.worker.services.ts rename to src/vs/workbench/api/worker/extHost.worker.services.ts diff --git a/lib/vscode/src/vs/workbench/api/worker/extHostExtensionService.ts b/src/vs/workbench/api/worker/extHostExtensionService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/worker/extHostExtensionService.ts rename to src/vs/workbench/api/worker/extHostExtensionService.ts diff --git a/lib/vscode/src/vs/workbench/api/worker/extHostLogService.ts b/src/vs/workbench/api/worker/extHostLogService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/api/worker/extHostLogService.ts rename to src/vs/workbench/api/worker/extHostLogService.ts diff --git a/lib/vscode/src/vs/workbench/browser/menuActions.ts b/src/vs/workbench/browser/actions.ts similarity index 99% rename from lib/vscode/src/vs/workbench/browser/menuActions.ts rename to src/vs/workbench/browser/actions.ts index 7aecec66effe..53eaf6741966 100644 --- a/lib/vscode/src/vs/workbench/browser/menuActions.ts +++ b/src/vs/workbench/browser/actions.ts @@ -32,7 +32,9 @@ class MenuActions extends Disposable { private readonly contextKeyService: IContextKeyService ) { super(); + this.menu = this._register(menuService.createMenu(menuId, contextKeyService)); + this._register(this.menu.onDidChange(() => this.updateActions())); this.updateActions(); } @@ -48,6 +50,7 @@ class MenuActions extends Disposable { private updateSubmenus(actions: readonly IAction[], submenus: { [id: number]: IMenu }): IDisposable { const disposables = new DisposableStore(); + for (const action of actions) { if (action instanceof SubmenuItemAction && !submenus[action.item.submenu.id]) { const menu = submenus[action.item.submenu.id] = disposables.add(this.menuService.createMenu(action.item.submenu, this.contextKeyService)); @@ -55,6 +58,7 @@ class MenuActions extends Disposable { disposables.add(this.updateSubmenus(action.actions, submenus)); } } + return disposables; } } @@ -75,7 +79,9 @@ export class CompositeMenuActions extends Disposable { @IMenuService private readonly menuService: IMenuService, ) { super(); + this.menuActions = this._register(new MenuActions(menuId, this.options, menuService, contextKeyService)); + this._register(this.menuActions.onDidChange(() => this._onDidChange.fire())); } @@ -89,11 +95,13 @@ export class CompositeMenuActions extends Disposable { getContextMenuActions(): IAction[] { const actions: IAction[] = []; + if (this.contextMenuId) { const menu = this.menuService.createMenu(this.contextMenuId, this.contextKeyService); this.contextMenuActionsDisposable.value = createAndFillInActionBarActions(menu, this.options, { primary: [], secondary: actions }); menu.dispose(); } + return actions; } } diff --git a/lib/vscode/src/vs/workbench/browser/actions/developerActions.ts b/src/vs/workbench/browser/actions/developerActions.ts similarity index 92% rename from lib/vscode/src/vs/workbench/browser/actions/developerActions.ts rename to src/vs/workbench/browser/actions/developerActions.ts index 82c377cd1f83..b12c147f01ff 100644 --- a/lib/vscode/src/vs/workbench/browser/actions/developerActions.ts +++ b/src/vs/workbench/browser/actions/developerActions.ts @@ -7,7 +7,7 @@ import 'vs/css!./media/actions'; import { localize } from 'vs/nls'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { domEvent } from 'vs/base/browser/event'; +import { DomEmitter } from 'vs/base/browser/event'; import { Color } from 'vs/base/common/color'; import { Event } from 'vs/base/common/event'; import { IDisposable, toDisposable, dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; @@ -63,8 +63,8 @@ class InspectContextKeysAction extends Action2 { hoverFeedback.style.backgroundColor = 'rgba(255, 0, 0, 0.5)'; hoverFeedback.style.zIndex = '1000'; - const onMouseMove = domEvent(document.body, 'mousemove', true); - disposables.add(onMouseMove(e => { + const onMouseMove = disposables.add(new DomEmitter(document.body, 'mousemove', true)); + disposables.add(onMouseMove.event(e => { const target = e.target as HTMLElement; const position = getDomNodePagePosition(target); @@ -74,11 +74,11 @@ class InspectContextKeysAction extends Action2 { hoverFeedback.style.height = `${position.height}px`; })); - const onMouseDown = Event.once(domEvent(document.body, 'mousedown', true)); - onMouseDown(e => { e.preventDefault(); e.stopPropagation(); }, null, disposables); + const onMouseDown = disposables.add(new DomEmitter(document.body, 'mousedown', true)); + Event.once(onMouseDown.event)(e => { e.preventDefault(); e.stopPropagation(); }, null, disposables); - const onMouseUp = Event.once(domEvent(document.body, 'mouseup', true)); - onMouseUp(e => { + const onMouseUp = disposables.add(new DomEmitter(document.body, 'mouseup', true)); + Event.once(onMouseUp.event)(e => { e.preventDefault(); e.stopPropagation(); @@ -120,9 +120,9 @@ class ToggleScreencastModeAction extends Action2 { const mouseMarker = append(container, $('.screencast-mouse')); disposables.add(toDisposable(() => mouseMarker.remove())); - const onMouseDown = domEvent(container, 'mousedown', true); - const onMouseUp = domEvent(container, 'mouseup', true); - const onMouseMove = domEvent(container, 'mousemove', true); + const onMouseDown = disposables.add(new DomEmitter(container, 'mousedown', true)); + const onMouseUp = disposables.add(new DomEmitter(container, 'mouseup', true)); + const onMouseMove = disposables.add(new DomEmitter(container, 'mousemove', true)); const updateMouseIndicatorColor = () => { mouseMarker.style.borderColor = Color.fromHex(configurationService.getValue('screencastMode.mouseIndicatorColor')).toString(); @@ -139,17 +139,17 @@ class ToggleScreencastModeAction extends Action2 { updateMouseIndicatorColor(); updateMouseIndicatorSize(); - disposables.add(onMouseDown(e => { + disposables.add(onMouseDown.event(e => { mouseMarker.style.top = `${e.clientY - mouseIndicatorSize / 2}px`; mouseMarker.style.left = `${e.clientX - mouseIndicatorSize / 2}px`; mouseMarker.style.display = 'block'; - const mouseMoveListener = onMouseMove(e => { + const mouseMoveListener = onMouseMove.event(e => { mouseMarker.style.top = `${e.clientY - mouseIndicatorSize / 2}px`; mouseMarker.style.left = `${e.clientX - mouseIndicatorSize / 2}px`; }); - Event.once(onMouseUp)(() => { + Event.once(onMouseUp.event)(() => { mouseMarker.style.display = 'none'; mouseMoveListener.dispose(); }); @@ -197,11 +197,11 @@ class ToggleScreencastModeAction extends Action2 { } })); - const onKeyDown = domEvent(window, 'keydown', true); + const onKeyDown = disposables.add(new DomEmitter(window, 'keydown', true)); let keyboardTimeout: IDisposable = Disposable.None; let length = 0; - disposables.add(onKeyDown(e => { + disposables.add(onKeyDown.event(e => { keyboardTimeout.dispose(); const event = new StandardKeyboardEvent(e); diff --git a/lib/vscode/src/vs/workbench/browser/actions/helpActions.ts b/src/vs/workbench/browser/actions/helpActions.ts similarity index 69% rename from lib/vscode/src/vs/workbench/browser/actions/helpActions.ts rename to src/vs/workbench/browser/actions/helpActions.ts index fccf60726145..107ccbc251d2 100644 --- a/lib/vscode/src/vs/workbench/browser/actions/helpActions.ts +++ b/src/vs/workbench/browser/actions/helpActions.ts @@ -9,7 +9,7 @@ import { isMacintosh, isLinux, language } from 'vs/base/common/platform'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { URI } from 'vs/base/common/uri'; -import { MenuId, Action2, registerAction2, MenuRegistry } from 'vs/platform/actions/common/actions'; +import { MenuId, Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { KeyChord, KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { IProductService } from 'vs/platform/product/common/productService'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; @@ -24,13 +24,22 @@ class KeybindingsReferenceAction extends Action2 { constructor() { super({ id: KeybindingsReferenceAction.ID, - title: { value: localize('keybindingsReference', "Keyboard Shortcuts Reference"), original: 'Keyboard Shortcuts Reference' }, + title: { + value: localize('keybindingsReference', "Keyboard Shortcuts Reference"), + mnemonicTitle: localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference"), + original: 'Keyboard Shortcuts Reference' + }, category: CATEGORIES.Help, f1: true, keybinding: { weight: KeybindingWeight.WorkbenchContrib, when: null, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_R) + }, + menu: { + id: MenuId.MenubarHelpMenu, + group: '2_reference', + order: 1 } }); } @@ -46,17 +55,26 @@ class KeybindingsReferenceAction extends Action2 { } } -class OpenDocumentationUrlAction extends Action2 { +class OpenIntroductoryVideosUrlAction extends Action2 { - static readonly ID = 'workbench.action.openDocumentationUrl'; - static readonly AVAILABLE = !!product.documentationUrl; + static readonly ID = 'workbench.action.openIntroductoryVideosUrl'; + static readonly AVAILABLE = !!product.introductoryVideosUrl; constructor() { super({ - id: OpenDocumentationUrlAction.ID, - title: { value: localize('openDocumentationUrl', "Documentation"), original: 'Documentation' }, + id: OpenIntroductoryVideosUrlAction.ID, + title: { + value: localize('openIntroductoryVideosUrl', "Introductory Videos"), + mnemonicTitle: localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos"), + original: 'Introductory Videos' + }, category: CATEGORIES.Help, - f1: true + f1: true, + menu: { + id: MenuId.MenubarHelpMenu, + group: '2_reference', + order: 2 + } }); } @@ -64,23 +82,32 @@ class OpenDocumentationUrlAction extends Action2 { const productService = accessor.get(IProductService); const openerService = accessor.get(IOpenerService); - if (productService.documentationUrl) { - openerService.open(URI.parse(productService.documentationUrl)); + if (productService.introductoryVideosUrl) { + openerService.open(URI.parse(productService.introductoryVideosUrl)); } } } -class OpenIntroductoryVideosUrlAction extends Action2 { +class OpenTipsAndTricksUrlAction extends Action2 { - static readonly ID = 'workbench.action.openIntroductoryVideosUrl'; - static readonly AVAILABLE = !!product.introductoryVideosUrl; + static readonly ID = 'workbench.action.openTipsAndTricksUrl'; + static readonly AVAILABLE = !!product.tipsAndTricksUrl; constructor() { super({ - id: OpenIntroductoryVideosUrlAction.ID, - title: { value: localize('openIntroductoryVideosUrl', "Introductory Videos"), original: 'Introductory Videos' }, + id: OpenTipsAndTricksUrlAction.ID, + title: { + value: localize('openTipsAndTricksUrl', "Tips and Tricks"), + mnemonicTitle: localize({ key: 'miTipsAndTricks', comment: ['&& denotes a mnemonic'] }, "Tips and Tri&&cks"), + original: 'Tips and Tricks' + }, category: CATEGORIES.Help, - f1: true + f1: true, + menu: { + id: MenuId.MenubarHelpMenu, + group: '2_reference', + order: 3 + } }); } @@ -88,23 +115,32 @@ class OpenIntroductoryVideosUrlAction extends Action2 { const productService = accessor.get(IProductService); const openerService = accessor.get(IOpenerService); - if (productService.introductoryVideosUrl) { - openerService.open(URI.parse(productService.introductoryVideosUrl)); + if (productService.tipsAndTricksUrl) { + openerService.open(URI.parse(productService.tipsAndTricksUrl)); } } } -class OpenTipsAndTricksUrlAction extends Action2 { +class OpenDocumentationUrlAction extends Action2 { - static readonly ID = 'workbench.action.openTipsAndTricksUrl'; - static readonly AVAILABLE = !!product.tipsAndTricksUrl; + static readonly ID = 'workbench.action.openDocumentationUrl'; + static readonly AVAILABLE = !!product.documentationUrl; constructor() { super({ - id: OpenTipsAndTricksUrlAction.ID, - title: { value: localize('openTipsAndTricksUrl', "Tips and Tricks"), original: 'Tips and Tricks' }, + id: OpenDocumentationUrlAction.ID, + title: { + value: localize('openDocumentationUrl', "Documentation"), + mnemonicTitle: localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation"), + original: 'Documentation' + }, category: CATEGORIES.Help, - f1: true + f1: true, + menu: { + id: MenuId.MenubarHelpMenu, + group: '1_welcome', + order: 3 + } }); } @@ -112,8 +148,8 @@ class OpenTipsAndTricksUrlAction extends Action2 { const productService = accessor.get(IProductService); const openerService = accessor.get(IOpenerService); - if (productService.tipsAndTricksUrl) { - openerService.open(URI.parse(productService.tipsAndTricksUrl)); + if (productService.documentationUrl) { + openerService.open(URI.parse(productService.documentationUrl)); } } } @@ -151,9 +187,18 @@ class OpenTwitterUrlAction extends Action2 { constructor() { super({ id: OpenTwitterUrlAction.ID, - title: { value: localize('openTwitterUrl', "Join Us on Twitter"), original: 'Join Us on Twitter' }, + title: { + value: localize('openTwitterUrl', "Join Us on Twitter"), + mnemonicTitle: localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join Us on Twitter"), + original: 'Join Us on Twitter' + }, category: CATEGORIES.Help, - f1: true + f1: true, + menu: { + id: MenuId.MenubarHelpMenu, + group: '3_feedback', + order: 1 + } }); } @@ -175,9 +220,18 @@ class OpenRequestFeatureUrlAction extends Action2 { constructor() { super({ id: OpenRequestFeatureUrlAction.ID, - title: { value: localize('openUserVoiceUrl', "Search Feature Requests"), original: 'Search Feature Requests' }, + title: { + value: localize('openUserVoiceUrl', "Search Feature Requests"), + mnemonicTitle: localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests"), + original: 'Search Feature Requests' + }, category: CATEGORIES.Help, - f1: true + f1: true, + menu: { + id: MenuId.MenubarHelpMenu, + group: '3_feedback', + order: 2 + } }); } @@ -199,9 +253,18 @@ class OpenLicenseUrlAction extends Action2 { constructor() { super({ id: OpenLicenseUrlAction.ID, - title: { value: localize('openLicenseUrl', "View License"), original: 'View License' }, + title: { + value: localize('openLicenseUrl', "View License"), + mnemonicTitle: localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "View &&License"), + original: 'View License' + }, category: CATEGORIES.Help, - f1: true + f1: true, + menu: { + id: MenuId.MenubarHelpMenu, + group: '4_legal', + order: 1 + } }); } @@ -228,9 +291,18 @@ class OpenPrivacyStatementUrlAction extends Action2 { constructor() { super({ id: OpenPrivacyStatementUrlAction.ID, - title: { value: localize('openPrivacyStatement', "Privacy Statement"), original: 'Privacy Statement' }, + title: { + value: localize('openPrivacyStatement', "Privacy Statement"), + mnemonicTitle: localize({ key: 'miPrivacyStatement', comment: ['&& denotes a mnemonic'] }, "Privac&&y Statement"), + original: 'Privacy Statement' + }, category: CATEGORIES.Help, - f1: true + f1: true, + menu: { + id: MenuId.MenubarHelpMenu, + group: '4_legal', + order: 2 + } }); } @@ -255,10 +327,6 @@ if (KeybindingsReferenceAction.AVAILABLE) { registerAction2(KeybindingsReferenceAction); } -if (OpenDocumentationUrlAction.AVAILABLE) { - registerAction2(OpenDocumentationUrlAction); -} - if (OpenIntroductoryVideosUrlAction.AVAILABLE) { registerAction2(OpenIntroductoryVideosUrlAction); } @@ -267,6 +335,10 @@ if (OpenTipsAndTricksUrlAction.AVAILABLE) { registerAction2(OpenTipsAndTricksUrlAction); } +if (OpenDocumentationUrlAction.AVAILABLE) { + registerAction2(OpenDocumentationUrlAction); +} + if (OpenNewsletterSignupUrlAction.AVAILABLE) { registerAction2(OpenNewsletterSignupUrlAction); } @@ -286,98 +358,3 @@ if (OpenLicenseUrlAction.AVAILABLE) { if (OpenPrivacyStatementUrlAction.AVAILABE) { registerAction2(OpenPrivacyStatementUrlAction); } - -// --- Menu Registration - -// Help - -if (OpenDocumentationUrlAction.AVAILABLE) { - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '1_welcome', - command: { - id: OpenDocumentationUrlAction.ID, - title: localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation") - }, - order: 3 - }); -} - -// Reference -if (KeybindingsReferenceAction.AVAILABLE) { - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '2_reference', - command: { - id: KeybindingsReferenceAction.ID, - title: localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference") - }, - order: 1 - }); -} - -if (OpenIntroductoryVideosUrlAction.AVAILABLE) { - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '2_reference', - command: { - id: OpenIntroductoryVideosUrlAction.ID, - title: localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos") - }, - order: 2 - }); -} - -if (OpenTipsAndTricksUrlAction.AVAILABLE) { - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '2_reference', - command: { - id: OpenTipsAndTricksUrlAction.ID, - title: localize({ key: 'miTipsAndTricks', comment: ['&& denotes a mnemonic'] }, "Tips and Tri&&cks") - }, - order: 3 - }); -} - -// Feedback -if (OpenTwitterUrlAction.AVAILABLE) { - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '3_feedback', - command: { - id: OpenTwitterUrlAction.ID, - title: localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join Us on Twitter") - }, - order: 1 - }); -} - -if (OpenRequestFeatureUrlAction.AVAILABLE) { - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '3_feedback', - command: { - id: OpenRequestFeatureUrlAction.ID, - title: localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests") - }, - order: 2 - }); -} - -// Legal -if (OpenLicenseUrlAction.AVAILABLE) { - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '4_legal', - command: { - id: OpenLicenseUrlAction.ID, - title: localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "View &&License") - }, - order: 1 - }); -} - -if (OpenPrivacyStatementUrlAction.AVAILABE) { - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '4_legal', - command: { - id: OpenPrivacyStatementUrlAction.ID, - title: localize({ key: 'miPrivacyStatement', comment: ['&& denotes a mnemonic'] }, "Privac&&y Statement") - }, - order: 2 - }); -} diff --git a/lib/vscode/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts similarity index 50% rename from lib/vscode/src/vs/workbench/browser/actions/layoutActions.ts rename to src/vs/workbench/browser/actions/layoutActions.ts index 1cd44e6d2362..3d94cd32bc65 100644 --- a/lib/vscode/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -4,10 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { Action } from 'vs/base/common/actions'; -import { SyncActionDescriptor, MenuId, MenuRegistry, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; -import { IWorkbenchActionRegistry, Extensions as WorkbenchExtensions, CATEGORIES } from 'vs/workbench/common/actions'; +import Severity from 'vs/base/common/severity'; +import { MenuId, MenuRegistry, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; +import { CATEGORIES } from 'vs/workbench/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService'; import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -20,15 +19,13 @@ import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/commo import { SideBarVisibleContext } from 'vs/workbench/common/viewlet'; import { IViewDescriptorService, IViewsService, FocusedViewContext, ViewContainerLocation, IViewDescriptor, ViewContainerLocationToString } from 'vs/workbench/common/views'; import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; -import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; -const registry = Registry.as(WorkbenchExtensions.WorkbenchActions); - // --- Close Side Bar -class CloseSidebarAction extends Action2 { +registerAction2(class extends Action2 { constructor() { super({ @@ -42,25 +39,32 @@ class CloseSidebarAction extends Action2 { run(accessor: ServicesAccessor): void { accessor.get(IWorkbenchLayoutService).setSideBarHidden(true); } -} - -registerAction2(CloseSidebarAction); +}); // --- Toggle Activity Bar export class ToggleActivityBarVisibilityAction extends Action2 { static readonly ID = 'workbench.action.toggleActivityBarVisibility'; - static readonly LABEL = localize('toggleActivityBar', "Toggle Activity Bar Visibility"); private static readonly activityBarVisibleKey = 'workbench.activityBar.visible'; constructor() { super({ id: ToggleActivityBarVisibilityAction.ID, - title: { value: ToggleActivityBarVisibilityAction.LABEL, original: 'Toggle Activity Bar Visibility' }, + title: { + value: localize('toggleActivityBar', "Toggle Activity Bar Visibility"), + mnemonicTitle: localize({ key: 'miShowActivityBar', comment: ['&& denotes a mnemonic'] }, "Show &&Activity Bar"), + original: 'Toggle Activity Bar Visibility' + }, category: CATEGORIES.View, - f1: true + f1: true, + toggled: ContextKeyExpr.equals('config.workbench.activityBar.visible', true), + menu: { + id: MenuId.MenubarAppearanceMenu, + group: '2_workbench_layout', + order: 4 + } }); } @@ -77,28 +81,26 @@ export class ToggleActivityBarVisibilityAction extends Action2 { registerAction2(ToggleActivityBarVisibilityAction); -MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '2_workbench_layout', - command: { - id: ToggleActivityBarVisibilityAction.ID, - title: localize({ key: 'miShowActivityBar', comment: ['&& denotes a mnemonic'] }, "Show &&Activity Bar"), - toggled: ContextKeyExpr.equals('config.workbench.activityBar.visible', true) - }, - order: 4 -}); - // --- Toggle Centered Layout -class ToggleCenteredLayout extends Action2 { - - static readonly ID = 'workbench.action.toggleCenteredLayout'; +registerAction2(class extends Action2 { constructor() { super({ - id: ToggleCenteredLayout.ID, - title: { value: localize('toggleCenteredLayout', "Toggle Centered Layout"), original: 'Toggle Centered Layout' }, + id: 'workbench.action.toggleCenteredLayout', + title: { + value: localize('toggleCenteredLayout', "Toggle Centered Layout"), + mnemonicTitle: localize({ key: 'miToggleCenteredLayout', comment: ['&& denotes a mnemonic'] }, "&&Centered Layout"), + original: 'Toggle Centered Layout' + }, category: CATEGORIES.View, - f1: true + f1: true, + toggled: IsCenteredLayoutContext, + menu: { + id: MenuId.MenubarAppearanceMenu, + group: '1_toggle_view', + order: 3 + } }); } @@ -107,51 +109,21 @@ class ToggleCenteredLayout extends Action2 { layoutService.centerEditorLayout(!layoutService.isEditorLayoutCentered()); } -} - -registerAction2(ToggleCenteredLayout); - -MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '1_toggle_view', - command: { - id: ToggleCenteredLayout.ID, - title: localize({ key: 'miToggleCenteredLayout', comment: ['&& denotes a mnemonic'] }, "&&Centered Layout"), - toggled: IsCenteredLayoutContext - }, - order: 3 }); // --- Toggle Sidebar Position -export class ToggleSidebarPositionAction extends Action { +export class ToggleSidebarPositionAction extends Action2 { static readonly ID = 'workbench.action.toggleSidebarPosition'; static readonly LABEL = localize('toggleSidebarPosition', "Toggle Side Bar Position"); private static readonly sidebarPositionConfigurationKey = 'workbench.sideBar.location'; - constructor( - id: string, - label: string, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, - @IConfigurationService private readonly configurationService: IConfigurationService - ) { - super(id, label); - } - - override run(): Promise { - const position = this.layoutService.getSideBarPosition(); - const newPositionValue = (position === Position.LEFT) ? 'right' : 'left'; - - return this.configurationService.updateValue(ToggleSidebarPositionAction.sidebarPositionConfigurationKey, newPositionValue); - } - static getLabel(layoutService: IWorkbenchLayoutService): string { return layoutService.getSideBarPosition() === Position.LEFT ? localize('moveSidebarRight', "Move Side Bar Right") : localize('moveSidebarLeft', "Move Side Bar Left"); } -} -registerAction2(class extends Action2 { constructor() { super({ id: ToggleSidebarPositionAction.ID, @@ -160,10 +132,20 @@ registerAction2(class extends Action2 { f1: true }); } - run(accessor: ServicesAccessor) { - accessor.get(IInstantiationService).createInstance(ToggleSidebarPositionAction, ToggleSidebarPositionAction.ID, ToggleSidebarPositionAction.LABEL).run(); + + run(accessor: ServicesAccessor): Promise { + const layoutService = accessor.get(IWorkbenchLayoutService); + const configurationService = accessor.get(IConfigurationService); + + const position = layoutService.getSideBarPosition(); + const newPositionValue = (position === Position.LEFT) ? 'right' : 'left'; + + return configurationService.updateValue(ToggleSidebarPositionAction.sidebarPositionConfigurationKey, newPositionValue); } -}); +} + +registerAction2(ToggleSidebarPositionAction); + MenuRegistry.appendMenuItems([{ id: MenuId.ViewContainerTitleContext, item: { @@ -230,35 +212,32 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { order: 2 }); -// --- Toggle Sidebar Visibility +// --- Toggle Editor Visibility -export class ToggleEditorVisibilityAction extends Action { - static readonly ID = 'workbench.action.toggleEditorVisibility'; - static readonly LABEL = localize('toggleEditor', "Toggle Editor Area Visibility"); +registerAction2(class extends Action2 { - constructor( - id: string, - label: string, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService - ) { - super(id, label); + constructor() { + super({ + id: 'workbench.action.toggleEditorVisibility', + title: { + value: localize('toggleEditor', "Toggle Editor Area Visibility"), + mnemonicTitle: localize({ key: 'miShowEditorArea', comment: ['&& denotes a mnemonic'] }, "Show &&Editor Area"), + original: 'Toggle Editor Area Visibility' + }, + category: CATEGORIES.View, + f1: true, + toggled: EditorAreaVisibleContext, + menu: { + id: MenuId.MenubarAppearanceMenu, + group: '2_workbench_layout', + order: 5 + } + }); } - override async run(): Promise { - this.layoutService.toggleMaximizedPanel(); + run(accessor: ServicesAccessor): void { + accessor.get(IWorkbenchLayoutService).toggleMaximizedPanel(); } -} - -registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleEditorVisibilityAction), 'View: Toggle Editor Area Visibility', CATEGORIES.View.value); - -MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '2_workbench_layout', - command: { - id: ToggleEditorVisibilityAction.ID, - title: localize({ key: 'miShowEditorArea', comment: ['&& denotes a mnemonic'] }, "Show &&Editor Area"), - toggled: EditorAreaVisibleContext - }, - order: 5 }); MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { @@ -268,11 +247,15 @@ MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { order: 1 }); -export const TOGGLE_SIDEBAR_VISIBILITY_ACTION_ID = 'workbench.action.toggleSidebarVisibility'; -registerAction2(class extends Action2 { +// Toggle Sidebar Visibility + +class ToggleSidebarVisibilityAction extends Action2 { + + static readonly ID = 'workbench.action.toggleSidebarVisibility'; + constructor() { super({ - id: TOGGLE_SIDEBAR_VISIBILITY_ACTION_ID, + id: ToggleSidebarVisibilityAction.ID, title: { value: localize('toggleSidebar', "Toggle Side Bar Visibility"), original: 'Toggle Side Bar Visibility' }, category: CATEGORIES.View, f1: true, @@ -282,17 +265,22 @@ registerAction2(class extends Action2 { } }); } - run(accessor: ServicesAccessor) { + + run(accessor: ServicesAccessor): void { const layoutService = accessor.get(IWorkbenchLayoutService); + layoutService.setSideBarHidden(layoutService.isVisible(Parts.SIDEBAR_PART)); } -}); +} + +registerAction2(ToggleSidebarVisibilityAction); + MenuRegistry.appendMenuItems([{ id: MenuId.ViewContainerTitleContext, item: { group: '3_workbench_layout_move', command: { - id: TOGGLE_SIDEBAR_VISIBILITY_ACTION_ID, + id: ToggleSidebarVisibilityAction.ID, title: localize('compositePart.hideSideBarLabel', "Hide Side Bar"), }, when: ContextKeyExpr.and(SideBarVisibleContext, ContextKeyExpr.equals('viewContainerLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))), @@ -303,123 +291,127 @@ MenuRegistry.appendMenuItems([{ item: { group: '3_workbench_layout_move', command: { - id: TOGGLE_SIDEBAR_VISIBILITY_ACTION_ID, + id: ToggleSidebarVisibilityAction.ID, title: localize('compositePart.hideSideBarLabel', "Hide Side Bar"), }, when: ContextKeyExpr.and(SideBarVisibleContext, ContextKeyExpr.equals('viewLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))), order: 2 } +}, { + id: MenuId.MenubarAppearanceMenu, + item: { + group: '2_workbench_layout', + command: { + id: ToggleSidebarVisibilityAction.ID, + title: localize({ key: 'miShowSidebar', comment: ['&& denotes a mnemonic'] }, "Show &&Side Bar"), + toggled: SideBarVisibleContext + }, + order: 1 + } }]); -MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '2_workbench_layout', - command: { - id: TOGGLE_SIDEBAR_VISIBILITY_ACTION_ID, - title: localize({ key: 'miShowSidebar', comment: ['&& denotes a mnemonic'] }, "Show &&Side Bar"), - toggled: SideBarVisibleContext - }, - order: 1 -}); - // --- Toggle Statusbar Visibility -export class ToggleStatusbarVisibilityAction extends Action { +export class ToggleStatusbarVisibilityAction extends Action2 { static readonly ID = 'workbench.action.toggleStatusbarVisibility'; - static readonly LABEL = localize('toggleStatusbar', "Toggle Status Bar Visibility"); private static readonly statusbarVisibleKey = 'workbench.statusBar.visible'; - constructor( - id: string, - label: string, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, - @IConfigurationService private readonly configurationService: IConfigurationService - ) { - super(id, label); + constructor() { + super({ + id: ToggleStatusbarVisibilityAction.ID, + title: { + value: localize('toggleStatusbar', "Toggle Status Bar Visibility"), + mnemonicTitle: localize({ key: 'miShowStatusbar', comment: ['&& denotes a mnemonic'] }, "Show S&&tatus Bar"), + original: 'Toggle Status Bar Visibility' + }, + category: CATEGORIES.View, + f1: true, + toggled: ContextKeyExpr.equals('config.workbench.statusBar.visible', true), + menu: { + id: MenuId.MenubarAppearanceMenu, + group: '2_workbench_layout', + order: 3 + } + }); } - override run(): Promise { - const visibility = this.layoutService.isVisible(Parts.STATUSBAR_PART); + run(accessor: ServicesAccessor): Promise { + const layoutService = accessor.get(IWorkbenchLayoutService); + const configurationService = accessor.get(IConfigurationService); + + const visibility = layoutService.isVisible(Parts.STATUSBAR_PART); const newVisibilityValue = !visibility; - return this.configurationService.updateValue(ToggleStatusbarVisibilityAction.statusbarVisibleKey, newVisibilityValue); + return configurationService.updateValue(ToggleStatusbarVisibilityAction.statusbarVisibleKey, newVisibilityValue); } } -registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleStatusbarVisibilityAction), 'View: Toggle Status Bar Visibility', CATEGORIES.View.value); - -MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '2_workbench_layout', - command: { - id: ToggleStatusbarVisibilityAction.ID, - title: localize({ key: 'miShowStatusbar', comment: ['&& denotes a mnemonic'] }, "Show S&&tatus Bar"), - toggled: ContextKeyExpr.equals('config.workbench.statusBar.visible', true) - }, - order: 3 -}); +registerAction2(ToggleStatusbarVisibilityAction); // --- Toggle Tabs Visibility -class ToggleTabsVisibilityAction extends Action { - - static readonly ID = 'workbench.action.toggleTabsVisibility'; - static readonly LABEL = localize('toggleTabs', "Toggle Tab Visibility"); - - private static readonly tabsVisibleKey = 'workbench.editor.showTabs'; +registerAction2(class extends Action2 { - constructor( - id: string, - label: string, - @IConfigurationService private readonly configurationService: IConfigurationService - ) { - super(id, label); + constructor() { + super({ + id: 'workbench.action.toggleTabsVisibility', + title: { + value: localize('toggleTabs', "Toggle Tab Visibility"), + original: 'Toggle Tab Visibility' + }, + category: CATEGORIES.View, + f1: true, + keybinding: { + weight: KeybindingWeight.WorkbenchContrib, + primary: undefined, + mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_W, }, + linux: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_W, } + } + }); } - override run(): Promise { - const visibility = this.configurationService.getValue(ToggleTabsVisibilityAction.tabsVisibleKey); + run(accessor: ServicesAccessor): Promise { + const configurationService = accessor.get(IConfigurationService); + + const visibility = configurationService.getValue('workbench.editor.showTabs'); const newVisibilityValue = !visibility; - return this.configurationService.updateValue(ToggleTabsVisibilityAction.tabsVisibleKey, newVisibilityValue); + return configurationService.updateValue('workbench.editor.showTabs', newVisibilityValue); } -} - -registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleTabsVisibilityAction, { - primary: undefined, - mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_W, }, - linux: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_W, } -}), 'View: Toggle Tab Visibility', CATEGORIES.View.value); +}); // --- Toggle Zen Mode -class ToggleZenMode extends Action { - - static readonly ID = 'workbench.action.toggleZenMode'; - static readonly LABEL = localize('toggleZenMode', "Toggle Zen Mode"); +registerAction2(class extends Action2 { - constructor( - id: string, - label: string, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService - ) { - super(id, label); + constructor() { + super({ + id: 'workbench.action.toggleZenMode', + title: { + value: localize('toggleZenMode', "Toggle Zen Mode"), + mnemonicTitle: localize('miToggleZenMode', "Zen Mode"), + original: 'Toggle Zen Mode' + }, + category: CATEGORIES.View, + f1: true, + keybinding: { + weight: KeybindingWeight.WorkbenchContrib, + primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_Z) + }, + toggled: InEditorZenModeContext, + menu: { + id: MenuId.MenubarAppearanceMenu, + group: '1_toggle_view', + order: 2 + } + }); } - override async run(): Promise { - this.layoutService.toggleZenMode(); + run(accessor: ServicesAccessor): void { + return accessor.get(IWorkbenchLayoutService).toggleZenMode(); } -} - -registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleZenMode, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_Z) }), 'View: Toggle Zen Mode', CATEGORIES.View.value); - -MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '1_toggle_view', - command: { - id: ToggleZenMode.ID, - title: localize('miToggleZenMode', "Zen Mode"), - toggled: InEditorZenModeContext - }, - order: 2 }); KeybindingsRegistry.registerCommandAndKeybindingRule({ @@ -435,85 +427,103 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ // --- Toggle Menu Bar -export class ToggleMenuBarAction extends Action { +if (isWindows || isLinux || isWeb) { + registerAction2(class extends Action2 { + + constructor() { + super({ + id: 'workbench.action.toggleMenuBar', + title: { + value: localize('toggleMenuBar', "Toggle Menu Bar"), + mnemonicTitle: localize({ key: 'miShowMenuBar', comment: ['&& denotes a mnemonic'] }, "Show Menu &&Bar"), + original: 'Toggle Menu Bar' + }, + category: CATEGORIES.View, + f1: true, + toggled: ContextKeyExpr.and(IsMacNativeContext.toNegated(), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'hidden'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'toggle'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'compact')), + menu: { + id: MenuId.MenubarAppearanceMenu, + group: '2_workbench_layout', + order: 0 + } + }); + } - static readonly ID = 'workbench.action.toggleMenuBar'; - static readonly LABEL = localize('toggleMenuBar', "Toggle Menu Bar"); + run(accessor: ServicesAccessor): void { + return accessor.get(IWorkbenchLayoutService).toggleMenuBar(); + } + }); +} - constructor( - id: string, - label: string, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService - ) { - super(id, label); - } +// --- Reset View Locations - override async run(): Promise { - this.layoutService.toggleMenuBar(); - } -} +registerAction2(class extends Action2 { -if (isWindows || isLinux || isWeb) { - registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleMenuBarAction), 'View: Toggle Menu Bar', CATEGORIES.View.value); -} + constructor() { + super({ + id: 'workbench.action.resetViewLocations', + title: { + value: localize('resetViewLocations', "Reset View Locations"), + original: 'Reset View Locations' + }, + category: CATEGORIES.View, + f1: true + }); + } -MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '2_workbench_layout', - command: { - id: ToggleMenuBarAction.ID, - title: localize({ key: 'miShowMenuBar', comment: ['&& denotes a mnemonic'] }, "Show Menu &&Bar"), - toggled: ContextKeyExpr.and(IsMacNativeContext.toNegated(), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'hidden'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'toggle'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'compact')) - }, - when: IsMacNativeContext.toNegated(), - order: 0 + run(accessor: ServicesAccessor): void { + return accessor.get(IViewDescriptorService).reset(); + } }); -// --- Reset View Positions +// --- Move View -export class ResetViewLocationsAction extends Action { - static readonly ID = 'workbench.action.resetViewLocations'; - static readonly LABEL = localize('resetViewLocations', "Reset View Locations"); +registerAction2(class extends Action2 { - constructor( - id: string, - label: string, - @IViewDescriptorService private viewDescriptorService: IViewDescriptorService - ) { - super(id, label); + constructor() { + super({ + id: 'workbench.action.moveView', + title: { + value: localize('moveView', "Move View"), + original: 'Move View' + }, + category: CATEGORIES.View, + f1: true + }); } - override async run(): Promise { - this.viewDescriptorService.reset(); - } -} + async run(accessor: ServicesAccessor): Promise { + const viewDescriptorService = accessor.get(IViewDescriptorService); + const instantiationService = accessor.get(IInstantiationService); + const quickInputService = accessor.get(IQuickInputService); + const contextKeyService = accessor.get(IContextKeyService); + const activityBarService = accessor.get(IActivityBarService); + const panelService = accessor.get(IPanelService); + + const focusedViewId = FocusedViewContext.getValue(contextKeyService); + let viewId: string; + + if (focusedViewId && viewDescriptorService.getViewDescriptorById(focusedViewId)?.canMoveView) { + viewId = focusedViewId; + } -registry.registerWorkbenchAction(SyncActionDescriptor.from(ResetViewLocationsAction), 'View: Reset View Locations', CATEGORIES.View.value); + viewId = await this.getView(quickInputService, activityBarService, viewDescriptorService, panelService, viewId!); -// --- Move View with Command -export class MoveViewAction extends Action { - static readonly ID = 'workbench.action.moveView'; - static readonly LABEL = localize('moveView', "Move View"); + if (!viewId) { + return; + } - constructor( - id: string, - label: string, - @IViewDescriptorService private viewDescriptorService: IViewDescriptorService, - @IInstantiationService private instantiationService: IInstantiationService, - @IQuickInputService private quickInputService: IQuickInputService, - @IContextKeyService private contextKeyService: IContextKeyService, - @IActivityBarService private activityBarService: IActivityBarService, - @IPanelService private panelService: IPanelService - ) { - super(id, label); + const moveFocusedViewAction = new MoveFocusedViewAction(); + instantiationService.invokeFunction(accessor => moveFocusedViewAction.run(accessor, viewId)); } - private getViewItems(): Array { + private getViewItems(activityBarService: IActivityBarService, viewDescriptorService: IViewDescriptorService, panelService: IPanelService): Array { const results: Array = []; - const viewlets = this.activityBarService.getVisibleViewContainerIds(); + const viewlets = activityBarService.getVisibleViewContainerIds(); viewlets.forEach(viewletId => { - const container = this.viewDescriptorService.getViewContainerById(viewletId)!; - const containerModel = this.viewDescriptorService.getViewContainerModel(container); + const container = viewDescriptorService.getViewContainerById(viewletId)!; + const containerModel = viewDescriptorService.getViewContainerModel(container); let hasAddedView = false; containerModel.visibleViewDescriptors.forEach(viewDescriptor => { @@ -534,10 +544,10 @@ export class MoveViewAction extends Action { }); }); - const panels = this.panelService.getPinnedPanels(); + const panels = panelService.getPinnedPanels(); panels.forEach(panel => { - const container = this.viewDescriptorService.getViewContainerById(panel.id)!; - const containerModel = this.viewDescriptorService.getViewContainerModel(container); + const container = viewDescriptorService.getViewContainerById(panel.id)!; + const containerModel = viewDescriptorService.getViewContainerModel(container); let hasAddedView = false; containerModel.visibleViewDescriptors.forEach(viewDescriptor => { @@ -561,10 +571,10 @@ export class MoveViewAction extends Action { return results; } - private async getView(viewId?: string): Promise { - const quickPick = this.quickInputService.createQuickPick(); + private async getView(quickInputService: IQuickInputService, activityBarService: IActivityBarService, viewDescriptorService: IViewDescriptorService, panelService: IPanelService, viewId?: string): Promise { + const quickPick = quickInputService.createQuickPick(); quickPick.placeholder = localize('moveFocusedView.selectView', "Select a View to Move"); - quickPick.items = this.getViewItems(); + quickPick.items = this.getViewItems(activityBarService, viewDescriptorService, panelService); quickPick.selectedItems = quickPick.items.filter(item => (item as IQuickPickItem).id === viewId) as IQuickPickItem[]; return new Promise((resolve, reject) => { @@ -584,68 +594,55 @@ export class MoveViewAction extends Action { quickPick.show(); }); } +}); - override async run(): Promise { - const focusedViewId = FocusedViewContext.getValue(this.contextKeyService); - let viewId: string; +// --- Move Focused View - if (focusedViewId && this.viewDescriptorService.getViewDescriptorById(focusedViewId)?.canMoveView) { - viewId = focusedViewId; - } +class MoveFocusedViewAction extends Action2 { - viewId = await this.getView(viewId!); - - if (!viewId) { - return; - } - - this.instantiationService.createInstance(MoveFocusedViewAction, MoveFocusedViewAction.ID, MoveFocusedViewAction.LABEL).run(viewId); + constructor() { + super({ + id: 'workbench.action.moveFocusedView', + title: { + value: localize('moveFocusedView', "Move Focused View"), + original: 'Move Focused View' + }, + category: CATEGORIES.View, + precondition: FocusedViewContext.notEqualsTo(''), + f1: true + }); } -} - -registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveViewAction), 'View: Move View', CATEGORIES.View.value); - -// --- Move Focused View with Command -export class MoveFocusedViewAction extends Action { - static readonly ID = 'workbench.action.moveFocusedView'; - static readonly LABEL = localize('moveFocusedView', "Move Focused View"); - constructor( - id: string, - label: string, - @IViewDescriptorService private viewDescriptorService: IViewDescriptorService, - @IViewsService private viewsService: IViewsService, - @IQuickInputService private quickInputService: IQuickInputService, - @IContextKeyService private contextKeyService: IContextKeyService, - @INotificationService private notificationService: INotificationService, - @IActivityBarService private activityBarService: IActivityBarService, - @IPanelService private panelService: IPanelService - ) { - super(id, label); - } + run(accessor: ServicesAccessor, viewId?: string): void { + const viewDescriptorService = accessor.get(IViewDescriptorService); + const viewsService = accessor.get(IViewsService); + const quickInputService = accessor.get(IQuickInputService); + const contextKeyService = accessor.get(IContextKeyService); + const dialogService = accessor.get(IDialogService); + const activityBarService = accessor.get(IActivityBarService); + const panelService = accessor.get(IPanelService); - override async run(viewId: string): Promise { - const focusedViewId = viewId || FocusedViewContext.getValue(this.contextKeyService); + const focusedViewId = viewId || FocusedViewContext.getValue(contextKeyService); if (focusedViewId === undefined || focusedViewId.trim() === '') { - this.notificationService.error(localize('moveFocusedView.error.noFocusedView', "There is no view currently focused.")); + dialogService.show(Severity.Error, localize('moveFocusedView.error.noFocusedView', "There is no view currently focused."), [localize('ok', 'OK')]); return; } - const viewDescriptor = this.viewDescriptorService.getViewDescriptorById(focusedViewId); + const viewDescriptor = viewDescriptorService.getViewDescriptorById(focusedViewId); if (!viewDescriptor || !viewDescriptor.canMoveView) { - this.notificationService.error(localize('moveFocusedView.error.nonMovableView', "The currently focused view is not movable.")); + dialogService.show(Severity.Error, localize('moveFocusedView.error.nonMovableView', "The currently focused view is not movable."), [localize('ok', 'OK')]); return; } - const quickPick = this.quickInputService.createQuickPick(); + const quickPick = quickInputService.createQuickPick(); quickPick.placeholder = localize('moveFocusedView.selectDestination', "Select a Destination for the View"); quickPick.title = localize({ key: 'moveFocusedView.title', comment: ['{0} indicates the title of the view the user has selected to move.'] }, "View: Move {0}", viewDescriptor.name); const items: Array = []; - const currentContainer = this.viewDescriptorService.getViewContainerByViewId(focusedViewId)!; - const currentLocation = this.viewDescriptorService.getViewLocationById(focusedViewId)!; - const isViewSolo = this.viewDescriptorService.getViewContainerModel(currentContainer).allViewDescriptors.length === 1; + const currentContainer = viewDescriptorService.getViewContainerByViewId(focusedViewId)!; + const currentLocation = viewDescriptorService.getViewLocationById(focusedViewId)!; + const isViewSolo = viewDescriptorService.getViewContainerModel(currentContainer).allViewDescriptors.length === 1; if (!(isViewSolo && currentLocation === ViewContainerLocation.Panel)) { items.push({ @@ -666,19 +663,19 @@ export class MoveFocusedViewAction extends Action { label: localize('sidebar', "Side Bar") }); - const pinnedViewlets = this.activityBarService.getVisibleViewContainerIds(); + const pinnedViewlets = activityBarService.getVisibleViewContainerIds(); items.push(...pinnedViewlets .filter(viewletId => { - if (viewletId === this.viewDescriptorService.getViewContainerByViewId(focusedViewId)!.id) { + if (viewletId === viewDescriptorService.getViewContainerByViewId(focusedViewId)!.id) { return false; } - return !this.viewDescriptorService.getViewContainerById(viewletId)!.rejectAddedViews; + return !viewDescriptorService.getViewContainerById(viewletId)!.rejectAddedViews; }) .map(viewletId => { return { id: viewletId, - label: this.viewDescriptorService.getViewContainerModel(this.viewDescriptorService.getViewContainerById(viewletId)!)!.title + label: viewDescriptorService.getViewContainerModel(viewDescriptorService.getViewContainerById(viewletId)!)!.title }; })); @@ -687,19 +684,19 @@ export class MoveFocusedViewAction extends Action { label: localize('panel', "Panel") }); - const pinnedPanels = this.panelService.getPinnedPanels(); + const pinnedPanels = panelService.getPinnedPanels(); items.push(...pinnedPanels .filter(panel => { - if (panel.id === this.viewDescriptorService.getViewContainerByViewId(focusedViewId)!.id) { + if (panel.id === viewDescriptorService.getViewContainerByViewId(focusedViewId)!.id) { return false; } - return !this.viewDescriptorService.getViewContainerById(panel.id)!.rejectAddedViews; + return !viewDescriptorService.getViewContainerById(panel.id)!.rejectAddedViews; }) .map(panel => { return { id: panel.id, - label: this.viewDescriptorService.getViewContainerModel(this.viewDescriptorService.getViewContainerById(panel.id)!)!.title + label: viewDescriptorService.getViewContainerModel(viewDescriptorService.getViewContainerById(panel.id)!)!.title }; })); @@ -709,14 +706,14 @@ export class MoveFocusedViewAction extends Action { const destination = quickPick.selectedItems[0]; if (destination.id === '_.panel.newcontainer') { - this.viewDescriptorService.moveViewToLocation(viewDescriptor!, ViewContainerLocation.Panel); - this.viewsService.openView(focusedViewId, true); + viewDescriptorService.moveViewToLocation(viewDescriptor!, ViewContainerLocation.Panel); + viewsService.openView(focusedViewId, true); } else if (destination.id === '_.sidebar.newcontainer') { - this.viewDescriptorService.moveViewToLocation(viewDescriptor!, ViewContainerLocation.Sidebar); - this.viewsService.openView(focusedViewId, true); + viewDescriptorService.moveViewToLocation(viewDescriptor!, ViewContainerLocation.Sidebar); + viewsService.openView(focusedViewId, true); } else if (destination.id) { - this.viewDescriptorService.moveViewsToContainer([viewDescriptor], this.viewDescriptorService.getViewContainerById(destination.id)!); - this.viewsService.openView(focusedViewId, true); + viewDescriptorService.moveViewsToContainer([viewDescriptor], viewDescriptorService.getViewContainerById(destination.id)!); + viewsService.openView(focusedViewId, true); } quickPick.hide(); @@ -726,54 +723,56 @@ export class MoveFocusedViewAction extends Action { } } -registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveFocusedViewAction), 'View: Move Focused View', CATEGORIES.View.value, FocusedViewContext.notEqualsTo('')); +registerAction2(MoveFocusedViewAction); + +// --- Reset Focused View Location -// --- Reset View Location with Command -export class ResetFocusedViewLocationAction extends Action { - static readonly ID = 'workbench.action.resetFocusedViewLocation'; - static readonly LABEL = localize('resetFocusedViewLocation', "Reset Focused View Location"); +registerAction2(class extends Action2 { - constructor( - id: string, - label: string, - @IViewDescriptorService private viewDescriptorService: IViewDescriptorService, - @IContextKeyService private contextKeyService: IContextKeyService, - @INotificationService private notificationService: INotificationService, - @IViewsService private viewsService: IViewsService - ) { - super(id, label); + constructor() { + super({ + id: 'workbench.action.resetFocusedViewLocation', + title: { + value: localize('resetFocusedViewLocation', "Reset Focused View Location"), + original: 'Reset Focused View Location' + }, + category: CATEGORIES.View, + f1: true, + precondition: FocusedViewContext.notEqualsTo('') + }); } - override async run(): Promise { - const focusedViewId = FocusedViewContext.getValue(this.contextKeyService); + run(accessor: ServicesAccessor): void { + const viewDescriptorService = accessor.get(IViewDescriptorService); + const contextKeyService = accessor.get(IContextKeyService); + const dialogService = accessor.get(IDialogService); + const viewsService = accessor.get(IViewsService); + + const focusedViewId = FocusedViewContext.getValue(contextKeyService); let viewDescriptor: IViewDescriptor | null = null; if (focusedViewId !== undefined && focusedViewId.trim() !== '') { - viewDescriptor = this.viewDescriptorService.getViewDescriptorById(focusedViewId); + viewDescriptor = viewDescriptorService.getViewDescriptorById(focusedViewId); } if (!viewDescriptor) { - this.notificationService.error(localize('resetFocusedView.error.noFocusedView', "There is no view currently focused.")); + dialogService.show(Severity.Error, localize('resetFocusedView.error.noFocusedView', "There is no view currently focused."), [localize('ok', 'OK')]); return; } - const defaultContainer = this.viewDescriptorService.getDefaultContainerById(viewDescriptor.id); - if (!defaultContainer || defaultContainer === this.viewDescriptorService.getViewContainerByViewId(viewDescriptor.id)) { + const defaultContainer = viewDescriptorService.getDefaultContainerById(viewDescriptor.id); + if (!defaultContainer || defaultContainer === viewDescriptorService.getViewContainerByViewId(viewDescriptor.id)) { return; } - this.viewDescriptorService.moveViewsToContainer([viewDescriptor], defaultContainer); - this.viewsService.openView(viewDescriptor.id, true); - + viewDescriptorService.moveViewsToContainer([viewDescriptor], defaultContainer); + viewsService.openView(viewDescriptor.id, true); } -} - -registry.registerWorkbenchAction(SyncActionDescriptor.from(ResetFocusedViewLocationAction), 'View: Reset Focused View Location', CATEGORIES.View.value, FocusedViewContext.notEqualsTo('')); - +}); // --- Resize View -export abstract class BaseResizeViewAction extends Action2 { +abstract class BaseResizeViewAction extends Action2 { protected static readonly RESIZE_INCREMENT = 6.5; // This is a media-size percentage @@ -802,7 +801,7 @@ export abstract class BaseResizeViewAction extends Action2 { } } -export class IncreaseViewSizeAction extends BaseResizeViewAction { +class IncreaseViewSizeAction extends BaseResizeViewAction { constructor() { super({ @@ -812,12 +811,12 @@ export class IncreaseViewSizeAction extends BaseResizeViewAction { }); } - async run(accessor: ServicesAccessor): Promise { + run(accessor: ServicesAccessor): void { this.resizePart(BaseResizeViewAction.RESIZE_INCREMENT, BaseResizeViewAction.RESIZE_INCREMENT, accessor.get(IWorkbenchLayoutService)); } } -export class IncreaseViewWidthAction extends BaseResizeViewAction { +class IncreaseViewWidthAction extends BaseResizeViewAction { constructor() { super({ @@ -827,12 +826,12 @@ export class IncreaseViewWidthAction extends BaseResizeViewAction { }); } - async run(accessor: ServicesAccessor): Promise { + run(accessor: ServicesAccessor): void { this.resizePart(BaseResizeViewAction.RESIZE_INCREMENT, 0, accessor.get(IWorkbenchLayoutService), Parts.EDITOR_PART); } } -export class IncreaseViewHeightAction extends BaseResizeViewAction { +class IncreaseViewHeightAction extends BaseResizeViewAction { constructor() { super({ @@ -841,12 +840,13 @@ export class IncreaseViewHeightAction extends BaseResizeViewAction { f1: true }); } - async run(accessor: ServicesAccessor): Promise { + + run(accessor: ServicesAccessor): void { this.resizePart(0, BaseResizeViewAction.RESIZE_INCREMENT, accessor.get(IWorkbenchLayoutService), Parts.EDITOR_PART); } } -export class DecreaseViewSizeAction extends BaseResizeViewAction { +class DecreaseViewSizeAction extends BaseResizeViewAction { constructor() { super({ @@ -856,12 +856,12 @@ export class DecreaseViewSizeAction extends BaseResizeViewAction { }); } - async run(accessor: ServicesAccessor): Promise { + run(accessor: ServicesAccessor): void { this.resizePart(-BaseResizeViewAction.RESIZE_INCREMENT, -BaseResizeViewAction.RESIZE_INCREMENT, accessor.get(IWorkbenchLayoutService)); } } -export class DecreaseViewWidthAction extends BaseResizeViewAction { +class DecreaseViewWidthAction extends BaseResizeViewAction { constructor() { super({ id: 'workbench.action.decreaseViewWidth', @@ -870,13 +870,12 @@ export class DecreaseViewWidthAction extends BaseResizeViewAction { }); } - async run(accessor: ServicesAccessor): Promise { + run(accessor: ServicesAccessor): void { this.resizePart(-BaseResizeViewAction.RESIZE_INCREMENT, 0, accessor.get(IWorkbenchLayoutService), Parts.EDITOR_PART); } } - -export class DecreaseViewHeightAction extends BaseResizeViewAction { +class DecreaseViewHeightAction extends BaseResizeViewAction { constructor() { super({ @@ -886,7 +885,7 @@ export class DecreaseViewHeightAction extends BaseResizeViewAction { }); } - async run(accessor: ServicesAccessor): Promise { + run(accessor: ServicesAccessor): void { this.resizePart(0, -BaseResizeViewAction.RESIZE_INCREMENT, accessor.get(IWorkbenchLayoutService), Parts.EDITOR_PART); } } diff --git a/lib/vscode/src/vs/workbench/browser/actions/listCommands.ts b/src/vs/workbench/browser/actions/listCommands.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/actions/listCommands.ts rename to src/vs/workbench/browser/actions/listCommands.ts diff --git a/lib/vscode/src/vs/workbench/browser/actions/media/actions.css b/src/vs/workbench/browser/actions/media/actions.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/actions/media/actions.css rename to src/vs/workbench/browser/actions/media/actions.css diff --git a/lib/vscode/src/vs/workbench/browser/actions/navigationActions.ts b/src/vs/workbench/browser/actions/navigationActions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/actions/navigationActions.ts rename to src/vs/workbench/browser/actions/navigationActions.ts diff --git a/lib/vscode/src/vs/workbench/browser/actions/quickAccessActions.ts b/src/vs/workbench/browser/actions/quickAccessActions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/actions/quickAccessActions.ts rename to src/vs/workbench/browser/actions/quickAccessActions.ts diff --git a/lib/vscode/src/vs/workbench/browser/actions/textInputActions.ts b/src/vs/workbench/browser/actions/textInputActions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/actions/textInputActions.ts rename to src/vs/workbench/browser/actions/textInputActions.ts diff --git a/lib/vscode/src/vs/workbench/browser/actions/windowActions.ts b/src/vs/workbench/browser/actions/windowActions.ts similarity index 56% rename from lib/vscode/src/vs/workbench/browser/actions/windowActions.ts rename to src/vs/workbench/browser/actions/windowActions.ts index 358af6804197..08c85b251c21 100644 --- a/lib/vscode/src/vs/workbench/browser/actions/windowActions.ts +++ b/src/vs/workbench/browser/actions/windowActions.ts @@ -4,15 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { Action } from 'vs/base/common/actions'; import { IWindowOpenable } from 'vs/platform/windows/common/windows'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { SyncActionDescriptor, MenuRegistry, MenuId, Action2, registerAction2 } from 'vs/platform/actions/common/actions'; -import { Registry } from 'vs/platform/registry/common/platform'; +import { MenuRegistry, MenuId, Action2, registerAction2, IAction2Options } from 'vs/platform/actions/common/actions'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { IsFullscreenContext } from 'vs/workbench/browser/contextkeys'; -import { IsMacNativeContext, IsDevelopmentContext, IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; -import { IWorkbenchActionRegistry, Extensions, CATEGORIES } from 'vs/workbench/common/actions'; +import { IsMacNativeContext, IsDevelopmentContext, IsWebContext, IsIOSContext } from 'vs/platform/contextkey/common/contextkeys'; +import { CATEGORIES } from 'vs/workbench/common/actions'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IQuickInputButton, IQuickInputService, IQuickPickSeparator, IKeyMods, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -34,6 +32,7 @@ import { Codicon } from 'vs/base/common/codicons'; import { isHTMLElement } from 'vs/base/browser/dom'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; export const inRecentFilesPickerContextKey = 'inRecentFilesPicker'; @@ -42,7 +41,9 @@ interface IRecentlyOpenedPick extends IQuickPickItem { openable: IWindowOpenable; } -abstract class BaseOpenRecentAction extends Action { +const fileCategory = { value: localize('file', "File"), original: 'File' }; + +abstract class BaseOpenRecentAction extends Action2 { private readonly removeFromRecentlyOpened: IQuickInputButton = { iconClass: Codicon.removeClose.classNames, @@ -60,27 +61,25 @@ abstract class BaseOpenRecentAction extends Action { tooltip: localize('dirtyRecentlyOpenedWorkspace', "Workspace With Unsaved Files"), }; - constructor( - id: string, - label: string, - private workspacesService: IWorkspacesService, - private quickInputService: IQuickInputService, - private contextService: IWorkspaceContextService, - private labelService: ILabelService, - private keybindingService: IKeybindingService, - private modelService: IModelService, - private modeService: IModeService, - private hostService: IHostService, - private dialogService: IDialogService - ) { - super(id, label); + constructor(desc: Readonly) { + super(desc); } protected abstract isQuickNavigate(): boolean; - override async run(): Promise { - const recentlyOpened = await this.workspacesService.getRecentlyOpened(); - const dirtyWorkspacesAndFolders = await this.workspacesService.getDirtyWorkspaces(); + override async run(accessor: ServicesAccessor): Promise { + const workspacesService = accessor.get(IWorkspacesService); + const quickInputService = accessor.get(IQuickInputService); + const contextService = accessor.get(IWorkspaceContextService); + const labelService = accessor.get(ILabelService); + const keybindingService = accessor.get(IKeybindingService); + const modelService = accessor.get(IModelService); + const modeService = accessor.get(IModeService); + const hostService = accessor.get(IHostService); + const dialogService = accessor.get(IDialogService); + + const recentlyOpened = await workspacesService.getRecentlyOpened(); + const dirtyWorkspacesAndFolders = await workspacesService.getDirtyWorkspaces(); let hasWorkspaces = false; @@ -113,23 +112,23 @@ abstract class BaseOpenRecentAction extends Action { for (const recent of recentlyOpened.workspaces) { const isDirty = isRecentFolder(recent) ? dirtyFolders.has(recent.folderUri) : dirtyWorkspaces.has(recent.workspace.configPath); - workspacePicks.push(this.toQuickPick(recent, isDirty)); + workspacePicks.push(this.toQuickPick(modelService, modeService, labelService, recent, isDirty)); } // Fill any backup workspace that is not yet shown at the end for (const dirtyWorkspaceOrFolder of dirtyWorkspacesAndFolders) { if (URI.isUri(dirtyWorkspaceOrFolder) && !recentFolders.has(dirtyWorkspaceOrFolder)) { - workspacePicks.push(this.toQuickPick({ folderUri: dirtyWorkspaceOrFolder }, true)); + workspacePicks.push(this.toQuickPick(modelService, modeService, labelService, { folderUri: dirtyWorkspaceOrFolder }, true)); } else if (isWorkspaceIdentifier(dirtyWorkspaceOrFolder) && !recentWorkspaces.has(dirtyWorkspaceOrFolder.configPath)) { - workspacePicks.push(this.toQuickPick({ workspace: dirtyWorkspaceOrFolder }, true)); + workspacePicks.push(this.toQuickPick(modelService, modeService, labelService, { workspace: dirtyWorkspaceOrFolder }, true)); } } - const filePicks = recentlyOpened.files.map(p => this.toQuickPick(p, false)); + const filePicks = recentlyOpened.files.map(p => this.toQuickPick(modelService, modeService, labelService, p, false)); // focus second entry if the first recent workspace is the current workspace const firstEntry = recentlyOpened.workspaces[0]; - const autoFocusSecondEntry: boolean = firstEntry && this.contextService.isCurrentWorkspace(isRecentWorkspace(firstEntry) ? firstEntry.workspace : firstEntry.folderUri); + const autoFocusSecondEntry: boolean = firstEntry && contextService.isCurrentWorkspace(isRecentWorkspace(firstEntry) ? firstEntry.workspace : firstEntry.folderUri); let keyMods: IKeyMods | undefined; @@ -137,25 +136,25 @@ abstract class BaseOpenRecentAction extends Action { const fileSeparator: IQuickPickSeparator = { type: 'separator', label: localize('files', "files") }; const picks = [workspaceSeparator, ...workspacePicks, fileSeparator, ...filePicks]; - const pick = await this.quickInputService.pick(picks, { + const pick = await quickInputService.pick(picks, { contextKey: inRecentFilesPickerContextKey, activeItem: [...workspacePicks, ...filePicks][autoFocusSecondEntry ? 1 : 0], placeHolder: isMacintosh ? localize('openRecentPlaceholderMac', "Select to open (hold Cmd-key to force new window or Alt-key for same window)") : localize('openRecentPlaceholder', "Select to open (hold Ctrl-key to force new window or Alt-key for same window)"), matchOnDescription: true, onKeyMods: mods => keyMods = mods, - quickNavigate: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : undefined, + quickNavigate: this.isQuickNavigate() ? { keybindings: keybindingService.lookupKeybindings(this.desc.id) } : undefined, onDidTriggerItemButton: async context => { // Remove if (context.button === this.removeFromRecentlyOpened) { - await this.workspacesService.removeRecentlyOpened([context.item.resource]); + await workspacesService.removeRecentlyOpened([context.item.resource]); context.removeItem(); } // Dirty Folder/Workspace else if (context.button === this.dirtyRecentlyOpenedFolder || context.button === this.dirtyRecentlyOpenedWorkspace) { const isDirtyWorkspace = context.button === this.dirtyRecentlyOpenedWorkspace; - const result = await this.dialogService.confirm({ + const result = await dialogService.confirm({ type: 'question', title: isDirtyWorkspace ? localize('dirtyWorkspace', "Workspace with Unsaved Files") : localize('dirtyFolder', "Folder with Unsaved Files"), message: isDirtyWorkspace ? localize('dirtyWorkspaceConfirm', "Do you want to open the workspace to review the unsaved files?") : localize('dirtyFolderConfirm', "Do you want to open the folder to review the unsaved files?"), @@ -163,19 +162,19 @@ abstract class BaseOpenRecentAction extends Action { }); if (result.confirmed) { - this.hostService.openWindow([context.item.openable]); - this.quickInputService.cancel(); + hostService.openWindow([context.item.openable]); + quickInputService.cancel(); } } } }); if (pick) { - return this.hostService.openWindow([pick.openable], { forceNewWindow: keyMods?.ctrlCmd, forceReuseWindow: keyMods?.alt }); + return hostService.openWindow([pick.openable], { forceNewWindow: keyMods?.ctrlCmd, forceReuseWindow: keyMods?.alt }); } } - private toQuickPick(recent: IRecent, isDirty: boolean): IRecentlyOpenedPick { + private toQuickPick(modelService: IModelService, modeService: IModeService, labelService: ILabelService, recent: IRecent, isDirty: boolean): IRecentlyOpenedPick { let openable: IWindowOpenable | undefined; let iconClasses: string[]; let fullLabel: string | undefined; @@ -185,26 +184,26 @@ abstract class BaseOpenRecentAction extends Action { // Folder if (isRecentFolder(recent)) { resource = recent.folderUri; - iconClasses = getIconClasses(this.modelService, this.modeService, resource, FileKind.FOLDER); + iconClasses = getIconClasses(modelService, modeService, resource, FileKind.FOLDER); openable = { folderUri: resource }; - fullLabel = recent.label || this.labelService.getWorkspaceLabel(resource, { verbose: true }); + fullLabel = recent.label || labelService.getWorkspaceLabel(resource, { verbose: true }); } // Workspace else if (isRecentWorkspace(recent)) { resource = recent.workspace.configPath; - iconClasses = getIconClasses(this.modelService, this.modeService, resource, FileKind.ROOT_FOLDER); + iconClasses = getIconClasses(modelService, modeService, resource, FileKind.ROOT_FOLDER); openable = { workspaceUri: resource }; - fullLabel = recent.label || this.labelService.getWorkspaceLabel(recent.workspace, { verbose: true }); + fullLabel = recent.label || labelService.getWorkspaceLabel(recent.workspace, { verbose: true }); isWorkspace = true; } // File else { resource = recent.fileUri; - iconClasses = getIconClasses(this.modelService, this.modeService, resource, FileKind.FILE); + iconClasses = getIconClasses(modelService, modeService, resource, FileKind.FILE); openable = { fileUri: resource }; - fullLabel = recent.label || this.labelService.getUriLabel(resource); + fullLabel = recent.label || labelService.getUriLabel(resource); } const { name, parentPath } = splitName(fullLabel); @@ -223,23 +222,27 @@ abstract class BaseOpenRecentAction extends Action { export class OpenRecentAction extends BaseOpenRecentAction { - static readonly ID = 'workbench.action.openRecent'; - static readonly LABEL = localize('openRecent', "Open Recent..."); - - constructor( - id: string, - label: string, - @IWorkspacesService workspacesService: IWorkspacesService, - @IQuickInputService quickInputService: IQuickInputService, - @IWorkspaceContextService contextService: IWorkspaceContextService, - @IKeybindingService keybindingService: IKeybindingService, - @IModelService modelService: IModelService, - @IModeService modeService: IModeService, - @ILabelService labelService: ILabelService, - @IHostService hostService: IHostService, - @IDialogService dialogService: IDialogService - ) { - super(id, label, workspacesService, quickInputService, contextService, labelService, keybindingService, modelService, modeService, hostService, dialogService); + constructor() { + super({ + id: 'workbench.action.openRecent', + title: { + value: localize('openRecent', "Open Recent..."), + mnemonicTitle: localize({ key: 'miMore', comment: ['&& denotes a mnemonic'] }, "&&More..."), + original: 'Open Recent...' + }, + category: fileCategory, + f1: true, + keybinding: { + weight: KeybindingWeight.WorkbenchContrib, + primary: KeyMod.CtrlCmd | KeyCode.KEY_R, + mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } + }, + menu: { + id: MenuId.MenubarRecentMenu, + group: 'y_more', + order: 1 + } + }); } protected isQuickNavigate(): boolean { @@ -249,23 +252,13 @@ export class OpenRecentAction extends BaseOpenRecentAction { class QuickPickRecentAction extends BaseOpenRecentAction { - static readonly ID = 'workbench.action.quickOpenRecent'; - static readonly LABEL = localize('quickOpenRecent', "Quick Open Recent..."); - - constructor( - id: string, - label: string, - @IWorkspacesService workspacesService: IWorkspacesService, - @IQuickInputService quickInputService: IQuickInputService, - @IWorkspaceContextService contextService: IWorkspaceContextService, - @IKeybindingService keybindingService: IKeybindingService, - @IModelService modelService: IModelService, - @IModeService modeService: IModeService, - @ILabelService labelService: ILabelService, - @IHostService hostService: IHostService, - @IDialogService dialogService: IDialogService - ) { - super(id, label, workspacesService, quickInputService, contextService, labelService, keybindingService, modelService, modeService, hostService, dialogService); + constructor() { + super({ + id: 'workbench.action.quickOpenRecent', + title: { value: localize('quickOpenRecent', "Quick Open Recent..."), original: 'Quick Open Recent...' }, + category: fileCategory, + f1: true + }); } protected isQuickNavigate(): boolean { @@ -273,75 +266,122 @@ class QuickPickRecentAction extends BaseOpenRecentAction { } } -class ToggleFullScreenAction extends Action { - - static readonly ID = 'workbench.action.toggleFullScreen'; - static readonly LABEL = localize('toggleFullScreen', "Toggle Full Screen"); +class ToggleFullScreenAction extends Action2 { - constructor( - id: string, - label: string, - @IHostService private readonly hostService: IHostService - ) { - super(id, label); + constructor() { + super({ + id: 'workbench.action.toggleFullScreen', + title: { + value: localize('toggleFullScreen', "Toggle Full Screen"), + mnemonicTitle: localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "&&Full Screen"), + original: 'Toggle Full Screen' + }, + category: CATEGORIES.View.value, + f1: true, + keybinding: { + weight: KeybindingWeight.WorkbenchContrib, + primary: KeyCode.F11, + mac: { + primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_F + } + }, + precondition: IsIOSContext.toNegated(), + toggled: IsFullscreenContext, + menu: { + id: MenuId.MenubarAppearanceMenu, + group: '1_toggle_view', + order: 1 + } + }); } - override run(): Promise { - return this.hostService.toggleFullScreen(); + override run(accessor: ServicesAccessor): Promise { + const hostService = accessor.get(IHostService); + + return hostService.toggleFullScreen(); } } -export class ReloadWindowAction extends Action { +export class ReloadWindowAction extends Action2 { static readonly ID = 'workbench.action.reloadWindow'; - static readonly LABEL = localize('reloadWindow', "Reload Window"); - - constructor( - id: string, - label: string, - @IHostService private readonly hostService: IHostService - ) { - super(id, label); + + constructor() { + super({ + id: ReloadWindowAction.ID, + title: { value: localize('reloadWindow', "Reload Window"), original: 'Reload Window' }, + category: CATEGORIES.Developer.value, + f1: true, + keybinding: { + weight: KeybindingWeight.WorkbenchContrib + 50, + when: IsDevelopmentContext, + primary: KeyMod.CtrlCmd | KeyCode.KEY_R + } + }); } - override async run(): Promise { - await this.hostService.reload(); + override run(accessor: ServicesAccessor): Promise { + const hostService = accessor.get(IHostService); + + return hostService.reload(); } } -class ShowAboutDialogAction extends Action { - - static readonly ID = 'workbench.action.showAboutDialog'; - static readonly LABEL = localize('about', "About"); +class ShowAboutDialogAction extends Action2 { - constructor( - id: string, - label: string, - @IDialogService private readonly dialogService: IDialogService - ) { - super(id, label); + constructor() { + super({ + id: 'workbench.action.showAboutDialog', + title: { + value: localize('about', "About"), + mnemonicTitle: localize({ key: 'miAbout', comment: ['&& denotes a mnemonic'] }, "&&About"), + original: 'About' + }, + category: CATEGORIES.Help.value, + f1: true, + menu: { + id: MenuId.MenubarHelpMenu, + group: 'z_about', + order: 1, + when: IsMacNativeContext.toNegated() + } + }); } - override run(): Promise { - return this.dialogService.about(); + override run(accessor: ServicesAccessor): Promise { + const dialogService = accessor.get(IDialogService); + + return dialogService.about(); } } -export class NewWindowAction extends Action { - - static readonly ID = 'workbench.action.newWindow'; - static readonly LABEL = localize('newWindow', "New Window"); +class NewWindowAction extends Action2 { - constructor( - id: string, - label: string, - @IHostService private readonly hostService: IHostService - ) { - super(id, label); + constructor() { + super({ + id: 'workbench.action.newWindow', + title: { + value: localize('newWindow', "New Window"), + mnemonicTitle: localize({ key: 'miNewWindow', comment: ['&& denotes a mnemonic'] }, "New &&Window"), + original: 'New Window' + }, + f1: true, + keybinding: { + weight: KeybindingWeight.WorkbenchContrib, + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_N + }, + menu: { + id: MenuId.MenubarFileMenu, + group: '1_new', + order: 2 + } + }); } - override run(): Promise { - return this.hostService.openWindow({ remoteAuthority: null }); + override run(accessor: ServicesAccessor): Promise { + const hostService = accessor.get(IHostService); + + return hostService.openWindow({ remoteAuthority: null }); } } @@ -350,7 +390,7 @@ class BlurAction extends Action2 { constructor() { super({ id: 'workbench.action.blur', - title: localize('blur', "Remove keyboard focus from focused element") + title: { value: localize('blur', "Remove keyboard focus from focused element"), original: 'Remove keyboard focus from focused element' } }); } @@ -363,21 +403,14 @@ class BlurAction extends Action2 { } } -const registry = Registry.as(Extensions.WorkbenchActions); - // --- Actions Registration -const fileCategory = localize('file', "File"); -registry.registerWorkbenchAction(SyncActionDescriptor.from(NewWindowAction, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_N }), 'New Window'); -registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickPickRecentAction), 'File: Quick Open Recent...', fileCategory); -registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenRecentAction, { primary: KeyMod.CtrlCmd | KeyCode.KEY_R, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } }), 'File: Open Recent...', fileCategory); - -registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleFullScreenAction, { primary: KeyCode.F11, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_F } }), 'View: Toggle Full Screen', CATEGORIES.View.value); - -registry.registerWorkbenchAction(SyncActionDescriptor.from(ReloadWindowAction), 'Developer: Reload Window', CATEGORIES.Developer.value, IsWebContext.toNegated()); - -registry.registerWorkbenchAction(SyncActionDescriptor.from(ShowAboutDialogAction), `Help: About`, CATEGORIES.Help.value); - +registerAction2(NewWindowAction); +registerAction2(ToggleFullScreenAction); +registerAction2(QuickPickRecentAction); +registerAction2(OpenRecentAction); +registerAction2(ReloadWindowAction); +registerAction2(ShowAboutDialogAction); registerAction2(BlurAction); // --- Commands/Keybindings Registration @@ -404,13 +437,6 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_R } }); -KeybindingsRegistry.registerKeybindingRule({ - id: ReloadWindowAction.ID, - weight: KeybindingWeight.WorkbenchContrib + 50, - when: IsDevelopmentContext, - primary: KeyMod.CtrlCmd | KeyCode.KEY_R -}); - CommandsRegistry.registerCommand('workbench.action.toggleConfirmBeforeClose', accessor => { const configurationService = accessor.get(IConfigurationService); const setting = configurationService.inspect<'always' | 'keyboardOnly' | 'never'>('window.confirmBeforeClose').userValue; @@ -431,47 +457,9 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { when: IsWebContext }); -MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '1_new', - command: { - id: NewWindowAction.ID, - title: localize({ key: 'miNewWindow', comment: ['&& denotes a mnemonic'] }, "New &&Window") - }, - order: 2 -}); - MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { title: localize({ key: 'miOpenRecent', comment: ['&& denotes a mnemonic'] }, "Open &&Recent"), submenu: MenuId.MenubarRecentMenu, group: '2_open', order: 4 }); - -MenuRegistry.appendMenuItem(MenuId.MenubarRecentMenu, { - group: 'y_more', - command: { - id: OpenRecentAction.ID, - title: localize({ key: 'miMore', comment: ['&& denotes a mnemonic'] }, "&&More...") - }, - order: 1 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '1_toggle_view', - command: { - id: ToggleFullScreenAction.ID, - title: localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "&&Full Screen"), - toggled: IsFullscreenContext - }, - order: 1 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: 'z_about', - command: { - id: ShowAboutDialogAction.ID, - title: localize({ key: 'miAbout', comment: ['&& denotes a mnemonic'] }, "&&About") - }, - order: 1, - when: IsMacNativeContext.toNegated() -}); diff --git a/lib/vscode/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts similarity index 55% rename from lib/vscode/src/vs/workbench/browser/actions/workspaceActions.ts rename to src/vs/workbench/browser/actions/workspaceActions.ts index 58837b5a2582..3824b4d3c4ba 100644 --- a/lib/vscode/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -11,20 +11,21 @@ import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/commo import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; 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 { MenuRegistry, MenuId, SyncActionDescriptor, Action2, registerAction2 } from 'vs/platform/actions/common/actions'; +import { IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { MenuRegistry, MenuId, Action2, registerAction2, ILocalizedString } from 'vs/platform/actions/common/actions'; import { EmptyWorkspaceSupportContext, WorkbenchStateContext, WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; -import { INotificationService } from 'vs/platform/notification/common/notification'; +import Severity from 'vs/base/common/severity'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IWorkspacesService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; -import { WORKSPACE_TRUST_ENABLED } from 'vs/workbench/services/workspaces/common/workspaceTrust'; +import { WorkspaceTrustContext, WORKSPACE_TRUST_ENABLED } from 'vs/workbench/services/workspaces/common/workspaceTrust'; import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; +import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; + +const workspacesCategory: ILocalizedString = { value: localize('workspaces', "Workspaces"), original: 'Workspaces' }; export class OpenFileAction extends Action { @@ -98,29 +99,36 @@ export class OpenWorkspaceAction extends Action { } } -export class CloseWorkspaceAction extends Action { +export class CloseWorkspaceAction extends Action2 { static readonly ID = 'workbench.action.closeFolder'; - static readonly LABEL = localize('closeWorkspace', "Close Workspace"); - constructor( - id: string, - label: string, - @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @INotificationService private readonly notificationService: INotificationService, - @IHostService private readonly hostService: IHostService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService - ) { - super(id, label); + constructor() { + super({ + id: CloseWorkspaceAction.ID, + title: { value: localize('closeWorkspace', "Close Workspace"), original: 'Close Workspace' }, + category: workspacesCategory, + f1: true, + keybinding: { + weight: KeybindingWeight.WorkbenchContrib, + when: EmptyWorkspaceSupportContext, + primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) + } + }); } - override async run(): Promise { - if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { - this.notificationService.info(localize('noWorkspaceOrFolderOpened', "There is currently no workspace or folder opened in this instance to close.")); + override async run(accessor: ServicesAccessor): Promise { + const contextService = accessor.get(IWorkspaceContextService); + const dialogService = accessor.get(IDialogService); + const hostService = accessor.get(IHostService); + const environmentService = accessor.get(IWorkbenchEnvironmentService); + + if (contextService.getWorkbenchState() === WorkbenchState.EMPTY) { + dialogService.show(Severity.Error, localize('noWorkspaceOrFolderOpened', "There is currently no workspace or folder opened in this instance to close."), [localize('ok', 'OK')]); return; } - return this.hostService.openWindow({ forceReuseWindow: true, remoteAuthority: this.environmentService.remoteAuthority }); + return hostService.openWindow({ forceReuseWindow: true, remoteAuthority: environmentService.remoteAuthority }); } } @@ -148,116 +156,120 @@ export class OpenWorkspaceConfigFileAction extends Action { } } -export class AddRootFolderAction extends Action { +export class AddRootFolderAction extends Action2 { static readonly ID = 'workbench.action.addRootFolder'; - static readonly LABEL = ADD_ROOT_FOLDER_LABEL; - constructor( - id: string, - label: string, - @ICommandService private readonly commandService: ICommandService - ) { - super(id, label); + constructor() { + super({ + id: AddRootFolderAction.ID, + title: ADD_ROOT_FOLDER_LABEL, + category: workspacesCategory, + f1: true + }); } - override run(): Promise { - return this.commandService.executeCommand(ADD_ROOT_FOLDER_COMMAND_ID); + override run(accessor: ServicesAccessor): Promise { + const commandService = accessor.get(ICommandService); + + return commandService.executeCommand(ADD_ROOT_FOLDER_COMMAND_ID); } } -export class GlobalRemoveRootFolderAction extends Action { - - static readonly ID = 'workbench.action.removeRootFolder'; - static readonly LABEL = localize('globalRemoveFolderFromWorkspace', "Remove Folder from Workspace..."); +class RemoveRootFolderAction extends Action2 { - constructor( - id: string, - label: string, - @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService, - @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @ICommandService private readonly commandService: ICommandService - ) { - super(id, label); + constructor() { + super({ + id: 'workbench.action.removeRootFolder', + title: { value: localize('globalRemoveFolderFromWorkspace', "Remove Folder from Workspace..."), original: 'Remove Folder from Workspace...' }, + category: workspacesCategory, + f1: true + }); } - override async run(): Promise { - const state = this.contextService.getWorkbenchState(); + override async run(accessor: ServicesAccessor): Promise { + const contextService = accessor.get(IWorkspaceContextService); + const commandService = accessor.get(ICommandService); + const workspaceEditingService = accessor.get(IWorkspaceEditingService); + + const state = contextService.getWorkbenchState(); // Workspace / Folder if (state === WorkbenchState.WORKSPACE || state === WorkbenchState.FOLDER) { - const folder = await this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND_ID); + const folder = await commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND_ID); if (folder) { - await this.workspaceEditingService.removeFolders([folder.uri]); + await workspaceEditingService.removeFolders([folder.uri]); } } } } -export class SaveWorkspaceAsAction extends Action { +class SaveWorkspaceAsAction extends Action2 { static readonly ID = 'workbench.action.saveWorkspaceAs'; - static readonly LABEL = localize('saveWorkspaceAsAction', "Save Workspace As..."); - - constructor( - id: string, - label: string, - @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService - ) { - super(id, label); + constructor() { + super({ + id: SaveWorkspaceAsAction.ID, + title: { value: localize('saveWorkspaceAsAction', "Save Workspace As..."), original: 'Save Workspace As...' }, + category: workspacesCategory, + f1: true + }); } - override async run(): Promise { - const configPathUri = await this.workspaceEditingService.pickNewWorkspacePath(); + override async run(accessor: ServicesAccessor): Promise { + const workspaceEditingService = accessor.get(IWorkspaceEditingService); + const contextService = accessor.get(IWorkspaceContextService); + + const configPathUri = await workspaceEditingService.pickNewWorkspacePath(); if (configPathUri && hasWorkspaceFileExtension(configPathUri)) { - switch (this.contextService.getWorkbenchState()) { + switch (contextService.getWorkbenchState()) { case WorkbenchState.EMPTY: case WorkbenchState.FOLDER: - const folders = this.contextService.getWorkspace().folders.map(folder => ({ uri: folder.uri })); - return this.workspaceEditingService.createAndEnterWorkspace(folders, configPathUri); + const folders = contextService.getWorkspace().folders.map(folder => ({ uri: folder.uri })); + return workspaceEditingService.createAndEnterWorkspace(folders, configPathUri); case WorkbenchState.WORKSPACE: - return this.workspaceEditingService.saveAndEnterWorkspace(configPathUri); + return workspaceEditingService.saveAndEnterWorkspace(configPathUri); } } } } -export class DuplicateWorkspaceInNewWindowAction extends Action { +class DuplicateWorkspaceInNewWindowAction extends Action2 { - static readonly ID = 'workbench.action.duplicateWorkspaceInNewWindow'; - static readonly LABEL = localize('duplicateWorkspaceInNewWindow', "Duplicate As Workspace in New Window"); - - constructor( - id: string, - label: string, - @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, - @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService, - @IHostService private readonly hostService: IHostService, - @IWorkspacesService private readonly workspacesService: IWorkspacesService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService - ) { - super(id, label); + constructor() { + super({ + id: 'workbench.action.duplicateWorkspaceInNewWindow', + title: { value: localize('duplicateWorkspaceInNewWindow', "Duplicate As Workspace in New Window"), original: 'Duplicate As Workspace in New Window' }, + category: workspacesCategory, + f1: true + }); } - override async run(): Promise { - const folders = this.workspaceContextService.getWorkspace().folders; - const remoteAuthority = this.environmentService.remoteAuthority; + override async run(accessor: ServicesAccessor): Promise { + const workspaceContextService = accessor.get(IWorkspaceContextService); + const workspaceEditingService = accessor.get(IWorkspaceEditingService); + const hostService = accessor.get(IHostService); + const workspacesService = accessor.get(IWorkspacesService); + const environmentService = accessor.get(IWorkbenchEnvironmentService); - const newWorkspace = await this.workspacesService.createUntitledWorkspace(folders, remoteAuthority); - await this.workspaceEditingService.copyWorkspaceSettings(newWorkspace); + const folders = workspaceContextService.getWorkspace().folders; + const remoteAuthority = environmentService.remoteAuthority; - return this.hostService.openWindow([{ workspaceUri: newWorkspace.configPath }], { forceNewWindow: true }); + const newWorkspace = await workspacesService.createUntitledWorkspace(folders, remoteAuthority); + await workspaceEditingService.copyWorkspaceSettings(newWorkspace); + + return hostService.openWindow([{ workspaceUri: newWorkspace.configPath }], { forceNewWindow: true }); } } class WorkspaceTrustManageAction extends Action2 { + constructor() { super({ id: 'workbench.action.manageTrust', title: { value: localize('manageTrustAction', "Manage Workspace Trust"), original: 'Manage Workspace Trust' }, - precondition: ContextKeyExpr.and(IsWebContext.negate(), ContextKeyExpr.equals(`config.${WORKSPACE_TRUST_ENABLED}`, true)), + precondition: ContextKeyExpr.and(WorkspaceTrustContext.IsEnabled, IsWebContext.negate(), ContextKeyExpr.equals(`config.${WORKSPACE_TRUST_ENABLED}`, true)), category: localize('workspacesCategory', "Workspaces"), f1: true }); @@ -273,14 +285,11 @@ registerAction2(WorkspaceTrustManageAction); // --- Actions Registration -const registry = Registry.as(Extensions.WorkbenchActions); -const workspacesCategory = localize('workspaces', "Workspaces"); - -registry.registerWorkbenchAction(SyncActionDescriptor.from(AddRootFolderAction), 'Workspaces: Add Folder to Workspace...', workspacesCategory); -registry.registerWorkbenchAction(SyncActionDescriptor.from(GlobalRemoveRootFolderAction), 'Workspaces: Remove Folder from Workspace...', workspacesCategory); -registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseWorkspaceAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'Workspaces: Close Workspace', workspacesCategory, EmptyWorkspaceSupportContext); -registry.registerWorkbenchAction(SyncActionDescriptor.from(SaveWorkspaceAsAction), 'Workspaces: Save Workspace As...', workspacesCategory, EmptyWorkspaceSupportContext); -registry.registerWorkbenchAction(SyncActionDescriptor.from(DuplicateWorkspaceInNewWindowAction), 'Workspaces: Duplicate As Workspace in New Window', workspacesCategory); +registerAction2(AddRootFolderAction); +registerAction2(RemoveRootFolderAction); +registerAction2(CloseWorkspaceAction); +registerAction2(SaveWorkspaceAsAction); +registerAction2(DuplicateWorkspaceInNewWindowAction); // --- Menu Registration @@ -310,7 +319,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: OpenWorkspaceConfigFileAction.ID, - title: { value: `${workspacesCategory}: ${OpenWorkspaceConfigFileAction.LABEL}`, original: 'Workspaces: Open Workspace Configuration File' }, + title: { value: OpenWorkspaceConfigFileAction.LABEL, original: 'Workspaces: Open Workspace Configuration File' }, + category: workspacesCategory }, when: WorkbenchStateContext.isEqualTo('workspace') }); diff --git a/lib/vscode/src/vs/workbench/browser/actions/workspaceCommands.ts b/src/vs/workbench/browser/actions/workspaceCommands.ts similarity index 68% rename from lib/vscode/src/vs/workbench/browser/actions/workspaceCommands.ts rename to src/vs/workbench/browser/actions/workspaceCommands.ts index c9e7bdde3c81..2b834b652c89 100644 --- a/lib/vscode/src/vs/workbench/browser/actions/workspaceCommands.ts +++ b/src/vs/workbench/browser/actions/workspaceCommands.ts @@ -20,12 +20,13 @@ import { IModeService } from 'vs/editor/common/services/modeService'; import { IFileDialogService, IPickAndOpenOptions } from 'vs/platform/dialogs/common/dialogs'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; -import { IOpenWindowOptions, IWindowOpenable } from 'vs/platform/windows/common/windows'; -import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; +import { IOpenEmptyWindowOptions, IOpenWindowOptions, IWindowOpenable } from 'vs/platform/windows/common/windows'; +import { hasWorkspaceFileExtension, IRecent, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; +import { ILocalizedString } from 'vs/platform/actions/common/actions'; export const ADD_ROOT_FOLDER_COMMAND_ID = 'addRootFolder'; -export const ADD_ROOT_FOLDER_LABEL = localize('addFolderToWorkspace', "Add Folder to Workspace..."); +export const ADD_ROOT_FOLDER_LABEL: ILocalizedString = { value: localize('addFolderToWorkspace', "Add Folder to Workspace..."), original: 'Add Folder to Workspace...' }; export const PICK_WORKSPACE_FOLDER_COMMAND_ID = '_workbench.pickWorkspaceFolder'; @@ -184,3 +185,91 @@ CommandsRegistry.registerCommand({ ] } }); + +interface INewWindowAPICommandOptions { + reuseWindow?: boolean; + /** + * If set, defines the remoteAuthority of the new window. `null` will open a local window. + * If not set, defaults to remoteAuthority of the current window. + */ + remoteAuthority?: string | null; +} + +CommandsRegistry.registerCommand({ + id: 'vscode.newWindow', + handler: (accessor: ServicesAccessor, options?: INewWindowAPICommandOptions) => { + const commandOptions: IOpenEmptyWindowOptions = { + forceReuseWindow: options && options.reuseWindow, + remoteAuthority: options && options.remoteAuthority + }; + const commandService = accessor.get(ICommandService); + return commandService.executeCommand('_files.newWindow', commandOptions); + }, + description: { + description: 'Opens an new window depending on the newWindow argument.', + args: [ + { + name: 'options', + description: '(optional) Options. Object with the following properties: ' + + '`reuseWindow`: Whether to open a new window or the same. Defaults to opening in a new window. ', + constraint: (value: any) => value === undefined || typeof value === 'object' + } + ] + } +}); + +// recent history commands + +CommandsRegistry.registerCommand('_workbench.removeFromRecentlyOpened', function (accessor: ServicesAccessor, uri: URI) { + const workspacesService = accessor.get(IWorkspacesService); + return workspacesService.removeRecentlyOpened([uri]); +}); + + +CommandsRegistry.registerCommand({ + id: 'vscode.removeFromRecentlyOpened', + handler: (accessor: ServicesAccessor, path: string | URI): Promise => { + if (typeof path === 'string') { + path = path.match(/^[^:/?#]+:\/\//) ? URI.parse(path) : URI.file(path); + } else { + path = URI.revive(path); // called from extension host + } + const workspacesService = accessor.get(IWorkspacesService); + return workspacesService.removeRecentlyOpened([path]); + }, + description: { + description: 'Removes an entry with the given path from the recently opened list.', + args: [ + { name: 'path', description: 'URI or URI string to remove from recently opened.', constraint: (value: any) => typeof value === 'string' || value instanceof URI } + ] + } +}); + +interface RecentEntry { + uri: URI; + type: 'workspace' | 'folder' | 'file'; + label?: string; + remoteAuthority?: string; +} + +CommandsRegistry.registerCommand('_workbench.addToRecentlyOpened', async function (accessor: ServicesAccessor, recentEntry: RecentEntry) { + const workspacesService = accessor.get(IWorkspacesService); + let recent: IRecent | undefined = undefined; + const uri = recentEntry.uri; + const label = recentEntry.label; + const remoteAuthority = recentEntry.remoteAuthority; + if (recentEntry.type === 'workspace') { + const workspace = await workspacesService.getWorkspaceIdentifier(uri); + recent = { workspace, label, remoteAuthority }; + } else if (recentEntry.type === 'folder') { + recent = { folderUri: uri, label, remoteAuthority }; + } else { + recent = { fileUri: uri, label, remoteAuthority }; + } + return workspacesService.addRecentlyOpened([recent]); +}); + +CommandsRegistry.registerCommand('_workbench.getRecentlyOpened', async function (accessor: ServicesAccessor) { + const workspacesService = accessor.get(IWorkspacesService); + return workspacesService.getRecentlyOpened(); +}); diff --git a/lib/vscode/src/vs/workbench/browser/codeeditor.ts b/src/vs/workbench/browser/codeeditor.ts similarity index 99% rename from lib/vscode/src/vs/workbench/browser/codeeditor.ts rename to src/vs/workbench/browser/codeeditor.ts index c25acef38ad5..3d381ca8089f 100644 --- a/lib/vscode/src/vs/workbench/browser/codeeditor.ts +++ b/src/vs/workbench/browser/codeeditor.ts @@ -107,12 +107,14 @@ export class RangeHighlightDecorations extends Disposable { } private static readonly _WHOLE_LINE_RANGE_HIGHLIGHT = ModelDecorationOptions.register({ + description: 'codeeditor-range-highlight-whole', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'rangeHighlight', isWholeLine: true }); private static readonly _RANGE_HIGHLIGHT = ModelDecorationOptions.register({ + description: 'codeeditor-range-highlight', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'rangeHighlight' }); diff --git a/lib/vscode/src/vs/workbench/browser/composite.ts b/src/vs/workbench/browser/composite.ts similarity index 99% rename from lib/vscode/src/vs/workbench/browser/composite.ts rename to src/vs/workbench/browser/composite.ts index 59cec8515e10..2239c0b97931 100644 --- a/lib/vscode/src/vs/workbench/browser/composite.ts +++ b/src/vs/workbench/browser/composite.ts @@ -118,10 +118,6 @@ export abstract class Composite extends Component implements IComposite { this.parent = parent; } - override updateStyles(): void { - super.updateStyles(); - } - /** * Returns the container this composite is being build in. */ @@ -158,6 +154,13 @@ export abstract class Composite extends Component implements IComposite { */ abstract layout(dimension: Dimension): void; + /** + * Update the styles of the contents of this composite. + */ + override updateStyles(): void { + super.updateStyles(); + } + /** * Returns an array of actions to show in the action bar of the composite. */ diff --git a/lib/vscode/src/vs/workbench/browser/contextkeys.ts b/src/vs/workbench/browser/contextkeys.ts similarity index 95% rename from lib/vscode/src/vs/workbench/browser/contextkeys.ts rename to src/vs/workbench/browser/contextkeys.ts index ebf069f22981..baeaddc1e443 100644 --- a/lib/vscode/src/vs/workbench/browser/contextkeys.ts +++ b/src/vs/workbench/browser/contextkeys.ts @@ -7,8 +7,8 @@ import { localize } from 'vs/nls'; import { Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { IContextKeyService, IContextKey, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, IsWebContext, IsMacNativeContext, IsDevelopmentContext } from 'vs/platform/contextkey/common/contextkeys'; -import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, EditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext } from 'vs/workbench/common/editor'; +import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, IsWebContext, IsMacNativeContext, IsDevelopmentContext, IsIOSContext } from 'vs/platform/contextkey/common/contextkeys'; +import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, EditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext, EditorInputCapabilities } from 'vs/workbench/common/editor'; import { trackFocus, addDisposableListener, EventType, WebFileSystemAccess } from 'vs/base/browser/dom'; import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -22,6 +22,7 @@ import { PanelMaximizedContext, PanelPositionContext, PanelVisibleContext } from import { getRemoteName, getVirtualWorkspaceScheme } from 'vs/platform/remote/common/remoteHosts'; import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { isNative } from 'vs/base/common/platform'; +import { IEditorOverrideService } from 'vs/workbench/services/editor/common/editorOverrideService'; export const WorkbenchStateContext = new RawContextKey('workbenchState', undefined, { type: 'string', description: localize('workbenchState', "The kind of workspace opened in the window, either 'empty' (no workspace), 'folder' (single folder) or 'workspace' (multi-root workspace)") }); export const WorkspaceFolderCountContext = new RawContextKey('workspaceFolderCount', 0, localize('workspaceFolderCount', "The number of root folders in the workspace")); @@ -77,6 +78,7 @@ export class WorkbenchContextKeysHandler extends Disposable { @IConfigurationService private readonly configurationService: IConfigurationService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IEditorService private readonly editorService: IEditorService, + @IEditorOverrideService private readonly editorOverrideService: IEditorOverrideService, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService, @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, @IViewletService private readonly viewletService: IViewletService, @@ -91,6 +93,7 @@ export class WorkbenchContextKeysHandler extends Disposable { IsWebContext.bindTo(this.contextKeyService); IsMacNativeContext.bindTo(this.contextKeyService); + IsIOSContext.bindTo(this.contextKeyService); RemoteNameContext.bindTo(this.contextKeyService).set(getRemoteName(this.environmentService.remoteAuthority) || ''); @@ -239,11 +242,11 @@ export class WorkbenchContextKeysHandler extends Disposable { if (activeEditorPane) { this.activeEditorContext.set(activeEditorPane.getId()); - this.activeEditorIsReadonly.set(activeEditorPane.input.isReadonly()); + this.activeEditorIsReadonly.set(activeEditorPane.input.hasCapability(EditorInputCapabilities.Readonly)); const activeEditorResource = activeEditorPane.input.resource; - const editors = activeEditorResource ? this.editorService.getEditorOverrides(activeEditorResource, undefined, activeGroup) : []; - this.activeEditorAvailableEditorIds.set(editors.map(([_, entry]) => entry.id).join(',')); + const editors = activeEditorResource ? this.editorOverrideService.getEditorIds(activeEditorResource) : []; + this.activeEditorAvailableEditorIds.set(editors.join(',')); } else { this.activeEditorContext.reset(); this.activeEditorIsReadonly.reset(); diff --git a/lib/vscode/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts similarity index 56% rename from lib/vscode/src/vs/workbench/browser/dnd.ts rename to src/vs/workbench/browser/dnd.ts index 8a188db95668..4d2d97b6a738 100644 --- a/lib/vscode/src/vs/workbench/browser/dnd.ts +++ b/src/vs/workbench/browser/dnd.ts @@ -3,73 +3,57 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Registry } from 'vs/platform/registry/common/platform'; -import { hasWorkspaceFileExtension, IWorkspaceFolderCreationData, IRecentFile, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; -import { normalize } from 'vs/base/common/path'; +import { hasWorkspaceFileExtension, IWorkspaceFolderCreationData, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { basename, isEqual } from 'vs/base/common/resources'; import { IFileService } from 'vs/platform/files/common/files'; import { IWindowOpenable } from 'vs/platform/windows/common/windows'; import { URI } from 'vs/base/common/uri'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { bufferToReadable, VSBuffer } from 'vs/base/common/buffer'; import { FileAccess, Schemas } from 'vs/base/common/network'; -import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; +import { IBaseTextResourceEditorInput } from 'vs/platform/editor/common/editor'; import { DataTransfers, IDragAndDropData } from 'vs/base/browser/dnd'; import { DragMouseEvent } from 'vs/base/browser/mouseEvent'; -import { normalizeDriveLetter } from 'vs/base/common/labels'; import { MIME_BINARY } from 'vs/base/common/mime'; import { isWindows } from 'vs/base/common/platform'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; -import { IEditorIdentifier, GroupIdentifier, IEditorInputFactoryRegistry, EditorExtensions } from 'vs/workbench/common/editor'; -import { IEditorService, IResourceEditorInputType } from 'vs/workbench/services/editor/common/editorService'; +import { IEditorIdentifier, GroupIdentifier, isEditorIdentifier } from 'vs/workbench/common/editor'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Disposable, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { addDisposableListener, EventType } from 'vs/base/browser/dom'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; import { withNullAsUndefined } from 'vs/base/common/types'; import { IHostService } from 'vs/workbench/services/host/browser/host'; -import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/common/workingCopyBackup'; import { Emitter } from 'vs/base/common/event'; -import { NO_TYPE_ID } from 'vs/workbench/services/workingCopy/common/workingCopy'; +import { coalesce } from 'vs/base/common/arrays'; +import { parse, stringify } from 'vs/base/common/marshalling'; +import { ILabelService } from 'vs/platform/label/common/label'; -export interface IDraggedResource { - resource: URI; - isExternal: boolean; -} - -interface ISerializedDraggedResource { - resource: string; -} +//#region Editor / Resources DND export class DraggedEditorIdentifier { - constructor(public readonly identifier: IEditorIdentifier) { } + constructor(readonly identifier: IEditorIdentifier) { } } export class DraggedEditorGroupIdentifier { - constructor(public readonly identifier: GroupIdentifier) { } + constructor(readonly identifier: GroupIdentifier) { } } -interface IDraggedEditorProps { - dirtyContent?: string; - encoding?: string; - mode?: string; - options?: ITextEditorOptions; -} - -export interface IDraggedEditor extends IDraggedResource, IDraggedEditorProps { } - -export interface ISerializedDraggedEditor extends ISerializedDraggedResource, IDraggedEditorProps { } - export const CodeDataTransfers = { EDITORS: 'CodeEditors', FILES: 'CodeFiles' }; -export function extractResources(e: DragEvent, externalOnly?: boolean): Array { - const resources: Array = []; +export interface IDraggedResourceEditorInput extends IBaseTextResourceEditorInput { + resource?: URI; + isExternal?: boolean; +} + +export function extractEditorsDropData(e: DragEvent, externalOnly?: boolean): Array { + const editors: IDraggedResourceEditorInput[] = []; if (e.dataTransfer && e.dataTransfer.types.length > 0) { // Check for window-to-window DND @@ -79,17 +63,7 @@ export function extractResources(e: DragEvent, externalOnly?: boolean): Array { - resources.push({ - resource: URI.parse(draggedEditor.resource), - dirtyContent: draggedEditor.dirtyContent, - options: draggedEditor.options, - encoding: draggedEditor.encoding, - mode: draggedEditor.mode, - isExternal: false - }); - }); + editors.push(...parse(rawEditorsData)); } catch (error) { // Invalid transfer } @@ -100,8 +74,8 @@ export function extractResources(e: DragEvent, externalOnly?: boolean): Array ({ resource: URI.parse(uriStr), isExternal: false }))); + const resourcesRaw: string[] = JSON.parse(rawResourcesData); + editors.push(...resourcesRaw.map(resourceRaw => ({ resource: URI.parse(resourceRaw) }))); } } catch (error) { // Invalid transfer @@ -110,12 +84,12 @@ export function extractResources(e: DragEvent, externalOnly?: boolean): Array resource.resource.fsPath === file.path) /* prevent duplicates */) { + if (file?.path /* Electron only */) { try { - resources.push({ resource: URI.file(file.path), isExternal: true }); + editors.push({ resource: URI.file(file.path), isExternal: true }); } catch (error) { // Invalid URI } @@ -128,18 +102,16 @@ export function extractResources(e: DragEvent, externalOnly?: boolean): Array { - if (!resources.some(resource => resource.resource.fsPath === codeFile) /* prevent duplicates */) { - resources.push({ resource: URI.file(codeFile), isExternal: true }); - } - }); + for (const codeFile of codeFiles) { + editors.push({ resource: URI.file(codeFile), isExternal: true }); + } } catch (error) { // Invalid transfer } } } - return resources; + return editors; } export interface IResourcesDropHandlerOptions { @@ -148,21 +120,20 @@ export interface IResourcesDropHandlerOptions { * Whether to open the actual workspace when a workspace configuration file is dropped * or whether to open the configuration file within the editor as normal file. */ - allowWorkspaceOpen: boolean; + readonly allowWorkspaceOpen: boolean; } /** - * Shared function across some components to handle drag & drop of resources. E.g. of folders and workspace files - * to open them in the window instead of the editor or to handle dirty editors being dropped between instances of Code. + * Shared function across some components to handle drag & drop of resources. + * E.g. of folders and workspace files to open them in the window instead of + * the editor or to handle dirty editors being dropped between instances of Code. */ export class ResourcesDropHandler { constructor( - private options: IResourcesDropHandlerOptions, + private readonly options: IResourcesDropHandlerOptions, @IFileService private readonly fileService: IFileService, @IWorkspacesService private readonly workspacesService: IWorkspacesService, - @ITextFileService private readonly textFileService: ITextFileService, - @IWorkingCopyBackupService private readonly workingCopyBackupService: IWorkingCopyBackupService, @IEditorService private readonly editorService: IEditorService, @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService, @IHostService private readonly hostService: IHostService @@ -170,110 +141,61 @@ export class ResourcesDropHandler { } async handleDrop(event: DragEvent, resolveTargetGroup: () => IEditorGroup | undefined, afterDrop: (targetGroup: IEditorGroup | undefined) => void, targetIndex?: number): Promise { - const untitledOrFileResources = extractResources(event).filter(resource => this.fileService.canHandleResource(resource.resource) || resource.resource.scheme === Schemas.untitled); - if (!untitledOrFileResources.length) { + const editors = extractEditorsDropData(event); + if (!editors.length) { return; } // Make the window active to handle the drop properly within await this.hostService.focus(); - // Check for special things being dropped - const isWorkspaceOpening = await this.doHandleDrop(untitledOrFileResources); - if (isWorkspaceOpening) { - return; // return early if the drop operation resulted in this window changing to a workspace + // Check for workspace file being dropped if we are allowed to do so + const externalLocalFiles = coalesce(editors.filter(editor => editor.isExternal && editor.resource?.scheme === Schemas.file).map(editor => editor.resource)); + if (this.options.allowWorkspaceOpen) { + if (externalLocalFiles.length > 0) { + const isWorkspaceOpening = await this.handleWorkspaceFileDrop(externalLocalFiles); + if (isWorkspaceOpening) { + return; // return early if the drop operation resulted in this window changing to a workspace + } + } } // Add external ones to recently open list unless dropped resource is a workspace - const recentFiles: IRecentFile[] = untitledOrFileResources.filter(untitledOrFileResource => untitledOrFileResource.isExternal && untitledOrFileResource.resource.scheme === Schemas.file).map(d => ({ fileUri: d.resource })); - if (recentFiles.length) { - this.workspacesService.addRecentlyOpened(recentFiles); + if (externalLocalFiles.length) { + this.workspacesService.addRecentlyOpened(externalLocalFiles.map(resource => ({ fileUri: resource }))); } - const editors: IResourceEditorInputType[] = untitledOrFileResources.map(untitledOrFileResource => ({ - resource: untitledOrFileResource.resource, - encoding: (untitledOrFileResource as IDraggedEditor).encoding, - mode: (untitledOrFileResource as IDraggedEditor).mode, + // Open in Editor + const targetGroup = resolveTargetGroup(); + await this.editorService.openEditors(editors.map(editor => ({ + ...editor, options: { - ...(untitledOrFileResource as IDraggedEditor).options, + ...editor.options, pinned: true, index: targetIndex } - })); - - // Open in Editor - const targetGroup = resolveTargetGroup(); - await this.editorService.openEditors(editors, targetGroup); + })), targetGroup, { validateTrust: true }); // Finish with provided function afterDrop(targetGroup); } - private async doHandleDrop(untitledOrFileResources: Array): Promise { - - // Check for dirty editors being dropped - const dirtyEditors: IDraggedEditor[] = untitledOrFileResources.filter(untitledOrFileResource => !untitledOrFileResource.isExternal && typeof (untitledOrFileResource as IDraggedEditor).dirtyContent === 'string'); - if (dirtyEditors.length > 0) { - await Promise.all(dirtyEditors.map(dirtyEditor => this.handleDirtyEditorDrop(dirtyEditor))); - return false; - } - - // Check for workspace file being dropped if we are allowed to do so - if (this.options.allowWorkspaceOpen) { - const externalFileOnDiskResources = untitledOrFileResources.filter(untitledOrFileResource => untitledOrFileResource.isExternal && untitledOrFileResource.resource.scheme === Schemas.file).map(d => d.resource); - if (externalFileOnDiskResources.length > 0) { - return this.handleWorkspaceFileDrop(externalFileOnDiskResources); - } - } - - return false; - } - - private async handleDirtyEditorDrop(droppedDirtyEditor: IDraggedEditor): Promise { - const fileEditorFactory = Registry.as(EditorExtensions.EditorInputFactories).getFileEditorInputFactory(); - - // Untitled: always ensure that we open a new untitled editor for each file we drop - if (droppedDirtyEditor.resource.scheme === Schemas.untitled) { - const untitledEditorResource = this.editorService.createEditorInput({ mode: droppedDirtyEditor.mode, encoding: droppedDirtyEditor.encoding, forceUntitled: true }).resource; - if (untitledEditorResource) { - droppedDirtyEditor.resource = untitledEditorResource; - } - } - - // File: ensure the file is not dirty or opened already - else if (this.textFileService.isDirty(droppedDirtyEditor.resource) || this.editorService.isOpened({ resource: droppedDirtyEditor.resource, typeId: fileEditorFactory.typeId })) { - return false; - } - - // If the dropped editor is dirty with content we simply take that - // content and turn it into a backup so that it loads the contents - if (typeof droppedDirtyEditor.dirtyContent === 'string') { - try { - await this.workingCopyBackupService.backup({ resource: droppedDirtyEditor.resource, typeId: NO_TYPE_ID }, bufferToReadable(VSBuffer.fromString(droppedDirtyEditor.dirtyContent))); - } catch (e) { - // Ignore error - } - } - - return false; - } - - private async handleWorkspaceFileDrop(fileOnDiskResources: URI[]): Promise { + private async handleWorkspaceFileDrop(resources: URI[]): Promise { const toOpen: IWindowOpenable[] = []; const folderURIs: IWorkspaceFolderCreationData[] = []; - await Promise.all(fileOnDiskResources.map(async fileOnDiskResource => { + await Promise.all(resources.map(async resource => { // Check for Workspace - if (hasWorkspaceFileExtension(fileOnDiskResource)) { - toOpen.push({ workspaceUri: fileOnDiskResource }); + if (hasWorkspaceFileExtension(resource)) { + toOpen.push({ workspaceUri: resource }); return; } // Check for Folder try { - const stat = await this.fileService.resolve(fileOnDiskResource); + const stat = await this.fileService.resolve(resource); if (stat.isDirectory) { toOpen.push({ folderUri: stat.resource }); folderURIs.push({ uri: stat.resource }); @@ -305,92 +227,141 @@ export class ResourcesDropHandler { } } -export function fillResourceDataTransfers(accessor: ServicesAccessor, resources: (URI | { resource: URI, isDirectory: boolean })[], optionsCallback: ((resource: URI) => ITextEditorOptions) | undefined, event: DragMouseEvent | DragEvent): void { - if (resources.length === 0 || !event.dataTransfer) { +interface IResourceStat { + resource: URI; + isDirectory?: boolean; +} + +export function fillEditorsDragData(accessor: ServicesAccessor, resources: URI[], event: DragMouseEvent | DragEvent): void; +export function fillEditorsDragData(accessor: ServicesAccessor, resources: IResourceStat[], event: DragMouseEvent | DragEvent): void; +export function fillEditorsDragData(accessor: ServicesAccessor, editors: IEditorIdentifier[], event: DragMouseEvent | DragEvent): void; +export function fillEditorsDragData(accessor: ServicesAccessor, resourcesOrEditors: Array, event: DragMouseEvent | DragEvent): void { + if (resourcesOrEditors.length === 0 || !event.dataTransfer) { return; } - const sources = resources.map(obj => { - if (URI.isUri(obj)) { - return { resource: obj, isDirectory: false /* assume resource is not a directory */ }; + const textFileService = accessor.get(ITextFileService); + const editorService = accessor.get(IEditorService); + const fileService = accessor.get(IFileService); + const labelService = accessor.get(ILabelService); + + // Extract resources from URIs or Editors that + // can be handled by the file service + const fileSystemResources = coalesce(resourcesOrEditors.map(resourceOrEditor => { + if (URI.isUri(resourceOrEditor)) { + return { resource: resourceOrEditor }; + } + + if (isEditorIdentifier(resourceOrEditor)) { + if (URI.isUri(resourceOrEditor.editor.resource)) { + return { resource: resourceOrEditor.editor.resource }; + } + + return undefined; // editor without resource } - return obj; - }); + return resourceOrEditor; + })).filter(({ resource }) => fileService.canHandleResource(resource)); // Text: allows to paste into text-capable areas const lineDelimiter = isWindows ? '\r\n' : '\n'; - event.dataTransfer.setData(DataTransfers.TEXT, sources.map(source => source.resource.scheme === Schemas.file ? normalize(normalizeDriveLetter(source.resource.fsPath)) : source.resource.toString()).join(lineDelimiter)); + event.dataTransfer.setData(DataTransfers.TEXT, fileSystemResources.map(({ resource }) => labelService.getUriLabel(resource, { noPrefix: true })).join(lineDelimiter)); // Download URL: enables support to drag a tab as file to desktop (only single file supported) - if (!sources[0].isDirectory) { - event.dataTransfer.setData(DataTransfers.DOWNLOAD_URL, [MIME_BINARY, basename(sources[0].resource), FileAccess.asBrowserUri(sources[0].resource).toString()].join(':')); + const firstFile = fileSystemResources.find(({ isDirectory }) => !isDirectory); + if (firstFile) { + // TODO@sandbox this will no longer work when `vscode-file` + // is enabled because we block loading resources that are not + // inside installation dir + event.dataTransfer.setData(DataTransfers.DOWNLOAD_URL, [MIME_BINARY, basename(firstFile.resource), FileAccess.asBrowserUri(firstFile.resource).toString()].join(':')); } - // Resource URLs: allows to drop multiple resources to a target in VS Code (not directories) - const files = sources.filter(source => !source.isDirectory); + // Resource URLs: allows to drop multiple file resources to a target in VS Code + const files = fileSystemResources.filter(({ isDirectory }) => !isDirectory); if (files.length) { - event.dataTransfer.setData(DataTransfers.RESOURCES, JSON.stringify(files.map(file => file.resource.toString()))); + event.dataTransfer.setData(DataTransfers.RESOURCES, JSON.stringify(files.map(({ resource }) => resource.toString()))); } - // Editors: enables cross window DND of tabs into the editor area - const textFileService = accessor.get(ITextFileService); - const editorService = accessor.get(IEditorService); + // Editors: enables cross window DND of editors + // into the editor area while presering UI state + const draggedEditors: IDraggedResourceEditorInput[] = []; - const draggedEditors: ISerializedDraggedEditor[] = []; - files.forEach(file => { - let options: ITextEditorOptions | undefined = undefined; + for (const resourceOrEditor of resourcesOrEditors) { - // Use provided callback for editor options - if (typeof optionsCallback === 'function') { - options = optionsCallback(file.resource); + // Extract resource editor from provided object or URI + let editor: IDraggedResourceEditorInput | undefined = undefined; + if (isEditorIdentifier(resourceOrEditor)) { + editor = resourceOrEditor.editor.asResourceEditorInput(resourceOrEditor.groupId); + } else if (URI.isUri(resourceOrEditor)) { + editor = { resource: resourceOrEditor }; + } else if (!resourceOrEditor.isDirectory) { + editor = { resource: resourceOrEditor.resource }; } - // Otherwise try to figure out the view state from opened editors that match - else { - options = { - viewState: (() => { - const textEditorControls = editorService.visibleTextEditorControls; - for (const textEditorControl of textEditorControls) { - if (isCodeEditor(textEditorControl)) { - const model = textEditorControl.getModel(); - if (isEqual(model?.uri, file.resource)) { - return withNullAsUndefined(textEditorControl.saveViewState()); - } - } + if (!editor) { + continue; // skip over editors that cannot be transferred via dnd + } + + // Fill in some properties if they are not there already by accessing + // some well known things from the text file universe. + // This is not ideal for custom editors, but those have a chance to + // provide everything from the `asResourceEditorInput` method. + { + const resource = editor.resource; + if (resource) { + const textFileModel = textFileService.files.get(resource); + if (textFileModel) { + + // mode + if (typeof editor.mode !== 'string') { + editor.mode = textFileModel.getMode(); } - return undefined; - })() - }; - } + // encoding + if (typeof editor.encoding !== 'string') { + editor.encoding = textFileModel.getEncoding(); + } - // Try to find encoding and mode from text model - let encoding: string | undefined = undefined; - let mode: string | undefined = undefined; + // contents (only if dirty) + if (typeof editor.contents !== 'string' && textFileModel.isDirty()) { + editor.contents = textFileModel.textEditorModel.getValue(); + } + } - const model = file.resource.scheme === Schemas.untitled ? textFileService.untitled.get(file.resource) : textFileService.files.get(file.resource); - if (model) { - encoding = model.getEncoding(); - mode = model.getMode(); - } + // viewState + if (!editor.options?.viewState) { + editor.options = { + ...editor.options, + viewState: (() => { + for (const textEditorControl of editorService.visibleTextEditorControls) { + if (isCodeEditor(textEditorControl)) { + const model = textEditorControl.getModel(); + if (isEqual(model?.uri, resource)) { + return withNullAsUndefined(textEditorControl.saveViewState()); + } + } + } - // If the resource is dirty or untitled, send over its content - // to restore dirty state. Get that from the text model directly - let dirtyContent: string | undefined = undefined; - if (model?.isDirty()) { - dirtyContent = model.textEditorModel.getValue(); + return undefined; + })() + }; + } + } } // Add as dragged editor - draggedEditors.push({ resource: file.resource.toString(), dirtyContent, options, encoding, mode }); - }); + draggedEditors.push(editor); + } if (draggedEditors.length) { - event.dataTransfer.setData(CodeDataTransfers.EDITORS, JSON.stringify(draggedEditors)); + event.dataTransfer.setData(CodeDataTransfers.EDITORS, stringify(draggedEditors)); } } +//#endregion + +//#region DND Utilities + /** * A singleton to store transfer data during drag & drop operations that are only valid within the application. */ @@ -437,12 +408,12 @@ export class LocalSelectionTransfer { } export interface IDragAndDropObserverCallbacks { - onDragEnter: (e: DragEvent) => void; - onDragLeave: (e: DragEvent) => void; - onDrop: (e: DragEvent) => void; - onDragEnd: (e: DragEvent) => void; + readonly onDragEnter: (e: DragEvent) => void; + readonly onDragLeave: (e: DragEvent) => void; + readonly onDrop: (e: DragEvent) => void; + readonly onDragEnd: (e: DragEvent) => void; - onDragOver?: (e: DragEvent) => void; + readonly onDragOver?: (e: DragEvent) => void; } export class DragAndDropObserver extends Disposable { @@ -453,7 +424,7 @@ export class DragAndDropObserver extends Disposable { // repeadedly. private counter: number = 0; - constructor(private element: HTMLElement, private callbacks: IDragAndDropObserverCallbacks) { + constructor(private readonly element: HTMLElement, private readonly callbacks: IDragAndDropObserverCallbacks) { super(); this.registerListeners(); @@ -514,7 +485,14 @@ export function containsDragType(event: DragEvent, ...dragTypesToFind: string[]) return false; } -export type Before2D = { verticallyBefore: boolean; horizontallyBefore: boolean; }; +//#endregion + +//#region Composites DND + +export type Before2D = { + readonly verticallyBefore: boolean; + readonly horizontallyBefore: boolean; +}; export interface ICompositeDragAndDrop { drop(data: IDragAndDropData, target: string | undefined, originalEvent: DragEvent, before?: Before2D): void; @@ -532,10 +510,13 @@ export interface ICompositeDragAndDropObserverCallbacks { } export class CompositeDragAndDropData implements IDragAndDropData { + constructor(private type: 'view' | 'composite', private id: string) { } + update(dataTransfer: DataTransfer): void { // no-op } + getData(): { type: 'view' | 'composite'; id: string; @@ -545,44 +526,51 @@ export class CompositeDragAndDropData implements IDragAndDropData { } export interface IDraggedCompositeData { - eventData: DragEvent; - dragAndDropData: CompositeDragAndDropData; + readonly eventData: DragEvent; + readonly dragAndDropData: CompositeDragAndDropData; } export class DraggedCompositeIdentifier { - constructor(private _compositeId: string) { } + + constructor(private compositeId: string) { } get id(): string { - return this._compositeId; + return this.compositeId; } } export class DraggedViewIdentifier { - constructor(private _viewId: string) { } + + constructor(private viewId: string) { } get id(): string { - return this._viewId; + return this.viewId; } } export type ViewType = 'composite' | 'view'; export class CompositeDragAndDropObserver extends Disposable { - private transferData: LocalSelectionTransfer; - private _onDragStart = this._register(new Emitter()); - private _onDragEnd = this._register(new Emitter()); - private static _instance: CompositeDragAndDropObserver | undefined; + + private static instance: CompositeDragAndDropObserver | undefined; + static get INSTANCE(): CompositeDragAndDropObserver { - if (!CompositeDragAndDropObserver._instance) { - CompositeDragAndDropObserver._instance = new CompositeDragAndDropObserver(); + if (!CompositeDragAndDropObserver.instance) { + CompositeDragAndDropObserver.instance = new CompositeDragAndDropObserver(); } - return CompositeDragAndDropObserver._instance; + + return CompositeDragAndDropObserver.instance; } + + private readonly transferData = LocalSelectionTransfer.getInstance(); + + private readonly onDragStart = this._register(new Emitter()); + private readonly onDragEnd = this._register(new Emitter()); + private constructor() { super(); - this.transferData = LocalSelectionTransfer.getInstance(); - this._register(this._onDragEnd.event(e => { + this._register(this.onDragEnd.event(e => { const id = e.dragAndDropData.getData().id; const type = e.dragAndDropData.getData().type; const data = this.readDragData(type); @@ -591,6 +579,7 @@ export class CompositeDragAndDropObserver extends Disposable { } })); } + private readDragData(type: ViewType): CompositeDragAndDropData | undefined { if (this.transferData.hasData(type === 'view' ? DraggedViewIdentifier.prototype : DraggedCompositeIdentifier.prototype)) { const data = this.transferData.getData(type === 'view' ? DraggedViewIdentifier.prototype : DraggedCompositeIdentifier.prototype); @@ -598,11 +587,14 @@ export class CompositeDragAndDropObserver extends Disposable { return new CompositeDragAndDropData(type, data[0].id); } } + return undefined; } + private writeDragData(id: string, type: ViewType): void { this.transferData.setData([type === 'view' ? new DraggedViewIdentifier(id) : new DraggedCompositeIdentifier(id)], type === 'view' ? DraggedViewIdentifier.prototype : DraggedCompositeIdentifier.prototype); } + registerTarget(element: HTMLElement, callbacks: ICompositeDragAndDropObserverCallbacks): IDisposable { const disposableStore = new DisposableStore(); disposableStore.add(new DragAndDropObserver(element, { @@ -611,6 +603,7 @@ export class CompositeDragAndDropObserver extends Disposable { }, onDragEnter: e => { e.preventDefault(); + if (callbacks.onDragEnter) { const data = this.readDragData('composite') || this.readDragData('view'); if (data) { @@ -634,11 +627,12 @@ export class CompositeDragAndDropObserver extends Disposable { callbacks.onDrop({ eventData: e, dragAndDropData: data! }); // Fire drag event in case drop handler destroys the dragged element - this._onDragEnd.fire({ eventData: e, dragAndDropData: data! }); + this.onDragEnd.fire({ eventData: e, dragAndDropData: data! }); } }, onDragOver: e => { e.preventDefault(); + if (callbacks.onDragOver) { const data = this.readDragData('composite') || this.readDragData('view'); if (!data) { @@ -649,45 +643,47 @@ export class CompositeDragAndDropObserver extends Disposable { } } })); + if (callbacks.onDragStart) { - this._onDragStart.event(e => { + this.onDragStart.event(e => { callbacks.onDragStart!(e); }, this, disposableStore); } + if (callbacks.onDragEnd) { - this._onDragEnd.event(e => { + this.onDragEnd.event(e => { callbacks.onDragEnd!(e); }); } + return this._register(disposableStore); } registerDraggable(element: HTMLElement, draggedItemProvider: () => { type: ViewType, id: string }, callbacks: ICompositeDragAndDropObserverCallbacks): IDisposable { element.draggable = true; + const disposableStore = new DisposableStore(); + disposableStore.add(addDisposableListener(element, EventType.DRAG_START, e => { const { id, type } = draggedItemProvider(); this.writeDragData(id, type); - if (e.dataTransfer) { - e.dataTransfer.setDragImage(element, 0, 0); - } + e.dataTransfer?.setDragImage(element, 0, 0); - this._onDragStart.fire({ eventData: e, dragAndDropData: this.readDragData(type)! }); + this.onDragStart.fire({ eventData: e, dragAndDropData: this.readDragData(type)! }); })); + disposableStore.add(new DragAndDropObserver(element, { onDragEnd: e => { const { type } = draggedItemProvider(); const data = this.readDragData(type); - if (!data) { return; } - this._onDragEnd.fire({ eventData: e, dragAndDropData: data! }); + this.onDragEnd.fire({ eventData: e, dragAndDropData: data! }); }, onDragEnter: e => { - if (callbacks.onDragEnter) { const data = this.readDragData('composite') || this.readDragData('view'); if (!data) { @@ -712,14 +708,14 @@ export class CompositeDragAndDropObserver extends Disposable { onDrop: e => { if (callbacks.onDrop) { const data = this.readDragData('composite') || this.readDragData('view'); - if (!data) { return; } + callbacks.onDrop({ eventData: e, dragAndDropData: data! }); // Fire drag event in case drop handler destroys the dragged element - this._onDragEnd.fire({ eventData: e, dragAndDropData: data! }); + this.onDragEnd.fire({ eventData: e, dragAndDropData: data! }); } }, onDragOver: e => { @@ -733,16 +729,19 @@ export class CompositeDragAndDropObserver extends Disposable { } } })); + if (callbacks.onDragStart) { - this._onDragStart.event(e => { + this.onDragStart.event(e => { callbacks.onDragStart!(e); }, this, disposableStore); } + if (callbacks.onDragEnd) { - this._onDragEnd.event(e => { + this.onDragEnd.event(e => { callbacks.onDragEnd!(e); }, this, disposableStore); } + return this._register(disposableStore); } } @@ -754,3 +753,5 @@ export function toggleDropEffect(dataTransfer: DataTransfer | null, dropEffect: dataTransfer.dropEffect = shouldHaveIt ? dropEffect : 'none'; } + +//#endregion diff --git a/lib/vscode/src/vs/workbench/browser/editor.ts b/src/vs/workbench/browser/editor.ts similarity index 72% rename from lib/vscode/src/vs/workbench/browser/editor.ts rename to src/vs/workbench/browser/editor.ts index adce1b321d3b..8fae366d3e42 100644 --- a/lib/vscode/src/vs/workbench/browser/editor.ts +++ b/src/vs/workbench/browser/editor.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { EditorInput, EditorResourceAccessor, IEditorInput, EditorExtensions, SideBySideEditor } from 'vs/workbench/common/editor'; +import { EditorResourceAccessor, IEditorInput, EditorExtensions, SideBySideEditor, IEditorDescriptor as ICommonEditorDescriptor } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { Registry } from 'vs/platform/registry/common/platform'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; @@ -20,22 +21,7 @@ import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsSe //#region Editors Registry -export interface IEditorDescriptor { - - /** - * The unique identifier of the editor - */ - getId(): string; - - /** - * The display name of the editor - */ - getName(): string; - - instantiate(instantiationService: IInstantiationService): EditorPane; - - describes(obj: unknown): boolean; -} +export interface IEditorDescriptor extends ICommonEditorDescriptor { } export interface IEditorRegistry { @@ -48,22 +34,12 @@ export interface IEditorRegistry { * @param inputDescriptors A set of constructor functions that return an instance of EditorInput for which the * registered editor should be used for. */ - registerEditor(descriptor: IEditorDescriptor, inputDescriptors: readonly SyncDescriptor[]): IDisposable; + registerEditor(editorDescriptor: IEditorDescriptor, inputDescriptors: readonly SyncDescriptor[]): IDisposable; /** * Returns the editor descriptor for the given input or `undefined` if none. */ getEditor(input: EditorInput): IEditorDescriptor | undefined; - - /** - * Returns the editor descriptor for the given identifier or `undefined` if none. - */ - getEditorById(editorId: string): IEditorDescriptor | undefined; - - /** - * Returns an array of registered editors known to the platform. - */ - getEditors(): readonly IEditorDescriptor[]; } /** @@ -74,36 +50,28 @@ export class EditorDescriptor implements IEditorDescriptor { static create( ctor: { new(...services: Services): EditorPane }, - id: string, + typeId: string, name: string ): EditorDescriptor { - return new EditorDescriptor(ctor as IConstructorSignature0, id, name); + return new EditorDescriptor(ctor as IConstructorSignature0, typeId, name); } - constructor( + private constructor( private readonly ctor: IConstructorSignature0, - private readonly id: string, - private readonly name: string + readonly typeId: string, + readonly name: string ) { } instantiate(instantiationService: IInstantiationService): EditorPane { return instantiationService.createInstance(this.ctor); } - getId(): string { - return this.id; - } - - getName(): string { - return this.name; - } - - describes(obj: unknown): boolean { - return obj instanceof EditorPane && obj.getId() === this.id; + describes(editorPane: EditorPane): boolean { + return editorPane.getId() === this.typeId; } } -class EditorRegistry implements IEditorRegistry { +export class EditorRegistry implements IEditorRegistry { private readonly editors: EditorDescriptor[] = []; private readonly mapEditorToInputs = new Map[]>(); @@ -120,58 +88,53 @@ class EditorRegistry implements IEditorRegistry { } getEditor(input: EditorInput): EditorDescriptor | undefined { - const findEditorDescriptors = (input: EditorInput, byInstanceOf?: boolean): EditorDescriptor[] => { - const matchingDescriptors: EditorDescriptor[] = []; - - for (const editor of this.editors) { - const inputDescriptors = this.mapEditorToInputs.get(editor) || []; - for (const inputDescriptor of inputDescriptors) { - const inputClass = inputDescriptor.ctor; - - // Direct check on constructor type (ignores prototype chain) - if (!byInstanceOf && input.constructor === inputClass) { - matchingDescriptors.push(editor); - break; - } - - // Normal instanceof check - else if (byInstanceOf && input instanceof inputClass) { - matchingDescriptors.push(editor); - break; - } - } - } + const descriptors = this.findEditorDescriptors(input); - // If no descriptors found, continue search using instanceof and prototype chain - if (!byInstanceOf && matchingDescriptors.length === 0) { - return findEditorDescriptors(input, true); - } + if (descriptors.length === 0) { + return undefined; + } - if (byInstanceOf) { - return matchingDescriptors; - } + if (descriptors.length === 1) { + return descriptors[0]; + } + + return input.prefersEditor(descriptors); + } - return matchingDescriptors; - }; + private findEditorDescriptors(input: EditorInput, byInstanceOf?: boolean): EditorDescriptor[] { + const matchingDescriptors: EditorDescriptor[] = []; - const descriptors = findEditorDescriptors(input); - if (descriptors.length > 0) { + for (const editor of this.editors) { + const inputDescriptors = this.mapEditorToInputs.get(editor) || []; + for (const inputDescriptor of inputDescriptors) { + const inputClass = inputDescriptor.ctor; + + // Direct check on constructor type (ignores prototype chain) + if (!byInstanceOf && input.constructor === inputClass) { + matchingDescriptors.push(editor); + break; + } - // Ask the input for its preferred Editor - const preferredEditorId = input.getPreferredEditorId(descriptors.map(descriptor => descriptor.getId())); - if (preferredEditorId) { - return this.getEditorById(preferredEditorId); + // Normal instanceof check + else if (byInstanceOf && input instanceof inputClass) { + matchingDescriptors.push(editor); + break; + } } + } - // Otherwise, first come first serve - return descriptors[0]; + // If no descriptors found, continue search using instanceof and prototype chain + if (!byInstanceOf && matchingDescriptors.length === 0) { + return this.findEditorDescriptors(input, true); } - return undefined; + return matchingDescriptors; } - getEditorById(editorId: string): EditorDescriptor | undefined { - return this.editors.find(editor => editor.getId() === editorId); + //#region Used for tests only + + getEditorByType(typeId: string): EditorDescriptor | undefined { + return this.editors.find(editor => editor.typeId === typeId); } getEditors(): readonly EditorDescriptor[] { @@ -189,6 +152,8 @@ class EditorRegistry implements IEditorRegistry { return inputClasses; } + + //#endregion } Registry.add(EditorExtensions.Editors, new EditorRegistry()); @@ -255,7 +220,6 @@ export function whenEditorClosed(accessor: ServicesAccessor, resources: URI[]): //#endregion - //#region ARIA export function computeEditorAriaLabel(input: IEditorInput, index: number | undefined, group: IEditorGroup | undefined, groupCount: number): string { diff --git a/lib/vscode/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/labels.ts rename to src/vs/workbench/browser/labels.ts diff --git a/lib/vscode/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts similarity index 96% rename from lib/vscode/src/vs/workbench/browser/layout.ts rename to src/vs/workbench/browser/layout.ts index 02ff8b3f52af..0670647b892f 100644 --- a/lib/vscode/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -9,8 +9,9 @@ import { EventType, addDisposableListener, getClientArea, Dimension, position, s import { onDidChangeFullscreen, isFullscreen } from 'vs/base/browser/browser'; import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/common/workingCopyBackup'; import { Registry } from 'vs/platform/registry/common/platform'; -import { isWindows, isLinux, isMacintosh, isWeb, isNative } from 'vs/base/common/platform'; -import { pathsToEditors, SideBySideEditorInput } from 'vs/workbench/common/editor'; +import { isWindows, isLinux, isMacintosh, isWeb, isNative, isIOS } from 'vs/base/common/platform'; +import { IResourceDiffEditorInput, pathsToEditors } from 'vs/workbench/common/editor'; +import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput'; import { SidebarPart } from 'vs/workbench/browser/parts/sidebar/sidebarPart'; import { PanelPart } from 'vs/workbench/browser/parts/panel/panelPart'; import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel'; @@ -48,6 +49,7 @@ import { mark } from 'vs/base/common/performance'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; import { Promises } from 'vs/base/common/async'; +import { IBannerService } from 'vs/workbench/services/banner/browser/bannerService'; export enum Settings { ACTIVITYBAR_VISIBLE = 'workbench.activityBar.visible', @@ -150,6 +152,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi private disposed: boolean | undefined; private titleBarPartView!: ISerializableView; + private bannerPartView!: ISerializableView; private activityBarPartView!: ISerializableView; private sideBarPartView!: ISerializableView; private panelPartView!: ISerializableView; @@ -263,6 +266,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.notificationService = accessor.get(INotificationService); this.activityBarService = accessor.get(IActivityBarService); this.statusBarService = accessor.get(IStatusbarService); + accessor.get(IBannerService); // Listeners this.registerLayoutListeners(); @@ -438,11 +442,11 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi } if (position === Position.LEFT) { - this.workbenchGrid.moveViewTo(this.activityBarPartView, [1, 0]); - this.workbenchGrid.moveViewTo(this.sideBarPartView, [1, 1]); + this.workbenchGrid.moveViewTo(this.activityBarPartView, [2, 0]); + this.workbenchGrid.moveViewTo(this.sideBarPartView, [2, 1]); } else { - this.workbenchGrid.moveViewTo(this.sideBarPartView, [1, 4]); - this.workbenchGrid.moveViewTo(this.activityBarPartView, [1, 4]); + this.workbenchGrid.moveViewTo(this.sideBarPartView, [2, 4]); + this.workbenchGrid.moveViewTo(this.activityBarPartView, [2, 4]); } this.layout(); @@ -597,12 +601,14 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // Files to diff is exclusive return pathsToEditors(initialFilesToOpen.filesToDiff, fileService).then(filesToDiff => { if (filesToDiff.length === 2) { - return [{ - leftResource: filesToDiff[0].resource, - rightResource: filesToDiff[1].resource, + const diffEditorInput: IResourceDiffEditorInput[] = [{ + originalInput: { resource: filesToDiff[0].resource }, + modifiedInput: { resource: filesToDiff[1].resource }, options: { pinned: true }, forceFile: true }]; + + return diffEditorInput; } // Otherwise: Open/Create files @@ -697,7 +703,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi let openEditorsPromise: Promise | undefined = undefined; if (editors.length) { - openEditorsPromise = this.editorService.openEditors(editors); + openEditorsPromise = this.editorService.openEditors(editors, undefined, { validateTrust: true }); } // do not block the overall layout ready flow from potentially @@ -900,7 +906,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi case Parts.STATUSBAR_PART: this.statusBarService.focus(); default: - // Title Bar simply pass focus to container + // Title Bar & Banner simply pass focus to container const container = this.getContainer(part); if (container) { container.focus(); @@ -912,6 +918,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi switch (part) { case Parts.TITLEBAR_PART: return this.getPart(Parts.TITLEBAR_PART).getContainer(); + case Parts.BANNER_PART: + return this.getPart(Parts.BANNER_PART).getContainer(); case Parts.ACTIVITYBAR_PART: return this.getPart(Parts.ACTIVITYBAR_PART).getContainer(); case Parts.SIDEBAR_PART: @@ -1044,7 +1052,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi silentNotifications: boolean; } = this.configurationService.getValue('zenMode'); - toggleFullScreen = !this.state.fullscreen && config.fullScreen; + toggleFullScreen = !this.state.fullscreen && config.fullScreen && !isIOS; this.state.zenMode.transitionedToFullScreen = restoring ? config.fullScreen : toggleFullScreen; this.state.zenMode.transitionedToCenteredEditorLayout = !this.isEditorLayoutCentered() && config.centerLayout; @@ -1159,6 +1167,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi protected createWorkbenchLayout(): void { const titleBar = this.getPart(Parts.TITLEBAR_PART); + const bannerPart = this.getPart(Parts.BANNER_PART); const editorPart = this.getPart(Parts.EDITOR_PART); const activityBar = this.getPart(Parts.ACTIVITYBAR_PART); const panelPart = this.getPart(Parts.PANEL_PART); @@ -1167,6 +1176,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // View references for all parts this.titleBarPartView = titleBar; + this.bannerPartView = bannerPart; this.sideBarPartView = sideBar; this.activityBarPartView = activityBar; this.editorPartView = editorPart; @@ -1175,6 +1185,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi const viewMap = { [Parts.ACTIVITYBAR_PART]: this.activityBarPartView, + [Parts.BANNER_PART]: this.bannerPartView, [Parts.TITLEBAR_PART]: this.titleBarPartView, [Parts.EDITOR_PART]: this.editorPartView, [Parts.PANEL_PART]: this.panelPartView, @@ -1223,6 +1234,10 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.storageService.store(Storage.PANEL_SIZE, panelSize, StorageScope.GLOBAL, StorageTarget.MACHINE); this.storageService.store(Storage.PANEL_DIMENSION, positionToString(this.state.panel.position), StorageScope.GLOBAL, StorageTarget.MACHINE); + // Remember last panel size for both dimensions + this.storageService.store(Storage.PANEL_LAST_NON_MAXIMIZED_HEIGHT, this.state.panel.lastNonMaximizedHeight, StorageScope.GLOBAL, StorageTarget.MACHINE); + this.storageService.store(Storage.PANEL_LAST_NON_MAXIMIZED_WIDTH, this.state.panel.lastNonMaximizedWidth, StorageScope.GLOBAL, StorageTarget.MACHINE); + const gridSize = grid.getViewSize(); this.storageService.store(Storage.GRID_WIDTH, gridSize.width, StorageScope.GLOBAL, StorageTarget.MACHINE); this.storageService.store(Storage.GRID_HEIGHT, gridSize.height, StorageScope.GLOBAL, StorageTarget.MACHINE); @@ -1354,6 +1369,10 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.workbenchGrid.setViewVisible(this.activityBarPartView, !hidden); } + setBannerHidden(hidden: boolean): void { + this.workbenchGrid.setViewVisible(this.bannerPartView, !hidden); + } + setEditorHidden(hidden: boolean, skipLayout?: boolean): void { this.state.editor.hidden = hidden; @@ -1609,7 +1628,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi let newVisibilityValue: string; if (currentVisibilityValue === 'visible' || currentVisibilityValue === 'classic') { - newVisibilityValue = 'compact'; + newVisibilityValue = getTitleBarStyle(this.configurationService) === 'native' ? 'toggle' : 'compact'; } else { newVisibilityValue = 'classic'; } @@ -1738,6 +1757,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi const panelSize = panelDimension === this.state.panel.position ? this.storageService.getNumber(Storage.PANEL_SIZE, StorageScope.GLOBAL, fallbackPanelSize) : fallbackPanelSize; const titleBarHeight = this.titleBarPartView.minimumHeight; + const bannerHeight = this.bannerPartView.minimumHeight; const statusBarHeight = this.statusBarPartView.minimumHeight; const activityBarWidth = this.activityBarPartView.minimumWidth; const middleSectionHeight = height - titleBarHeight - statusBarHeight; @@ -1790,6 +1810,12 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi size: titleBarHeight, visible: this.isVisible(Parts.TITLEBAR_PART) }, + { + type: 'leaf', + data: { type: Parts.BANNER_PART }, + size: bannerHeight, + visible: false + }, { type: 'branch', data: middleSection, diff --git a/lib/vscode/src/vs/workbench/browser/media/code-icon.svg b/src/vs/workbench/browser/media/code-icon.svg similarity index 100% rename from lib/vscode/src/vs/workbench/browser/media/code-icon.svg rename to src/vs/workbench/browser/media/code-icon.svg diff --git a/lib/vscode/src/vs/workbench/browser/media/part.css b/src/vs/workbench/browser/media/part.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/media/part.css rename to src/vs/workbench/browser/media/part.css diff --git a/lib/vscode/src/vs/workbench/browser/media/style.css b/src/vs/workbench/browser/media/style.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/media/style.css rename to src/vs/workbench/browser/media/style.css diff --git a/lib/vscode/src/vs/workbench/browser/panecomposite.ts b/src/vs/workbench/browser/panecomposite.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/panecomposite.ts rename to src/vs/workbench/browser/panecomposite.ts diff --git a/lib/vscode/src/vs/workbench/browser/panel.ts b/src/vs/workbench/browser/panel.ts similarity index 98% rename from lib/vscode/src/vs/workbench/browser/panel.ts rename to src/vs/workbench/browser/panel.ts index 1364f49a41e7..8f861e04dc74 100644 --- a/lib/vscode/src/vs/workbench/browser/panel.ts +++ b/src/vs/workbench/browser/panel.ts @@ -10,7 +10,7 @@ import { IConstructorSignature0, BrandedService, IInstantiationService } from 'v import { assertIsDefined } from 'vs/base/common/types'; import { PaneComposite } from 'vs/workbench/browser/panecomposite'; import { IAction, Separator } from 'vs/base/common/actions'; -import { CompositeMenuActions } from 'vs/workbench/browser/menuActions'; +import { CompositeMenuActions } from 'vs/workbench/browser/actions'; import { MenuId } from 'vs/platform/actions/common/actions'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IStorageService } from 'vs/platform/storage/common/storage'; diff --git a/lib/vscode/src/vs/workbench/browser/part.ts b/src/vs/workbench/browser/part.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/part.ts rename to src/vs/workbench/browser/part.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts rename to src/vs/workbench/browser/parts/activitybar/activitybarActions.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts similarity index 97% rename from lib/vscode/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts rename to src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 21c6e8d0c79f..fdfb3f17dac4 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -169,16 +169,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { // Menu const menuBarVisibility = getMenuBarVisibility(this.configurationService); if (menuBarVisibility === 'compact' || menuBarVisibility === 'hidden' || menuBarVisibility === 'toggle') { - topActions.push({ - id: 'toggleMenuVisibility', - label: localize('menu', "Menu"), - class: undefined, - tooltip: localize('menu', "Menu"), - checked: menuBarVisibility === 'compact', - enabled: true, - run: async () => this.configurationService.updateValue('window.menuBarVisibility', menuBarVisibility === 'compact' ? 'toggle' : 'compact'), - dispose: () => { } - }); + topActions.push(toAction({ id: 'toggleMenuVisibility', label: localize('menu', "Menu"), checked: menuBarVisibility === 'compact', run: () => this.configurationService.updateValue('window.menuBarVisibility', menuBarVisibility === 'compact' ? 'toggle' : 'compact') })); } if (topActions.length) { @@ -187,24 +178,14 @@ export class ActivitybarPart extends Part implements IActivityBarService { // Accounts actions.push(new Separator()); - actions.push({ - id: 'toggleAccountsVisibility', - label: localize('accounts', "Accounts"), - class: undefined, - tooltip: localize('accounts', "Accounts"), - checked: this.accountsVisibilityPreference, - enabled: true, - run: async () => this.accountsVisibilityPreference = !this.accountsVisibilityPreference, - dispose: () => { } - }); - + actions.push(toAction({ id: 'toggleAccountsVisibility', label: localize('accounts', "Accounts"), checked: this.accountsVisibilityPreference, run: () => this.accountsVisibilityPreference = !this.accountsVisibilityPreference })); actions.push(new Separator()); // Toggle Sidebar - actions.push(this.instantiationService.createInstance(ToggleSidebarPositionAction, ToggleSidebarPositionAction.ID, ToggleSidebarPositionAction.getLabel(this.layoutService))); + actions.push(toAction({ id: ToggleSidebarPositionAction.ID, label: ToggleSidebarPositionAction.getLabel(this.layoutService), run: () => this.instantiationService.invokeFunction(accessor => new ToggleSidebarPositionAction().run(accessor)) })); // Toggle Activity Bar - actions.push(toAction({ id: ToggleActivityBarVisibilityAction.ID, label: localize('hideActivitBar', "Hide Activity Bar"), run: async () => this.instantiationService.invokeFunction(accessor => new ToggleActivityBarVisibilityAction().run(accessor)) })); + actions.push(toAction({ id: ToggleActivityBarVisibilityAction.ID, label: localize('hideActivitBar', "Hide Activity Bar"), run: () => this.instantiationService.invokeFunction(accessor => new ToggleActivityBarVisibilityAction().run(accessor)) })); }, getContextMenuActionsForComposite: compositeId => this.getContextMenuActionsForComposite(compositeId), getDefaultCompositeId: () => this.viewDescriptorService.getDefaultViewContainer(this.location)!.id, diff --git a/lib/vscode/src/vs/workbench/browser/parts/activitybar/media/activityaction.css b/src/vs/workbench/browser/parts/activitybar/media/activityaction.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/activitybar/media/activityaction.css rename to src/vs/workbench/browser/parts/activitybar/media/activityaction.css diff --git a/lib/vscode/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css rename to src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css diff --git a/src/vs/workbench/browser/parts/banner/bannerPart.ts b/src/vs/workbench/browser/parts/banner/bannerPart.ts new file mode 100644 index 000000000000..0a9e336bb293 --- /dev/null +++ b/src/vs/workbench/browser/parts/banner/bannerPart.ts @@ -0,0 +1,331 @@ +/*--------------------------------------------------------------------------------------------- + * 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!./media/bannerpart'; +import { localize } from 'vs/nls'; +import { $, addDisposableListener, append, clearNode, EventType } from 'vs/base/browser/dom'; +import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; +import { Codicon, registerCodicon } from 'vs/base/common/codicons'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { Part } from 'vs/workbench/browser/part'; +import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; +import { Action } from 'vs/base/common/actions'; +import { Link } from 'vs/platform/opener/browser/link'; +import { MarkdownString } from 'vs/base/common/htmlContent'; +import { Emitter } from 'vs/base/common/event'; +import { IBannerItem, IBannerService } from 'vs/workbench/services/banner/browser/bannerService'; +import { MarkdownRenderer } from 'vs/editor/browser/core/markdownRenderer'; +import { BANNER_BACKGROUND, BANNER_FOREGROUND, BANNER_ICON_FOREGROUND } from 'vs/workbench/common/theme'; +import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; +import { CATEGORIES } from 'vs/workbench/common/actions'; +import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; + + +// Icons + +const bannerCloseIcon = registerCodicon('banner-close', Codicon.close); + + +// Theme support + +registerThemingParticipant((theme, collector) => { + const backgroundColor = theme.getColor(BANNER_BACKGROUND); + if (backgroundColor) { + collector.addRule(`.monaco-workbench .part.banner { background-color: ${backgroundColor}; }`); + } + + const foregroundColor = theme.getColor(BANNER_FOREGROUND); + if (foregroundColor) { + collector.addRule(` + .monaco-workbench .part.banner, + .monaco-workbench .part.banner .action-container .codicon, + .monaco-workbench .part.banner .message-actions-container .monaco-link + { color: ${foregroundColor}; } + `); + } + + const iconForegroundColor = theme.getColor(BANNER_ICON_FOREGROUND); + if (iconForegroundColor) { + collector.addRule(`.monaco-workbench .part.banner .icon-container .codicon { color: ${iconForegroundColor} }`); + } +}); + + +// Banner Part + +const CONTEXT_BANNER_FOCUSED = new RawContextKey('bannerFocused', false, localize('bannerFocused', "Whether the banner has keyboard focus")); + +export class BannerPart extends Part implements IBannerService { + declare readonly _serviceBrand: undefined; + + // #region IView + + readonly height: number = 26; + readonly minimumWidth: number = 0; + readonly maximumWidth: number = Number.POSITIVE_INFINITY; + + get minimumHeight(): number { + return this.visible ? this.height : 0; + } + + get maximumHeight(): number { + return this.visible ? this.height : 0; + } + + private _onDidChangeSize = new Emitter<{ width: number; height: number; } | undefined>(); + + override get onDidChange() { return this._onDidChangeSize.event; } + + //#endregion + + private item: IBannerItem | undefined; + private readonly markdownRenderer: MarkdownRenderer; + private visible = false; + + private actionBar: ActionBar | undefined; + private messageActionsContainer: HTMLElement | undefined; + private focusedActionIndex: number = -1; + + constructor( + @IThemeService themeService: IThemeService, + @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, + @IStorageService storageService: IStorageService, + @IContextKeyService private readonly contextKeyService: IContextKeyService, + @IInstantiationService private readonly instantiationService: IInstantiationService, + ) { + super(Parts.BANNER_PART, { hasTitle: false }, themeService, storageService, layoutService); + + this.markdownRenderer = this.instantiationService.createInstance(MarkdownRenderer, {}); + } + + override createContentArea(parent: HTMLElement): HTMLElement { + this.element = parent; + this.element.tabIndex = 0; + + // Restore focused action if needed + this._register(addDisposableListener(this.element, EventType.FOCUS, () => { + if (this.focusedActionIndex !== -1) { + this.focusActionLink(); + } + })); + + // Track focus + const scopedContextKeyService = this.contextKeyService.createScoped(this.element); + CONTEXT_BANNER_FOCUSED.bindTo(scopedContextKeyService).set(true); + + return this.element; + } + + private close(item: IBannerItem): void { + // Hide banner + this.setVisibility(false); + + // Remove from document + clearNode(this.element); + + // Remember choice + if (typeof item.onClose === 'function') { + item.onClose(); + } + + this.item = undefined; + } + + private focusActionLink(): void { + const length = this.item?.actions?.length ?? 0; + + if (this.focusedActionIndex < length) { + const actionLink = this.messageActionsContainer?.children[this.focusedActionIndex]; + if (actionLink instanceof HTMLElement) { + this.actionBar?.setFocusable(false); + actionLink.focus(); + } + } else { + this.actionBar?.focus(0); + } + } + + private getAriaLabel(item: IBannerItem): string | undefined { + if (item.ariaLabel) { + return item.ariaLabel; + } + if (typeof item.message === 'string') { + return item.message; + } + + return undefined; + } + + private getBannerMessage(message: MarkdownString | string): HTMLElement { + if (typeof message === 'string') { + const element = $('span'); + element.innerText = message; + return element; + } + + return this.markdownRenderer.render(message).element; + } + + private setVisibility(visible: boolean): void { + if (visible !== this.visible) { + this.visible = visible; + this.focusedActionIndex = -1; + + this.layoutService.setBannerHidden(!visible); + this._onDidChangeSize.fire(undefined); + } + } + + focus(): void { + this.focusedActionIndex = -1; + this.element.focus(); + } + + focusNextAction(): void { + const length = this.item?.actions?.length ?? 0; + this.focusedActionIndex = this.focusedActionIndex < length ? this.focusedActionIndex + 1 : 0; + + this.focusActionLink(); + } + + focusPreviousAction(): void { + const length = this.item?.actions?.length ?? 0; + this.focusedActionIndex = this.focusedActionIndex > 0 ? this.focusedActionIndex - 1 : length; + + this.focusActionLink(); + } + + hide(id: string): void { + if (this.item?.id !== id) { + return; + } + + this.setVisibility(false); + } + + show(item: IBannerItem): void { + if (item.id === this.item?.id) { + this.setVisibility(true); + return; + } + + // Clear previous item + clearNode(this.element); + + // Banner aria label + const ariaLabel = this.getAriaLabel(item); + if (ariaLabel) { + this.element.setAttribute('aria-label', ariaLabel); + } + + // Icon + const iconContainer = append(this.element, $('div.icon-container')); + iconContainer.setAttribute('aria-hidden', 'true'); + iconContainer.appendChild($(`div${item.icon.cssSelector}`)); + + // Message + const messageContainer = append(this.element, $('div.message-container')); + messageContainer.setAttribute('aria-hidden', 'true'); + messageContainer.appendChild(this.getBannerMessage(item.message)); + + // Message Actions + if (item.actions) { + this.messageActionsContainer = append(this.element, $('div.message-actions-container')); + + for (const action of item.actions) { + const actionLink = this._register(this.instantiationService.createInstance(Link, action, {})); + actionLink.el.tabIndex = -1; + actionLink.el.setAttribute('role', 'button'); + this.messageActionsContainer.appendChild(actionLink.el); + } + } + + // Action + const actionBarContainer = append(this.element, $('div.action-container')); + this.actionBar = this._register(new ActionBar(actionBarContainer)); + const closeAction = this._register(new Action('banner.close', 'Close Banner', bannerCloseIcon.classNames, true, () => this.close(item))); + this.actionBar.push(closeAction, { icon: true, label: false }); + this.actionBar.setFocusable(false); + + this.setVisibility(true); + this.item = item; + } + + toJSON(): object { + return { + type: Parts.BANNER_PART + }; + } +} + +registerSingleton(IBannerService, BannerPart); + + +// Keybindings + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'workbench.banner.focusBanner', + weight: KeybindingWeight.WorkbenchContrib, + primary: KeyCode.Escape, + when: CONTEXT_BANNER_FOCUSED, + handler: (accessor: ServicesAccessor) => { + const bannerService = accessor.get(IBannerService); + bannerService.focus(); + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'workbench.banner.focusNextAction', + weight: KeybindingWeight.WorkbenchContrib, + primary: KeyCode.RightArrow, + secondary: [KeyCode.DownArrow], + when: CONTEXT_BANNER_FOCUSED, + handler: (accessor: ServicesAccessor) => { + const bannerService = accessor.get(IBannerService); + bannerService.focusNextAction(); + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'workbench.banner.focusPreviousAction', + weight: KeybindingWeight.WorkbenchContrib, + primary: KeyCode.LeftArrow, + secondary: [KeyCode.UpArrow], + when: CONTEXT_BANNER_FOCUSED, + handler: (accessor: ServicesAccessor) => { + const bannerService = accessor.get(IBannerService); + bannerService.focusPreviousAction(); + } +}); + + +// Actions + +class FocusBannerAction extends Action2 { + + static readonly ID = 'workbench.action.focusBanner'; + static readonly LABEL = localize('focusBanner', "Focus Banner"); + + constructor() { + super({ + id: FocusBannerAction.ID, + title: { value: FocusBannerAction.LABEL, original: 'Focus Banner' }, + category: CATEGORIES.View, + f1: true + }); + } + + async run(accessor: ServicesAccessor): Promise { + const layoutService = accessor.get(IWorkbenchLayoutService); + layoutService.focusPart(Parts.BANNER_PART); + } +} + +registerAction2(FocusBannerAction); diff --git a/src/vs/workbench/browser/parts/banner/media/bannerpart.css b/src/vs/workbench/browser/parts/banner/media/bannerpart.css new file mode 100644 index 000000000000..0b348bafbda2 --- /dev/null +++ b/src/vs/workbench/browser/parts/banner/media/bannerpart.css @@ -0,0 +1,52 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.monaco-workbench .part.banner { + box-sizing: border-box; + cursor: default; + width: 100%; + height: 100%; + font-size: 12px; + display: flex; + overflow: visible; +} + +.monaco-workbench .part.banner .icon-container { + display: flex; + align-items: center; + padding: 0 6px 0 10px; +} + +.monaco-workbench .part.banner .message-container { + line-height: 26px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} + +.monaco-workbench .part.banner .message-container p { + margin-block-start: 0; + margin-block-end: 0; +} + +.monaco-workbench .part.banner .message-actions-container { + flex-grow: 1; + flex-shrink: 0; + line-height: 26px; +} + +.monaco-workbench .part.banner .message-actions-container a { + padding: 3px; + margin-left: 12px; + text-decoration: underline; +} + +.monaco-workbench .part.banner .message-actions-container a:hover { + text-decoration: none; +} + +.monaco-workbench .part.banner .action-container { + padding: 0 10px 0 6px; +} diff --git a/lib/vscode/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/compositeBar.ts rename to src/vs/workbench/browser/parts/compositeBar.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositeBarActions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/compositeBarActions.ts rename to src/vs/workbench/browser/parts/compositeBarActions.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/compositePart.ts b/src/vs/workbench/browser/parts/compositePart.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/compositePart.ts rename to src/vs/workbench/browser/parts/compositePart.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/dialogs/dialog.web.contribution.ts b/src/vs/workbench/browser/parts/dialogs/dialog.web.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/dialogs/dialog.web.contribution.ts rename to src/vs/workbench/browser/parts/dialogs/dialog.web.contribution.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts b/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts similarity index 97% rename from lib/vscode/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts rename to src/vs/workbench/browser/parts/dialogs/dialogHandler.ts index 2defb9ee22ca..84c51a948ad9 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts +++ b/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts @@ -144,12 +144,11 @@ export class BrowserDialogHandler implements IDialogHandler { async about(): Promise { const detailString = (useAgo: boolean): string => { return localize('aboutDetail', - "code-server: v{4}\n VS Code: v{0}\nCommit: {1}\nDate: {2}\nBrowser: {3}", + "Version: {0}\nCommit: {1}\nDate: {2}\nBrowser: {3}", this.productService.version || 'Unknown', this.productService.commit || 'Unknown', this.productService.date ? `${this.productService.date}${useAgo ? ' (' + fromNow(new Date(this.productService.date), true) + ')' : ''}` : 'Unknown', - navigator.userAgent, - this.productService.codeServerVersion || 'Unknown', + navigator.userAgent ); }; diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts b/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts rename to src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/binaryEditor.ts b/src/vs/workbench/browser/parts/editor/binaryEditor.ts similarity index 90% rename from lib/vscode/src/vs/workbench/browser/parts/editor/binaryEditor.ts rename to src/vs/workbench/browser/parts/editor/binaryEditor.ts index edfc611887e4..3608f7181b0b 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/binaryEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryEditor.ts @@ -6,7 +6,8 @@ import 'vs/css!./media/binaryeditor'; import { localize } from 'vs/nls'; import { Emitter } from 'vs/base/common/event'; -import { EditorInput, EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor'; +import { IEditorOpenContext } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -19,9 +20,10 @@ import { DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/ import { IStorageService } from 'vs/platform/storage/common/storage'; import { assertIsDefined, assertAllDefined } from 'vs/base/common/types'; import { ByteSize } from 'vs/platform/files/common/files'; +import { IEditorOptions } from 'vs/platform/editor/common/editor'; export interface IOpenCallbacks { - openInternal: (input: EditorInput, options: EditorOptions | undefined) => Promise; + openInternal: (input: EditorInput, options: IEditorOptions | undefined) => Promise; } /* @@ -70,7 +72,7 @@ export abstract class BaseBinaryResourceEditor extends EditorPane { parent.appendChild(this.scrollbar.getDomNode()); } - override async setInput(input: EditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + override async setInput(input: EditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { await super.setInput(input, options, context, token); const model = await input.resolve(); @@ -88,7 +90,7 @@ export abstract class BaseBinaryResourceEditor extends EditorPane { this.inputDisposable.value = this.renderInput(input, options, model); } - private renderInput(input: EditorInput, options: EditorOptions | undefined, model: BinaryEditorModel): IDisposable { + private renderInput(input: EditorInput, options: IEditorOptions | undefined, model: BinaryEditorModel): IDisposable { const [binaryContainer, scrollbar] = assertAllDefined(this.binaryContainer, this.scrollbar); clearNode(binaryContainer); diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/breadcrumbs.ts b/src/vs/workbench/browser/parts/editor/breadcrumbs.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/editor/breadcrumbs.ts rename to src/vs/workbench/browser/parts/editor/breadcrumbs.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts similarity index 99% rename from lib/vscode/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts rename to src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index f0957c16ec5b..f24ca6352bb1 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -24,7 +24,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IListService, WorkbenchDataTree, WorkbenchListFocusContextKey } from 'vs/platform/list/browser/listService'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; -import { ColorIdentifier, ColorFunction } from 'vs/platform/theme/common/colorRegistry'; +import { ColorIdentifier, ColorTransform } from 'vs/platform/theme/common/colorRegistry'; import { attachBreadcrumbsStyler } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ResourceLabel } from 'vs/workbench/browser/labels'; @@ -146,7 +146,7 @@ export interface IBreadcrumbsControlOptions { showFileIcons: boolean; showSymbolIcons: boolean; showDecorationColors: boolean; - breadcrumbsBackground: ColorIdentifier | ColorFunction; + breadcrumbsBackground: ColorIdentifier | ColorTransform; showPlaceholder: boolean; } @@ -219,6 +219,7 @@ export class BreadcrumbsControl { this._ckBreadcrumbsActive = BreadcrumbsControl.CK_BreadcrumbsActive.bindTo(this._contextKeyService); this._disposables.add(breadcrumbsService.register(this._editorGroup.id, this._widget)); + this.hide(); } dispose(): void { @@ -312,6 +313,7 @@ export class BreadcrumbsControl { this._breadcrumbsDisposables.add(model); this._breadcrumbsDisposables.add(listener); this._breadcrumbsDisposables.add(configListener); + this._breadcrumbsDisposables.add(toDisposable(() => this._widget.setItems([]))); const updateScrollbarSizing = () => { const sizing = this._cfTitleScrollbarSizing.getValue() ?? 'default'; diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/breadcrumbsModel.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsModel.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/editor/breadcrumbsModel.ts rename to src/vs/workbench/browser/parts/editor/breadcrumbsModel.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts rename to src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts similarity index 85% rename from lib/vscode/src/vs/workbench/browser/parts/editor/editor.contribution.ts rename to src/vs/workbench/browser/parts/editor/editor.contribution.ts index 54d768672041..5b579ff10f1f 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -5,17 +5,19 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { localize } from 'vs/nls'; -import { URI, UriComponents } from 'vs/base/common/uri'; +import { URI } from 'vs/base/common/uri'; import { IEditorRegistry, EditorDescriptor } from 'vs/workbench/browser/editor'; -import { EditorInput, IEditorInputSerializer, SideBySideEditorInput, IEditorInputFactoryRegistry, TextCompareEditorActiveContext, ActiveEditorPinnedContext, EditorGroupEditorsCountContext, ActiveEditorStickyContext, ActiveEditorAvailableEditorIdsContext, MultipleEditorGroupsContext, ActiveEditorDirtyContext, EditorExtensions } from 'vs/workbench/common/editor'; +import { + IEditorInputFactoryRegistry, TextCompareEditorActiveContext, ActiveEditorPinnedContext, EditorExtensions, EditorGroupEditorsCountContext, + ActiveEditorStickyContext, ActiveEditorAvailableEditorIdsContext, MultipleEditorGroupsContext, ActiveEditorDirtyContext +} from 'vs/workbench/common/editor'; +import { SideBySideEditorInput, SideBySideEditorInputSerializer } from 'vs/workbench/common/editor/sideBySideEditorInput'; import { TextResourceEditor } from 'vs/workbench/browser/parts/editor/textResourceEditor'; import { SideBySideEditor } from 'vs/workbench/browser/parts/editor/sideBySideEditor'; -import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; +import { DiffEditorInput, DiffEditorInputSerializer } from 'vs/workbench/common/editor/diffEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput'; -import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { TextResourceEditorInput } from 'vs/workbench/common/editor/textResourceEditorInput'; import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor'; -import { UntitledHintContribution } from 'vs/workbench/browser/parts/editor/untitledHint'; import { BinaryResourceDiffEditor } from 'vs/workbench/browser/parts/editor/binaryDiffEditor'; import { ChangeEncodingAction, ChangeEOLAction, ChangeModeAction, EditorStatus } from 'vs/workbench/browser/parts/editor/editorStatus'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions, CATEGORIES } from 'vs/workbench/common/actions'; @@ -34,37 +36,33 @@ import { JoinAllGroupsAction, FocusLeftGroup, FocusAboveGroup, FocusRightGroup, FocusBelowGroup, EditorLayoutSingleAction, EditorLayoutTwoColumnsAction, EditorLayoutThreeColumnsAction, EditorLayoutTwoByTwoGridAction, EditorLayoutTwoRowsAction, EditorLayoutThreeRowsAction, EditorLayoutTwoColumnsBottomAction, EditorLayoutTwoRowsRightAction, NewEditorGroupLeftAction, NewEditorGroupRightAction, NewEditorGroupAboveAction, NewEditorGroupBelowAction, SplitEditorOrthogonalAction, CloseEditorInAllGroupsAction, NavigateToLastEditLocationAction, ToggleGroupSizesAction, ShowAllEditorsByMostRecentlyUsedAction, - QuickAccessPreviousRecentlyUsedEditorAction, OpenPreviousRecentlyUsedEditorInGroupAction, OpenNextRecentlyUsedEditorInGroupAction, QuickAccessLeastRecentlyUsedEditorAction, QuickAccessLeastRecentlyUsedEditorInGroupAction, ReopenResourcesAction, ToggleEditorTypeAction, DuplicateGroupDownAction, DuplicateGroupLeftAction, DuplicateGroupRightAction, DuplicateGroupUpAction + QuickAccessPreviousRecentlyUsedEditorAction, OpenPreviousRecentlyUsedEditorInGroupAction, OpenNextRecentlyUsedEditorInGroupAction, QuickAccessLeastRecentlyUsedEditorAction, QuickAccessLeastRecentlyUsedEditorInGroupAction, ReopenResourcesAction, ReOpenInTextEditorAction, DuplicateGroupDownAction, DuplicateGroupLeftAction, DuplicateGroupRightAction, DuplicateGroupUpAction } from 'vs/workbench/browser/parts/editor/editorActions'; import { CLOSE_EDITORS_AND_GROUP_COMMAND_ID, CLOSE_EDITORS_IN_GROUP_COMMAND_ID, CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID, CLOSE_EDITOR_COMMAND_ID, CLOSE_EDITOR_GROUP_COMMAND_ID, CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID, CLOSE_PINNED_EDITOR_COMMAND_ID, CLOSE_SAVED_EDITORS_COMMAND_ID, GOTO_NEXT_CHANGE, GOTO_PREVIOUS_CHANGE, KEEP_EDITOR_COMMAND_ID, PIN_EDITOR_COMMAND_ID, SHOW_EDITORS_IN_GROUP, SPLIT_EDITOR_DOWN, SPLIT_EDITOR_LEFT, SPLIT_EDITOR_RIGHT, SPLIT_EDITOR_UP, TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE, - TOGGLE_DIFF_SIDE_BY_SIDE, TOGGLE_KEEP_EDITORS_COMMAND_ID, UNPIN_EDITOR_COMMAND_ID, setup + TOGGLE_DIFF_SIDE_BY_SIDE, TOGGLE_KEEP_EDITORS_COMMAND_ID, UNPIN_EDITOR_COMMAND_ID, setup as registerEditorCommands } from 'vs/workbench/browser/parts/editor/editorCommands'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { inQuickPickContext, getQuickNavigateHandler } from 'vs/workbench/browser/quickaccess'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey'; import { isMacintosh } from 'vs/base/common/platform'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { OpenWorkspaceButtonContribution } from 'vs/workbench/browser/codeeditor'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { toLocalResource } from 'vs/base/common/resources'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { EditorAutoSave } from 'vs/workbench/browser/parts/editor/editorAutoSave'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; import { IQuickAccessRegistry, Extensions as QuickAccessExtensions } from 'vs/platform/quickinput/common/quickAccess'; import { ActiveGroupEditorsByMostRecentlyUsedQuickAccess, AllEditorsByAppearanceQuickAccess, AllEditorsByMostRecentlyUsedQuickAccess } from 'vs/workbench/browser/parts/editor/editorQuickAccess'; -import { IPathService } from 'vs/workbench/services/path/common/pathService'; import { FileAccess } from 'vs/base/common/network'; import { Codicon } from 'vs/base/common/codicons'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; +import { UntitledTextEditorInputSerializer, UntitledTextEditorWorkingCopyEditorHandler } from 'vs/workbench/services/untitled/common/untitledTextEditorHandler'; + +//#region Editor Registrations -// Register String Editor Registry.as(EditorExtensions.Editors).registerEditor( EditorDescriptor.create( TextResourceEditor, @@ -73,11 +71,10 @@ Registry.as(EditorExtensions.Editors).registerEditor( ), [ new SyncDescriptor(UntitledTextEditorInput), - new SyncDescriptor(ResourceEditorInput) + new SyncDescriptor(TextResourceEditorInput) ] ); -// Register Text Diff Editor Registry.as(EditorExtensions.Editors).registerEditor( EditorDescriptor.create( TextDiffEditor, @@ -89,7 +86,6 @@ Registry.as(EditorExtensions.Editors).registerEditor( ] ); -// Register Binary Resource Diff Editor Registry.as(EditorExtensions.Editors).registerEditor( EditorDescriptor.create( BinaryResourceDiffEditor, @@ -112,186 +108,24 @@ Registry.as(EditorExtensions.Editors).registerEditor( ] ); -interface ISerializedUntitledTextEditorInput { - resourceJSON: UriComponents; - modeId: string | undefined; - encoding: string | undefined; -} - -// Register Editor Input Serializer -class UntitledTextEditorInputSerializer implements IEditorInputSerializer { - - constructor( - @IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, - @IPathService private readonly pathService: IPathService - ) { } - - canSerialize(editorInput: EditorInput): boolean { - return this.filesConfigurationService.isHotExitEnabled && !editorInput.isDisposed(); - } - - serialize(editorInput: EditorInput): string | undefined { - if (!this.filesConfigurationService.isHotExitEnabled || editorInput.isDisposed()) { - return undefined; - } - - const untitledTextEditorInput = editorInput as UntitledTextEditorInput; - - let resource = untitledTextEditorInput.resource; - if (untitledTextEditorInput.model.hasAssociatedFilePath) { - resource = toLocalResource(resource, this.environmentService.remoteAuthority, this.pathService.defaultUriScheme); // untitled with associated file path use the local schema - } - - // Mode: only remember mode if it is either specific (not text) - // or if the mode was explicitly set by the user. We want to preserve - // this information across restarts and not set the mode unless - // this is the case. - let modeId: string | undefined; - const modeIdCandidate = untitledTextEditorInput.getMode(); - if (modeIdCandidate !== PLAINTEXT_MODE_ID) { - modeId = modeIdCandidate; - } else if (untitledTextEditorInput.model.hasModeSetExplicitly) { - modeId = modeIdCandidate; - } - - const serialized: ISerializedUntitledTextEditorInput = { - resourceJSON: resource.toJSON(), - modeId, - encoding: untitledTextEditorInput.getEncoding() - }; - - return JSON.stringify(serialized); - } - - deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): UntitledTextEditorInput { - return instantiationService.invokeFunction(accessor => { - const deserialized: ISerializedUntitledTextEditorInput = JSON.parse(serializedEditorInput); - const resource = URI.revive(deserialized.resourceJSON); - const mode = deserialized.modeId; - const encoding = deserialized.encoding; - - return accessor.get(IEditorService).createEditorInput({ resource, mode, encoding, forceUntitled: true }) as UntitledTextEditorInput; - }); - } -} - Registry.as(EditorExtensions.EditorInputFactories).registerEditorInputSerializer(UntitledTextEditorInput.ID, UntitledTextEditorInputSerializer); - -// Register SideBySide/DiffEditor Input Serializer -interface ISerializedSideBySideEditorInput { - name: string; - description: string | undefined; - - primarySerialized: string; - secondarySerialized: string; - - primaryTypeId: string; - secondaryTypeId: string; -} - -export abstract class AbstractSideBySideEditorInputSerializer implements IEditorInputSerializer { - - private getInputSerializers(secondaryEditorInputTypeId: string, primaryEditorInputTypeId: string): [IEditorInputSerializer | undefined, IEditorInputSerializer | undefined] { - const registry = Registry.as(EditorExtensions.EditorInputFactories); - - return [registry.getEditorInputSerializer(secondaryEditorInputTypeId), registry.getEditorInputSerializer(primaryEditorInputTypeId)]; - } - - canSerialize(editorInput: EditorInput): boolean { - const input = editorInput as SideBySideEditorInput | DiffEditorInput; - - if (input.primary && input.secondary) { - const [secondaryInputSerializer, primaryInputSerializer] = this.getInputSerializers(input.secondary.typeId, input.primary.typeId); - - return !!(secondaryInputSerializer?.canSerialize(input.secondary) && primaryInputSerializer?.canSerialize(input.primary)); - } - - return false; - } - - serialize(editorInput: EditorInput): string | undefined { - const input = editorInput as SideBySideEditorInput | DiffEditorInput; - - if (input.primary && input.secondary) { - const [secondaryInputSerializer, primaryInputSerializer] = this.getInputSerializers(input.secondary.typeId, input.primary.typeId); - if (primaryInputSerializer && secondaryInputSerializer) { - const primarySerialized = primaryInputSerializer.serialize(input.primary); - const secondarySerialized = secondaryInputSerializer.serialize(input.secondary); - - if (primarySerialized && secondarySerialized) { - const serializedEditorInput: ISerializedSideBySideEditorInput = { - name: input.getName(), - description: input.getDescription(), - primarySerialized: primarySerialized, - secondarySerialized: secondarySerialized, - primaryTypeId: input.primary.typeId, - secondaryTypeId: input.secondary.typeId - }; - - return JSON.stringify(serializedEditorInput); - } - } - } - - return undefined; - } - - deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput | undefined { - const deserialized: ISerializedSideBySideEditorInput = JSON.parse(serializedEditorInput); - - const [secondaryInputSerializer, primaryInputSerializer] = this.getInputSerializers(deserialized.secondaryTypeId, deserialized.primaryTypeId); - if (primaryInputSerializer && secondaryInputSerializer) { - const primaryInput = primaryInputSerializer.deserialize(instantiationService, deserialized.primarySerialized); - const secondaryInput = secondaryInputSerializer.deserialize(instantiationService, deserialized.secondarySerialized); - - if (primaryInput && secondaryInput) { - return this.createEditorInput(instantiationService, deserialized.name, deserialized.description, secondaryInput, primaryInput); - } - } - - return undefined; - } - - protected abstract createEditorInput(instantiationService: IInstantiationService, name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput; -} - -class SideBySideEditorInputSerializer extends AbstractSideBySideEditorInputSerializer { - - protected createEditorInput(instantiationService: IInstantiationService, name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput { - return new SideBySideEditorInput(name, description, secondaryInput, primaryInput); - } -} - -class DiffEditorInputSerializer extends AbstractSideBySideEditorInputSerializer { - - protected createEditorInput(instantiationService: IInstantiationService, name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput { - return instantiationService.createInstance(DiffEditorInput, name, description, secondaryInput, primaryInput, undefined); - } -} - Registry.as(EditorExtensions.EditorInputFactories).registerEditorInputSerializer(SideBySideEditorInput.ID, SideBySideEditorInputSerializer); Registry.as(EditorExtensions.EditorInputFactories).registerEditorInputSerializer(DiffEditorInput.ID, DiffEditorInputSerializer); -// Register Editor Contributions -registerEditorContribution(OpenWorkspaceButtonContribution.ID, OpenWorkspaceButtonContribution); +//#endregion -// Register Editor Status -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(EditorStatus, LifecyclePhase.Ready); +//#region Workbench Contributions -// Register Editor Auto Save Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(EditorAutoSave, LifecyclePhase.Ready); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(EditorStatus, LifecyclePhase.Ready); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(UntitledTextEditorWorkingCopyEditorHandler, LifecyclePhase.Ready); -// Register Untitled Hint -registerEditorContribution(UntitledHintContribution.ID, UntitledHintContribution); +registerEditorContribution(OpenWorkspaceButtonContribution.ID, OpenWorkspaceButtonContribution); -// Register Status Actions -const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ChangeModeAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_M) }), 'Change Language Mode', undefined, ContextKeyExpr.not('notebookEditorFocused')); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ChangeEOLAction), 'Change End of Line Sequence'); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ChangeEncodingAction), 'Change File Encoding'); +//#endregion + +//#region Quick Access -// Register Editor Quick Access const quickAccessRegistry = Registry.as(QuickAccessExtensions.Quickaccess); const editorPickerContextKey = 'inEditorsPicker'; const editorPickerContext = ContextKeyExpr.and(inQuickPickContext, ContextKeyExpr.has(editorPickerContextKey)); @@ -320,7 +154,17 @@ quickAccessRegistry.registerQuickAccessProvider({ helpEntries: [{ description: localize('allEditorsByMostRecentlyUsedQuickAccess', "Show All Opened Editors By Most Recently Used"), needsEditor: false }] }); -// Register Editor Actions +//#endregion + +//#region Actions & Commands + +// Editor Status +const registry = Registry.as(ActionExtensions.WorkbenchActions); +registry.registerWorkbenchAction(SyncActionDescriptor.from(ChangeModeAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_M) }), 'Change Language Mode', undefined, ContextKeyExpr.not('notebookEditorFocused')); +registry.registerWorkbenchAction(SyncActionDescriptor.from(ChangeEOLAction), 'Change End of Line Sequence'); +registry.registerWorkbenchAction(SyncActionDescriptor.from(ChangeEncodingAction), 'Change File Encoding'); + +// Editor Management registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenNextEditor, { primary: KeyMod.CtrlCmd | KeyCode.PageDown, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.RightArrow, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_CLOSE_SQUARE_BRACKET] } }), 'View: Open Next Editor', CATEGORIES.View.value); registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenPreviousEditor, { primary: KeyMod.CtrlCmd | KeyCode.PageUp, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.LeftArrow, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_OPEN_SQUARE_BRACKET] } }), 'View: Open Previous Editor', CATEGORIES.View.value); registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenNextEditorInGroup, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.PageDown), mac: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.RightArrow) } }), 'View: Open Next Editor in Group', CATEGORIES.View.value); @@ -400,16 +244,11 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutTwoByTwoG registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutTwoRowsRightAction), 'View: Two Rows Right Editor Layout', CATEGORIES.View.value); registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutTwoColumnsBottomAction), 'View: Two Columns Bottom Editor Layout', CATEGORIES.View.value); registry.registerWorkbenchAction(SyncActionDescriptor.from(ReopenResourcesAction), 'View: Reopen Editor With...', CATEGORIES.View.value, ActiveEditorAvailableEditorIdsContext); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleEditorTypeAction), 'View: Toggle Editor Type', CATEGORIES.View.value, ActiveEditorAvailableEditorIdsContext); - -// Register Quick Editor Actions including built in quick navigate support for some - +registry.registerWorkbenchAction(SyncActionDescriptor.from(ReOpenInTextEditorAction), 'View: Reopen Editor With Text Editor', CATEGORIES.View.value, ActiveEditorAvailableEditorIdsContext); registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessPreviousRecentlyUsedEditorAction), 'View: Quick Open Previous Recently Used Editor', CATEGORIES.View.value); registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessLeastRecentlyUsedEditorAction), 'View: Quick Open Least Recently Used Editor', CATEGORIES.View.value); - registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessPreviousRecentlyUsedEditorInGroupAction, { primary: KeyMod.CtrlCmd | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyCode.Tab } }), 'View: Quick Open Previous Recently Used Editor in Group', CATEGORIES.View.value); registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessLeastRecentlyUsedEditorInGroupAction, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Tab } }), 'View: Quick Open Least Recently Used Editor in Group', CATEGORIES.View.value); - registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickAccessPreviousEditorFromHistoryAction), 'Quick Open Previous Editor from History'); const quickAccessNavigateNextInEditorPickerId = 'workbench.action.quickOpenNavigateNextInEditorPicker'; @@ -432,10 +271,13 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Tab } }); -// Editor Commands -setup(); +registerEditorCommands(); -// Touch Bar +//#endregion Workbench Actions + +//#region Menus + +// macOS: Touchbar if (isMacintosh) { MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { command: { id: NavigateBackwardsAction.ID, title: NavigateBackwardsAction.LABEL, icon: { dark: FileAccess.asFileUri('vs/workbench/browser/parts/editor/media/back-tb.png', require) } }, @@ -605,7 +447,6 @@ const previousChangeIcon = registerIcon('diff-editor-previous-change', Codicon.a const nextChangeIcon = registerIcon('diff-editor-next-change', Codicon.arrowDown, localize('nextChangeIcon', 'Icon for the next change action in the diff editor.')); const toggleWhitespace = registerIcon('diff-editor-toggle-whitespace', Codicon.whitespace, localize('toggleWhitespace', 'Icon for the toggle whitespace action in the diff editor.')); - // Diff Editor Title Menu: Previous Change appendEditorToolItem( { @@ -1026,3 +867,5 @@ MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, { submenu: MenuId.MenubarSwitchGroupMenu, order: 2 }); + +//#endregion diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/editor.ts b/src/vs/workbench/browser/parts/editor/editor.ts similarity index 88% rename from lib/vscode/src/vs/workbench/browser/parts/editor/editor.ts rename to src/vs/workbench/browser/parts/editor/editor.ts index 6984779b870f..0761fee8bf6d 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/editor.ts +++ b/src/vs/workbench/browser/parts/editor/editor.ts @@ -3,7 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { GroupIdentifier, IWorkbenchEditorConfiguration, EditorOptions, TextEditorOptions, IEditorInput, IEditorIdentifier, IEditorCloseEvent, IEditorPartOptions, IEditorPartOptionsChangeEvent, EditorInput } from 'vs/workbench/common/editor'; +import { GroupIdentifier, IWorkbenchEditorConfiguration, IEditorInput, IEditorIdentifier, IEditorCloseEvent, IEditorPartOptions, IEditorPartOptionsChangeEvent } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { IEditorGroup, GroupDirection, IAddGroupOptions, IMergeGroupOptions, GroupsOrder, GroupsArrangement } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Dimension } from 'vs/base/browser/dom'; @@ -13,6 +14,8 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ISerializableView } from 'vs/base/browser/ui/grid/grid'; import { getIEditor } from 'vs/editor/browser/editorBrowser'; import { IEditorService, IResourceEditorInputType } from 'vs/workbench/services/editor/common/editorService'; +import { withNullAsUndefined } from 'vs/base/common/types'; +import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor'; export interface IEditorPartCreationOptions { restorePreviousState: boolean; @@ -129,15 +132,20 @@ export interface IEditorGroupView extends IDisposable, ISerializableView, IEdito relayout(): void; } -export function getActiveTextEditorOptions(group: IEditorGroup, expectedActiveEditor?: IEditorInput, presetOptions?: EditorOptions): EditorOptions { +export function getActiveTextEditorOptions(group: IEditorGroup, expectedActiveEditor?: IEditorInput, presetOptions?: IEditorOptions): ITextEditorOptions { const activeGroupCodeEditor = group.activeEditorPane ? getIEditor(group.activeEditorPane.getControl()) : undefined; if (activeGroupCodeEditor) { if (!expectedActiveEditor || expectedActiveEditor.matches(group.activeEditor)) { - return TextEditorOptions.fromEditor(activeGroupCodeEditor, presetOptions); + const textOptions: ITextEditorOptions = { + ...presetOptions, + viewState: withNullAsUndefined(activeGroupCodeEditor.saveViewState()) + }; + + return textOptions; } } - return presetOptions || new EditorOptions(); + return presetOptions || Object.create(null); } /** diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts similarity index 98% rename from lib/vscode/src/vs/workbench/browser/parts/editor/editorActions.ts rename to src/vs/workbench/browser/parts/editor/editorActions.ts index 0cb09967252b..e901b3805879 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/editorActions.ts +++ b/src/vs/workbench/browser/parts/editor/editorActions.ts @@ -5,7 +5,8 @@ import { localize } from 'vs/nls'; import { Action } from 'vs/base/common/actions'; -import { IEditorInput, IEditorIdentifier, IEditorCommandsContext, CloseDirection, SaveReason, EditorsOrder, SideBySideEditorInput } from 'vs/workbench/common/editor'; +import { IEditorInput, IEditorIdentifier, IEditorCommandsContext, CloseDirection, SaveReason, EditorsOrder, EditorInputCapabilities, IEditorInputFactoryRegistry, EditorExtensions } from 'vs/workbench/common/editor'; +import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -24,6 +25,8 @@ import { Codicon } from 'vs/base/common/codicons'; import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { EditorOverride } from 'vs/platform/editor/common/editor'; import { Schemas } from 'vs/base/common/network'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/services/editor/common/editorOverrideService'; export class ExecuteCommandAction extends Action { @@ -592,7 +595,7 @@ abstract class BaseCloseAllAction extends Action { // Auto-save on focus change: assume to Save unless the editor is untitled // because bringing up a dialog would save in this case anyway. - if (this.filesConfigurationService.getAutoSaveMode() === AutoSaveMode.ON_FOCUS_CHANGE && !editor.isUntitled()) { + if (this.filesConfigurationService.getAutoSaveMode() === AutoSaveMode.ON_FOCUS_CHANGE && !editor.hasCapability(EditorInputCapabilities.Untitled)) { dirtyEditorsToAutoSave.add(editor); } @@ -1925,10 +1928,12 @@ export class ReopenResourcesAction extends Action { } } -export class ToggleEditorTypeAction extends Action { +export class ReOpenInTextEditorAction extends Action { - static readonly ID = 'workbench.action.toggleEditorType'; - static readonly LABEL = localize('workbench.action.toggleEditorType', "Toggle Editor Type"); + static readonly ID = 'workbench.action.reopenTextEditor'; + static readonly LABEL = localize('workbench.action.reopenTextEditor', "Reopen Editor With Text Editor"); + + private readonly fileEditorInputFactory = Registry.as(EditorExtensions.EditorInputFactories).getFileEditorInputFactory(); constructor( id: string, @@ -1952,12 +1957,17 @@ export class ToggleEditorTypeAction extends Action { const options = activeEditorPane.options; const group = activeEditorPane.group; - const overrides = this.editorService.getEditorOverrides(activeEditorResource, options, group); - const firstNonActiveOverride = overrides.find(([_, entry]) => !entry.active); - if (!firstNonActiveOverride) { + if (this.fileEditorInputFactory.isFileEditorInput(this.editorService.activeEditor)) { return; } - await firstNonActiveOverride[0].open(activeEditorPane.input, { ...options, override: firstNonActiveOverride[1].id }, group)?.override; + // Replace the current editor with the text editor + await this.editorService.replaceEditors([ + { + editor: activeEditorPane.input, + replacement: activeEditorPane.input, + options: { ...options, override: DEFAULT_EDITOR_ASSOCIATION.id }, + } + ], group); } } diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/editorAutoSave.ts b/src/vs/workbench/browser/parts/editor/editorAutoSave.ts similarity index 97% rename from lib/vscode/src/vs/workbench/browser/parts/editor/editorAutoSave.ts rename to src/vs/workbench/browser/parts/editor/editorAutoSave.ts index 8bddd352872b..09ffc4af2a25 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/editorAutoSave.ts +++ b/src/vs/workbench/browser/parts/editor/editorAutoSave.ts @@ -7,7 +7,7 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { Disposable, DisposableStore, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { IFilesConfigurationService, AutoSaveMode, IAutoSaveConfiguration } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; -import { SaveReason, IEditorIdentifier, IEditorInput, GroupIdentifier, ISaveOptions } from 'vs/workbench/common/editor'; +import { SaveReason, IEditorIdentifier, IEditorInput, GroupIdentifier, ISaveOptions, EditorInputCapabilities } from 'vs/workbench/common/editor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { withNullAsUndefined } from 'vs/base/common/types'; @@ -90,7 +90,7 @@ export class EditorAutoSave extends Disposable implements IWorkbenchContribution } private maybeTriggerAutoSave(reason: SaveReason, editorIdentifier?: IEditorIdentifier): void { - if (editorIdentifier && (editorIdentifier.editor.isReadonly() || editorIdentifier.editor.isUntitled())) { + if (editorIdentifier?.editor.hasCapability(EditorInputCapabilities.Readonly) || editorIdentifier?.editor.hasCapability(EditorInputCapabilities.Untitled)) { return; // no auto save for readonly or untitled editors } diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/editorCommands.ts b/src/vs/workbench/browser/parts/editor/editorCommands.ts similarity index 97% rename from lib/vscode/src/vs/workbench/browser/parts/editor/editorCommands.ts rename to src/vs/workbench/browser/parts/editor/editorCommands.ts index 625742980224..f30102c65b81 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/editorCommands.ts +++ b/src/vs/workbench/browser/parts/editor/editorCommands.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import { isObject, isString, isUndefined, isNumber, withNullAsUndefined } from 'vs/base/common/types'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { TextCompareEditorVisibleContext, EditorInput, IEditorIdentifier, IEditorCommandsContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, CloseDirection, IEditorInput, IVisibleEditorPane, ActiveEditorStickyContext, EditorsOrder, viewColumnToEditorGroup, EditorGroupColumn } from 'vs/workbench/common/editor'; +import { TextCompareEditorVisibleContext, IEditorIdentifier, IEditorCommandsContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, CloseDirection, IEditorInput, IVisibleEditorPane, ActiveEditorStickyContext, EditorsOrder, viewColumnToEditorGroup, EditorGroupColumn, EditorInputCapabilities, isEditorIdentifier } from 'vs/workbench/common/editor'; import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor'; @@ -452,7 +452,7 @@ function registerOpenEditorAPICommands(): void { } }); - CommandsRegistry.registerCommand(API_OPEN_DIFF_EDITOR_COMMAND_ID, async function (accessor: ServicesAccessor, leftResource: UriComponents, rightResource: UriComponents, label?: string, columnAndOptions?: [EditorGroupColumn?, ITextEditorOptions?], context?: IOpenEvent) { + CommandsRegistry.registerCommand(API_OPEN_DIFF_EDITOR_COMMAND_ID, async function (accessor: ServicesAccessor, originalResource: UriComponents, modifiedResource: UriComponents, label?: string, columnAndOptions?: [EditorGroupColumn?, ITextEditorOptions?], context?: IOpenEvent) { const editorService = accessor.get(IEditorService); const editorGroupService = accessor.get(IEditorGroupsService); @@ -460,8 +460,8 @@ function registerOpenEditorAPICommands(): void { const [options, column] = mixinContext(context, optionsArg, columnArg); await editorService.openEditor({ - leftResource: URI.revive(leftResource), - rightResource: URI.revive(rightResource), + originalInput: { resource: URI.revive(originalResource) }, + modifiedInput: { resource: URI.revive(modifiedResource) }, label, options }, viewColumnToEditorGroup(editorGroupService, column)); @@ -487,7 +487,7 @@ function registerOpenEditorAPICommands(): void { group = editorGroupsService.getGroup(viewColumnToEditorGroup(editorGroupsService, columnArg)) ?? editorGroupsService.activeGroup; } - return editorService.openEditor({ resource: URI.revive(resource), options: { ...optionsArg, override: id } }, group); + return editorService.openEditor({ resource: URI.revive(resource), options: { ...optionsArg, pinned: true, override: id } }, group); }); } @@ -631,13 +631,14 @@ export function splitEditor(editorGroupService: IEditorGroupsService, direction: editorToCopy = withNullAsUndefined(sourceGroup.activeEditor); } - // Copy the editor to the new group, else move the editor to the new group - if (editorToCopy && (editorToCopy as EditorInput).canSplit()) { + // Copy the editor to the new group, else create an empty group + if (editorToCopy && !editorToCopy.hasCapability(EditorInputCapabilities.Singleton)) { sourceGroup.copyEditor(editorToCopy, newGroup); - // Focus - newGroup.focus(); } + // Focus + newGroup.focus(); + } function registerSplitEditorCommands() { @@ -1045,15 +1046,12 @@ export function getMultiSelectedEditorContexts(editorContext: IEditorCommandsCon } function isEditorGroup(thing: unknown): thing is IEditorGroup { - const group = thing as IEditorGroup; - - return group && typeof group.id === 'number' && Array.isArray(group.editors); -} - -function isEditorIdentifier(thing: unknown): thing is IEditorIdentifier { - const identifier = thing as IEditorIdentifier; + const group = thing as IEditorGroup | undefined; + if (!group) { + return false; + } - return identifier && typeof identifier.groupId === 'number'; + return typeof group.id === 'number' && Array.isArray(group.editors); } export function setup(): void { diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/editorControl.ts b/src/vs/workbench/browser/parts/editor/editorControl.ts similarity index 77% rename from lib/vscode/src/vs/workbench/browser/parts/editor/editorControl.ts rename to src/vs/workbench/browser/parts/editor/editorControl.ts index 10819e7d186d..b49d6dd9e0f6 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/editorControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorControl.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { EditorExtensions, EditorInput, EditorOptions, IEditorOpenContext, IVisibleEditorPane } from 'vs/workbench/common/editor'; +import { EditorExtensions, EditorInputCapabilities, IEditorOpenContext, IVisibleEditorPane } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { Dimension, show, hide } from 'vs/base/browser/dom'; import { Registry } from 'vs/platform/registry/common/platform'; import { IEditorRegistry, IEditorDescriptor } from 'vs/workbench/browser/editor'; @@ -15,6 +16,9 @@ import { IEditorProgressService, LongRunningOperation } from 'vs/platform/progre import { IEditorGroupView, DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor'; import { Emitter } from 'vs/base/common/event'; import { assertIsDefined } from 'vs/base/common/types'; +import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; +import { WorkspaceTrustRequiredEditor } from 'vs/workbench/browser/parts/editor/workspaceTrustRequiredEditor'; +import { IEditorOptions } from 'vs/platform/editor/common/editor'; export interface IOpenEditorResult { readonly editorPane: EditorPane; @@ -42,31 +46,64 @@ export class EditorControl extends Disposable { private readonly activeEditorPaneDisposables = this._register(new DisposableStore()); private dimension: Dimension | undefined; private readonly editorOperation = this._register(new LongRunningOperation(this.editorProgressService)); + private readonly editorsRegistry = Registry.as(EditorExtensions.Editors); constructor( private parent: HTMLElement, private groupView: IEditorGroupView, @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, @IInstantiationService private readonly instantiationService: IInstantiationService, - @IEditorProgressService private readonly editorProgressService: IEditorProgressService + @IEditorProgressService private readonly editorProgressService: IEditorProgressService, + @IWorkspaceTrustManagementService private readonly workspaceTrustService: IWorkspaceTrustManagementService, ) { super(); + + this.registerListeners(); } - async openEditor(editor: EditorInput, options: EditorOptions | undefined, context: IEditorOpenContext): Promise { + private registerListeners(): void { + this._register(this.workspaceTrustService.onDidChangeTrust(() => this.onDidChangeWorkspaceTrust())); + } - // Editor pane - const descriptor = Registry.as(EditorExtensions.Editors).getEditor(editor); - if (!descriptor) { - throw new Error(`No editor descriptor found for input id ${editor.typeId}`); + private onDidChangeWorkspaceTrust() { + + // If the active editor pane requires workspace trust + // we need to re-open it anytime trust changes to + // account for it. + // For that we explicitly call into the group-view + // to handle errors properly. + const editor = this._activeEditorPane?.input; + const options = this._activeEditorPane?.options; + if (editor?.hasCapability(EditorInputCapabilities.RequiresTrust)) { + this.groupView.openEditor(editor, options); } + } + + async openEditor(editor: EditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext = Object.create(null)): Promise { + + // Editor descriptor + const descriptor = this.getEditorDescriptor(editor); + + // Editor pane const editorPane = this.doShowEditorPane(descriptor); - // Set input + // Apply input to pane const editorChanged = await this.doSetInput(editorPane, editor, options, context); return { editorPane, editorChanged }; } + private getEditorDescriptor(editor: EditorInput): IEditorDescriptor { + if (editor.hasCapability(EditorInputCapabilities.RequiresTrust) && !this.workspaceTrustService.isWorkpaceTrusted()) { + // Workspace trust: if an editor signals it needs workspace trust + // but the current workspace is untrusted, we fallback to a generic + // editor descriptor to indicate this an do NOT load the registered + // editor. + return WorkspaceTrustRequiredEditor.DESCRIPTOR; + } + + return assertIsDefined(this.editorsRegistry.getEditor(editor)); + } + private doShowEditorPane(descriptor: IEditorDescriptor): EditorPane { // Return early if the currently active editor pane can handle the input @@ -108,7 +145,6 @@ export class EditorControl extends Disposable { if (!editorPane.getContainer()) { const editorPaneContainer = document.createElement('div'); editorPaneContainer.classList.add('editor-instance'); - editorPaneContainer.setAttribute('data-editor-id', descriptor.getId()); editorPane.create(editorPaneContainer); } @@ -147,7 +183,7 @@ export class EditorControl extends Disposable { this._onDidChangeSizeConstraints.fire(undefined); } - private async doSetInput(editorPane: EditorPane, editor: EditorInput, options: EditorOptions | undefined, context: IEditorOpenContext): Promise { + private async doSetInput(editorPane: EditorPane, editor: EditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext): Promise { // If the input did not change, return early and only apply the options // unless the options instruct us to force open it even if it is the same diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/editorDropTarget.ts b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts similarity index 96% rename from lib/vscode/src/vs/workbench/browser/parts/editor/editorDropTarget.ts rename to src/vs/workbench/browser/parts/editor/editorDropTarget.ts index 2d813d3e68e3..10cecdf94a43 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/editorDropTarget.ts +++ b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts @@ -10,7 +10,7 @@ import { IEditorGroupsAccessor, IEditorGroupView, getActiveTextEditorOptions } f import { EDITOR_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme'; import { IThemeService, Themable } from 'vs/platform/theme/common/themeService'; import { activeContrastBorder } from 'vs/platform/theme/common/colorRegistry'; -import { IEditorIdentifier, EditorInput, EditorOptions } from 'vs/workbench/common/editor'; +import { IEditorIdentifier, EditorInputCapabilities } from 'vs/workbench/common/editor'; import { isMacintosh, isWeb } from 'vs/base/common/platform'; import { GroupDirection, IEditorGroupsService, MergeGroupMode } from 'vs/workbench/services/editor/common/editorGroupsService'; import { toDisposable } from 'vs/base/common/lifecycle'; @@ -18,12 +18,12 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { RunOnceScheduler } from 'vs/base/common/async'; import { DataTransfers } from 'vs/base/browser/dnd'; import { VSBuffer } from 'vs/base/common/buffer'; -import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { URI } from 'vs/base/common/uri'; import { joinPath } from 'vs/base/common/resources'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { assertIsDefined, assertAllDefined } from 'vs/base/common/types'; -import { INotificationService } from 'vs/platform/notification/common/notification'; +import Severity from 'vs/base/common/severity'; import { localize } from 'vs/nls'; import { ByteSize } from 'vs/platform/files/common/files'; @@ -55,7 +55,7 @@ class DropOverlay extends Themable { @IInstantiationService private instantiationService: IInstantiationService, @IFileDialogService private readonly fileDialogService: IFileDialogService, @IEditorService private readonly editorService: IEditorService, - @INotificationService private readonly notificationService: INotificationService, + @IDialogService private readonly dialogService: IDialogService, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService ) { super(themeService); @@ -281,10 +281,10 @@ class DropOverlay extends Themable { } // Open in target group - const options = getActiveTextEditorOptions(sourceGroup, draggedEditor.editor, EditorOptions.create({ + const options = getActiveTextEditorOptions(sourceGroup, draggedEditor.editor, { pinned: true, // always pin dropped editor sticky: sourceGroup.isSticky(draggedEditor.editor), // preserve sticky state - })); + }); const copyEditor = this.isCopyOperation(event, draggedEditor); if (!copyEditor) { @@ -313,7 +313,7 @@ class DropOverlay extends Themable { // Skip for very large files because this operation is unbuffered if (file.size > DropOverlay.MAX_FILE_UPLOAD_SIZE) { - this.notificationService.warn(localize('fileTooLarge', "File is too large to open as untitled editor. Please upload it first into the file explorer and then try again.")); + this.dialogService.show(Severity.Warning, localize('fileTooLarge', "File is too large to open as untitled editor. Please upload it first into the file explorer and then try again."), [localize('ok', 'OK')]); continue; } @@ -332,18 +332,16 @@ class DropOverlay extends Themable { proposedFilePath = joinPath(defaultFilePath, name); } - // Open as untitled file with the provided contents - const untitledEditor = this.editorService.createEditorInput({ - resource: proposedFilePath, - forceUntitled: true, - contents: VSBuffer.wrap(new Uint8Array(event.target.result)).toString() - }); - if (!targetGroup) { targetGroup = ensureTargetGroup(); } - await targetGroup.openEditor(untitledEditor); + // Open as untitled text file with the provided contents + await this.editorService.openEditor({ + resource: proposedFilePath, + forceUntitled: true, + contents: VSBuffer.wrap(new Uint8Array(event.target.result)).toString() + }, targetGroup.id); } }; } @@ -354,16 +352,12 @@ class DropOverlay extends Themable { // Check for URI transfer else { const dropHandler = this.instantiationService.createInstance(ResourcesDropHandler, { allowWorkspaceOpen: true /* open workspace instead of file if dropped */ }); - dropHandler.handleDrop(event, () => ensureTargetGroup(), targetGroup => { - if (targetGroup) { - targetGroup.focus(); - } - }); + dropHandler.handleDrop(event, () => ensureTargetGroup(), targetGroup => targetGroup?.focus()); } } private isCopyOperation(e: DragEvent, draggedEditor?: IEditorIdentifier): boolean { - if (draggedEditor?.editor instanceof EditorInput && !draggedEditor.editor.canSplit()) { + if (draggedEditor?.editor.hasCapability(EditorInputCapabilities.Singleton)) { return false; } diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts similarity index 95% rename from lib/vscode/src/vs/workbench/browser/parts/editor/editorGroupView.ts rename to src/vs/workbench/browser/parts/editor/editorGroupView.ts index b30b4a700101..fe11ee21bad4 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -5,7 +5,9 @@ import 'vs/css!./media/editorgroupview'; import { EditorGroupModel, IEditorOpenOptions, EditorCloseEvent, ISerializedEditorGroupModel, isSerializedEditorGroupModel } from 'vs/workbench/common/editor/editorGroupModel'; -import { EditorInput, EditorOptions, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, ActiveEditorDirtyContext, IEditorPane, EditorGroupEditorsCountContext, SaveReason, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditorPane, ActiveEditorStickyContext, ActiveEditorPinnedContext, EditorResourceAccessor, IEditorMoveEvent } from 'vs/workbench/common/editor'; +import { GroupIdentifier, CloseDirection, IEditorCloseEvent, ActiveEditorDirtyContext, IEditorPane, EditorGroupEditorsCountContext, SaveReason, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditorPane, ActiveEditorStickyContext, ActiveEditorPinnedContext, EditorResourceAccessor, IEditorMoveEvent, EditorInputCapabilities, IEditorOpenEvent } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; +import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput'; import { Event, Emitter, Relay } from 'vs/base/common/event'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { Dimension, trackFocus, addDisposableListener, EventType, EventHelper, findParentWithClass, clearNode, isAncestor, asCSSUrl } from 'vs/base/browser/dom'; @@ -45,7 +47,7 @@ import { hash } from 'vs/base/common/hash'; import { guessMimeTypes } from 'vs/base/common/mime'; import { extname, isEqual } from 'vs/base/common/resources'; import { FileAccess, Schemas } from 'vs/base/common/network'; -import { EditorActivation, EditorOpenContext } from 'vs/platform/editor/common/editor'; +import { EditorActivation, EditorOpenContext, IEditorOptions } from 'vs/platform/editor/common/editor'; import { IDialogService, IFileDialogService, ConfirmResult } from 'vs/platform/dialogs/common/dialogs'; import { ILogService } from 'vs/platform/log/common/log'; import { Codicon } from 'vs/base/common/codicons'; @@ -100,6 +102,9 @@ export class EditorGroupView extends Themable implements IEditorGroupView { private readonly _onWillMoveEditor = this._register(new Emitter()); readonly onWillMoveEditor = this._onWillMoveEditor.event; + private readonly _onWillOpenEditor = this._register(new Emitter()); + readonly onWillOpenEditor = this._onWillOpenEditor.event; + //#endregion private readonly model: EditorGroupModel; @@ -286,7 +291,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { if (this.isEmpty) { EventHelper.stop(e); - this.openEditor(this.editorService.createEditorInput({ forceUntitled: true }), EditorOptions.create({ pinned: true })); + this.openEditor(this.editorService.createEditorInput({ forceUntitled: true }), { pinned: true }); } })); @@ -456,11 +461,11 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } // Determine editor options - let options: EditorOptions; + let options: IEditorOptions; if (from instanceof EditorGroupView) { options = getActiveTextEditorOptions(from); // if we copy from another group, ensure to copy its active editor viewstate } else { - options = new EditorOptions(); + options = Object.create(null); } const activeEditor = this.model.activeEditor; @@ -499,7 +504,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView { this._register(this.model.onDidCloseEditor(editor => this.handleOnDidCloseEditor(editor))); this._register(this.model.onWillDisposeEditor(editor => this.onWillDisposeEditor(editor))); this._register(this.model.onDidChangeEditorDirty(editor => this.onDidChangeEditorDirty(editor))); - this._register(this.model.onDidEditorLabelChange(editor => this.onDidEditorLabelChange(editor))); + this._register(this.model.onDidChangeEditorLabel(editor => this.onDidChangeEditorLabel(editor))); + this._register(this.model.onDidChangeEditorCapabilities(editor => this.onDidChangeEditorCapabilities(editor))); // Option Changes this._register(this.accessor.onDidChangeEditorPartOptions(e => this.onDidChangeEditorPartOptions(e))); @@ -687,7 +693,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_DIRTY, editor }); } - private onDidEditorLabelChange(editor: EditorInput): void { + private onDidChangeEditorLabel(editor: EditorInput): void { // Forward to title control this.titleAreaControl.updateEditorLabel(editor); @@ -696,6 +702,15 @@ export class EditorGroupView extends Themable implements IEditorGroupView { this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_LABEL, editor }); } + private onDidChangeEditorCapabilities(editor: EditorInput): void { + + // Forward to title control + this.titleAreaControl.updateEditorCapabilities(editor); + + // Event + this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_CAPABILITIES, editor }); + } + private onDidVisibilityChange(visible: boolean): void { // Forward to editor control @@ -899,26 +914,18 @@ export class EditorGroupView extends Themable implements IEditorGroupView { //#region openEditor() - async openEditor(editor: EditorInput, options?: EditorOptions): Promise { - - // Guard against invalid inputs - if (!editor) { - return undefined; - } - - // Proceed with opening - return this.doOpenEditor(editor, options); - } - - private async doOpenEditor(editor: EditorInput, options?: EditorOptions): Promise { + async openEditor(editor: EditorInput, options?: IEditorOptions): Promise { // Guard against invalid inputs. Disposed inputs // should never open because they emit no events // e.g. to indicate dirty changes. - if (editor.isDisposed()) { + if (!editor || editor.isDisposed()) { return; } + // Fire the event letting everyone know we are about to open an editor + this._onWillOpenEditor.fire({ editor, groupId: this.id }); + // Determine options const openEditorOptions: IEditorOpenOptions = { index: options ? options.index : undefined, @@ -991,7 +998,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { return showEditorResult; } - private doShowEditor(editor: EditorInput, context: { active: boolean, isNew: boolean }, options?: EditorOptions): Promise { + private doShowEditor(editor: EditorInput, context: { active: boolean, isNew: boolean }, options?: IEditorOptions): Promise { // Show in editor control if the active editor changed let openEditorPromise: Promise; @@ -1024,11 +1031,14 @@ export class EditorGroupView extends Themable implements IEditorGroupView { return openEditorPromise; } - private async doHandleOpenEditorError(error: Error, editor: EditorInput, options?: EditorOptions): Promise { + private async doHandleOpenEditorError(error: Error, editor: EditorInput, options?: IEditorOptions): Promise { // Report error only if we are not told to ignore errors that occur from opening an editor if (!isPromiseCanceledError(error) && (!options || !options.ignoreError)) { + // Always log the error to figure out what is going on + this.logService.error(error); + // Since it is more likely that errors fail to open when restoring them e.g. // because files got deleted or moved meanwhile, we do not show any notifications // if we are still restoring editors. @@ -1093,11 +1103,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView { Event.once(handle.onDidClose)(() => actions.primary && dispose(actions.primary)); } } - - // Restoring: just log errors to console - else { - this.logService.error(error); - } } // Event @@ -1114,7 +1119,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { //#region openEditors() - async openEditors(editors: { editor: EditorInput, options?: EditorOptions }[]): Promise { + async openEditors(editors: { editor: EditorInput, options?: IEditorOptions }[]): Promise { if (!editors.length) { return null; } @@ -1129,7 +1134,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Open the other ones inactive const startingIndex = this.getIndexOfEditor(editor) + 1; await Promises.settled(editors.map(async ({ editor, options }, index) => { - const adjustedEditorOptions = options || new EditorOptions(); + const adjustedEditorOptions = options || Object.create(null); adjustedEditorOptions.inactive = true; adjustedEditorOptions.pinned = true; adjustedEditorOptions.index = startingIndex + index; @@ -1147,7 +1152,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { //#region moveEditor() - moveEditor(editor: EditorInput, target: IEditorGroupView, options?: EditorOptions): void { + moveEditor(editor: EditorInput, target: IEditorGroupView, options?: IEditorOptions): void { // Move within same group if (this === target) { @@ -1196,11 +1201,11 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // When moving/copying an editor, try to preserve as much view state as possible // by checking for the editor to be a text editor and creating the options accordingly // if so - const options = getActiveTextEditorOptions(this, editor, EditorOptions.create({ + const options = getActiveTextEditorOptions(this, editor, { ...openOptions, pinned: true, // always pin moved editor sticky: !keepCopy && this.model.isSticky(editor) // preserve sticky state only if editor is moved (https://github.com/microsoft/vscode/issues/99035) - })); + }); // Indicate will move event if (!keepCopy) { @@ -1224,7 +1229,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { //#region copyEditor() - copyEditor(editor: EditorInput, target: IEditorGroupView, options?: EditorOptions): void { + copyEditor(editor: EditorInput, target: IEditorGroupView, options?: IEditorOptions): void { // Move within same group because we do not support to show the same editor // multiple times in the same group @@ -1322,16 +1327,16 @@ export class EditorGroupView extends Themable implements IEditorGroupView { activation = EditorActivation.PRESERVE; } - const options = EditorOptions.create({ preserveFocus, activation }); - - // When closing an editor due to an error we can end up in a loop where we continue closing - // editors that fail to open (e.g. when the file no longer exists). We do not want to show - // repeated errors in this case to the user. As such, if we open the next editor and we are - // in a scope of a previous editor failing, we silence the input errors until the editor is - // opened by setting ignoreError: true. - if (fromError) { - options.ignoreError = true; - } + const options: IEditorOptions = { + preserveFocus, + activation, + // When closing an editor due to an error we can end up in a loop where we continue closing + // editors that fail to open (e.g. when the file no longer exists). We do not want to show + // repeated errors in this case to the user. As such, if we open the next editor and we are + // in a scope of a previous editor failing, we silence the input errors until the editor is + // opened by setting ignoreError: true. + ignoreError: fromError + }; this.openEditor(nextActiveEditor, options); } @@ -1448,7 +1453,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { let confirmation: ConfirmResult; let saveReason = SaveReason.EXPLICIT; let autoSave = false; - if (this.filesConfigurationService.getAutoSaveMode() === AutoSaveMode.ON_FOCUS_CHANGE && !editor.isUntitled() && !options?.skipAutoSave) { + if (this.filesConfigurationService.getAutoSaveMode() === AutoSaveMode.ON_FOCUS_CHANGE && !editor.hasCapability(EditorInputCapabilities.Untitled) && !options?.skipAutoSave) { autoSave = true; confirmation = ConfirmResult.SAVE; saveReason = SaveReason.FOCUS_CHANGE; @@ -1654,7 +1659,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { if (options) { options.index = index; } else { - options = EditorOptions.create({ index }); + options = { index }; } options.inactive = !isActiveEditor; @@ -1673,7 +1678,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { for (const { editor, replacement, forceReplaceDirty, options } of inactiveReplacements) { // Open inactive editor - await this.doOpenEditor(replacement, options); + await this.openEditor(replacement, options); // Close replaced inactive editor unless they match if (!editor.matches(replacement)) { @@ -1694,7 +1699,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { if (activeReplacement) { // Open replacement as active editor - const openEditorResult = this.doOpenEditor(activeReplacement.replacement, activeReplacement.options); + const openEditorResult = this.openEditor(activeReplacement.replacement, activeReplacement.options); // Close replaced active editor unless they match if (!activeReplacement.editor.matches(activeReplacement.replacement)) { @@ -1796,7 +1801,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { export interface EditorReplacement extends IEditorReplacement { readonly editor: EditorInput; readonly replacement: EditorInput; - readonly options?: EditorOptions; + readonly options?: IEditorOptions; } registerThemingParticipant((theme, collector) => { diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/editorPane.ts b/src/vs/workbench/browser/parts/editor/editorPane.ts similarity index 95% rename from lib/vscode/src/vs/workbench/browser/parts/editor/editorPane.ts rename to src/vs/workbench/browser/parts/editor/editorPane.ts index 081a0a8ae31d..b07b6a1c1f79 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/editorPane.ts +++ b/src/vs/workbench/browser/parts/editor/editorPane.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { Composite } from 'vs/workbench/browser/composite'; -import { EditorInput, EditorOptions, IEditorPane, GroupIdentifier, IEditorMemento, IEditorOpenContext } from 'vs/workbench/common/editor'; +import { IEditorPane, GroupIdentifier, IEditorMemento, IEditorOpenContext } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -20,6 +21,7 @@ import { joinPath, IExtUri, isEqual } from 'vs/base/common/resources'; import { indexOfPath } from 'vs/base/common/extpath'; import { IDisposable } from 'vs/base/common/lifecycle'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IEditorOptions } from 'vs/platform/editor/common/editor'; /** * The base class of editors in the workbench. Editors register themselves for specific editor inputs. @@ -56,8 +58,8 @@ export abstract class EditorPane extends Composite implements IEditorPane { protected _input: EditorInput | undefined; get input(): EditorInput | undefined { return this._input; } - protected _options: EditorOptions | undefined; - get options(): EditorOptions | undefined { return this._options; } + protected _options: IEditorOptions | undefined; + get options(): IEditorOptions | undefined { return this._options; } private _group: IEditorGroup | undefined; get group(): IEditorGroup | undefined { return this._group; } @@ -102,7 +104,7 @@ export abstract class EditorPane extends Composite implements IEditorPane { * The provided cancellation token should be used to test if the operation * was cancelled. */ - async setInput(input: EditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + async setInput(input: EditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { this._input = input; this._options = options; } @@ -129,7 +131,7 @@ export abstract class EditorPane extends Composite implements IEditorPane { * Sets the given options to the editor. Clients should apply the options * to the current input. */ - setOptions(options: EditorOptions | undefined): void { + setOptions(options: IEditorOptions | undefined): void { this._options = options; } @@ -193,7 +195,7 @@ export class EditorMemento implements IEditorMemento { private editorDisposables: Map | undefined; constructor( - public readonly id: string, + readonly id: string, private key: string, private memento: MementoObject, private limit: number, diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts similarity index 99% rename from lib/vscode/src/vs/workbench/browser/parts/editor/editorPart.ts rename to src/vs/workbench/browser/parts/editor/editorPart.ts index 1383de7ab678..fddbc8a13c11 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -211,11 +211,6 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro private whenRestoredResolve: (() => void) | undefined; readonly whenRestored = new Promise(resolve => (this.whenRestoredResolve = resolve)); - private restored = false; - - isRestored(): boolean { - return this.restored; - } get hasRestorableState(): boolean { return !!this.workspaceMemento[EditorPart.EDITOR_PART_UI_STATE_STORAGE_KEY]; @@ -845,7 +840,6 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro // Signal restored Promises.settled(this.groups.map(group => group.whenRestored)).finally(() => { - this.restored = true; this.whenRestoredResolve?.(); }); diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/editorQuickAccess.ts b/src/vs/workbench/browser/parts/editor/editorQuickAccess.ts similarity index 99% rename from lib/vscode/src/vs/workbench/browser/parts/editor/editorQuickAccess.ts rename to src/vs/workbench/browser/parts/editor/editorQuickAccess.ts index a2e88453c0dc..7f8a6094a07f 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/editorQuickAccess.ts +++ b/src/vs/workbench/browser/parts/editor/editorQuickAccess.ts @@ -68,7 +68,7 @@ export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessPro return super.provide(picker, token); } - protected getPicks(filter: string): Array { + protected _getPicks(filter: string): Array { const query = prepareQuery(filter); // Filtering diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts similarity index 96% rename from lib/vscode/src/vs/workbench/browser/parts/editor/editorStatus.ts rename to src/vs/workbench/browser/parts/editor/editorStatus.ts index 4c2e352c4550..cd87db7f04d3 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -13,7 +13,7 @@ import { URI } from 'vs/base/common/uri'; import { Action, WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions'; import { Language } from 'vs/base/common/platform'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput'; -import { IFileEditorInput, EditorResourceAccessor, SideBySideEditorInput, IEditorPane, IEditorInput, SideBySideEditor } from 'vs/workbench/common/editor'; +import { IFileEditorInput, EditorResourceAccessor, IEditorPane, IEditorInput, SideBySideEditor, EditorInputCapabilities } from 'vs/workbench/common/editor'; import { Disposable, MutableDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IEditorAction } from 'vs/editor/common/editorCommon'; import { EndOfLineSequence } from 'vs/editor/common/model'; @@ -53,6 +53,7 @@ import { IMarker, IMarkerService, MarkerSeverity, IMarkerData } from 'vs/platfor import { STATUS_BAR_PROMINENT_ITEM_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_FOREGROUND } from 'vs/workbench/common/theme'; import { themeColorFromId } from 'vs/platform/theme/common/themeService'; import { ITelemetryData, ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput'; class SideBySideEditorEncodingSupport implements IEncodingSupport { constructor(private primary: IEncodingSupport, private secondary: IEncodingSupport) { } @@ -369,7 +370,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { return this.quickInputService.pick([{ label: localize('noEditor', "No text editor active at this time") }]); } - if (this.editorService.activeEditor?.isReadonly()) { + if (this.editorService.activeEditor?.hasCapability(EditorInputCapabilities.Readonly)) { return this.quickInputService.pick([{ label: localize('noWritableCodeEditor', "The active code editor is read-only.") }]); } @@ -404,13 +405,14 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { if (!this.tabFocusModeElement.value) { const text = localize('tabFocusModeEnabled', "Tab Moves Focus"); this.tabFocusModeElement.value = this.statusbarService.addEntry({ + name: localize('status.editor.tabFocusMode', "Accessibility Mode"), text, ariaLabel: text, tooltip: localize('disableTabMode', "Disable Accessibility Mode"), command: 'editor.action.toggleTabFocusMode', backgroundColor: themeColorFromId(STATUS_BAR_PROMINENT_ITEM_BACKGROUND), color: themeColorFromId(STATUS_BAR_PROMINENT_ITEM_FOREGROUND) - }, 'status.editor.tabFocusMode', localize('status.editor.tabFocusMode', "Accessibility Mode"), StatusbarAlignment.RIGHT, 100.7); + }, 'status.editor.tabFocusMode', StatusbarAlignment.RIGHT, 100.7); } } else { this.tabFocusModeElement.clear(); @@ -422,13 +424,14 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { if (!this.columnSelectionModeElement.value) { const text = localize('columnSelectionModeEnabled', "Column Selection"); this.columnSelectionModeElement.value = this.statusbarService.addEntry({ + name: localize('status.editor.columnSelectionMode', "Column Selection Mode"), text, ariaLabel: text, tooltip: localize('disableColumnSelectionMode', "Disable Column Selection Mode"), command: 'editor.action.toggleColumnSelection', backgroundColor: themeColorFromId(STATUS_BAR_PROMINENT_ITEM_BACKGROUND), color: themeColorFromId(STATUS_BAR_PROMINENT_ITEM_FOREGROUND) - }, 'status.editor.columnSelectionMode', localize('status.editor.columnSelectionMode', "Column Selection Mode"), StatusbarAlignment.RIGHT, 100.8); + }, 'status.editor.columnSelectionMode', StatusbarAlignment.RIGHT, 100.8); } } else { this.columnSelectionModeElement.clear(); @@ -440,12 +443,13 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { if (!this.screenRedearModeElement.value) { const text = localize('screenReaderDetected', "Screen Reader Optimized"); this.screenRedearModeElement.value = this.statusbarService.addEntry({ + name: localize('status.editor.screenReaderMode', "Screen Reader Mode"), text, ariaLabel: text, command: 'showEditorScreenReaderNotification', backgroundColor: themeColorFromId(STATUS_BAR_PROMINENT_ITEM_BACKGROUND), color: themeColorFromId(STATUS_BAR_PROMINENT_ITEM_FOREGROUND) - }, 'status.editor.screenReaderMode', localize('status.editor.screenReaderMode', "Screen Reader Mode"), StatusbarAlignment.RIGHT, 100.6); + }, 'status.editor.screenReaderMode', StatusbarAlignment.RIGHT, 100.6); } } else { this.screenRedearModeElement.clear(); @@ -459,13 +463,14 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } const props: IStatusbarEntry = { + name: localize('status.editor.selection', "Editor Selection"), text, ariaLabel: text, tooltip: localize('gotoLine', "Go to Line/Column"), command: 'workbench.action.gotoLine' }; - this.updateElement(this.selectionElement, props, 'status.editor.selection', localize('status.editor.selection', "Editor Selection"), StatusbarAlignment.RIGHT, 100.5); + this.updateElement(this.selectionElement, props, 'status.editor.selection', StatusbarAlignment.RIGHT, 100.5); } private updateIndentationElement(text: string | undefined): void { @@ -475,13 +480,14 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } const props: IStatusbarEntry = { + name: localize('status.editor.indentation', "Editor Indentation"), text, ariaLabel: text, tooltip: localize('selectIndentation', "Select Indentation"), command: 'changeEditorIndentation' }; - this.updateElement(this.indentationElement, props, 'status.editor.indentation', localize('status.editor.indentation', "Editor Indentation"), StatusbarAlignment.RIGHT, 100.4); + this.updateElement(this.indentationElement, props, 'status.editor.indentation', StatusbarAlignment.RIGHT, 100.4); } private updateEncodingElement(text: string | undefined): void { @@ -491,13 +497,14 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } const props: IStatusbarEntry = { + name: localize('status.editor.encoding', "Editor Encoding"), text, ariaLabel: text, tooltip: localize('selectEncoding', "Select Encoding"), command: 'workbench.action.editor.changeEncoding' }; - this.updateElement(this.encodingElement, props, 'status.editor.encoding', localize('status.editor.encoding', "Editor Encoding"), StatusbarAlignment.RIGHT, 100.3); + this.updateElement(this.encodingElement, props, 'status.editor.encoding', StatusbarAlignment.RIGHT, 100.3); } private updateEOLElement(text: string | undefined): void { @@ -507,13 +514,14 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } const props: IStatusbarEntry = { + name: localize('status.editor.eol', "Editor End of Line"), text, ariaLabel: text, tooltip: localize('selectEOL', "Select End of Line Sequence"), command: 'workbench.action.editor.changeEOL' }; - this.updateElement(this.eolElement, props, 'status.editor.eol', localize('status.editor.eol', "Editor End of Line"), StatusbarAlignment.RIGHT, 100.2); + this.updateElement(this.eolElement, props, 'status.editor.eol', StatusbarAlignment.RIGHT, 100.2); } private updateModeElement(text: string | undefined): void { @@ -523,13 +531,14 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } const props: IStatusbarEntry = { + name: localize('status.editor.mode', "Editor Language"), text, ariaLabel: text, tooltip: localize('selectLanguageMode', "Select Language Mode"), command: 'workbench.action.editor.changeLanguageMode' }; - this.updateElement(this.modeElement, props, 'status.editor.mode', localize('status.editor.mode', "Editor Language"), StatusbarAlignment.RIGHT, 100.1); + this.updateElement(this.modeElement, props, 'status.editor.mode', StatusbarAlignment.RIGHT, 100.1); } private updateMetadataElement(text: string | undefined): void { @@ -539,17 +548,18 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } const props: IStatusbarEntry = { + name: localize('status.editor.info', "File Information"), text, ariaLabel: text, tooltip: localize('fileInfo', "File Information") }; - this.updateElement(this.metadataElement, props, 'status.editor.info', localize('status.editor.info', "File Information"), StatusbarAlignment.RIGHT, 100); + this.updateElement(this.metadataElement, props, 'status.editor.info', StatusbarAlignment.RIGHT, 100); } - private updateElement(element: MutableDisposable, props: IStatusbarEntry, id: string, name: string, alignment: StatusbarAlignment, priority: number) { + private updateElement(element: MutableDisposable, props: IStatusbarEntry, id: string, alignment: StatusbarAlignment, priority: number) { if (!element.value) { - element.value = this.statusbarService.addEntry(props, id, name, alignment, priority); + element.value = this.statusbarService.addEntry(props, id, alignment, priority); } else { element.value.update(props); } @@ -923,9 +933,9 @@ class ShowCurrentMarkerInStatusbarContribution extends Disposable { const line = splitLines(this.currentMarker.message)[0]; const text = `${this.getType(this.currentMarker)} ${line}`; if (!this.statusBarEntryAccessor.value) { - this.statusBarEntryAccessor.value = this.statusbarService.addEntry({ text: '', ariaLabel: '' }, 'statusbar.currentProblem', localize('currentProblem', "Current Problem"), StatusbarAlignment.LEFT); + this.statusBarEntryAccessor.value = this.statusbarService.addEntry({ name: localize('currentProblem', "Current Problem"), text: '', ariaLabel: '' }, 'statusbar.currentProblem', StatusbarAlignment.LEFT); } - this.statusBarEntryAccessor.value.update({ text, ariaLabel: text }); + this.statusBarEntryAccessor.value.update({ name: localize('currentProblem', "Current Problem"), text, ariaLabel: text }); } else { this.statusBarEntryAccessor.clear(); } @@ -1270,7 +1280,7 @@ export class ChangeEOLAction extends Action { return; } - if (this.editorService.activeEditor?.isReadonly()) { + if (this.editorService.activeEditor?.hasCapability(EditorInputCapabilities.Readonly)) { await this.quickInputService.pick([{ label: localize('noWritableCodeEditor', "The active code editor is read-only.") }]); return; } @@ -1287,7 +1297,7 @@ export class ChangeEOLAction extends Action { const eol = await this.quickInputService.pick(EOLOptions, { placeHolder: localize('pickEndOfLine', "Select End of Line Sequence"), activeItem: EOLOptions[selectedIndex] }); if (eol) { const activeCodeEditor = getCodeEditor(this.editorService.activeTextEditorControl); - if (activeCodeEditor?.hasModel() && !this.editorService.activeEditor?.isReadonly()) { + if (activeCodeEditor?.hasModel() && !this.editorService.activeEditor?.hasCapability(EditorInputCapabilities.Readonly)) { textModel = activeCodeEditor.getModel(); textModel.pushStackElement(); textModel.pushEOL(eol.eol); @@ -1353,7 +1363,7 @@ export class ChangeEncodingAction extends Action { let action: IQuickPickItem | undefined; if (encodingSupport instanceof UntitledTextEditorInput) { action = saveWithEncodingPick; - } else if (activeEditorPane.input.isReadonly()) { + } else if (activeEditorPane.input.hasCapability(EditorInputCapabilities.Readonly)) { action = reopenWithEncodingPick; } else { action = await this.quickInputService.pick([reopenWithEncodingPick, saveWithEncodingPick], { placeHolder: localize('pickAction', "Select Action"), matchOnDetail: true }); diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/editorsObserver.ts b/src/vs/workbench/browser/parts/editor/editorsObserver.ts similarity index 99% rename from lib/vscode/src/vs/workbench/browser/parts/editor/editorsObserver.ts rename to src/vs/workbench/browser/parts/editor/editorsObserver.ts index 1abe2fd4004a..108a035f888d 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/editorsObserver.ts +++ b/src/vs/workbench/browser/parts/editor/editorsObserver.ts @@ -3,7 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IEditorInput, IEditorInputFactoryRegistry, IEditorIdentifier, GroupIdentifier, EditorExtensions, IEditorPartOptionsChangeEvent, EditorsOrder, SideBySideEditorInput } from 'vs/workbench/common/editor'; +import { IEditorInput, IEditorInputFactoryRegistry, IEditorIdentifier, GroupIdentifier, EditorExtensions, IEditorPartOptionsChangeEvent, EditorsOrder } from 'vs/workbench/common/editor'; +import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput'; import { dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { Registry } from 'vs/platform/registry/common/platform'; diff --git a/src/vs/workbench/browser/parts/editor/media/back-tb.png b/src/vs/workbench/browser/parts/editor/media/back-tb.png new file mode 100644 index 0000000000000000000000000000000000000000..d279d15d18bb8dfc6f06bf5e052ac27433c625d1 GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{$x)V$B+ufw>LKOHaiHoT->O=LA#LqUBk2& zELu%rD;iP-6=EH_9E$&YDo?Bvyz2$j!ocuAOmO46v$aq3l;d~mnKjpz2=0FMq$eWW z^!T?Tw>8>Hv4XF)nE(6t*1nbs{`j}sE6y?Z``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{sK=I$B+ufx7TlTHaiHoJ-iu`VCAX#Qe$b3 zR?wRxTr%!41s`K4)SqK-esDW6Q9li+g@NIL*t>sQb(FUKdYJx7si21_B(@1(MuzJQDmL)$w>?)qiJ{~!i0kR<=d#Wz Gp$PyfOJ-pJ literal 0 HcmV?d00001 diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/media/letterpress-dark.svg b/src/vs/workbench/browser/parts/editor/media/letterpress-dark.svg similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/editor/media/letterpress-dark.svg rename to src/vs/workbench/browser/parts/editor/media/letterpress-dark.svg diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/media/letterpress-hc.svg b/src/vs/workbench/browser/parts/editor/media/letterpress-hc.svg similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/editor/media/letterpress-hc.svg rename to src/vs/workbench/browser/parts/editor/media/letterpress-hc.svg diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/media/letterpress.svg b/src/vs/workbench/browser/parts/editor/media/letterpress.svg similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/editor/media/letterpress.svg rename to src/vs/workbench/browser/parts/editor/media/letterpress.svg diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css b/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css rename to src/vs/workbench/browser/parts/editor/media/notabstitlecontrol.css diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css b/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css rename to src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/media/titlecontrol.css b/src/vs/workbench/browser/parts/editor/media/titlecontrol.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/editor/media/titlecontrol.css rename to src/vs/workbench/browser/parts/editor/media/titlecontrol.css diff --git a/src/vs/workbench/browser/parts/editor/media/workspacetrusteditor.css b/src/vs/workbench/browser/parts/editor/media/workspacetrusteditor.css new file mode 100644 index 000000000000..e345faf8f2fd --- /dev/null +++ b/src/vs/workbench/browser/parts/editor/media/workspacetrusteditor.css @@ -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. + *--------------------------------------------------------------------------------------------*/ + +.monaco-workspace-trust-required-editor:focus { + outline: none !important; +} + +.monaco-workspace-trust-required-editor { + padding: 5px 0 0 10px; + box-sizing: border-box; +} + +.monaco-workspace-trust-required-editor .embedded-link, +.monaco-workspace-trust-required-editor .embedded-link:hover { + cursor: pointer; + text-decoration: underline; + margin-left: 5px; +} diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts similarity index 97% rename from lib/vscode/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts rename to src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts index 8d3ae15eecb6..edd17f5975fc 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts @@ -50,7 +50,7 @@ export class NoTabsTitleControl extends TitleControl { this._register(addDisposableListener(this.editorLabel.element, EventType.CLICK, e => this.onTitleLabelClick(e))); // Breadcrumbs - this.createBreadcrumbsControl(labelContainer, { showFileIcons: false, showSymbolIcons: true, showDecorationColors: false, breadcrumbsBackground: () => Color.transparent, showPlaceholder: false }); + this.createBreadcrumbsControl(labelContainer, { showFileIcons: false, showSymbolIcons: true, showDecorationColors: false, breadcrumbsBackground: Color.transparent.toString(), showPlaceholder: false }); titleContainer.classList.toggle('breadcrumbs', Boolean(this.breadcrumbsControl)); this._register(toDisposable(() => titleContainer.classList.remove('breadcrumbs'))); // important to remove because the container is a shared dom node @@ -114,7 +114,7 @@ export class NoTabsTitleControl extends TitleControl { private onTitleTap(e: GestureEvent): void { // We only want to open the quick access picker when - // the tap occured over the editor label, so we need + // the tap occurred over the editor label, so we need // to check on the target // (https://github.com/microsoft/vscode/issues/107543) const target = e.initialTarget; @@ -167,6 +167,10 @@ export class NoTabsTitleControl extends TitleControl { this.ifEditorIsActive(editor, () => this.redraw()); } + updateEditorCapabilities(editor: IEditorInput): void { + this.ifEditorIsActive(editor, () => this.redraw()); + } + updateEditorLabels(): void { if (this.group.activeEditor) { this.updateEditorLabel(this.group.activeEditor); // we only have the active one to update diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts similarity index 81% rename from lib/vscode/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts rename to src/vs/workbench/browser/parts/editor/sideBySideEditor.ts index 5a857f4cc0aa..bf1508b3dde9 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts +++ b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts @@ -5,7 +5,9 @@ import { Dimension, $, clearNode } from 'vs/base/browser/dom'; import { Registry } from 'vs/platform/registry/common/platform'; -import { EditorInput, EditorOptions, SideBySideEditorInput, IEditorControl, IEditorPane, IEditorOpenContext, EditorExtensions } from 'vs/workbench/common/editor'; +import { IEditorControl, IEditorPane, IEditorOpenContext, EditorExtensions } from 'vs/workbench/common/editor'; +import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -18,6 +20,7 @@ import { SplitView, Sizing, Orientation } from 'vs/base/browser/ui/splitview/spl import { Event, Relay, Emitter } from 'vs/base/common/event'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { assertIsDefined } from 'vs/base/common/types'; +import { IEditorOptions } from 'vs/platform/editor/common/editor'; export class SideBySideEditor extends EditorPane { @@ -94,14 +97,14 @@ export class SideBySideEditor extends EditorPane { this.updateStyles(); } - override async setInput(newInput: EditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { - const oldInput = this.input as SideBySideEditorInput; - await super.setInput(newInput, options, context, token); + override async setInput(input: SideBySideEditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + const oldInput = this.input; + await super.setInput(input, options, context, token); - return this.updateInput(oldInput, (newInput as SideBySideEditorInput), options, context, token); + return this.updateInput(oldInput, input, options, context, token); } - override setOptions(options: EditorOptions | undefined): void { + override setOptions(options: IEditorOptions | undefined): void { if (this.primaryEditorPane) { this.primaryEditorPane.setOptions(options); } @@ -162,7 +165,7 @@ export class SideBySideEditor extends EditorPane { return this.secondaryEditorPane; } - private async updateInput(oldInput: SideBySideEditorInput, newInput: SideBySideEditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + private async updateInput(oldInput: EditorInput | undefined, newInput: SideBySideEditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { if (!newInput.matches(oldInput)) { if (oldInput) { this.disposeEditors(); @@ -181,11 +184,23 @@ export class SideBySideEditor extends EditorPane { ]); } - private setNewInput(newInput: SideBySideEditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { - const secondaryEditor = this.doCreateEditor(newInput.secondary, assertIsDefined(this.secondaryEditorContainer)); - const primaryEditor = this.doCreateEditor(newInput.primary, assertIsDefined(this.primaryEditorContainer)); + private async setNewInput(newInput: SideBySideEditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + this.secondaryEditorPane = this.doCreateEditor(newInput.secondary, assertIsDefined(this.secondaryEditorContainer)); + this.primaryEditorPane = this.doCreateEditor(newInput.primary, assertIsDefined(this.primaryEditorContainer)); - return this.onEditorsCreated(secondaryEditor, primaryEditor, newInput.secondary, newInput.primary, options, context, token); + this.layout(this.dimension); + + this._onDidChangeSizeConstraints.input = Event.any( + Event.map(this.secondaryEditorPane.onDidChangeSizeConstraints, () => undefined), + Event.map(this.primaryEditorPane.onDidChangeSizeConstraints, () => undefined) + ); + + this.onDidCreateEditors.fire(undefined); + + await Promise.all([ + this.secondaryEditorPane.setInput(newInput.secondary, undefined, context, token), + this.primaryEditorPane.setInput(newInput.primary, options, context, token)] + ); } private doCreateEditor(editorInput: EditorInput, container: HTMLElement): EditorPane { @@ -201,23 +216,6 @@ export class SideBySideEditor extends EditorPane { return editor; } - private async onEditorsCreated(secondary: EditorPane, primary: EditorPane, secondaryInput: EditorInput, primaryInput: EditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { - this.secondaryEditorPane = secondary; - this.primaryEditorPane = primary; - - this._onDidChangeSizeConstraints.input = Event.any( - Event.map(secondary.onDidChangeSizeConstraints, () => undefined), - Event.map(primary.onDidChangeSizeConstraints, () => undefined) - ); - - this.onDidCreateEditors.fire(undefined); - - await Promise.all([ - this.secondaryEditorPane.setInput(secondaryInput, undefined, context, token), - this.primaryEditorPane.setInput(primaryInput, options, context, token)] - ); - } - override updateStyles(): void { super.updateStyles(); diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts similarity index 99% rename from lib/vscode/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts rename to src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index 5ca4311be8b7..ae94f70f7a2f 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/tabstitlecontrol'; import { isMacintosh, isWindows } from 'vs/base/common/platform'; import { shorten } from 'vs/base/common/labels'; -import { EditorResourceAccessor, GroupIdentifier, IEditorInput, Verbosity, EditorCommandsContextActionRunner, IEditorPartOptions, SideBySideEditor } from 'vs/workbench/common/editor'; +import { EditorResourceAccessor, GroupIdentifier, IEditorInput, Verbosity, IEditorPartOptions, SideBySideEditor } from 'vs/workbench/common/editor'; import { computeEditorAriaLabel } from 'vs/workbench/browser/editor'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { EventType as TouchEventType, GestureEvent, Gesture } from 'vs/base/browser/touch'; @@ -19,7 +19,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IMenuService } from 'vs/platform/actions/common/actions'; -import { ITitleControlDimensions, TitleControl } from 'vs/workbench/browser/parts/editor/titleControl'; +import { EditorCommandsContextActionRunner, ITitleControlDimensions, TitleControl } from 'vs/workbench/browser/parts/editor/titleControl'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { IDisposable, dispose, DisposableStore, combinedDisposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; @@ -410,14 +410,8 @@ export class TabsTitleControl extends TitleControl { } closeEditors(editors: IEditorInput[]): void { - // Cleanup closed editors this.handleClosedEditors(); - - // Update Breadcrumbs when last editor closed - if (this.group.count === 0) { - this.breadcrumbsControl?.update(); - } } private handleClosedEditors(): void { @@ -455,6 +449,8 @@ export class TabsTitleControl extends TitleControl { this.tabActionBars = []; this.clearEditorActionsToolbar(); + + this.breadcrumbsControl?.update(); } } @@ -513,6 +509,10 @@ export class TabsTitleControl extends TitleControl { this.layout(this.dimensions); } + updateEditorCapabilities(editor: IEditorInput): void { + this.updateEditorLabel(editor); + } + private updateEditorLabelAggregator = this._register(new RunOnceScheduler(() => this.updateEditorLabels(), 0)); updateEditorLabel(editor: IEditorInput): void { @@ -806,7 +806,7 @@ export class TabsTitleControl extends TitleControl { } // Apply some datatransfer types to allow for dragging the element outside of the application - this.doFillResourceDataTransfers(editor, e); + this.doFillResourceDataTransfers([editor], e); // Fixes https://github.com/microsoft/vscode/issues/18733 tab.classList.add('dragged'); diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts similarity index 75% rename from lib/vscode/src/vs/workbench/browser/parts/editor/textDiffEditor.ts rename to src/vs/workbench/browser/parts/editor/textDiffEditor.ts index e9a4d85f130e..4e5aee431f97 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -5,11 +5,12 @@ import { localize } from 'vs/nls'; import { deepClone } from 'vs/base/common/objects'; -import { isFunction, isObject, isArray, assertIsDefined, withUndefinedAsNull } from 'vs/base/common/types'; +import { isObject, isArray, assertIsDefined, withUndefinedAsNull } from 'vs/base/common/types'; import { IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { IDiffEditorOptions, IEditorOptions as ICodeEditorOptions } from 'vs/editor/common/config/editorOptions'; import { BaseTextEditor, IEditorConfiguration } from 'vs/workbench/browser/parts/editor/textEditor'; -import { TextEditorOptions, EditorInput, EditorOptions, TEXT_DIFF_EDITOR_ID, IEditorInputFactoryRegistry, EditorExtensions, ITextDiffEditorPane, IEditorInput, IEditorOpenContext } from 'vs/workbench/common/editor'; +import { TEXT_DIFF_EDITOR_ID, IEditorInputFactoryRegistry, EditorExtensions, ITextDiffEditorPane, IEditorInput, IEditorOpenContext, EditorInputCapabilities } from 'vs/workbench/common/editor'; +import { applyTextEditorOptions } from 'vs/workbench/common/editor/editorOptions'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { DiffNavigator } from 'vs/editor/browser/widget/diffNavigator'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; @@ -21,13 +22,13 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IThemeService } from 'vs/platform/theme/common/themeService'; import { TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles'; import { ScrollType, IDiffEditorViewState, IDiffEditorModel } from 'vs/editor/common/editorCommon'; -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; import { URI } from 'vs/base/common/uri'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { EditorActivation, IEditorOptions } from 'vs/platform/editor/common/editor'; +import { EditorActivation, ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { isEqual } from 'vs/base/common/resources'; import { multibyteAwareBtoa } from 'vs/base/browser/dom'; @@ -43,6 +44,8 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan private diffNavigator: DiffNavigator | undefined; private readonly diffNavigatorDisposables = this._register(new DisposableStore()); + private readonly inputListener = this._register(new MutableDisposable()); + override get scopedContextKeyService(): IContextKeyService | undefined { const control = this.getControl(); if (!control) { @@ -68,21 +71,29 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, editorService, editorGroupService); // Listen to file system provider changes - this._register(this.fileService.onDidChangeFileSystemProviderCapabilities(e => this.onDidFileSystemProviderChange(e.scheme))); - this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(e => this.onDidFileSystemProviderChange(e.scheme))); + this._register(this.fileService.onDidChangeFileSystemProviderCapabilities(e => this.onDidChangeFileSystemProvider(e.scheme))); + this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(e => this.onDidChangeFileSystemProvider(e.scheme))); + } + + private onDidChangeFileSystemProvider(scheme: string): void { + if (this.input instanceof DiffEditorInput && (this.input.originalInput.resource?.scheme === scheme || this.input.modifiedInput.resource?.scheme === scheme)) { + this.updateReadonly(this.input); + } + } + + private onDidChangeInputCapabilities(input: DiffEditorInput): void { + if (this.input === input) { + this.updateReadonly(input); + } } - private onDidFileSystemProviderChange(scheme: string): void { + private updateReadonly(input: DiffEditorInput): void { const control = this.getControl(); - const input = this.input; - - if (control && input instanceof DiffEditorInput) { - if (input.originalInput.resource?.scheme === scheme || input.modifiedInput.resource?.scheme === scheme) { - control.updateOptions({ - readOnly: input.modifiedInput.isReadonly(), - originalEditable: !input.originalInput.isReadonly() - }); - } + if (control) { + control.updateOptions({ + readOnly: input.modifiedInput.hasCapability(EditorInputCapabilities.Readonly), + originalEditable: !input.originalInput.hasCapability(EditorInputCapabilities.Readonly) + }); } } @@ -106,7 +117,10 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan return this.instantiationService.createInstance(DiffEditorWidget, parent, configuration, {}); } - override async setInput(input: EditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + override async setInput(input: DiffEditorInput, options: ITextEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + + // Update our listener for input capabilities + this.inputListener.value = input.onDidChangeCapabilities(() => this.onDidChangeInputCapabilities(input)); // Dispose previous diff navigator this.diffNavigatorDisposables.clear(); @@ -125,8 +139,9 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan return undefined; } - // Assert Model Instance - if (!(resolvedModel instanceof TextDiffEditorModel) && this.openAsBinary(input, options)) { + // Fallback to open as binary if not text + if (!(resolvedModel instanceof TextDiffEditorModel)) { + this.openAsBinary(input, options); return undefined; } @@ -135,10 +150,10 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan const resolvedDiffEditorModel = resolvedModel as TextDiffEditorModel; diffEditor.setModel(withUndefinedAsNull(resolvedDiffEditorModel.textDiffEditorModel)); - // Apply Options from TextOptions + /// Apply options to editor if any let optionsGotApplied = false; - if (options && isFunction((options).apply)) { - optionsGotApplied = (options).apply(diffEditor, ScrollType.Immediate); + if (options) { + optionsGotApplied = applyTextEditorOptions(options, diffEditor, ScrollType.Immediate); } // Otherwise restore View State unless disabled via settings @@ -165,7 +180,8 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan } catch (error) { // In case we tried to open a file and the response indicates that this is not a text file, fallback to binary diff. - if (this.isFileBinaryError(error) && this.openAsBinary(input, options)) { + if (this.isFileBinaryError(error)) { + this.openAsBinary(input, options); return; } @@ -173,62 +189,51 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan } } - private restoreTextDiffEditorViewState(editor: EditorInput, control: IDiffEditor): boolean { - if (editor instanceof DiffEditorInput) { - const resource = this.toDiffEditorViewStateResource(editor); - if (resource) { - const viewState = this.loadTextEditorViewState(resource); - if (viewState) { - control.restoreViewState(viewState); + private restoreTextDiffEditorViewState(editor: DiffEditorInput, control: IDiffEditor): boolean { + const resource = this.toDiffEditorViewStateResource(editor); + if (resource) { + const viewState = this.loadTextEditorViewState(resource); + if (viewState) { + control.restoreViewState(viewState); - return true; - } + return true; } } return false; } - private openAsBinary(input: EditorInput, options: EditorOptions | undefined): boolean { - if (input instanceof DiffEditorInput) { - const originalInput = input.originalInput; - const modifiedInput = input.modifiedInput; + private openAsBinary(input: DiffEditorInput, options: ITextEditorOptions | undefined): void { + const originalInput = input.originalInput; + const modifiedInput = input.modifiedInput; - const binaryDiffInput = this.instantiationService.createInstance(DiffEditorInput, input.getName(), input.getDescription(), originalInput, modifiedInput, true); + const binaryDiffInput = this.instantiationService.createInstance(DiffEditorInput, input.getName(), input.getDescription(), originalInput, modifiedInput, true); - // Forward binary flag to input if supported - const fileEditorInputFactory = Registry.as(EditorExtensions.EditorInputFactories).getFileEditorInputFactory(); - if (fileEditorInputFactory.isFileEditorInput(originalInput)) { - originalInput.setForceOpenAsBinary(); - } + // Forward binary flag to input if supported + const fileEditorInputFactory = Registry.as(EditorExtensions.EditorInputFactories).getFileEditorInputFactory(); + if (fileEditorInputFactory.isFileEditorInput(originalInput)) { + originalInput.setForceOpenAsBinary(); + } - if (fileEditorInputFactory.isFileEditorInput(modifiedInput)) { - modifiedInput.setForceOpenAsBinary(); - } + if (fileEditorInputFactory.isFileEditorInput(modifiedInput)) { + modifiedInput.setForceOpenAsBinary(); + } - // Make sure to not steal away the currently active group - // because we are triggering another openEditor() call - // and do not control the initial intent that resulted - // in us now opening as binary. - const preservingOptions: IEditorOptions = { + // Replace this editor with the binary one + this.editorService.replaceEditors([{ + editor: input, + replacement: binaryDiffInput, + options: { + ...options, + // Make sure to not steal away the currently active group + // because we are triggering another openEditor() call + // and do not control the initial intent that resulted + // in us now opening as binary. activation: EditorActivation.PRESERVE, pinned: this.group?.isPinned(input), sticky: this.group?.isSticky(input) - }; - - if (options) { - options.overwrite(preservingOptions); - } else { - options = EditorOptions.create(preservingOptions); } - - // Replace this editor with the binary one - this.editorService.replaceEditors([{ editor: input, replacement: binaryDiffInput, options }], this.group || ACTIVE_GROUP); - - return true; - } - - return false; + }], this.group || ACTIVE_GROUP); } protected override computeConfiguration(configuration: IEditorConfiguration): ICodeEditorOptions { @@ -255,8 +260,8 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan protected override getConfigurationOverrides(): ICodeEditorOptions { const options: IDiffEditorOptions = super.getConfigurationOverrides(); - options.readOnly = this.input instanceof DiffEditorInput && this.input.modifiedInput.isReadonly(); - options.originalEditable = this.input instanceof DiffEditorInput && !this.input.originalInput.isReadonly(); + options.readOnly = this.input instanceof DiffEditorInput && this.input.modifiedInput.hasCapability(EditorInputCapabilities.Readonly); + options.originalEditable = this.input instanceof DiffEditorInput && !this.input.originalInput.hasCapability(EditorInputCapabilities.Readonly); options.lineDecorationsWidth = '2ch'; return options; @@ -276,6 +281,9 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan override clearInput(): void { + // Clear input listener + this.inputListener.clear(); + // Dispose previous diff navigator this.diffNavigatorDisposables.clear(); diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/textEditor.ts b/src/vs/workbench/browser/parts/editor/textEditor.ts similarity index 88% rename from lib/vscode/src/vs/workbench/browser/parts/editor/textEditor.ts rename to src/vs/workbench/browser/parts/editor/textEditor.ts index bf11b188d4f1..eea7340bdb92 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/textEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textEditor.ts @@ -7,10 +7,12 @@ import { localize } from 'vs/nls'; import { URI } from 'vs/base/common/uri'; import { distinct, deepClone } from 'vs/base/common/objects'; import { Event } from 'vs/base/common/event'; -import { isObject, assertIsDefined, withNullAsUndefined, isFunction } from 'vs/base/common/types'; +import { isObject, assertIsDefined, withNullAsUndefined } from 'vs/base/common/types'; import { Dimension } from 'vs/base/browser/dom'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; -import { EditorInput, EditorOptions, IEditorMemento, ITextEditorPane, TextEditorOptions, IEditorCloseEvent, IEditorInput, IEditorOpenContext, EditorResourceAccessor, SideBySideEditor } from 'vs/workbench/common/editor'; +import { IEditorMemento, ITextEditorPane, IEditorCloseEvent, IEditorInput, IEditorOpenContext, EditorResourceAccessor, SideBySideEditor, EditorInputCapabilities } from 'vs/workbench/common/editor'; +import { applyTextEditorOptions } from 'vs/workbench/common/editor/editorOptions'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { computeEditorAriaLabel } from 'vs/workbench/browser/editor'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; import { IEditorViewState, IEditor, ScrollType } from 'vs/editor/common/editorCommon'; @@ -19,7 +21,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService'; -import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IEditorOptions as ICodeEditorOptions } from 'vs/editor/common/config/editorOptions'; import { isCodeEditor, getCodeEditor } from 'vs/editor/browser/editorBrowser'; import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -27,6 +29,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { IExtUri } from 'vs/base/common/resources'; import { MutableDisposable } from 'vs/base/common/lifecycle'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; export interface IEditorConfiguration { editor: object; @@ -44,15 +47,11 @@ export abstract class BaseTextEditor extends EditorPane implements ITextEditorPa private editorControl: IEditor | undefined; private editorContainer: HTMLElement | undefined; private hasPendingConfigurationChange: boolean | undefined; - private lastAppliedEditorOptions?: IEditorOptions; + private lastAppliedEditorOptions?: ICodeEditorOptions; private editorMemento: IEditorMemento; private readonly groupListener = this._register(new MutableDisposable()); - private _instantiationService: IInstantiationService; - protected get instantiationService(): IInstantiationService { return this._instantiationService; } - protected set instantiationService(value: IInstantiationService) { this._instantiationService = value; } - override get scopedContextKeyService(): IContextKeyService | undefined { return isCodeEditor(this.editorControl) ? this.editorControl.invokeWithinContext(accessor => accessor.get(IContextKeyService)) : undefined; } @@ -60,7 +59,7 @@ export abstract class BaseTextEditor extends EditorPane implements ITextEditorPa constructor( id: string, @ITelemetryService telemetryService: ITelemetryService, - @IInstantiationService instantiationService: IInstantiationService, + @IInstantiationService protected instantiationService: IInstantiationService, @IStorageService storageService: IStorageService, @ITextResourceConfigurationService protected readonly textResourceConfigurationService: ITextResourceConfigurationService, @IThemeService themeService: IThemeService, @@ -69,8 +68,6 @@ export abstract class BaseTextEditor extends EditorPane implements ITextEditorPa ) { super(id, telemetryService, themeService, storageService); - this._instantiationService = instantiationService; - this.editorMemento = this.getEditorMemento(editorGroupService, BaseTextEditor.TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY, 100); this._register(this.textResourceConfigurationService.onDidChangeConfiguration(() => { @@ -105,10 +102,10 @@ export abstract class BaseTextEditor extends EditorPane implements ITextEditorPa } } - protected computeConfiguration(configuration: IEditorConfiguration): IEditorOptions { + protected computeConfiguration(configuration: IEditorConfiguration): ICodeEditorOptions { // Specific editor options always overwrite user configuration - const editorConfiguration: IEditorOptions = isObject(configuration.editor) ? deepClone(configuration.editor) : Object.create(null); + const editorConfiguration: ICodeEditorOptions = isObject(configuration.editor) ? deepClone(configuration.editor) : Object.create(null); Object.assign(editorConfiguration, this.getConfigurationOverrides()); // ARIA label @@ -121,12 +118,12 @@ export abstract class BaseTextEditor extends EditorPane implements ITextEditorPa return this._input ? computeEditorAriaLabel(this._input, undefined, this.group, this.editorGroupService.count) : localize('editor', "Editor"); } - protected getConfigurationOverrides(): IEditorOptions { + protected getConfigurationOverrides(): ICodeEditorOptions { return { overviewRulerLanes: 3, lineNumbersMinChars: 3, fixedOverflowWidgets: true, - readOnly: this.input?.isReadonly(), + readOnly: this.input?.hasCapability(EditorInputCapabilities.Readonly), // render problems even in readonly editors // https://github.com/microsoft/vscode/issues/89057 renderValidationDecorations: 'on' @@ -153,13 +150,13 @@ export abstract class BaseTextEditor extends EditorPane implements ITextEditorPa * * The passed in configuration object should be passed to the editor control when creating it. */ - protected createEditorControl(parent: HTMLElement, configuration: IEditorOptions): IEditor { + protected createEditorControl(parent: HTMLElement, configuration: ICodeEditorOptions): IEditor { // Use a getter for the instantiation service since some subclasses might use scoped instantiation services return this.instantiationService.createInstance(CodeEditorWidget, parent, configuration, {}); } - override async setInput(input: EditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + override async setInput(input: EditorInput, options: ITextEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { await super.setInput(input, options, context, token); // Update editor options after having set the input. We do this because there can be @@ -171,11 +168,9 @@ export abstract class BaseTextEditor extends EditorPane implements ITextEditorPa editorContainer.setAttribute('aria-label', this.computeAriaLabel()); } - override setOptions(options: EditorOptions | undefined): void { - const textOptions = options as TextEditorOptions; - if (textOptions && isFunction(textOptions.apply)) { - const textEditor = assertIsDefined(this.getControl()); - textOptions.apply(textEditor, ScrollType.Smooth); + override setOptions(options: ITextEditorOptions | undefined): void { + if (options) { + applyTextEditorOptions(options, assertIsDefined(this.getControl()), ScrollType.Smooth); } } diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/textResourceEditor.ts b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts similarity index 88% rename from lib/vscode/src/vs/workbench/browser/parts/editor/textResourceEditor.ts rename to src/vs/workbench/browser/parts/editor/textResourceEditor.ts index 5105d227a4af..562945e369ca 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/textResourceEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts @@ -4,10 +4,12 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { assertIsDefined, isFunction, withNullAsUndefined } from 'vs/base/common/types'; +import { assertIsDefined, withNullAsUndefined } from 'vs/base/common/types'; import { ICodeEditor, getCodeEditor, IPasteEvent } from 'vs/editor/browser/editorBrowser'; -import { TextEditorOptions, EditorInput, EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor'; -import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; +import { IEditorOpenContext } from 'vs/workbench/common/editor'; +import { applyTextEditorOptions } from 'vs/workbench/common/editor/editorOptions'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; +import { AbstractTextResourceEditorInput, TextResourceEditorInput } from 'vs/workbench/common/editor/textResourceEditorInput'; import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput'; import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor'; @@ -23,8 +25,9 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { IModelService } from 'vs/editor/common/services/modelService'; import { IModeService } from 'vs/editor/common/services/modeService'; import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; -import { EditorOption, IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { EditorOption, IEditorOptions as ICodeEditorOptions } from 'vs/editor/common/config/editorOptions'; import { ModelConstants } from 'vs/editor/common/model'; +import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; /** * An editor implementation that is capable of showing the contents of resource inputs. Uses @@ -53,7 +56,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor { return localize('textEditor', "Text Editor"); } - override async setInput(input: EditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + override async setInput(input: AbstractTextResourceEditorInput, options: ITextEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { // Remember view settings if input changes this.saveTextResourceEditorViewState(this.input); @@ -77,11 +80,10 @@ export class AbstractTextResourceEditor extends BaseTextEditor { const textEditorModel = resolvedModel.textEditorModel; textEditor.setModel(textEditorModel); - // Apply Options from TextOptions + // Apply options to editor if any let optionsGotApplied = false; - const textOptions = options; - if (textOptions && isFunction(textOptions.apply)) { - optionsGotApplied = textOptions.apply(textEditor, ScrollType.Immediate); + if (options) { + optionsGotApplied = applyTextEditorOptions(options, textEditor, ScrollType.Immediate); } // Otherwise restore View State unless disabled via settings @@ -97,8 +99,8 @@ export class AbstractTextResourceEditor extends BaseTextEditor { textEditor.updateOptions({ readOnly: resolvedModel.isReadonly() }); } - private restoreTextResourceEditorViewState(editor: EditorInput, control: IEditor) { - if (editor instanceof UntitledTextEditorInput || editor instanceof ResourceEditorInput) { + private restoreTextResourceEditorViewState(editor: AbstractTextResourceEditorInput, control: IEditor) { + if (editor instanceof UntitledTextEditorInput || editor instanceof TextResourceEditorInput) { const viewState = this.loadTextEditorViewState(editor.resource); if (viewState) { control.restoreViewState(viewState); @@ -144,7 +146,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor { } private saveTextResourceEditorViewState(input: EditorInput | undefined): void { - if (!(input instanceof UntitledTextEditorInput) && !(input instanceof ResourceEditorInput)) { + if (!(input instanceof UntitledTextEditorInput) && !(input instanceof TextResourceEditorInput)) { return; // only enabled for untitled and resource inputs } @@ -180,7 +182,7 @@ export class TextResourceEditor extends AbstractTextResourceEditor { super(TextResourceEditor.ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, editorService); } - protected override createEditorControl(parent: HTMLElement, configuration: IEditorOptions): IEditor { + protected override createEditorControl(parent: HTMLElement, configuration: ICodeEditorOptions): IEditor { const control = super.createEditorControl(parent, configuration); // Install a listener for paste to update this editors diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts similarity index 91% rename from lib/vscode/src/vs/workbench/browser/parts/editor/titleControl.ts rename to src/vs/workbench/browser/parts/editor/titleControl.ts index e2d0ed9a806c..3de99faa1196 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -4,16 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/titlecontrol'; +import { localize } from 'vs/nls'; import { applyDragImage, DataTransfers } from 'vs/base/browser/dnd'; import { addDisposableListener, Dimension, EventType } from 'vs/base/browser/dom'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { ActionsOrientation, IActionViewItem, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; -import { IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification, SubmenuAction } from 'vs/base/common/actions'; +import { IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification, SubmenuAction, ActionRunner } from 'vs/base/common/actions'; import { ResolvedKeybinding } from 'vs/base/common/keyCodes'; import { dispose, DisposableStore } from 'vs/base/common/lifecycle'; -import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; -import { localize } from 'vs/nls'; import { createActionViewItem, createAndFillInActionBarActions, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IMenu, IMenuService, MenuId } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -26,18 +25,17 @@ import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { listActiveSelectionBackground, listActiveSelectionForeground } from 'vs/platform/theme/common/colorRegistry'; import { IThemeService, registerThemingParticipant, Themable } from 'vs/platform/theme/common/themeService'; -import { DraggedEditorGroupIdentifier, DraggedEditorIdentifier, fillResourceDataTransfers, LocalSelectionTransfer } from 'vs/workbench/browser/dnd'; +import { DraggedEditorGroupIdentifier, DraggedEditorIdentifier, fillEditorsDragData, LocalSelectionTransfer } from 'vs/workbench/browser/dnd'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; import { BreadcrumbsConfig } from 'vs/workbench/browser/parts/editor/breadcrumbs'; import { BreadcrumbsControl, IBreadcrumbsControlOptions } from 'vs/workbench/browser/parts/editor/breadcrumbsControl'; import { IEditorGroupsAccessor, IEditorGroupTitleHeight, IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor'; -import { EditorCommandsContextActionRunner, IEditorCommandsContext, IEditorInput, EditorResourceAccessor, IEditorPartOptions, SideBySideEditor, ActiveEditorPinnedContext, ActiveEditorStickyContext } from 'vs/workbench/common/editor'; +import { IEditorCommandsContext, IEditorInput, EditorResourceAccessor, IEditorPartOptions, SideBySideEditor, ActiveEditorPinnedContext, ActiveEditorStickyContext, EditorsOrder } from 'vs/workbench/common/editor'; import { ResourceContextKey } from 'vs/workbench/common/resources'; import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { IFileService } from 'vs/platform/files/common/files'; import { withNullAsUndefined, withUndefinedAsNull, assertIsDefined } from 'vs/base/common/types'; import { isFirefox } from 'vs/base/browser/browser'; -import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { isPromiseCanceledError } from 'vs/base/common/errors'; export interface IToolbarActions { @@ -59,6 +57,19 @@ export interface ITitleControlDimensions { available: Dimension; } +export class EditorCommandsContextActionRunner extends ActionRunner { + + constructor( + private context: IEditorCommandsContext + ) { + super(); + } + + override run(action: IAction): Promise { + return super.run(action, this.context); + } +} + export abstract class TitleControl extends Themable { protected readonly groupTransfer = LocalSelectionTransfer.getInstance(); @@ -254,11 +265,16 @@ export abstract class TitleControl extends Themable { e.dataTransfer.effectAllowed = 'copyMove'; } - // If tabs are disabled, treat dragging as if an editor tab was dragged + // Drag all tabs of the group if tabs are enabled let hasDataTransfer = false; - if (!this.accessor.partOptions.showTabs) { + if (this.accessor.partOptions.showTabs) { + hasDataTransfer = this.doFillResourceDataTransfers(this.group.getEditors(EditorsOrder.SEQUENTIAL), e); + } + + // Otherwise only drag the active editor + else { if (this.group.activeEditor) { - hasDataTransfer = this.doFillResourceDataTransfers(this.group.activeEditor, e); + hasDataTransfer = this.doFillResourceDataTransfers([this.group.activeEditor], e); } } @@ -284,29 +300,14 @@ export abstract class TitleControl extends Themable { })); } - protected doFillResourceDataTransfers(editor: IEditorInput, e: DragEvent): boolean { - const resource = EditorResourceAccessor.getOriginalUri(editor, { supportSideBySide: SideBySideEditor.PRIMARY }); - if (!resource) { - return false; - } + protected doFillResourceDataTransfers(editors: readonly IEditorInput[], e: DragEvent): boolean { + if (editors.length) { + this.instantiationService.invokeFunction(fillEditorsDragData, editors.map(editor => ({ editor, groupId: this.group.id })), e); - const editorOptions: ITextEditorOptions = { - viewState: (() => { - if (this.group.activeEditor === editor) { - const activeControl = this.group.activeEditorPane?.getControl(); - if (isCodeEditor(activeControl)) { - return withNullAsUndefined(activeControl.saveViewState()); - } - } - - return undefined; - })(), - sticky: this.group.isSticky(editor) - }; - - this.instantiationService.invokeFunction(fillResourceDataTransfers, [resource], () => editorOptions, e); + return true; + } - return true; + return false; } protected onContextMenu(editor: IEditorInput, e: Event, node: HTMLElement): void { @@ -380,6 +381,8 @@ export abstract class TitleControl extends Themable { abstract updateEditorLabel(editor: IEditorInput): void; + abstract updateEditorCapabilities(editor: IEditorInput): void; + abstract updateEditorLabels(): void; abstract updateEditorDirty(editor: IEditorInput): void; diff --git a/src/vs/workbench/browser/parts/editor/workspaceTrustRequiredEditor.ts b/src/vs/workbench/browser/parts/editor/workspaceTrustRequiredEditor.ts new file mode 100644 index 000000000000..a08710ea570a --- /dev/null +++ b/src/vs/workbench/browser/parts/editor/workspaceTrustRequiredEditor.ts @@ -0,0 +1,129 @@ +/*--------------------------------------------------------------------------------------------- + * 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!./media/workspacetrusteditor'; +import { localize } from 'vs/nls'; +import { IEditorOpenContext } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; +import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; +import { ScrollbarVisibility } from 'vs/base/common/scrollable'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { Dimension, size, clearNode, append, addDisposableListener, EventType, $ } from 'vs/base/browser/dom'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { assertIsDefined, assertAllDefined } from 'vs/base/common/types'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { isSingleFolderWorkspaceIdentifier, toWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { EditorDescriptor } from 'vs/workbench/browser/editor'; +import { IEditorOptions } from 'vs/platform/editor/common/editor'; + +export class WorkspaceTrustRequiredEditor extends EditorPane { + + static readonly ID = 'workbench.editors.workspaceTrustRequiredEditor'; + static readonly LABEL = localize('trustRequiredEditor', "Workspace Trust Required"); + static readonly DESCRIPTOR = EditorDescriptor.create(WorkspaceTrustRequiredEditor, WorkspaceTrustRequiredEditor.ID, WorkspaceTrustRequiredEditor.LABEL); + + private container: HTMLElement | undefined; + private scrollbar: DomScrollableElement | undefined; + private inputDisposable = this._register(new MutableDisposable()); + + constructor( + @ITelemetryService telemetryService: ITelemetryService, + @IThemeService themeService: IThemeService, + @ICommandService private readonly commandService: ICommandService, + @IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService, + @IStorageService storageService: IStorageService + ) { + super(WorkspaceTrustRequiredEditor.ID, telemetryService, themeService, storageService); + } + + override getTitle(): string { + return WorkspaceTrustRequiredEditor.LABEL; + } + + protected createEditor(parent: HTMLElement): void { + + // Container + this.container = document.createElement('div'); + this.container.className = 'monaco-workspace-trust-required-editor'; + this.container.style.outline = 'none'; + this.container.tabIndex = 0; // enable focus support from the editor part (do not remove) + + // Custom Scrollbars + this.scrollbar = this._register(new DomScrollableElement(this.container, { horizontal: ScrollbarVisibility.Auto, vertical: ScrollbarVisibility.Auto })); + parent.appendChild(this.scrollbar.getDomNode()); + } + + override async setInput(input: EditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + await super.setInput(input, options, context, token); + + // Check for cancellation + if (token.isCancellationRequested) { + return; + } + + // Render Input + this.inputDisposable.value = this.renderInput(); + } + + private renderInput(): IDisposable { + const [container, scrollbar] = assertAllDefined(this.container, this.scrollbar); + + clearNode(container); + + const disposables = new DisposableStore(); + + const label = container.appendChild(document.createElement('p')); + label.textContent = isSingleFolderWorkspaceIdentifier(toWorkspaceIdentifier(this.workspaceService.getWorkspace())) ? + localize('requiresFolderTrustText', "The file is not displayed in the editor because trust has not been granted to the folder.") : + localize('requiresWorkspaceTrustText', "The file is not displayed in the editor because trust has not been granted to the workspace."); + + const link = append(label, $('a.embedded-link')); + link.setAttribute('role', 'button'); + link.textContent = localize('manageTrust', "Manage Workspace Trust"); + + disposables.add(addDisposableListener(link, EventType.CLICK, async () => { + await this.commandService.executeCommand('workbench.trust.manage'); + })); + + scrollbar.scanDomNode(); + + return disposables; + } + + override clearInput(): void { + if (this.container) { + clearNode(this.container); + } + + this.inputDisposable.clear(); + + super.clearInput(); + } + + layout(dimension: Dimension): void { + + // Pass on to Container + const [container, scrollbar] = assertAllDefined(this.container, this.scrollbar); + size(container, dimension.width, dimension.height); + scrollbar.scanDomNode(); + } + + override focus(): void { + const container = assertIsDefined(this.container); + + container.focus(); + } + + override dispose(): void { + this.container?.remove(); + + super.dispose(); + } +} diff --git a/lib/vscode/src/vs/workbench/browser/parts/media/compositepart.css b/src/vs/workbench/browser/parts/media/compositepart.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/media/compositepart.css rename to src/vs/workbench/browser/parts/media/compositepart.css diff --git a/lib/vscode/src/vs/workbench/browser/parts/notifications/media/notificationsActions.css b/src/vs/workbench/browser/parts/notifications/media/notificationsActions.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/notifications/media/notificationsActions.css rename to src/vs/workbench/browser/parts/notifications/media/notificationsActions.css diff --git a/lib/vscode/src/vs/workbench/browser/parts/notifications/media/notificationsCenter.css b/src/vs/workbench/browser/parts/notifications/media/notificationsCenter.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/notifications/media/notificationsCenter.css rename to src/vs/workbench/browser/parts/notifications/media/notificationsCenter.css diff --git a/lib/vscode/src/vs/workbench/browser/parts/notifications/media/notificationsList.css b/src/vs/workbench/browser/parts/notifications/media/notificationsList.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/notifications/media/notificationsList.css rename to src/vs/workbench/browser/parts/notifications/media/notificationsList.css diff --git a/lib/vscode/src/vs/workbench/browser/parts/notifications/media/notificationsToasts.css b/src/vs/workbench/browser/parts/notifications/media/notificationsToasts.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/notifications/media/notificationsToasts.css rename to src/vs/workbench/browser/parts/notifications/media/notificationsToasts.css diff --git a/lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsActions.ts b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts similarity index 99% rename from lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsActions.ts rename to src/vs/workbench/browser/parts/notifications/notificationsActions.ts index a7af76e8d881..27fc5cdb9634 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsActions.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts @@ -122,7 +122,7 @@ export class ConfigureNotificationAction extends Action { constructor( id: string, label: string, - public readonly configurationActions: readonly IAction[] + readonly configurationActions: readonly IAction[] ) { super(id, label, ThemeIcon.asClassName(configureIcon)); } diff --git a/lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsAlerts.ts b/src/vs/workbench/browser/parts/notifications/notificationsAlerts.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsAlerts.ts rename to src/vs/workbench/browser/parts/notifications/notificationsAlerts.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts rename to src/vs/workbench/browser/parts/notifications/notificationsCenter.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts b/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts rename to src/vs/workbench/browser/parts/notifications/notificationsCommands.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsList.ts b/src/vs/workbench/browser/parts/notifications/notificationsList.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsList.ts rename to src/vs/workbench/browser/parts/notifications/notificationsList.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts b/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts similarity index 97% rename from lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts rename to src/vs/workbench/browser/parts/notifications/notificationsStatus.ts index 228208bd1805..063cf045525c 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts @@ -71,6 +71,7 @@ export class NotificationsStatus extends Disposable { // Show the bell with a dot if there are unread or in-progress notifications const statusProperties: IStatusbarEntry = { + name: localize('status.notifications', "Notifications"), text: `${notificationsInProgress > 0 || this.newNotificationsCount > 0 ? '$(bell-dot)' : '$(bell)'}`, ariaLabel: localize('status.notifications', "Notifications"), command: this.isNotificationsCenterVisible ? HIDE_NOTIFICATIONS_CENTER : SHOW_NOTIFICATIONS_CENTER, @@ -82,7 +83,6 @@ export class NotificationsStatus extends Disposable { this.notificationsCenterStatusItem = this.statusbarService.addEntry( statusProperties, 'status.notifications', - localize('status.notifications', "Notifications"), StatusbarAlignment.RIGHT, -Number.MAX_VALUE /* towards the far end of the right hand side */ ); @@ -180,9 +180,12 @@ export class NotificationsStatus extends Disposable { let statusMessageEntry: IStatusbarEntryAccessor; let showHandle: any = setTimeout(() => { statusMessageEntry = this.statusbarService.addEntry( - { text: message, ariaLabel: message }, + { + name: localize('status.message', "Status Message"), + text: message, + ariaLabel: message + }, 'status.message', - localize('status.message', "Status Message"), StatusbarAlignment.LEFT, -Number.MAX_VALUE /* far right on left hand side */ ); diff --git a/lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsTelemetry.ts b/src/vs/workbench/browser/parts/notifications/notificationsTelemetry.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsTelemetry.ts rename to src/vs/workbench/browser/parts/notifications/notificationsTelemetry.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts rename to src/vs/workbench/browser/parts/notifications/notificationsToasts.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsViewer.ts b/src/vs/workbench/browser/parts/notifications/notificationsViewer.ts similarity index 96% rename from lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsViewer.ts rename to src/vs/workbench/browser/parts/notifications/notificationsViewer.ts index 1a316c061d04..fc96d2263efb 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/notifications/notificationsViewer.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsViewer.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IListVirtualDelegate, IListRenderer } from 'vs/base/browser/ui/list/list'; -import { clearNode, addDisposableListener, EventType, EventHelper, $ } from 'vs/base/browser/dom'; +import { clearNode, addDisposableListener, EventType, EventHelper, $, EventLike } from 'vs/base/browser/dom'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; @@ -24,6 +24,9 @@ import { Severity } from 'vs/platform/notification/common/notification'; import { isNonEmptyArray } from 'vs/base/common/arrays'; import { Codicon } from 'vs/base/common/codicons'; import { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem'; +import { DomEmitter } from 'vs/base/browser/event'; +import { Gesture, EventType as GestureEventType } from 'vs/base/browser/touch'; +import { Event } from 'vs/base/common/event'; export class NotificationsListDelegate implements IListVirtualDelegate { @@ -151,10 +154,17 @@ class NotificationMessageRenderer { const anchor = $('a', { href: node.href, title: title, }, node.label); if (actionHandler) { - actionHandler.toDispose.add(addDisposableListener(anchor, EventType.CLICK, e => { + const onPointer = (e: EventLike) => { EventHelper.stop(e, true); actionHandler.callback(node.href); - })); + }; + + const onClick = actionHandler.toDispose.add(new DomEmitter(anchor, 'click')).event; + + actionHandler.toDispose.add(Gesture.addTarget(anchor)); + const onTap = actionHandler.toDispose.add(new DomEmitter(anchor, GestureEventType.Tap)).event; + + Event.any(onClick, onTap)(onPointer, null, actionHandler.toDispose); } messageContainer.appendChild(anchor); diff --git a/lib/vscode/src/vs/workbench/browser/parts/panel/media/panelpart.css b/src/vs/workbench/browser/parts/panel/media/panelpart.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/panel/media/panelpart.css rename to src/vs/workbench/browser/parts/panel/media/panelpart.css diff --git a/lib/vscode/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/panel/panelActions.ts rename to src/vs/workbench/browser/parts/panel/panelActions.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/panel/panelPart.ts rename to src/vs/workbench/browser/parts/panel/panelPart.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css b/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css rename to src/vs/workbench/browser/parts/sidebar/media/sidebarpart.css diff --git a/lib/vscode/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts rename to src/vs/workbench/browser/parts/sidebar/sidebarPart.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css rename to src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css diff --git a/lib/vscode/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts similarity index 87% rename from lib/vscode/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts rename to src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index 20fe201cd090..f2dbea288b41 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -14,7 +14,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { StatusbarAlignment, IStatusbarService, IStatusbarEntry, IStatusbarEntryAccessor } from 'vs/workbench/services/statusbar/common/statusbar'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { Action, IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification, Separator } from 'vs/base/common/actions'; +import { Action, IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification, Separator, toAction } from 'vs/base/common/actions'; import { IThemeService, registerThemingParticipant, ThemeColor } from 'vs/platform/theme/common/themeService'; import { STATUS_BAR_BACKGROUND, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_ITEM_HOVER_BACKGROUND, STATUS_BAR_ITEM_ACTIVE_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_FOREGROUND, STATUS_BAR_PROMINENT_ITEM_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_HOVER_BACKGROUND, STATUS_BAR_BORDER, STATUS_BAR_NO_FOLDER_FOREGROUND, STATUS_BAR_NO_FOLDER_BORDER } from 'vs/workbench/common/theme'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; @@ -42,13 +42,38 @@ import { syncing } from 'vs/platform/theme/common/iconRegistry'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { CATEGORIES } from 'vs/workbench/common/actions'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { hash } from 'vs/base/common/hash'; +import { setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover'; +import { IHoverService } from 'vs/workbench/services/hover/browser/hover'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { isMarkdownString, markdownStringEqual } from 'vs/base/common/htmlContent'; +import { IHoverDelegate, IHoverDelegateOptions } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; + +interface IStatusbarEntryPriority { + + /** + * The main priority of the entry that + * defines the order of appearance. + * + * May not be unique across all entries. + */ + primary: number; + + /** + * The secondary priority of the entry + * is used in case the main priority + * matches another one's priority. + * + * Should be unique across all entries. + */ + secondary: number; +} interface IPendingStatusbarEntry { id: string; - name: string; entry: IStatusbarEntry; alignment: StatusbarAlignment; - priority: number; + priority: IStatusbarEntryPriority; accessor?: IStatusbarEntryAccessor; } @@ -56,7 +81,7 @@ interface IStatusbarViewModelEntry { id: string; name: string; alignment: StatusbarAlignment; - priority: number; + priority: IStatusbarEntryPriority; container: HTMLElement; labelContainer: HTMLElement; } @@ -294,14 +319,16 @@ class StatusbarViewModel extends Disposable { this._entries.sort((entryA, entryB) => { if (entryA.alignment === entryB.alignment) { - if (entryA.priority !== entryB.priority) { - return entryB.priority - entryA.priority; // higher priority towards the left + if (entryA.priority.primary !== entryB.priority.primary) { + return entryB.priority.primary - entryA.priority.primary; // higher priority towards the left (primary) } - const indexA = mapEntryToIndex.get(entryA); - const indexB = mapEntryToIndex.get(entryB); + if (entryA.priority.secondary !== entryB.priority.secondary) { + return entryB.priority.secondary - entryA.priority.secondary; // higher priority towards the left (secondary) + } - return indexA! - indexB!; // otherwise maintain stable order (both values known to be in map) + // otherwise maintain stable order (both values known to be in map) + return mapEntryToIndex.get(entryA)! - mapEntryToIndex.get(entryB)!; } if (entryA.alignment === StatusbarAlignment.LEFT) { @@ -404,6 +431,8 @@ export class StatusbarPart extends Part implements IStatusbarService { private leftItemsContainer: HTMLElement | undefined; private rightItemsContainer: HTMLElement | undefined; + private hoverDelegate: IHoverDelegate; + constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @IThemeService themeService: IThemeService, @@ -412,30 +441,42 @@ export class StatusbarPart extends Part implements IStatusbarService { @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @IContextMenuService private contextMenuService: IContextMenuService, @IContextKeyService private readonly contextKeyService: IContextKeyService, + @IHoverService hoverService: IHoverService, + @IConfigurationService configurationService: IConfigurationService ) { super(Parts.STATUSBAR_PART, { hasTitle: false }, themeService, storageService, layoutService); this.registerListeners(); + + this.hoverDelegate = { + showHover: (options: IHoverDelegateOptions) => hoverService.showHover(options), + delay: configurationService.getValue('workbench.hover.delay'), + placement: 'element' + }; } private registerListeners(): void { this._register(this.contextService.onDidChangeWorkbenchState(() => this.updateStyles())); } - addEntry(entry: IStatusbarEntry, id: string, name: string, alignment: StatusbarAlignment, priority: number = 0): IStatusbarEntryAccessor { + addEntry(entry: IStatusbarEntry, id: string, alignment: StatusbarAlignment, primaryPriority = 0): IStatusbarEntryAccessor { + const priority: IStatusbarEntryPriority = { + primary: primaryPriority, + secondary: hash(id) // derive from identifier to accomplish uniqueness + }; // As long as we have not been created into a container yet, record all entries // that are pending so that they can get created at a later point if (!this.element) { - return this.doAddPendingEntry(entry, id, name, alignment, priority); + return this.doAddPendingEntry(entry, id, alignment, priority); } // Otherwise add to view - return this.doAddEntry(entry, id, name, alignment, priority); + return this.doAddEntry(entry, id, alignment, priority); } - private doAddPendingEntry(entry: IStatusbarEntry, id: string, name: string, alignment: StatusbarAlignment, priority: number): IStatusbarEntryAccessor { - const pendingEntry: IPendingStatusbarEntry = { entry, id, name, alignment, priority }; + private doAddPendingEntry(entry: IStatusbarEntry, id: string, alignment: StatusbarAlignment, priority: IStatusbarEntryPriority): IStatusbarEntryAccessor { + const pendingEntry: IPendingStatusbarEntry = { entry, id, alignment, priority }; this.pendingEntries.push(pendingEntry); const accessor: IStatusbarEntryAccessor = { @@ -459,17 +500,25 @@ export class StatusbarPart extends Part implements IStatusbarService { return accessor; } - private doAddEntry(entry: IStatusbarEntry, id: string, name: string, alignment: StatusbarAlignment, priority: number): IStatusbarEntryAccessor { + private doAddEntry(entry: IStatusbarEntry, id: string, alignment: StatusbarAlignment, priority: IStatusbarEntryPriority): IStatusbarEntryAccessor { // Create item const itemContainer = this.doCreateStatusItem(id, alignment, ...coalesce([entry.showBeak ? 'has-beak' : undefined])); - const item = this.instantiationService.createInstance(StatusbarEntryItem, itemContainer, entry); + const item = this.instantiationService.createInstance(StatusbarEntryItem, itemContainer, entry, this.hoverDelegate); // Append to parent this.appendOneStatusbarEntry(itemContainer, alignment, priority); // Add to view model - const viewModelEntry: IStatusbarViewModelEntry = { id, name, alignment, priority, container: itemContainer, labelContainer: item.labelContainer }; + const viewModelEntry: IStatusbarViewModelEntry = new class implements IStatusbarViewModelEntry { + readonly id = id; + readonly alignment = alignment; + readonly priority = priority; + readonly container = itemContainer; + readonly labelContainer = item.labelContainer; + + get name() { return item.name; } + }; const viewModelEntryDispose = this.viewModel.add(viewModelEntry); return { @@ -553,7 +602,7 @@ export class StatusbarPart extends Part implements IStatusbarService { while (this.pendingEntries.length) { const pending = this.pendingEntries.shift(); if (pending) { - pending.accessor = this.addEntry(pending.entry, pending.id, pending.name, pending.alignment, pending.priority); + pending.accessor = this.addEntry(pending.entry, pending.id, pending.alignment, pending.priority.primary); } } } @@ -571,7 +620,7 @@ export class StatusbarPart extends Part implements IStatusbarService { }); } - private appendOneStatusbarEntry(itemContainer: HTMLElement, alignment: StatusbarAlignment, priority: number): void { + private appendOneStatusbarEntry(itemContainer: HTMLElement, alignment: StatusbarAlignment, priority: IStatusbarEntryPriority): void { const entries = this.viewModel.getEntries(alignment); if (alignment === StatusbarAlignment.RIGHT) { @@ -584,9 +633,20 @@ export class StatusbarPart extends Part implements IStatusbarService { // and then insert the item before that one let appended = false; for (const entry of entries) { + + // pick a priority that ideally is not the same + // by falling back to secondary priority + let existingEntryPriority = entry.priority.primary; + let newEntryPriority = priority.primary; + if (existingEntryPriority === newEntryPriority) { + existingEntryPriority = entry.priority.secondary; + newEntryPriority = priority.secondary; + } + + // insert according to priority if ( - alignment === StatusbarAlignment.LEFT && entry.priority < priority || - alignment === StatusbarAlignment.RIGHT && entry.priority > priority // reversing due to flex: row-reverse + alignment === StatusbarAlignment.LEFT && existingEntryPriority < newEntryPriority || + alignment === StatusbarAlignment.RIGHT && existingEntryPriority > newEntryPriority // reversing due to flex: row-reverse ) { target.insertBefore(itemContainer, entry.container); appended = true; @@ -625,7 +685,7 @@ export class StatusbarPart extends Part implements IStatusbarService { const actions: IAction[] = []; // Provide an action to hide the status bar at last - actions.push(this.instantiationService.createInstance(ToggleStatusbarVisibilityAction, ToggleStatusbarVisibilityAction.ID, localize('hideStatusBar', "Hide Status Bar"))); + actions.push(toAction({ id: ToggleStatusbarVisibilityAction.ID, label: localize('hideStatusBar', "Hide Status Bar"), run: () => this.instantiationService.invokeFunction(accessor => new ToggleStatusbarVisibilityAction().run(accessor)) })); actions.push(new Separator()); // Show an entry per known status entry @@ -776,7 +836,10 @@ class StatusbarEntryItem extends Disposable { readonly labelContainer: HTMLElement; private readonly label: StatusBarCodiconLabel; + private customHover: IDisposable | undefined; + private entry: IStatusbarEntry | undefined = undefined; + get name(): string { return assertIsDefined(this.entry).name; } private readonly foregroundListener = this._register(new MutableDisposable()); private readonly backgroundListener = this._register(new MutableDisposable()); @@ -787,6 +850,7 @@ class StatusbarEntryItem extends Disposable { constructor( private container: HTMLElement, entry: IStatusbarEntry, + private readonly customHoverDelegate: IHoverDelegate, @ICommandService private readonly commandService: ICommandService, @INotificationService private readonly notificationService: INotificationService, @ITelemetryService private readonly telemetryService: ITelemetryService, @@ -835,8 +899,15 @@ class StatusbarEntryItem extends Disposable { } // Update: Tooltip (on the container, because label can be disabled) - if (!this.entry || entry.tooltip !== this.entry.tooltip) { - if (entry.tooltip) { + if (!this.entry || !isEqualTooltip(this.entry, entry)) { + if (this.customHover) { + this.customHover.dispose(); + this.customHover = undefined; + } + if (isMarkdownString(entry.tooltip)) { + this.container.removeAttribute('title'); + this.customHover = setupCustomHover(this.customHoverDelegate, this.container, { markdown: entry.tooltip, markdownNotSupportedFallback: undefined }); + } else if (entry.tooltip) { this.container.title = entry.tooltip; } else { this.container.title = ''; @@ -947,7 +1018,22 @@ class StatusbarEntryItem extends Disposable { dispose(this.backgroundListener); dispose(this.commandMouseListener); dispose(this.commandKeyboardListener); + if (this.customHover) { + this.customHover.dispose(); + } + } +} + +function isEqualTooltip(e1: IStatusbarEntry, e2: IStatusbarEntry) { + const t1 = e1.tooltip; + const t2 = e2.tooltip; + if (t1 === undefined) { + return t2 === undefined; + } + if (isMarkdownString(t1)) { + return isMarkdownString(t2) && markdownStringEqual(t1, t2); } + return t1 === t2; } registerThemingParticipant((theme, collector) => { diff --git a/lib/vscode/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css rename to src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css diff --git a/lib/vscode/src/vs/workbench/browser/parts/titlebar/menubarControl.ts b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts similarity index 87% rename from lib/vscode/src/vs/workbench/browser/parts/titlebar/menubarControl.ts rename to src/vs/workbench/browser/parts/titlebar/menubarControl.ts index ac94cca192e5..144ec97e8309 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { IMenuService, MenuId, IMenu, SubmenuItemAction, registerAction2, Action2, MenuItemAction } from 'vs/platform/actions/common/actions'; +import { IMenuService, MenuId, IMenu, SubmenuItemAction, registerAction2, Action2, MenuItemAction, MenuRegistry } from 'vs/platform/actions/common/actions'; import { registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService'; import { MenuBarVisibility, getTitleBarStyle, IWindowOpenable, getMenuBarVisibility } from 'vs/platform/windows/common/windows'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -14,7 +14,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { isMacintosh, isWeb, isIOS, isNative } from 'vs/base/common/platform'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { Event, Emitter } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IRecentlyOpened, isRecentFolder, IRecent, isRecentWorkspace, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { RunOnceScheduler } from 'vs/base/common/async'; import { MENUBAR_SELECTION_FOREGROUND, MENUBAR_SELECTION_BACKGROUND, MENUBAR_SELECTION_BORDER, TITLE_BAR_ACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_FOREGROUND, ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_INACTIVE_FOREGROUND } from 'vs/workbench/common/theme'; @@ -36,11 +36,92 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { BrowserFeatures } from 'vs/base/browser/canIUse'; import { KeyCode } from 'vs/base/common/keyCodes'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; +import { IsMacNativeContext, IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; import { ICommandService } from 'vs/platform/commands/common/commands'; export type IOpenRecentAction = IAction & { uri: URI, remoteAuthority?: string }; +MenuRegistry.appendMenuItem(MenuId.MenubarMainMenu, { + submenu: MenuId.MenubarFileMenu, + title: { + value: 'File', + original: 'File', + mnemonicTitle: localize({ key: 'mFile', comment: ['&& denotes a mnemonic'] }, "&&File"), + }, + order: 1 +}); + +MenuRegistry.appendMenuItem(MenuId.MenubarMainMenu, { + submenu: MenuId.MenubarEditMenu, + title: { + value: 'Edit', + original: 'Edit', + mnemonicTitle: localize({ key: 'mEdit', comment: ['&& denotes a mnemonic'] }, "&&Edit") + }, + order: 2 +}); + +MenuRegistry.appendMenuItem(MenuId.MenubarMainMenu, { + submenu: MenuId.MenubarSelectionMenu, + title: { + value: 'Selection', + original: 'Selection', + mnemonicTitle: localize({ key: 'mSelection', comment: ['&& denotes a mnemonic'] }, "&&Selection") + }, + order: 3 +}); + +MenuRegistry.appendMenuItem(MenuId.MenubarMainMenu, { + submenu: MenuId.MenubarViewMenu, + title: { + value: 'View', + original: 'View', + mnemonicTitle: localize({ key: 'mView', comment: ['&& denotes a mnemonic'] }, "&&View") + }, + order: 4 +}); + +MenuRegistry.appendMenuItem(MenuId.MenubarMainMenu, { + submenu: MenuId.MenubarGoMenu, + title: { + value: 'Go', + original: 'Go', + mnemonicTitle: localize({ key: 'mGoto', comment: ['&& denotes a mnemonic'] }, "&&Go") + }, + order: 5 +}); + +MenuRegistry.appendMenuItem(MenuId.MenubarMainMenu, { + submenu: MenuId.MenubarTerminalMenu, + title: { + value: 'Terminal', + original: 'Terminal', + mnemonicTitle: localize({ key: 'mTerminal', comment: ['&& denotes a mnemonic'] }, "&&Terminal") + }, + order: 7 +}); + +MenuRegistry.appendMenuItem(MenuId.MenubarMainMenu, { + submenu: MenuId.MenubarHelpMenu, + title: { + value: 'Help', + original: 'Help', + mnemonicTitle: localize({ key: 'mHelp', comment: ['&& denotes a mnemonic'] }, "&&Help") + }, + order: 8 +}); + +MenuRegistry.appendMenuItem(MenuId.MenubarMainMenu, { + submenu: MenuId.MenubarPreferencesMenu, + title: { + value: 'Preferences', + original: 'Preferences', + mnemonicTitle: localize('mPreferences', "Preferences") + }, + when: IsMacNativeContext, + order: 9 +}); + export abstract class MenubarControl extends Disposable { protected keys = [ @@ -52,28 +133,10 @@ export abstract class MenubarControl extends Disposable { ]; protected menus: { - 'File': IMenu; - 'Edit': IMenu; - 'Selection': IMenu; - 'View': IMenu; - 'Go': IMenu; - 'Run': IMenu; - 'Terminal': IMenu; - 'Window'?: IMenu; - 'Help': IMenu; [index: string]: IMenu | undefined; - }; - - protected topLevelTitles: { [menu: string]: string } = { - 'File': localize({ key: 'mFile', comment: ['&& denotes a mnemonic'] }, "&&File"), - 'Edit': localize({ key: 'mEdit', comment: ['&& denotes a mnemonic'] }, "&&Edit"), - 'Selection': localize({ key: 'mSelection', comment: ['&& denotes a mnemonic'] }, "&&Selection"), - 'View': localize({ key: 'mView', comment: ['&& denotes a mnemonic'] }, "&&View"), - 'Go': localize({ key: 'mGoto', comment: ['&& denotes a mnemonic'] }, "&&Go"), - 'Run': localize({ key: 'mRun', comment: ['&& denotes a mnemonic'] }, "&&Run"), - 'Terminal': localize({ key: 'mTerminal', comment: ['&& denotes a mnemonic'] }, "&&Terminal"), - 'Help': localize({ key: 'mHelp', comment: ['&& denotes a mnemonic'] }, "&&Help") - }; + } = {}; + + protected topLevelTitles: { [menu: string]: string } = {}; protected recentlyOpened: IRecentlyOpened = { files: [], workspaces: [] }; @@ -100,17 +163,30 @@ export abstract class MenubarControl extends Disposable { super(); - this.menus = { - 'File': this._register(this.menuService.createMenu(MenuId.MenubarFileMenu, this.contextKeyService)), - 'Edit': this._register(this.menuService.createMenu(MenuId.MenubarEditMenu, this.contextKeyService)), - 'Selection': this._register(this.menuService.createMenu(MenuId.MenubarSelectionMenu, this.contextKeyService)), - 'View': this._register(this.menuService.createMenu(MenuId.MenubarViewMenu, this.contextKeyService)), - 'Go': this._register(this.menuService.createMenu(MenuId.MenubarGoMenu, this.contextKeyService)), - 'Run': this._register(this.menuService.createMenu(MenuId.MenubarDebugMenu, this.contextKeyService)), - 'Terminal': this._register(this.menuService.createMenu(MenuId.MenubarTerminalMenu, this.contextKeyService)), - 'Help': this._register(this.menuService.createMenu(MenuId.MenubarHelpMenu, this.contextKeyService)) + const mainMenu = this._register(this.menuService.createMenu(MenuId.MenubarMainMenu, this.contextKeyService)); + const mainMenuDisposables = this._register(new DisposableStore()); + + const setupMenu = () => { + mainMenuDisposables.clear(); + this.menus = {}; + this.topLevelTitles = {}; + + const [, mainMenuActions] = mainMenu.getActions()[0]; + for (const mainMenuAction of mainMenuActions) { + if (mainMenuAction instanceof SubmenuItemAction && typeof mainMenuAction.item.title !== 'string') { + this.menus[mainMenuAction.item.title.original] = mainMenuDisposables.add(this.menuService.createMenu(mainMenuAction.item.submenu, this.contextKeyService)); + this.topLevelTitles[mainMenuAction.item.title.original] = mainMenuAction.item.title.mnemonicTitle ?? mainMenuAction.item.title.value; + } + } }; + setupMenu(); + + mainMenu.onDidChange(() => { + setupMenu(); + this.doUpdateMenubar(true); + }); + this.menuUpdater = this._register(new RunOnceScheduler(() => this.doUpdateMenubar(false), 200)); this.notifyUserOfCustomMenubarAccessibility(); @@ -551,6 +627,7 @@ export class CustomMenubarControl extends MenubarControl { this._onVisibilityChange.fire(visible); } + private reinstallDisposables = this._register(new DisposableStore()); private setupCustomMenubar(firstTime: boolean): void { // If there is no container, we cannot setup the menubar if (!this.container) { @@ -558,14 +635,19 @@ export class CustomMenubarControl extends MenubarControl { } if (firstTime) { - this.menubar = this._register(new MenuBar(this.container, this.getMenuBarOptions())); + // Reset and create new menubar + if (this.menubar) { + this.reinstallDisposables.clear(); + } + + this.menubar = this.reinstallDisposables.add(new MenuBar(this.container, this.getMenuBarOptions())); this.accessibilityService.alwaysUnderlineAccessKeys().then(val => { this.alwaysOnMnemonics = val; this.menubar?.update(this.getMenuBarOptions()); }); - this._register(this.menubar.onFocusStateChange(focused => { + this.reinstallDisposables.add(this.menubar.onFocusStateChange(focused => { this._onFocusStateChange.fire(focused); // When the menubar loses focus, update it to clear any pending updates @@ -575,18 +657,18 @@ export class CustomMenubarControl extends MenubarControl { } })); - this._register(this.menubar.onVisibilityChange(e => this.onDidVisibilityChange(e))); + this.reinstallDisposables.add(this.menubar.onVisibilityChange(e => this.onDidVisibilityChange(e))); // Before we focus the menubar, stop updates to it so that focus-related context keys will work - this._register(addDisposableListener(this.container, EventType.FOCUS_IN, () => { + this.reinstallDisposables.add(addDisposableListener(this.container, EventType.FOCUS_IN, () => { this.focusInsideMenubar = true; })); - this._register(addDisposableListener(this.container, EventType.FOCUS_OUT, () => { + this.reinstallDisposables.add(addDisposableListener(this.container, EventType.FOCUS_OUT, () => { this.focusInsideMenubar = false; })); - this._register(attachMenuStyler(this.menubar, this.themeService)); + this.reinstallDisposables.add(attachMenuStyler(this.menubar, this.themeService)); } else { this.menubar?.update(this.getMenuBarOptions()); } @@ -654,7 +736,7 @@ export class CustomMenubarControl extends MenubarControl { for (const title of Object.keys(this.topLevelTitles)) { const menu = this.menus[title]; if (firstTime && menu) { - this._register(menu.onDidChange(() => { + this.reinstallDisposables.add(menu.onDidChange(() => { if (!this.focusInsideMenubar) { const actions: IAction[] = []; updateActions(menu, actions, title); @@ -666,7 +748,7 @@ export class CustomMenubarControl extends MenubarControl { // For the file menu, we need to update if the web nav menu updates as well if (menu === this.menus.File) { - this._register(this.webNavigationMenu.onDidChange(() => { + this.reinstallDisposables.add(this.webNavigationMenu.onDidChange(() => { if (!this.focusInsideMenubar) { const actions: IAction[] = []; updateActions(menu, actions, title); diff --git a/lib/vscode/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts similarity index 99% rename from lib/vscode/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts rename to src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index 8572b7f405fd..d00e11c292c1 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -166,6 +166,7 @@ export class TitlebarPart extends Part implements ITitleService { if (activeEditor) { this.activeEditorListeners.add(activeEditor.onDidChangeDirty(() => this.titleUpdater.schedule())); this.activeEditorListeners.add(activeEditor.onDidChangeLabel(() => this.titleUpdater.schedule())); + this.activeEditorListeners.add(activeEditor.onDidChangeCapabilities(() => this.titleUpdater.schedule())); } } diff --git a/lib/vscode/src/vs/workbench/browser/parts/views/media/paneviewlet.css b/src/vs/workbench/browser/parts/views/media/paneviewlet.css similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/views/media/paneviewlet.css rename to src/vs/workbench/browser/parts/views/media/paneviewlet.css diff --git a/lib/vscode/src/vs/workbench/browser/parts/views/media/views.css b/src/vs/workbench/browser/parts/views/media/views.css similarity index 95% rename from lib/vscode/src/vs/workbench/browser/parts/views/media/views.css rename to src/vs/workbench/browser/parts/views/media/views.css index d82afb63ebdc..09e6c7c8b1f8 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/views/media/views.css +++ b/src/vs/workbench/browser/parts/views/media/views.css @@ -143,12 +143,17 @@ padding-right: 6px; width: 16px; height: 22px; + display: flex; + align-items: center; + justify-content: center; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } -.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item > .custom-view-tree-node-item-icon.codicon { - margin-top: 3px; +/* makes spinning icons square */ +.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item > .custom-view-tree-node-item-icon.codicon.codicon-modifier-spin { + padding-left: 6px; + margin-left: -6px; } .customview-tree .monaco-list .monaco-list-row.selected .custom-view-tree-node-item > .custom-view-tree-node-item-icon.codicon { diff --git a/lib/vscode/src/vs/workbench/browser/parts/views/treeView.ts b/src/vs/workbench/browser/parts/views/treeView.ts similarity index 95% rename from lib/vscode/src/vs/workbench/browser/parts/views/treeView.ts rename to src/vs/workbench/browser/parts/views/treeView.ts index 075cf857ad18..29cb607489a2 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/views/treeView.ts +++ b/src/vs/workbench/browser/parts/views/treeView.ts @@ -10,7 +10,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { MenuId, IMenuService, registerAction2, Action2 } from 'vs/platform/actions/common/actions'; import { IContextKeyService, ContextKeyExpr, ContextKeyEqualsExpr, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { ITreeView, ITreeViewDescriptor, IViewsRegistry, Extensions, IViewDescriptorService, ITreeItem, TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ITreeItemLabel, ViewContainer, ViewContainerLocation, ResolvableTreeItem } from 'vs/workbench/common/views'; +import { ITreeView, ITreeViewDescriptor, IViewsRegistry, Extensions, IViewDescriptorService, ITreeItem, TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ITreeItemLabel, ViewContainer, ViewContainerLocation, ResolvableTreeItem, ITreeViewDragAndDropController } from 'vs/workbench/common/views'; import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IThemeService, FileThemeIcon, FolderThemeIcon, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService'; @@ -38,7 +38,9 @@ import { textLinkForeground, textCodeBlockBackground, focusBorder, listFilterMat import { isString } from 'vs/base/common/types'; import { ILabelService } from 'vs/platform/label/common/label'; import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list'; -import { ITreeRenderer, ITreeNode, IAsyncDataSource, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree'; +import { ITreeRenderer, ITreeNode, IAsyncDataSource, ITreeContextMenuEvent, ITreeDragAndDrop, ITreeDragOverReaction, TreeDragOverBubble } from 'vs/base/browser/ui/tree/tree'; +import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView'; +import { IDragAndDropData } from 'vs/base/browser/dnd'; import { FuzzyScore, createMatches } from 'vs/base/common/filters'; import { CollapseAllAction } from 'vs/base/browser/ui/tree/treeDefaults'; import { isFalsyOrWhitespace } from 'vs/base/common/strings'; @@ -87,6 +89,7 @@ export class TreeViewPane extends ViewPane { if (options.titleDescription !== this.treeView.description) { this.updateTitleDescription(this.treeView.description); } + this.updateTreeVisibility(); } @@ -237,6 +240,13 @@ export class TreeView extends Disposable implements ITreeView { get viewLocation(): ViewContainerLocation { return this.viewDescriptorService.getViewLocationById(this.id)!; } + private _dragAndDropController: ITreeViewDragAndDropController | undefined; + get dragAndDropController(): ITreeViewDragAndDropController | undefined { + return this._dragAndDropController; + } + set dragAndDropController(dnd: ITreeViewDragAndDropController | undefined) { + this._dragAndDropController = dnd; + } private _dataProvider: ITreeViewDataProvider | undefined; get dataProvider(): ITreeViewDataProvider | undefined { @@ -503,6 +513,7 @@ export class TreeView extends Disposable implements ITreeView { return e.collapsibleState !== TreeItemCollapsibleState.Expanded; }, multipleSelectionSupport: this.canSelectMany, + dnd: this.dragAndDropController ? this.instantiationService.createInstance(CustomTreeViewDragAndDrop, this.dragAndDropController) : undefined, overrideStyles: { listBackground: this.viewLocation === ViewContainerLocation.Sidebar ? SIDE_BAR_BACKGROUND : PANEL_BACKGROUND } @@ -1183,3 +1194,32 @@ export class CustomTreeView extends TreeView { } } } + +export class CustomTreeViewDragAndDrop implements ITreeDragAndDrop { + constructor(private dndController: ITreeViewDragAndDropController, @ILabelService private readonly labelService: ILabelService) { } + + onDragOver(data: IDragAndDropData, targetElement: ITreeItem, targetIndex: number, originalEvent: DragEvent): boolean | ITreeDragOverReaction { + return { accept: true, bubble: TreeDragOverBubble.Down, autoExpand: true }; + } + + getDragURI(element: ITreeItem): string | null { + return element.resourceUri ? URI.revive(element.resourceUri).toString() : element.handle; + } + + getDragLabel?(elements: ITreeItem[]): string | undefined { + if (elements.length > 1) { + return String(elements.length); + } + const element = elements[0]; + return element.label ? element.label.label : (element.resourceUri ? this.labelService.getUriLabel(URI.revive(element.resourceUri)) : undefined); + } + + async drop(data: IDragAndDropData, targetNode: ITreeItem | undefined, targetIndex: number | undefined, originalEvent: DragEvent): Promise { + if (data instanceof ElementsDragAndDropData) { + const elements = data.elements; + if (targetNode) { + await this.dndController.onDrop(elements, targetNode); + } + } + } +} diff --git a/lib/vscode/src/vs/workbench/browser/parts/views/viewPane.ts b/src/vs/workbench/browser/parts/views/viewPane.ts similarity index 98% rename from lib/vscode/src/vs/workbench/browser/parts/views/viewPane.ts rename to src/vs/workbench/browser/parts/views/viewPane.ts index 7b20423c227f..655410652bfd 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/views/viewPane.ts +++ b/src/vs/workbench/browser/parts/views/viewPane.ts @@ -7,7 +7,7 @@ import 'vs/css!./media/paneviewlet'; import * as nls from 'vs/nls'; import { Event, Emitter } from 'vs/base/common/event'; import { foreground } from 'vs/platform/theme/common/colorRegistry'; -import { attachButtonStyler, attachLinkStyler, attachProgressBarStyler } from 'vs/platform/theme/common/styler'; +import { attachButtonStyler, attachProgressBarStyler } from 'vs/platform/theme/common/styler'; import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; import { after, append, $, trackFocus, EventType, addDisposableListener, createCSSRule, asCSSUrl } from 'vs/base/browser/dom'; import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; @@ -40,7 +40,7 @@ import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { URI } from 'vs/base/common/uri'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; import { Codicon } from 'vs/base/common/codicons'; -import { CompositeMenuActions } from 'vs/workbench/browser/menuActions'; +import { CompositeMenuActions } from 'vs/workbench/browser/actions'; export interface IViewPaneOptions extends IPaneOptions { id: string; @@ -445,6 +445,10 @@ export abstract class ViewPane extends Pane implements IView { this.scrollableElement.scanDomNode(); } + onDidScrollRoot() { + // noop + } + getProgressIndicator() { if (this.progressBar === undefined) { // Progress bar @@ -575,13 +579,12 @@ export abstract class ViewPane extends Pane implements IView { if (typeof node === 'string') { append(p, document.createTextNode(node)); } else { - const link = this.instantiationService.createInstance(Link, node); + const link = this.instantiationService.createInstance(Link, node, {}); append(p, link.el); disposables.add(link); - disposables.add(attachLinkStyler(link, this.themeService)); if (precondition && node.href.startsWith('command:')) { - const updateEnablement = () => link.style({ disabled: !this.contextKeyService.contextMatchesRules(precondition) }); + const updateEnablement = () => link.enabled = this.contextKeyService.contextMatchesRules(precondition); updateEnablement(); const keys = new Set(); diff --git a/lib/vscode/src/vs/workbench/browser/parts/views/viewPaneContainer.ts b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts similarity index 99% rename from lib/vscode/src/vs/workbench/browser/parts/views/viewPaneContainer.ts rename to src/vs/workbench/browser/parts/views/viewPaneContainer.ts index 255e8eab1de7..0ed15426be7b 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/views/viewPaneContainer.ts +++ b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts @@ -35,7 +35,7 @@ import { RunOnceScheduler } from 'vs/base/common/async'; import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ViewPane } from 'vs/workbench/browser/parts/views/viewPane'; -import { CompositeMenuActions } from 'vs/workbench/browser/menuActions'; +import { CompositeMenuActions } from 'vs/workbench/browser/actions'; import { createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; @@ -407,6 +407,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { options.orientation = this.orientation; this.paneview = this._register(new PaneView(parent, this.options)); this._register(this.paneview.onDidDrop(({ from, to }) => this.movePane(from as ViewPane, to as ViewPane))); + this._register(this.paneview.onDidScroll(_ => this.onDidScrollPane())); this._register(addDisposableListener(parent, EventType.CONTEXT_MENU, (e: MouseEvent) => this.showContextMenu(new StandardMouseEvent(e)))); this._menuActions = this._register(this.instantiationService.createInstance(ViewContainerMenuActions, this.paneview.element, this.viewContainer)); @@ -1064,6 +1065,12 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { return true; } + private onDidScrollPane() { + for (const pane of this.panes) { + pane.onDidScrollRoot(); + } + } + override dispose(): void { super.dispose(); this.paneItems.forEach(i => i.disposable.dispose()); diff --git a/lib/vscode/src/vs/workbench/browser/parts/views/viewsService.ts b/src/vs/workbench/browser/parts/views/viewsService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/views/viewsService.ts rename to src/vs/workbench/browser/parts/views/viewsService.ts diff --git a/lib/vscode/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/parts/views/viewsViewlet.ts rename to src/vs/workbench/browser/parts/views/viewsViewlet.ts diff --git a/lib/vscode/src/vs/workbench/browser/quickaccess.ts b/src/vs/workbench/browser/quickaccess.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/quickaccess.ts rename to src/vs/workbench/browser/quickaccess.ts diff --git a/lib/vscode/src/vs/workbench/browser/style.ts b/src/vs/workbench/browser/style.ts similarity index 94% rename from lib/vscode/src/vs/workbench/browser/style.ts rename to src/vs/workbench/browser/style.ts index c83278bda46a..6971905465ea 100644 --- a/lib/vscode/src/vs/workbench/browser/style.ts +++ b/src/vs/workbench/browser/style.ts @@ -5,7 +5,7 @@ import 'vs/css!./media/style'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { iconForeground, foreground, selectionBackground, focusBorder, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, listHighlightForeground, inputPlaceholderForeground, toolbarHoverBackground, toolbarActiveBackground, toolbarHoverOutline } from 'vs/platform/theme/common/colorRegistry'; +import { iconForeground, foreground, selectionBackground, focusBorder, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, listHighlightForeground, inputPlaceholderForeground, toolbarHoverBackground, toolbarActiveBackground, toolbarHoverOutline, listFocusHighlightForeground } from 'vs/platform/theme/common/colorRegistry'; import { WORKBENCH_BACKGROUND, TITLE_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme'; import { isWeb, isIOS, isMacintosh, isWindows } from 'vs/base/common/platform'; import { createMetaElement } from 'vs/base/browser/dom'; @@ -61,6 +61,16 @@ registerThemingParticipant((theme, collector) => { `); } + // List highlight w/ focus + const listHighlightFocusForegroundColor = theme.getColor(listFocusHighlightForeground); + if (listHighlightFocusForegroundColor) { + collector.addRule(` + .monaco-workbench .monaco-list .monaco-list-row.focused .monaco-highlighted-label .highlight { + color: ${listHighlightFocusForegroundColor}; + } + `); + } + // Scrollbars const scrollbarShadowColor = theme.getColor(scrollbarShadow); if (scrollbarShadowColor) { diff --git a/lib/vscode/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/viewlet.ts rename to src/vs/workbench/browser/viewlet.ts diff --git a/lib/vscode/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts similarity index 97% rename from lib/vscode/src/vs/workbench/browser/web.main.ts rename to src/vs/workbench/browser/web.main.ts index 61d5dfe34302..ef1a454bf1c2 100644 --- a/lib/vscode/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -39,7 +39,6 @@ import { BufferLogService } from 'vs/platform/log/common/bufferLog'; import { FileLogger } from 'vs/platform/log/common/fileLog'; import { toLocalISOString } from 'vs/base/common/date'; import { isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows'; -import { initialize } from 'vs/server/browser/client'; import { getSingleFolderWorkspaceIdentifier, getWorkspaceIdentifier } from 'vs/workbench/services/workspaces/browser/workspaces'; import { coalesce } from 'vs/base/common/arrays'; import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider'; @@ -64,6 +63,7 @@ import { ITimerService } from 'vs/workbench/services/timer/browser/timerService' import { WorkspaceTrustManagementService } from 'vs/workbench/services/workspaces/common/workspaceTrust'; import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; import { HTMLFileSystemProvider } from 'vs/platform/files/browser/htmlFileSystemProvider'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; class BrowserMain extends Disposable { @@ -96,7 +96,6 @@ class BrowserMain extends Disposable { // Startup const instantiationService = workbench.startup(); - await initialize(services.serviceCollection); // Window this._register(instantiationService.createInstance(BrowserWindow)); @@ -108,16 +107,22 @@ class BrowserMain extends Disposable { const commandService = accessor.get(ICommandService); const lifecycleService = accessor.get(ILifecycleService); const timerService = accessor.get(ITimerService); + const openerService = accessor.get(IOpenerService); + const productService = accessor.get(IProductService); return { commands: { executeCommand: (command, ...args) => commandService.executeCommand(command, ...args) }, env: { + uriScheme: productService.urlProtocol, async retrievePerformanceMarks() { await timerService.whenReady(); return timerService.getPerformanceMarks(); + }, + async openUri(uri: URI): Promise { + return openerService.open(uri, {}); } }, shutdown: () => lifecycleService.shutdown() @@ -178,7 +183,7 @@ class BrowserMain extends Disposable { serviceCollection.set(IFileService, fileService); await this.registerFileSystemProviders(environmentService, fileService, remoteAgentService, logService, logsPath); - // IURIIdentityService + // URI Identity const uriIdentityService = new UriIdentityService(fileService); serviceCollection.set(IUriIdentityService, uriIdentityService); @@ -205,7 +210,7 @@ class BrowserMain extends Disposable { ]); // Workspace Trust Service - const workspaceTrustManagementService = new WorkspaceTrustManagementService(configurationService, environmentService, storageService, uriIdentityService, configurationService); + const workspaceTrustManagementService = new WorkspaceTrustManagementService(configurationService, storageService, uriIdentityService, environmentService, configurationService, remoteAuthorityResolverService); serviceCollection.set(IWorkspaceTrustManagementService, workspaceTrustManagementService); // Update workspace trust so that configuration is updated accordingly diff --git a/lib/vscode/src/vs/workbench/browser/window.ts b/src/vs/workbench/browser/window.ts similarity index 91% rename from lib/vscode/src/vs/workbench/browser/window.ts rename to src/vs/workbench/browser/window.ts index fa5f82cd07af..05b9f806f35b 100644 --- a/lib/vscode/src/vs/workbench/browser/window.ts +++ b/src/vs/workbench/browser/window.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { setFullscreen } from 'vs/base/browser/browser'; -import { addDisposableListener, addDisposableThrottledListener, detectFullscreen, EventHelper, EventType, windowOpenNoOpener } from 'vs/base/browser/dom'; -import { domEvent } from 'vs/base/browser/event'; +import { addDisposableListener, addDisposableThrottledListener, detectFullscreen, EventHelper, EventType, windowOpenNoOpenerWithSuccess, windowOpenNoOpener } from 'vs/base/browser/dom'; +import { DomEmitter } from 'vs/base/browser/event'; import { timeout } from 'vs/base/common/async'; import { Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -50,7 +50,13 @@ export class BrowserWindow extends Disposable { // Layout const viewport = isIOS && window.visualViewport ? window.visualViewport /** Visual viewport */ : window /** Layout viewport */; - this._register(addDisposableListener(viewport, EventType.RESIZE, () => this.onWindowResize())); + this._register(addDisposableListener(viewport, EventType.RESIZE, () => { + this.onWindowResize(); + if (isIOS) { + // Sometimes the keyboard appearing scrolls the whole workbench out of view, as a workaround scroll back into view #121206 + window.scrollTo(0, 0); + } + })); // Prevent the back/forward gestures in macOS this._register(addDisposableListener(this.layoutService.container, EventType.WHEEL, e => e.preventDefault(), { passive: false })); @@ -74,7 +80,6 @@ export class BrowserWindow extends Disposable { private onWindowResize(): void { this.logService.trace(`web.main#${isIOS && window.visualViewport ? 'visualViewport' : 'window'}Resize`); - this.layoutService.layout(); } @@ -84,8 +89,8 @@ export class BrowserWindow extends Disposable { // when shutdown has happened to not show the dialog e.g. // when navigation takes a longer time. Event.toPromise(Event.any( - Event.once(domEvent(document.body, EventType.KEY_DOWN, true)), - Event.once(domEvent(document.body, EventType.MOUSE_DOWN, true)) + Event.once(new DomEmitter(document.body, EventType.KEY_DOWN, true).event), + Event.once(new DomEmitter(document.body, EventType.MOUSE_DOWN, true).event) )).then(async () => { // Delay the dialog in case the user interacted @@ -139,7 +144,7 @@ export class BrowserWindow extends Disposable { this.openerService.setDefaultExternalOpener({ openExternal: async (href: string) => { if (matchesScheme(href, Schemas.http) || matchesScheme(href, Schemas.https)) { - const opened = windowOpenNoOpener(href); + const opened = windowOpenNoOpenerWithSuccess(href); if (!opened) { const showResult = await this.dialogService.show(Severity.Warning, localize('unableToOpenExternal', "The browser interrupted the opening of a new tab or window. Press 'Open' to open it anyway."), [localize('open', "Open"), localize('learnMore', "Learn More"), localize('cancel', "Cancel")], { cancelId: 2, detail: href }); diff --git a/lib/vscode/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/browser/workbench.contribution.ts rename to src/vs/workbench/browser/workbench.contribution.ts diff --git a/lib/vscode/src/vs/workbench/browser/workbench.ts b/src/vs/workbench/browser/workbench.ts similarity index 95% rename from lib/vscode/src/vs/workbench/browser/workbench.ts rename to src/vs/workbench/browser/workbench.ts index 2074e0c7776a..ffa6372c5302 100644 --- a/lib/vscode/src/vs/workbench/browser/workbench.ts +++ b/src/vs/workbench/browser/workbench.ts @@ -275,9 +275,7 @@ export class Workbench extends Layout { } private restoreFontInfo(storageService: IStorageService, configurationService: IConfigurationService): void { - - // Restore (native: use storage service, web: use browser specific local storage) - const storedFontInfoRaw = isNative ? storageService.get('editorFontInfo', StorageScope.GLOBAL) : window.localStorage.getItem('vscode.editorFontInfo'); + const storedFontInfoRaw = storageService.get('editorFontInfo', StorageScope.GLOBAL); if (storedFontInfoRaw) { try { const storedFontInfo = JSON.parse(storedFontInfoRaw); @@ -295,17 +293,7 @@ export class Workbench extends Layout { private storeFontInfo(storageService: IStorageService): void { const serializedFontInfo = serializeFontInfo(); if (serializedFontInfo) { - const serializedFontInfoRaw = JSON.stringify(serializedFontInfo); - - // Font info is very specific to the machine the workbench runs - // on. As such, in the web, we prefer to store this info in - // local storage and not global storage because it would not make - // much sense to synchronize to other machines. - if (isNative) { - storageService.store('editorFontInfo', serializedFontInfoRaw, StorageScope.GLOBAL, StorageTarget.MACHINE); - } else { - window.localStorage.setItem('vscode.editorFontInfo', serializedFontInfoRaw); - } + storageService.store('editorFontInfo', JSON.stringify(serializedFontInfo), StorageScope.GLOBAL, StorageTarget.MACHINE); } } @@ -340,6 +328,7 @@ export class Workbench extends Layout { // Create Parts [ { id: Parts.TITLEBAR_PART, role: 'contentinfo', classes: ['titlebar'] }, + { id: Parts.BANNER_PART, role: 'banner', classes: ['banner'] }, { id: Parts.ACTIVITYBAR_PART, role: 'none', classes: ['activitybar', this.state.sideBar.position === Position.LEFT ? 'left' : 'right'] }, // Use role 'none' for some parts to make screen readers less chatty #114892 { id: Parts.SIDEBAR_PART, role: 'none', classes: ['sidebar', this.state.sideBar.position === Position.LEFT ? 'left' : 'right'] }, { id: Parts.EDITOR_PART, role: 'main', classes: ['editor'], options: { restorePreviousState: this.state.editor.restoreEditors } }, diff --git a/lib/vscode/src/vs/workbench/buildfile.desktop.js b/src/vs/workbench/buildfile.desktop.js similarity index 100% rename from lib/vscode/src/vs/workbench/buildfile.desktop.js rename to src/vs/workbench/buildfile.desktop.js diff --git a/lib/vscode/src/vs/workbench/buildfile.web.js b/src/vs/workbench/buildfile.web.js similarity index 100% rename from lib/vscode/src/vs/workbench/buildfile.web.js rename to src/vs/workbench/buildfile.web.js diff --git a/lib/vscode/src/vs/workbench/common/actions.ts b/src/vs/workbench/common/actions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/common/actions.ts rename to src/vs/workbench/common/actions.ts diff --git a/lib/vscode/src/vs/workbench/common/activity.ts b/src/vs/workbench/common/activity.ts similarity index 100% rename from lib/vscode/src/vs/workbench/common/activity.ts rename to src/vs/workbench/common/activity.ts diff --git a/lib/vscode/src/vs/workbench/common/component.ts b/src/vs/workbench/common/component.ts similarity index 100% rename from lib/vscode/src/vs/workbench/common/component.ts rename to src/vs/workbench/common/component.ts diff --git a/lib/vscode/src/vs/workbench/common/composite.ts b/src/vs/workbench/common/composite.ts similarity index 100% rename from lib/vscode/src/vs/workbench/common/composite.ts rename to src/vs/workbench/common/composite.ts diff --git a/lib/vscode/src/vs/workbench/common/configuration.ts b/src/vs/workbench/common/configuration.ts similarity index 100% rename from lib/vscode/src/vs/workbench/common/configuration.ts rename to src/vs/workbench/common/configuration.ts diff --git a/lib/vscode/src/vs/workbench/common/contributions.ts b/src/vs/workbench/common/contributions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/common/contributions.ts rename to src/vs/workbench/common/contributions.ts diff --git a/lib/vscode/src/vs/workbench/common/dialogs.ts b/src/vs/workbench/common/dialogs.ts similarity index 100% rename from lib/vscode/src/vs/workbench/common/dialogs.ts rename to src/vs/workbench/common/dialogs.ts diff --git a/lib/vscode/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts similarity index 64% rename from lib/vscode/src/vs/workbench/common/editor.ts rename to src/vs/workbench/common/editor.ts index d33a1daabce8..c2ac8757b109 100644 --- a/lib/vscode/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -4,24 +4,22 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { Event, Emitter } from 'vs/base/common/event'; -import { withNullAsUndefined, assertIsDefined } from 'vs/base/common/types'; +import { Event } from 'vs/base/common/event'; +import { assertIsDefined, isUndefinedOrNull } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; -import { IDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle'; -import { IEditor, IEditorViewState, ScrollType, IDiffEditor } from 'vs/editor/common/editorCommon'; -import { IEditorModel, IEditorOptions, ITextEditorOptions, IBaseResourceEditorInput, IResourceEditorInput, EditorActivation, EditorOpenContext, ITextEditorSelection, TextEditorSelectionRevealType, EditorOverride } from 'vs/platform/editor/common/editor'; +import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { IEditor, IEditorViewState, IDiffEditor } from 'vs/editor/common/editorCommon'; +import { IEditorModel, IEditorOptions, ITextEditorOptions, IBaseResourceEditorInput, IResourceEditorInput, ITextResourceEditorInput, IBaseTextResourceEditorInput } from 'vs/platform/editor/common/editor'; import { IInstantiationService, IConstructorSignature0, ServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation'; import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { Registry } from 'vs/platform/registry/common/platform'; import { IEncodingSupport, IModeSupport } from 'vs/workbench/services/textfile/common/textfiles'; import { GroupsOrder, IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ICompositeControl, IComposite } from 'vs/workbench/common/composite'; -import { ActionRunner, IAction } from 'vs/base/common/actions'; import { IFileService } from 'vs/platform/files/common/files'; import { IPathData } from 'vs/platform/windows/common/windows'; -import { coalesce, firstOrDefault } from 'vs/base/common/arrays'; +import { coalesce } from 'vs/base/common/arrays'; import { ACTIVE_GROUP, IResourceEditorInputType, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; -import { IRange } from 'vs/editor/common/core/range'; import { IExtUri } from 'vs/base/common/resources'; // Static values for editor contributions @@ -68,6 +66,31 @@ export const TEXT_DIFF_EDITOR_ID = 'workbench.editors.textDiffEditor'; */ export const BINARY_DIFF_EDITOR_ID = 'workbench.editors.binaryResourceDiffEditor'; +export interface IEditorDescriptor { + + /** + * The unique type identifier of the editor. All instances + * of the same `IEditorPane` should have the same type + * identifier. + */ + readonly typeId: string; + + /** + * The display name of the editor. + */ + readonly name: string; + + /** + * Instantiates the editor pane using the provided services. + */ + instantiate(instantiationService: IInstantiationService): T; + + /** + * Whether the descriptor is for the provided editor pane. + */ + describes(editorPane: T): boolean; +} + /** * The editor pane is the container for workbench editors. */ @@ -190,7 +213,7 @@ export interface IFileEditorInputFactory { /** * Creates new new editor input capable of showing files. */ - createFileEditorInput(resource: URI, preferredResource: URI | undefined, preferredName: string | undefined, preferredDescription: string | undefined, preferredEncoding: string | undefined, preferredMode: string | undefined, instantiationService: IInstantiationService): IFileEditorInput; + createFileEditorInput(resource: URI, preferredResource: URI | undefined, preferredName: string | undefined, preferredDescription: string | undefined, preferredEncoding: string | undefined, preferredMode: string | undefined, preferredContents: string | undefined, instantiationService: IInstantiationService): IFileEditorInput; /** * Check if the provided object is a file editor input. @@ -198,22 +221,6 @@ export interface IFileEditorInputFactory { isFileEditorInput(obj: unknown): obj is IFileEditorInput; } -/** - * @deprecated obsolete - * - * TODO@bpasero remove this API and users once the generic backup restorer has been removed - */ -export interface ICustomEditorInputFactory { - /** - * @deprecated obsolete - */ - createCustomEditorInput(resource: URI, instantiationService: IInstantiationService): Promise; - /** - * @deprecated obsolete - */ - canResolveBackup(editorInput: IEditorInput, backupResource: URI): boolean; -} - export interface IEditorInputFactoryRegistry { /** @@ -226,20 +233,6 @@ export interface IEditorInputFactoryRegistry { */ getFileEditorInputFactory(): IFileEditorInputFactory; - /** - * Registers the custom editor input factory to use for custom inputs. - * - * @deprecated obsolete - */ - registerCustomEditorInputFactory(scheme: string, factory: ICustomEditorInputFactory): void; - - /** - * Returns the custom editor input factory to use for custom inputs. - * - * @deprecated obsolete - */ - getCustomEditorInputFactory(scheme: string): ICustomEditorInputFactory | undefined; - /** * Registers a editor input serializer for the given editor input to the registry. * An editor input serializer is capable of serializing and deserializing editor @@ -279,10 +272,10 @@ export interface IEditorInputSerializer { * Returns an editor input from the provided serialized form of the editor input. This form matches * the value returned from the serialize() method. */ - deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput | undefined; + deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): IEditorInput | undefined; } -export interface IUntitledTextResourceEditorInput extends IBaseResourceEditorInput { +export interface IUntitledTextResourceEditorInput extends IBaseTextResourceEditorInput { /** * Optional resource. If the resource is not provided a new untitled file is created (e.g. Untitled-1). @@ -291,34 +284,19 @@ export interface IUntitledTextResourceEditorInput extends IBaseResourceEditorInp * the untitled editor. */ readonly resource?: URI; - - /** - * Optional language of the untitled resource. - */ - readonly mode?: string; - - /** - * Optional contents of the untitled resource. - */ - readonly contents?: string; - - /** - * Optional encoding of the untitled resource. - */ - readonly encoding?: string; } export interface IResourceDiffEditorInput extends IBaseResourceEditorInput { /** - * The left hand side URI to open inside a diff editor. + * The left hand side editor to open inside a diff editor. */ - readonly leftResource: URI; + readonly originalInput: IResourceEditorInput | ITextResourceEditorInput | IUntitledTextResourceEditorInput; /** - * The right hand side URI to open inside a diff editor. + * The right hand side editor to open inside a diff editor. */ - readonly rightResource: URI; + readonly modifiedInput: IResourceEditorInput | ITextResourceEditorInput | IUntitledTextResourceEditorInput; } export const enum Verbosity { @@ -393,10 +371,39 @@ export interface IRevertOptions { } export interface IMoveResult { - editor: EditorInput | IResourceEditorInputType; + editor: IEditorInput | IResourceEditorInputType; options?: IEditorOptions; } +export const enum EditorInputCapabilities { + + /** + * Signals no specific capability for the input. + */ + None = 0, + + /** + * Signals that the input is readonly. + */ + Readonly = 1 << 1, + + /** + * Signals that the input is untitled. + */ + Untitled = 1 << 2, + + /** + * Signals that the input can only be shown in one group + * and not be split into multiple groups. + */ + Singleton = 1 << 3, + + /** + * Signals that the input requires workspace trust. + */ + RequiresTrust = 1 << 4, +} + export interface IEditorInput extends IDisposable { /** @@ -415,7 +422,12 @@ export interface IEditorInput extends IDisposable { readonly onDidChangeLabel: Event; /** - * Unique type identifier for this inpput. Every editor input of the + * Triggered when this input changes its capabilities. + */ + readonly onDidChangeCapabilities: Event; + + /** + * Unique type identifier for this input. Every editor input of the * same class should share the same type identifier. The type identifier * is used for example for serialising/deserialising editor inputs * via the serialisers of the `IEditorInputFactoryRegistry`. @@ -435,6 +447,16 @@ export interface IEditorInput extends IDisposable { */ readonly resource: URI | undefined; + /** + * The capabilities of the input. + */ + readonly capabilities: EditorInputCapabilities; + + /** + * Figure out if the input has the provided capability. + */ + hasCapability(capability: EditorInputCapabilities): boolean; + /** * Returns the display name of this input. */ @@ -462,16 +484,6 @@ export interface IEditorInput extends IDisposable { */ resolve(): Promise; - /** - * Returns if this input is readonly or not. - */ - isReadonly(): boolean; - - /** - * Returns if the input is an untitled editor or not. - */ - isUntitled(): boolean; - /** * Returns if this input is dirty or not. */ @@ -523,9 +535,18 @@ export interface IEditorInput extends IDisposable { rename(group: GroupIdentifier, target: URI): IMoveResult | undefined; /** - * Subclasses can set this to false if it does not make sense to split the editor input. + * Returns a copy of the current editor input. Used when we can't just reuse the input */ - canSplit(): boolean; + copy(): IEditorInput; + + /** + * Returns a representation of this typed editor input as untyped + * resource editor input that e.g. can be used to serialize the + * editor input into a form that it can be restored. + * + * May return `undefined` if a untyped representatin is not supported. + */ + asResourceEditorInput(groupId: GroupIdentifier): IBaseResourceEditorInput | undefined; /** * Returns if the other object matches this input. @@ -536,130 +557,6 @@ export interface IEditorInput extends IDisposable { * Returns if this editor is disposed. */ isDisposed(): boolean; - - /** - * Returns a copy of the current editor input. Used when we can't just reuse the input - */ - copy(): IEditorInput; -} - -/** - * Editor inputs are lightweight objects that can be passed to the workbench API to open inside the editor part. - * Each editor input is mapped to an editor that is capable of opening it through the Platform facade. - */ -export abstract class EditorInput extends Disposable implements IEditorInput { - - protected readonly _onDidChangeDirty = this._register(new Emitter()); - readonly onDidChangeDirty = this._onDidChangeDirty.event; - - protected readonly _onDidChangeLabel = this._register(new Emitter()); - readonly onDidChangeLabel = this._onDidChangeLabel.event; - - private readonly _onWillDispose = this._register(new Emitter()); - readonly onWillDispose = this._onWillDispose.event; - - private disposed: boolean = false; - - abstract get typeId(): string; - - abstract get resource(): URI | undefined; - - getName(): string { - return `Editor ${this.typeId}`; - } - - getDescription(verbosity?: Verbosity): string | undefined { - return undefined; - } - - getTitle(verbosity?: Verbosity): string { - return this.getName(); - } - - getAriaLabel(): string { - return this.getTitle(Verbosity.SHORT); - } - - /** - * Returns the preferred editor for this input. A list of candidate editors is passed in that whee registered - * for the input. This allows subclasses to decide late which editor to use for the input on a case by case basis. - */ - getPreferredEditorId(candidates: string[]): string | undefined { - return firstOrDefault(candidates); - } - - /** - * Returns a descriptor suitable for telemetry events. - * - * Subclasses should extend if they can contribute. - */ - getTelemetryDescriptor(): { [key: string]: unknown } { - /* __GDPR__FRAGMENT__ - "EditorTelemetryDescriptor" : { - "typeId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - return { typeId: this.typeId }; - } - - isReadonly(): boolean { - return true; - } - - isUntitled(): boolean { - return false; - } - - isDirty(): boolean { - return false; - } - - isSaving(): boolean { - return false; - } - - async resolve(): Promise { - return null; - } - - async save(group: GroupIdentifier, options?: ISaveOptions): Promise { - return this; - } - - async saveAs(group: GroupIdentifier, options?: ISaveOptions): Promise { - return this; - } - - async revert(group: GroupIdentifier, options?: IRevertOptions): Promise { } - - rename(group: GroupIdentifier, target: URI): IMoveResult | undefined { - return undefined; - } - - canSplit(): boolean { - return true; - } - - matches(otherInput: unknown): boolean { - return this === otherInput; - } - - copy(): IEditorInput { - return this; - } - - isDisposed(): boolean { - return this.disposed; - } - - override dispose(): void { - if (!this.disposed) { - this.disposed = true; - this._onWillDispose.fire(); - } - - super.dispose(); - } } export interface IEditorInputWithPreferredResource { @@ -685,9 +582,34 @@ export interface IEditorInputWithPreferredResource { } export function isEditorInputWithPreferredResource(obj: unknown): obj is IEditorInputWithPreferredResource { - const editorInputWithPreferredResource = obj as IEditorInputWithPreferredResource; + const editorInputWithPreferredResource = obj as IEditorInputWithPreferredResource | undefined; + if (!editorInputWithPreferredResource) { + return false; + } - return editorInputWithPreferredResource && !!editorInputWithPreferredResource.preferredResource; + return URI.isUri(editorInputWithPreferredResource.preferredResource); +} + +export interface ISideBySideEditorInput extends IEditorInput { + + /** + * The primary editor input is shown on the right hand side. + */ + primary: IEditorInput; + + /** + * The secondary editor input is shown on the left hand side. + */ + secondary: IEditorInput; +} + +function isSideBySideEditorInput(obj: unknown): obj is ISideBySideEditorInput { + const sideBySideEditorInput = obj as ISideBySideEditorInput | undefined; + if (!sideBySideEditorInput) { + return false; + } + + return !!sideBySideEditorInput.primary && !!sideBySideEditorInput.secondary; } /** @@ -737,6 +659,11 @@ export interface IFileEditorInput extends IEditorInput, IEncodingSupport, IModeS */ setPreferredMode(mode: string): void; + /** + * Sets the preferred contents to use for this file input. + */ + setPreferredContents(contents: string): void; + /** * Forces this file input to open as binary instead of text. */ @@ -748,173 +675,9 @@ export interface IFileEditorInput extends IEditorInput, IEncodingSupport, IModeS isResolved(): boolean; } -/** - * Side by side editor inputs that have a primary and secondary side. - */ -export class SideBySideEditorInput extends EditorInput { - - static readonly ID: string = 'workbench.editorinputs.sidebysideEditorInput'; - - override get typeId(): string { - return SideBySideEditorInput.ID; - } - - constructor( - protected readonly name: string | undefined, - protected readonly description: string | undefined, - private readonly _secondary: EditorInput, - private readonly _primary: EditorInput - ) { - super(); - - this.registerListeners(); - } - - private registerListeners(): void { - - // When the primary or secondary input gets disposed, dispose this diff editor input - const onceSecondaryDisposed = Event.once(this.secondary.onWillDispose); - this._register(onceSecondaryDisposed(() => { - if (!this.isDisposed()) { - this.dispose(); - } - })); - - const oncePrimaryDisposed = Event.once(this.primary.onWillDispose); - this._register(oncePrimaryDisposed(() => { - if (!this.isDisposed()) { - this.dispose(); - } - })); - - // Reemit some events from the primary side to the outside - this._register(this.primary.onDidChangeDirty(() => this._onDidChangeDirty.fire())); - this._register(this.primary.onDidChangeLabel(() => this._onDidChangeLabel.fire())); - } - - /** - * Use `EditorResourceAccessor` utility method to access the resources - * of both sides of the diff editor. - */ - get resource(): URI | undefined { - return undefined; - } - - get primary(): EditorInput { - return this._primary; - } - - get secondary(): EditorInput { - return this._secondary; - } - - override getName(): string { - if (!this.name) { - return localize('sideBySideLabels', "{0} - {1}", this._secondary.getName(), this._primary.getName()); - } - - return this.name; - } - - override getDescription(): string | undefined { - return this.description; - } - - override isReadonly(): boolean { - return this.primary.isReadonly(); - } - - override isUntitled(): boolean { - return this.primary.isUntitled(); - } - - override isDirty(): boolean { - return this.primary.isDirty(); - } - - override isSaving(): boolean { - return this.primary.isSaving(); - } - - override save(group: GroupIdentifier, options?: ISaveOptions): Promise { - return this.primary.save(group, options); - } - - override saveAs(group: GroupIdentifier, options?: ISaveOptions): Promise { - return this.primary.saveAs(group, options); - } - - override revert(group: GroupIdentifier, options?: IRevertOptions): Promise { - return this.primary.revert(group, options); - } - - override getTelemetryDescriptor(): { [key: string]: unknown } { - const descriptor = this.primary.getTelemetryDescriptor(); - - return Object.assign(descriptor, super.getTelemetryDescriptor()); - } - - override matches(otherInput: unknown): boolean { - if (otherInput === this) { - return true; - } - - if (otherInput instanceof SideBySideEditorInput) { - return this.primary.matches(otherInput.primary) && this.secondary.matches(otherInput.secondary); - } - - return false; - } -} - -/** - * The editor model is the heavyweight counterpart of editor input. Depending on the editor input, it - * resolves from a file system retrieve content and may allow for saving it back or reverting it. - * Editor models are typically cached for some while because they are expensive to construct. - */ -export class EditorModel extends Disposable implements IEditorModel { - - private readonly _onWillDispose = this._register(new Emitter()); - readonly onWillDispose = this._onWillDispose.event; - - private disposed = false; - private resolved = false; - - /** - * Causes this model to resolve returning a promise when loading is completed. - */ - async resolve(): Promise { - this.resolved = true; - } - - /** - * Returns whether this model was loaded or not. - */ - isResolved(): boolean { - return this.resolved; - } - - /** - * Find out if this model has been disposed. - */ - isDisposed(): boolean { - return this.disposed; - } - - /** - * Subclasses should implement to free resources that have been claimed through loading. - */ - override dispose(): void { - this.disposed = true; - this._onWillDispose.fire(); - - super.dispose(); - } -} - export interface IEditorInputWithOptions { editor: IEditorInput; - options?: IEditorOptions | ITextEditorOptions; + options?: IEditorOptions; } export interface IEditorInputWithOptionsAndGroup extends IEditorInputWithOptions { @@ -927,289 +690,6 @@ export function isEditorInputWithOptions(obj: unknown): obj is IEditorInputWithO return !!editorInputWithOptions && !!editorInputWithOptions.editor; } -/** - * The editor options is the base class of options that can be passed in when opening an editor. - */ -export class EditorOptions implements IEditorOptions { - - /** - * Helper to create EditorOptions inline. - */ - static create(settings: IEditorOptions): EditorOptions { - const options = new EditorOptions(); - options.overwrite(settings); - - return options; - } - - /** - * Tells the editor to not receive keyboard focus when the editor is being opened. - * - * Will also not activate the group the editor opens in unless the group is already - * the active one. This behaviour can be overridden via the `activation` option. - */ - preserveFocus: boolean | undefined; - - /** - * This option is only relevant if an editor is opened into a group that is not active - * already and allows to control if the inactive group should become active, restored - * or preserved. - * - * By default, the editor group will become active unless `preserveFocus` or `inactive` - * is specified. - */ - activation: EditorActivation | undefined; - - /** - * Tells the editor to reload the editor input in the editor even if it is identical to the one - * already showing. By default, the editor will not reload the input if it is identical to the - * one showing. - */ - forceReload: boolean | undefined; - - /** - * Will reveal the editor if it is already opened and visible in any of the opened editor groups. - */ - revealIfVisible: boolean | undefined; - - /** - * Will reveal the editor if it is already opened (even when not visible) in any of the opened editor groups. - */ - revealIfOpened: boolean | undefined; - - /** - * An editor that is pinned remains in the editor stack even when another editor is being opened. - * An editor that is not pinned will always get replaced by another editor that is not pinned. - */ - pinned: boolean | undefined; - - /** - * An editor that is sticky moves to the beginning of the editors list within the group and will remain - * there unless explicitly closed. Operations such as "Close All" will not close sticky editors. - */ - sticky: boolean | undefined; - - /** - * The index in the document stack where to insert the editor into when opening. - */ - index: number | undefined; - - /** - * An active editor that is opened will show its contents directly. Set to true to open an editor - * in the background without loading its contents. - * - * Will also not activate the group the editor opens in unless the group is already - * the active one. This behaviour can be overridden via the `activation` option. - */ - inactive: boolean | undefined; - - /** - * Will not show an error in case opening the editor fails and thus allows to show a custom error - * message as needed. By default, an error will be presented as notification if opening was not possible. - */ - ignoreError: boolean | undefined; - - /** - * Allows to override the editor that should be used to display the input: - * - `undefined`: let the editor decide for itself - * - `string`: specific override by id - * - `EditorOverride`: specific override handling - */ - override: string | EditorOverride | undefined; - - /** - * A optional hint to signal in which context the editor opens. - * - * If configured to be `EditorOpenContext.USER`, this hint can be - * used in various places to control the experience. For example, - * if the editor to open fails with an error, a notification could - * inform about this in a modal dialog. If the editor opened through - * some background task, the notification would show in the background, - * not as a modal dialog. - */ - context: EditorOpenContext | undefined; - - /** - * Overwrites option values from the provided bag. - */ - overwrite(options: IEditorOptions): EditorOptions { - if (typeof options.forceReload === 'boolean') { - this.forceReload = options.forceReload; - } - - if (typeof options.revealIfVisible === 'boolean') { - this.revealIfVisible = options.revealIfVisible; - } - - if (typeof options.revealIfOpened === 'boolean') { - this.revealIfOpened = options.revealIfOpened; - } - - if (typeof options.preserveFocus === 'boolean') { - this.preserveFocus = options.preserveFocus; - } - - if (typeof options.activation === 'number') { - this.activation = options.activation; - } - - if (typeof options.pinned === 'boolean') { - this.pinned = options.pinned; - } - - if (typeof options.sticky === 'boolean') { - this.sticky = options.sticky; - } - - if (typeof options.inactive === 'boolean') { - this.inactive = options.inactive; - } - - if (typeof options.ignoreError === 'boolean') { - this.ignoreError = options.ignoreError; - } - - if (typeof options.index === 'number') { - this.index = options.index; - } - - if (options.override !== undefined) { - this.override = options.override; - } - - if (typeof options.context === 'number') { - this.context = options.context; - } - - return this; - } -} - -/** - * Base Text Editor Options. - */ -export class TextEditorOptions extends EditorOptions implements ITextEditorOptions { - - /** - * Text editor selection. - */ - selection: ITextEditorSelection | undefined; - - /** - * Text editor view state. - */ - editorViewState: IEditorViewState | undefined; - - /** - * Option to control the text editor selection reveal type. - */ - selectionRevealType: TextEditorSelectionRevealType | undefined; - - static from(input?: IBaseResourceEditorInput): TextEditorOptions | undefined { - if (!input?.options) { - return undefined; - } - - return TextEditorOptions.create(input.options); - } - - /** - * Helper to convert options bag to real class - */ - static override create(options: ITextEditorOptions = Object.create(null)): TextEditorOptions { - const textEditorOptions = new TextEditorOptions(); - textEditorOptions.overwrite(options); - - return textEditorOptions; - } - - /** - * Overwrites option values from the provided bag. - */ - override overwrite(options: ITextEditorOptions): TextEditorOptions { - super.overwrite(options); - - if (options.selection) { - this.selection = { - startLineNumber: options.selection.startLineNumber, - startColumn: options.selection.startColumn, - endLineNumber: options.selection.endLineNumber ?? options.selection.startLineNumber, - endColumn: options.selection.endColumn ?? options.selection.startColumn - }; - } - - if (options.viewState) { - this.editorViewState = options.viewState as IEditorViewState; - } - - if (typeof options.selectionRevealType !== 'undefined') { - this.selectionRevealType = options.selectionRevealType; - } - - return this; - } - - /** - * Returns if this options object has objects defined for the editor. - */ - hasOptionsDefined(): boolean { - return !!this.editorViewState || !!this.selectionRevealType || !!this.selection; - } - - /** - * Create a TextEditorOptions inline to be used when the editor is opening. - */ - static fromEditor(editor: IEditor, settings?: IEditorOptions): TextEditorOptions { - const options = TextEditorOptions.create(settings); - - // View state - options.editorViewState = withNullAsUndefined(editor.saveViewState()); - - return options; - } - - /** - * Apply the view state or selection to the given editor. - * - * @return if something was applied - */ - apply(editor: IEditor, scrollType: ScrollType): boolean { - let gotApplied = false; - - // First try viewstate - if (this.editorViewState) { - editor.restoreViewState(this.editorViewState); - gotApplied = true; - } - - // Otherwise check for selection - else if (this.selection) { - const range: IRange = { - startLineNumber: this.selection.startLineNumber, - startColumn: this.selection.startColumn, - endLineNumber: this.selection.endLineNumber ?? this.selection.startLineNumber, - endColumn: this.selection.endColumn ?? this.selection.startColumn - }; - - editor.setSelection(range); - - if (this.selectionRevealType === TextEditorSelectionRevealType.NearTop) { - editor.revealRangeNearTop(range, scrollType); - } else if (this.selectionRevealType === TextEditorSelectionRevealType.NearTopIfOutsideViewport) { - editor.revealRangeNearTopIfOutsideViewport(range, scrollType); - } else if (this.selectionRevealType === TextEditorSelectionRevealType.CenterIfOutsideViewport) { - editor.revealRangeInCenterIfOutsideViewport(range, scrollType); - } else { - editor.revealRangeInCenter(range, scrollType); - } - - gotApplied = true; - } - - return gotApplied; - } -} - /** * Context passed into `EditorPane#setInput` to give additional * context information around why the editor was opened. @@ -1231,6 +711,15 @@ export interface IEditorIdentifier { editor: IEditorInput; } +export function isEditorIdentifier(thing: unknown): thing is IEditorIdentifier { + const identifier = thing as IEditorIdentifier | undefined; + if (!identifier) { + return false; + } + + return typeof identifier.groupId === 'number' && !isUndefinedOrNull(identifier.editor); +} + /** * The editor commands context is used for editor commands (e.g. in the editor title) * and we must ensure that the context is serializable because it potentially travels @@ -1241,19 +730,6 @@ export interface IEditorCommandsContext { editorIndex?: number; } -export class EditorCommandsContextActionRunner extends ActionRunner { - - constructor( - private context: IEditorCommandsContext - ) { - super(); - } - - override run(action: IAction): Promise { - return super.run(action, this.context); - } -} - export interface IEditorCloseEvent extends IEditorIdentifier { replaced: boolean; index: number; @@ -1264,6 +740,8 @@ export interface IEditorMoveEvent extends IEditorIdentifier { target: GroupIdentifier; } +export interface IEditorOpenEvent extends IEditorIdentifier { } + export type GroupIdentifier = number; export interface IWorkbenchEditorConfiguration { @@ -1366,7 +844,7 @@ class EditorResourceAccessorImpl { } // Optionally support side-by-side editors - if (options?.supportSideBySide && editor instanceof SideBySideEditorInput) { + if (options?.supportSideBySide && isSideBySideEditorInput(editor)) { if (options?.supportSideBySide === SideBySideEditor.BOTH) { return { primary: this.getOriginalUri(editor.primary, { filterByScheme: options.filterByScheme }), @@ -1408,7 +886,7 @@ class EditorResourceAccessorImpl { } // Optionally support side-by-side editors - if (options?.supportSideBySide && editor instanceof SideBySideEditorInput) { + if (options?.supportSideBySide && isSideBySideEditorInput(editor)) { if (options?.supportSideBySide === SideBySideEditor.BOTH) { return { primary: this.getCanonicalUri(editor.primary, { filterByScheme: options.filterByScheme }), @@ -1475,7 +953,6 @@ class EditorInputFactoryRegistry implements IEditorInputFactoryRegistry { private instantiationService: IInstantiationService | undefined; private fileEditorInputFactory: IFileEditorInputFactory | undefined; - private readonly customEditorInputFactoryInstances: Map = new Map(); private readonly editorInputSerializerConstructors: Map> = new Map(); private readonly editorInputSerializerInstances: Map = new Map(); @@ -1529,14 +1006,6 @@ class EditorInputFactoryRegistry implements IEditorInputFactoryRegistry { getEditorInputSerializer(arg1: string | IEditorInput): IEditorInputSerializer | undefined { return this.editorInputSerializerInstances.get(typeof arg1 === 'string' ? arg1 : arg1.typeId); } - - registerCustomEditorInputFactory(scheme: string, factory: ICustomEditorInputFactory): void { - this.customEditorInputFactoryInstances.set(scheme, factory); - } - - getCustomEditorInputFactory(scheme: string): ICustomEditorInputFactory | undefined { - return this.customEditorInputFactoryInstances.get(scheme); - } } Registry.add(EditorExtensions.EditorInputFactories, new EditorInputFactoryRegistry()); diff --git a/lib/vscode/src/vs/workbench/common/editor/binaryEditorModel.ts b/src/vs/workbench/common/editor/binaryEditorModel.ts similarity index 89% rename from lib/vscode/src/vs/workbench/common/editor/binaryEditorModel.ts rename to src/vs/workbench/common/editor/binaryEditorModel.ts index 98bbf9360ba3..7e4e6a7ae46b 100644 --- a/lib/vscode/src/vs/workbench/common/editor/binaryEditorModel.ts +++ b/src/vs/workbench/common/editor/binaryEditorModel.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { EditorModel } from 'vs/workbench/common/editor'; +import { EditorModel } from 'vs/workbench/common/editor/editorModel'; import { URI } from 'vs/base/common/uri'; import { IFileService } from 'vs/platform/files/common/files'; import { MIME_BINARY } from 'vs/base/common/mime'; @@ -12,20 +12,18 @@ import { MIME_BINARY } from 'vs/base/common/mime'; * An editor model that just represents a resource that can be loaded. */ export class BinaryEditorModel extends EditorModel { + + private readonly mime = MIME_BINARY; + private size: number | undefined; private etag: string | undefined; - private readonly mime: string; constructor( - public readonly resource: URI, + readonly resource: URI, private readonly name: string, @IFileService private readonly fileService: IFileService ) { super(); - - this.resource = resource; - this.name = name; - this.mime = MIME_BINARY; } /** diff --git a/lib/vscode/src/vs/workbench/common/editor/diffEditorInput.ts b/src/vs/workbench/common/editor/diffEditorInput.ts similarity index 73% rename from lib/vscode/src/vs/workbench/common/editor/diffEditorInput.ts rename to src/vs/workbench/common/editor/diffEditorInput.ts index 93c0ed19cd2b..83aab2ce17e8 100644 --- a/lib/vscode/src/vs/workbench/common/editor/diffEditorInput.ts +++ b/src/vs/workbench/common/editor/diffEditorInput.ts @@ -3,7 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { EditorModel, EditorInput, SideBySideEditorInput, TEXT_DIFF_EDITOR_ID, BINARY_DIFF_EDITOR_ID, Verbosity } from 'vs/workbench/common/editor'; +import { AbstractSideBySideEditorInputSerializer, SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; +import { EditorModel } from 'vs/workbench/common/editor/editorModel'; +import { TEXT_DIFF_EDITOR_ID, BINARY_DIFF_EDITOR_ID, Verbosity, IEditorDescriptor, IEditorPane, GroupIdentifier, IResourceDiffEditorInput } from 'vs/workbench/common/editor'; import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel'; import { DiffEditorModel } from 'vs/workbench/common/editor/diffEditorModel'; import { TextDiffEditorModel } from 'vs/workbench/common/editor/textDiffEditorModel'; @@ -14,6 +17,7 @@ import { ILabelService } from 'vs/platform/label/common/label'; import { IFileService } from 'vs/platform/files/common/files'; import { URI } from 'vs/base/common/uri'; import { withNullAsUndefined } from 'vs/base/common/types'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; /** * The base editor input for the diff editor. It is made up of two editor inputs, the original version @@ -32,8 +36,8 @@ export class DiffEditorInput extends SideBySideEditorInput { constructor( name: string | undefined, description: string | undefined, - public readonly originalInput: EditorInput, - public readonly modifiedInput: EditorInput, + readonly originalInput: EditorInput, + readonly modifiedInput: EditorInput, private readonly forceOpenAsBinary: boolean | undefined, @ILabelService private readonly labelService: ILabelService, @IFileService private readonly fileService: IFileService @@ -58,7 +62,7 @@ export class DiffEditorInput extends SideBySideEditorInput { return this.name; } - override getDescription(verbosity: Verbosity = Verbosity.MEDIUM): string | undefined { + override getDescription(verbosity = Verbosity.MEDIUM): string | undefined { if (typeof this.description !== 'string') { // Pass the description of the modified side in case both original @@ -104,8 +108,12 @@ export class DiffEditorInput extends SideBySideEditorInput { return this.cachedModel; } - override getPreferredEditorId(candidates: string[]): string { - return this.forceOpenAsBinary ? BINARY_DIFF_EDITOR_ID : TEXT_DIFF_EDITOR_ID; + override prefersEditor>(editors: T[]): T | undefined { + if (this.forceOpenAsBinary) { + return editors.find(editor => editor.typeId === BINARY_DIFF_EDITOR_ID); + } + + return editors.find(editor => editor.typeId === TEXT_DIFF_EDITOR_ID); } private async createModel(): Promise { @@ -125,6 +133,22 @@ export class DiffEditorInput extends SideBySideEditorInput { return new DiffEditorModel(withNullAsUndefined(originalEditorModel), withNullAsUndefined(modifiedEditorModel)); } + override asResourceEditorInput(groupId: GroupIdentifier): IResourceDiffEditorInput | undefined { + const originalResourceEditorInput = this.secondary.asResourceEditorInput(groupId); + const modifiedResourceEditorInput = this.primary.asResourceEditorInput(groupId); + + if (originalResourceEditorInput && modifiedResourceEditorInput) { + return { + label: this.name, + description: this.description, + originalInput: originalResourceEditorInput, + modifiedInput: modifiedResourceEditorInput + }; + } + + return undefined; + } + override matches(otherInput: unknown): boolean { if (!super.matches(otherInput)) { return false; @@ -146,3 +170,10 @@ export class DiffEditorInput extends SideBySideEditorInput { super.dispose(); } } + +export class DiffEditorInputSerializer extends AbstractSideBySideEditorInputSerializer { + + protected createEditorInput(instantiationService: IInstantiationService, name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput { + return instantiationService.createInstance(DiffEditorInput, name, description, secondaryInput, primaryInput, undefined); + } +} diff --git a/lib/vscode/src/vs/workbench/common/editor/diffEditorModel.ts b/src/vs/workbench/common/editor/diffEditorModel.ts similarity index 96% rename from lib/vscode/src/vs/workbench/common/editor/diffEditorModel.ts rename to src/vs/workbench/common/editor/diffEditorModel.ts index 9de37bf7e02a..cddd3bbb0fb5 100644 --- a/lib/vscode/src/vs/workbench/common/editor/diffEditorModel.ts +++ b/src/vs/workbench/common/editor/diffEditorModel.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { EditorModel } from 'vs/workbench/common/editor'; +import { EditorModel } from 'vs/workbench/common/editor/editorModel'; import { IEditorModel } from 'vs/platform/editor/common/editor'; /** diff --git a/lib/vscode/src/vs/workbench/common/editor/editorGroupModel.ts b/src/vs/workbench/common/editor/editorGroupModel.ts similarity index 96% rename from lib/vscode/src/vs/workbench/common/editor/editorGroupModel.ts rename to src/vs/workbench/common/editor/editorGroupModel.ts index 85076d88d213..ec7c3b4ca397 100644 --- a/lib/vscode/src/vs/workbench/common/editor/editorGroupModel.ts +++ b/src/vs/workbench/common/editor/editorGroupModel.ts @@ -4,7 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import { Event, Emitter } from 'vs/base/common/event'; -import { IEditorInputFactoryRegistry, EditorInput, IEditorIdentifier, IEditorCloseEvent, GroupIdentifier, SideBySideEditorInput, IEditorInput, EditorsOrder, EditorExtensions } from 'vs/workbench/common/editor'; +import { IEditorInputFactoryRegistry, IEditorIdentifier, IEditorCloseEvent, GroupIdentifier, IEditorInput, EditorsOrder, EditorExtensions } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; +import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; @@ -80,7 +82,10 @@ export class EditorGroupModel extends Disposable { readonly onDidChangeEditorDirty = this._onDidChangeEditorDirty.event; private readonly _onDidChangeEditorLabel = this._register(new Emitter()); - readonly onDidEditorLabelChange = this._onDidChangeEditorLabel.event; + readonly onDidChangeEditorLabel = this._onDidChangeEditorLabel.event; + + private readonly _onDidChangeEditorCapabilities = this._register(new Emitter()); + readonly onDidChangeEditorCapabilities = this._onDidChangeEditorCapabilities.event; private readonly _onDidMoveEditor = this._register(new Emitter()); readonly onDidMoveEditor = this._onDidMoveEditor.event; @@ -331,6 +336,11 @@ export class EditorGroupModel extends Disposable { this._onDidChangeEditorLabel.fire(editor); })); + // Re-Emit capability changes + listeners.add(editor.onDidChangeCapabilities(() => { + this._onDidChangeEditorCapabilities.fire(editor); + })); + // Clean up dispose listeners once the editor gets closed listeners.add(this.onDidCloseEditor(event => { if (event.editor.matches(editor)) { @@ -810,8 +820,9 @@ export class EditorGroupModel extends Disposable { const editorSerializer = registry.getEditorInputSerializer(e.id); if (editorSerializer) { - editor = editorSerializer.deserialize(this.instantiationService, e.value); - if (editor) { + const deserializedEditor = editorSerializer.deserialize(this.instantiationService, e.value); + if (deserializedEditor instanceof EditorInput) { + editor = deserializedEditor; this.registerEditorListeners(editor); } } diff --git a/src/vs/workbench/common/editor/editorInput.ts b/src/vs/workbench/common/editor/editorInput.ts new file mode 100644 index 000000000000..82250013fff8 --- /dev/null +++ b/src/vs/workbench/common/editor/editorInput.ts @@ -0,0 +1,140 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Emitter } from 'vs/base/common/event'; +import { URI } from 'vs/base/common/uri'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IBaseResourceEditorInput, IEditorModel } from 'vs/platform/editor/common/editor'; +import { firstOrDefault } from 'vs/base/common/arrays'; +import { IEditorInput, EditorInputCapabilities, Verbosity, GroupIdentifier, ISaveOptions, IRevertOptions, IMoveResult, IEditorDescriptor, IEditorPane } from 'vs/workbench/common/editor'; + +/** + * Editor inputs are lightweight objects that can be passed to the workbench API to open inside the editor part. + * Each editor input is mapped to an editor that is capable of opening it through the Platform facade. + */ +export abstract class EditorInput extends Disposable implements IEditorInput { + + protected readonly _onDidChangeDirty = this._register(new Emitter()); + readonly onDidChangeDirty = this._onDidChangeDirty.event; + + protected readonly _onDidChangeLabel = this._register(new Emitter()); + readonly onDidChangeLabel = this._onDidChangeLabel.event; + + protected readonly _onDidChangeCapabilities = this._register(new Emitter()); + readonly onDidChangeCapabilities = this._onDidChangeCapabilities.event; + + private readonly _onWillDispose = this._register(new Emitter()); + readonly onWillDispose = this._onWillDispose.event; + + private disposed: boolean = false; + + abstract get typeId(): string; + + abstract get resource(): URI | undefined; + + get capabilities(): EditorInputCapabilities { + return EditorInputCapabilities.Readonly; + } + + hasCapability(capability: EditorInputCapabilities): boolean { + if (capability === EditorInputCapabilities.None) { + return this.capabilities === EditorInputCapabilities.None; + } + + return (this.capabilities & capability) !== 0; + } + + getName(): string { + return `Editor ${this.typeId}`; + } + + getDescription(verbosity?: Verbosity): string | undefined { + return undefined; + } + + getTitle(verbosity?: Verbosity): string { + return this.getName(); + } + + getAriaLabel(): string { + return this.getTitle(Verbosity.SHORT); + } + + /** + * Returns a descriptor suitable for telemetry events. + * + * Subclasses should extend if they can contribute. + */ + getTelemetryDescriptor(): { [key: string]: unknown } { + /* __GDPR__FRAGMENT__ + "EditorTelemetryDescriptor" : { + "typeId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + return { typeId: this.typeId }; + } + + isDirty(): boolean { + return false; + } + + isSaving(): boolean { + return false; + } + + async resolve(): Promise { + return null; + } + + async save(group: GroupIdentifier, options?: ISaveOptions): Promise { + return this; + } + + async saveAs(group: GroupIdentifier, options?: ISaveOptions): Promise { + return this; + } + + async revert(group: GroupIdentifier, options?: IRevertOptions): Promise { } + + rename(group: GroupIdentifier, target: URI): IMoveResult | undefined { + return undefined; + } + + copy(): IEditorInput { + return this; + } + + matches(otherInput: unknown): boolean { + return this === otherInput; + } + + /** + * If a input was registered onto multiple editors, this method + * will be asked to return the preferred one to use. + * + * @param editors a list of editor descriptors that are candidates + * for the editor input to open in. + */ + prefersEditor>(editors: T[]): T | undefined { + return firstOrDefault(editors); + } + + asResourceEditorInput(groupId: GroupIdentifier): IBaseResourceEditorInput | undefined { + return undefined; + } + + isDisposed(): boolean { + return this.disposed; + } + + override dispose(): void { + if (!this.disposed) { + this.disposed = true; + this._onWillDispose.fire(); + } + + super.dispose(); + } +} diff --git a/src/vs/workbench/common/editor/editorModel.ts b/src/vs/workbench/common/editor/editorModel.ts new file mode 100644 index 000000000000..ae5ba0d1cc34 --- /dev/null +++ b/src/vs/workbench/common/editor/editorModel.ts @@ -0,0 +1,53 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Emitter } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IEditorModel } from 'vs/platform/editor/common/editor'; + +/** + * The editor model is the heavyweight counterpart of editor input. Depending on the editor input, it + * resolves from a file system retrieve content and may allow for saving it back or reverting it. + * Editor models are typically cached for some while because they are expensive to construct. + */ +export class EditorModel extends Disposable implements IEditorModel { + + private readonly _onWillDispose = this._register(new Emitter()); + readonly onWillDispose = this._onWillDispose.event; + + private disposed = false; + private resolved = false; + + /** + * Causes this model to resolve returning a promise when loading is completed. + */ + async resolve(): Promise { + this.resolved = true; + } + + /** + * Returns whether this model was loaded or not. + */ + isResolved(): boolean { + return this.resolved; + } + + /** + * Find out if this model has been disposed. + */ + isDisposed(): boolean { + return this.disposed; + } + + /** + * Subclasses should implement to free resources that have been claimed through loading. + */ + override dispose(): void { + this.disposed = true; + this._onWillDispose.fire(); + + super.dispose(); + } +} diff --git a/src/vs/workbench/common/editor/editorOptions.ts b/src/vs/workbench/common/editor/editorOptions.ts new file mode 100644 index 000000000000..a9113b39f742 --- /dev/null +++ b/src/vs/workbench/common/editor/editorOptions.ts @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IRange } from 'vs/editor/common/core/range'; +import { IEditor, IEditorViewState, ScrollType } from 'vs/editor/common/editorCommon'; +import { ITextEditorOptions, TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor'; + +export function applyTextEditorOptions(options: ITextEditorOptions, editor: IEditor, scrollType: ScrollType): boolean { + + // First try viewstate + if (options.viewState) { + editor.restoreViewState(options.viewState as IEditorViewState); + + return true; + } + + // Otherwise check for selection + else if (options.selection) { + const range: IRange = { + startLineNumber: options.selection.startLineNumber, + startColumn: options.selection.startColumn, + endLineNumber: options.selection.endLineNumber ?? options.selection.startLineNumber, + endColumn: options.selection.endColumn ?? options.selection.startColumn + }; + + editor.setSelection(range); + + if (options.selectionRevealType === TextEditorSelectionRevealType.NearTop) { + editor.revealRangeNearTop(range, scrollType); + } else if (options.selectionRevealType === TextEditorSelectionRevealType.NearTopIfOutsideViewport) { + editor.revealRangeNearTopIfOutsideViewport(range, scrollType); + } else if (options.selectionRevealType === TextEditorSelectionRevealType.CenterIfOutsideViewport) { + editor.revealRangeInCenterIfOutsideViewport(range, scrollType); + } else { + editor.revealRangeInCenter(range, scrollType); + } + + return true; + } + + return false; +} diff --git a/lib/vscode/src/vs/workbench/common/editor/textResourceEditorInput.ts b/src/vs/workbench/common/editor/resourceEditorInput.ts similarity index 50% rename from lib/vscode/src/vs/workbench/common/editor/textResourceEditorInput.ts rename to src/vs/workbench/common/editor/resourceEditorInput.ts index 26d5f3fff5ea..c0564f712efc 100644 --- a/lib/vscode/src/vs/workbench/common/editor/textResourceEditorInput.ts +++ b/src/vs/workbench/common/editor/resourceEditorInput.ts @@ -3,34 +3,41 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { EditorInput, Verbosity, GroupIdentifier, IEditorInput, IRevertOptions, IEditorInputWithPreferredResource } from 'vs/workbench/common/editor'; +import { localize } from 'vs/nls'; +import { Verbosity, IEditorInputWithPreferredResource, EditorInputCapabilities } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { URI } from 'vs/base/common/uri'; -import { ITextFileService, ITextFileSaveOptions } from 'vs/workbench/services/textfile/common/textfiles'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IFileService, FileSystemProviderCapabilities } from 'vs/platform/files/common/files'; import { ILabelService } from 'vs/platform/label/common/label'; -import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; -import { Schemas } from 'vs/base/common/network'; import { dirname, isEqual } from 'vs/base/common/resources'; /** - * The base class for all editor inputs that open in text editors. + * The base class for all editor inputs that open resources. */ -export abstract class AbstractTextResourceEditorInput extends EditorInput implements IEditorInputWithPreferredResource { +export abstract class AbstractResourceEditorInput extends EditorInput implements IEditorInputWithPreferredResource { + + override get capabilities(): EditorInputCapabilities { + let capabilities = EditorInputCapabilities.None; + + if (this.fileService.canHandleResource(this.resource)) { + if (this.fileService.hasCapability(this.resource, FileSystemProviderCapabilities.Readonly)) { + capabilities |= EditorInputCapabilities.Readonly; + } + } else { + capabilities |= EditorInputCapabilities.Untitled; + } + + return capabilities; + } private _preferredResource: URI; get preferredResource(): URI { return this._preferredResource; } constructor( - public readonly resource: URI, + readonly resource: URI, preferredResource: URI | undefined, - @IEditorService protected readonly editorService: IEditorService, - @IEditorGroupsService protected readonly editorGroupService: IEditorGroupsService, - @ITextFileService protected readonly textFileService: ITextFileService, @ILabelService protected readonly labelService: ILabelService, - @IFileService protected readonly fileService: IFileService, - @IFilesConfigurationService protected readonly filesConfigurationService: IFilesConfigurationService + @IFileService protected readonly fileService: IFileService ) { super(); @@ -39,9 +46,9 @@ export abstract class AbstractTextResourceEditorInput extends EditorInput implem this.registerListeners(); } - protected registerListeners(): void { + private registerListeners(): void { - // Clear label memoizer on certain events that have impact + // Clear our labels on certain label related events this._register(this.labelService.onDidChangeFormatters(e => this.onLabelEvent(e.scheme))); this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(e => this.onLabelEvent(e.scheme))); this._register(this.fileService.onDidChangeFileSystemProviderCapabilities(e => this.onLabelEvent(e.scheme))); @@ -77,15 +84,15 @@ export abstract class AbstractTextResourceEditorInput extends EditorInput implem } private _name: string | undefined = undefined; - override getName(): string { + override getName(skipDecorate?: boolean): string { if (typeof this._name !== 'string') { this._name = this.labelService.getUriBasenameLabel(this._preferredResource); } - return this._name; + return skipDecorate ? this._name : this.decorateLabel(this._name); } - override getDescription(verbosity: Verbosity = Verbosity.MEDIUM): string | undefined { + override getDescription(verbosity = Verbosity.MEDIUM): string | undefined { switch (verbosity) { case Verbosity.SHORT: return this.shortDescription; @@ -127,7 +134,7 @@ export abstract class AbstractTextResourceEditorInput extends EditorInput implem private _shortTitle: string | undefined = undefined; private get shortTitle(): string { if (typeof this._shortTitle !== 'string') { - this._shortTitle = this.getName(); + this._shortTitle = this.getName(true /* skip decorations */); } return this._shortTitle; @@ -151,89 +158,42 @@ export abstract class AbstractTextResourceEditorInput extends EditorInput implem return this._longTitle; } - override getTitle(verbosity: Verbosity): string { + override getTitle(verbosity?: Verbosity): string { switch (verbosity) { case Verbosity.SHORT: - return this.shortTitle; + return this.decorateLabel(this.shortTitle); case Verbosity.LONG: - return this.longTitle; + return this.decorateLabel(this.longTitle); default: case Verbosity.MEDIUM: - return this.mediumTitle; + return this.decorateLabel(this.mediumTitle); } } - override isUntitled(): boolean { - // any file: is never untitled as it can be saved - // untitled: is untitled by definition - // any other: is untitled because it cannot be saved, as such we expect a "Save As" dialog - return !this.fileService.canHandleResource(this.resource); - } + private decorateLabel(label: string): string { + const readonly = this.hasCapability(EditorInputCapabilities.Readonly); + const orphaned = this.isOrphaned(); - override isReadonly(): boolean { - if (this.isUntitled()) { - return false; // untitled is never readonly - } - - return this.fileService.hasCapability(this.resource, FileSystemProviderCapabilities.Readonly); + return decorateFileEditorLabel(label, { orphaned, readonly }); } - override isSaving(): boolean { - if (this.isUntitled()) { - return false; // untitled is never saving automatically - } - - if (this.filesConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { - return true; // a short auto save is configured, treat this as being saved - } - + isOrphaned(): boolean { return false; } +} - override save(group: GroupIdentifier, options?: ITextFileSaveOptions): Promise { - - // If this is neither an `untitled` resource, nor a resource - // we can handle with the file service, we can only "Save As..." - if (this.resource.scheme !== Schemas.untitled && !this.fileService.canHandleResource(this.resource)) { - return this.saveAs(group, options); - } - - // Normal save - return this.doSave(options, false); +export function decorateFileEditorLabel(label: string, state: { orphaned: boolean, readonly: boolean }): string { + if (state.orphaned && state.readonly) { + return localize('orphanedReadonlyFile', "{0} (deleted, read-only)", label); } - override saveAs(group: GroupIdentifier, options?: ITextFileSaveOptions): Promise { - return this.doSave(options, true); + if (state.orphaned) { + return localize('orphanedFile', "{0} (deleted)", label); } - private async doSave(options: ITextFileSaveOptions | undefined, saveAs: boolean): Promise { - - // Save / Save As - let target: URI | undefined; - if (saveAs) { - target = await this.textFileService.saveAs(this.resource, undefined, { ...options, suggestedTarget: this.preferredResource }); - } else { - target = await this.textFileService.save(this.resource, options); - } - - if (!target) { - return undefined; // save cancelled - } - - // If this save operation results in a new editor, either - // because it was saved to disk (e.g. from untitled) or - // through an explicit "Save As", make sure to replace it. - if ( - target.scheme !== this.resource.scheme || - (saveAs && !isEqual(target, this.preferredResource)) - ) { - return this.editorService.createEditorInput({ resource: target }); - } - - return this; + if (state.readonly) { + return localize('readonlyFile', "{0} (read-only)", label); } - override async revert(group: GroupIdentifier, options?: IRevertOptions): Promise { - await this.textFileService.revert(this.resource, options); - } + return label; } diff --git a/src/vs/workbench/common/editor/sideBySideEditorInput.ts b/src/vs/workbench/common/editor/sideBySideEditorInput.ts new file mode 100644 index 000000000000..2eafa406afd3 --- /dev/null +++ b/src/vs/workbench/common/editor/sideBySideEditorInput.ts @@ -0,0 +1,227 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { URI } from 'vs/base/common/uri'; +import { localize } from 'vs/nls'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IEditorInput, EditorInputCapabilities, GroupIdentifier, ISaveOptions, IRevertOptions, EditorExtensions, IEditorInputFactoryRegistry, IEditorInputSerializer, ISideBySideEditorInput } from 'vs/workbench/common/editor'; +import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; + +/** + * Side by side editor inputs that have a primary and secondary side. + */ +export class SideBySideEditorInput extends EditorInput implements ISideBySideEditorInput { + + static readonly ID: string = 'workbench.editorinputs.sidebysideEditorInput'; + + override get typeId(): string { + return SideBySideEditorInput.ID; + } + + override get capabilities(): EditorInputCapabilities { + + // Use primary capabilities as main capabilities + let capabilities = this._primary.capabilities; + + // Trust: should be considered for both sides + if (this._secondary.hasCapability(EditorInputCapabilities.RequiresTrust)) { + capabilities |= EditorInputCapabilities.RequiresTrust; + } + + // Singleton: should be considered for both sides + if (this._secondary.hasCapability(EditorInputCapabilities.Singleton)) { + capabilities |= EditorInputCapabilities.Singleton; + } + + return capabilities; + } + + get resource(): URI | undefined { + return undefined; // use `EditorResourceAccessor` to obtain one side's resource + } + + get primary(): EditorInput { + return this._primary; + } + + get secondary(): EditorInput { + return this._secondary; + } + + constructor( + protected readonly name: string | undefined, + protected readonly description: string | undefined, + private readonly _secondary: EditorInput, + private readonly _primary: EditorInput + ) { + super(); + + this.registerListeners(); + } + + private registerListeners(): void { + + // When the primary or secondary input gets disposed, dispose this diff editor input + const onceSecondaryDisposed = Event.once(this.secondary.onWillDispose); + this._register(onceSecondaryDisposed(() => { + if (!this.isDisposed()) { + this.dispose(); + } + })); + + const oncePrimaryDisposed = Event.once(this.primary.onWillDispose); + this._register(oncePrimaryDisposed(() => { + if (!this.isDisposed()) { + this.dispose(); + } + })); + + // Re-emit some events from the primary side to the outside + this._register(this.primary.onDidChangeDirty(() => this._onDidChangeDirty.fire())); + this._register(this.primary.onDidChangeLabel(() => this._onDidChangeLabel.fire())); + + // Re-emit some events from both sides to the outside + this._register(this.primary.onDidChangeCapabilities(() => this._onDidChangeCapabilities.fire())); + this._register(this.secondary.onDidChangeCapabilities(() => this._onDidChangeCapabilities.fire())); + } + + override getName(): string { + if (!this.name) { + return localize('sideBySideLabels', "{0} - {1}", this._secondary.getName(), this._primary.getName()); + } + + return this.name; + } + + override getDescription(): string | undefined { + return this.description; + } + + override getTelemetryDescriptor(): { [key: string]: unknown } { + const descriptor = this.primary.getTelemetryDescriptor(); + + return { ...descriptor, ...super.getTelemetryDescriptor() }; + } + + override isDirty(): boolean { + return this.primary.isDirty(); + } + + override isSaving(): boolean { + return this.primary.isSaving(); + } + + override save(group: GroupIdentifier, options?: ISaveOptions): Promise { + return this.primary.save(group, options); + } + + override saveAs(group: GroupIdentifier, options?: ISaveOptions): Promise { + return this.primary.saveAs(group, options); + } + + override revert(group: GroupIdentifier, options?: IRevertOptions): Promise { + return this.primary.revert(group, options); + } + + override matches(otherInput: unknown): boolean { + if (super.matches(otherInput)) { + return true; + } + + if (otherInput instanceof SideBySideEditorInput) { + return this.primary.matches(otherInput.primary) && this.secondary.matches(otherInput.secondary); + } + + return false; + } +} + +// Register SideBySide/DiffEditor Input Serializer +interface ISerializedSideBySideEditorInput { + name: string; + description: string | undefined; + + primarySerialized: string; + secondarySerialized: string; + + primaryTypeId: string; + secondaryTypeId: string; +} + +export abstract class AbstractSideBySideEditorInputSerializer implements IEditorInputSerializer { + + private getInputSerializers(secondaryEditorInputTypeId: string, primaryEditorInputTypeId: string): [IEditorInputSerializer | undefined, IEditorInputSerializer | undefined] { + const registry = Registry.as(EditorExtensions.EditorInputFactories); + + return [registry.getEditorInputSerializer(secondaryEditorInputTypeId), registry.getEditorInputSerializer(primaryEditorInputTypeId)]; + } + + canSerialize(editorInput: EditorInput): boolean { + const input = editorInput as SideBySideEditorInput | DiffEditorInput; + + if (input.primary && input.secondary) { + const [secondaryInputSerializer, primaryInputSerializer] = this.getInputSerializers(input.secondary.typeId, input.primary.typeId); + + return !!(secondaryInputSerializer?.canSerialize(input.secondary) && primaryInputSerializer?.canSerialize(input.primary)); + } + + return false; + } + + serialize(editorInput: EditorInput): string | undefined { + const input = editorInput as SideBySideEditorInput; + + if (input.primary && input.secondary) { + const [secondaryInputSerializer, primaryInputSerializer] = this.getInputSerializers(input.secondary.typeId, input.primary.typeId); + if (primaryInputSerializer && secondaryInputSerializer) { + const primarySerialized = primaryInputSerializer.serialize(input.primary); + const secondarySerialized = secondaryInputSerializer.serialize(input.secondary); + + if (primarySerialized && secondarySerialized) { + const serializedEditorInput: ISerializedSideBySideEditorInput = { + name: input.getName(), + description: input.getDescription(), + primarySerialized: primarySerialized, + secondarySerialized: secondarySerialized, + primaryTypeId: input.primary.typeId, + secondaryTypeId: input.secondary.typeId + }; + + return JSON.stringify(serializedEditorInput); + } + } + } + + return undefined; + } + + deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput | undefined { + const deserialized: ISerializedSideBySideEditorInput = JSON.parse(serializedEditorInput); + + const [secondaryInputSerializer, primaryInputSerializer] = this.getInputSerializers(deserialized.secondaryTypeId, deserialized.primaryTypeId); + if (primaryInputSerializer && secondaryInputSerializer) { + const primaryInput = primaryInputSerializer.deserialize(instantiationService, deserialized.primarySerialized); + const secondaryInput = secondaryInputSerializer.deserialize(instantiationService, deserialized.secondarySerialized); + + if (primaryInput instanceof EditorInput && secondaryInput instanceof EditorInput) { + return this.createEditorInput(instantiationService, deserialized.name, deserialized.description, secondaryInput, primaryInput); + } + } + + return undefined; + } + + protected abstract createEditorInput(instantiationService: IInstantiationService, name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput; +} + +export class SideBySideEditorInputSerializer extends AbstractSideBySideEditorInputSerializer { + + protected createEditorInput(instantiationService: IInstantiationService, name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput { + return new SideBySideEditorInput(name, description, secondaryInput, primaryInput); + } +} diff --git a/lib/vscode/src/vs/workbench/common/editor/textDiffEditorModel.ts b/src/vs/workbench/common/editor/textDiffEditorModel.ts similarity index 100% rename from lib/vscode/src/vs/workbench/common/editor/textDiffEditorModel.ts rename to src/vs/workbench/common/editor/textDiffEditorModel.ts diff --git a/lib/vscode/src/vs/workbench/common/editor/textEditorModel.ts b/src/vs/workbench/common/editor/textEditorModel.ts similarity index 98% rename from lib/vscode/src/vs/workbench/common/editor/textEditorModel.ts rename to src/vs/workbench/common/editor/textEditorModel.ts index e7bd48733ce7..bff2d6e78f57 100644 --- a/lib/vscode/src/vs/workbench/common/editor/textEditorModel.ts +++ b/src/vs/workbench/common/editor/textEditorModel.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ITextModel, ITextBufferFactory, ITextSnapshot, ModelConstants } from 'vs/editor/common/model'; -import { EditorModel } from 'vs/workbench/common/editor'; +import { EditorModel } from 'vs/workbench/common/editor/editorModel'; import { IModeSupport } from 'vs/workbench/services/textfile/common/textfiles'; import { URI } from 'vs/base/common/uri'; import { ITextEditorModel, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService'; diff --git a/src/vs/workbench/common/editor/textResourceEditorInput.ts b/src/vs/workbench/common/editor/textResourceEditorInput.ts new file mode 100644 index 000000000000..487c19fe3913 --- /dev/null +++ b/src/vs/workbench/common/editor/textResourceEditorInput.ts @@ -0,0 +1,226 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { GroupIdentifier, IEditorInput, IRevertOptions, isTextEditorPane } from 'vs/workbench/common/editor'; +import { AbstractResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; +import { URI } from 'vs/base/common/uri'; +import { ITextFileService, ITextFileSaveOptions, IModeSupport } from 'vs/workbench/services/textfile/common/textfiles'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IFileService } from 'vs/platform/files/common/files'; +import { ILabelService } from 'vs/platform/label/common/label'; +import { Schemas } from 'vs/base/common/network'; +import { isEqual } from 'vs/base/common/resources'; +import { ITextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; +import { TextResourceEditorModel } from 'vs/workbench/common/editor/textResourceEditorModel'; +import { IReference } from 'vs/base/common/lifecycle'; +import { IEditorViewState } from 'vs/editor/common/editorCommon'; +import { createTextBufferFactory } from 'vs/editor/common/model/textModel'; + +/** + * The base class for all editor inputs that open in text editors. + */ +export abstract class AbstractTextResourceEditorInput extends AbstractResourceEditorInput { + + constructor( + resource: URI, + preferredResource: URI | undefined, + @IEditorService protected readonly editorService: IEditorService, + @ITextFileService protected readonly textFileService: ITextFileService, + @ILabelService labelService: ILabelService, + @IFileService fileService: IFileService + ) { + super(resource, preferredResource, labelService, fileService); + } + + override save(group: GroupIdentifier, options?: ITextFileSaveOptions): Promise { + + // If this is neither an `untitled` resource, nor a resource + // we can handle with the file service, we can only "Save As..." + if (this.resource.scheme !== Schemas.untitled && !this.fileService.canHandleResource(this.resource)) { + return this.saveAs(group, options); + } + + // Normal save + return this.doSave(options, false); + } + + override saveAs(group: GroupIdentifier, options?: ITextFileSaveOptions): Promise { + return this.doSave(options, true); + } + + private async doSave(options: ITextFileSaveOptions | undefined, saveAs: boolean): Promise { + + // Save / Save As + let target: URI | undefined; + if (saveAs) { + target = await this.textFileService.saveAs(this.resource, undefined, { ...options, suggestedTarget: this.preferredResource }); + } else { + target = await this.textFileService.save(this.resource, options); + } + + if (!target) { + return undefined; // save cancelled + } + + // If this save operation results in a new editor, either + // because it was saved to disk (e.g. from untitled) or + // through an explicit "Save As", make sure to replace it. + if ( + target.scheme !== this.resource.scheme || + (saveAs && !isEqual(target, this.preferredResource)) + ) { + return this.editorService.createEditorInput({ resource: target }); + } + + return this; + } + + override async revert(group: GroupIdentifier, options?: IRevertOptions): Promise { + await this.textFileService.revert(this.resource, options); + } + + protected getViewStateFor(group: GroupIdentifier): IEditorViewState | undefined { + for (const editorPane of this.editorService.visibleEditorPanes) { + if (editorPane.group.id === group && this.matches(editorPane.input)) { + if (isTextEditorPane(editorPane)) { + return editorPane.getViewState(); + } + } + } + + return undefined; + } +} + +/** + * A read-only text editor input whos contents are made of the provided resource that points to an existing + * code editor model. + */ +export class TextResourceEditorInput extends AbstractTextResourceEditorInput implements IModeSupport { + + static readonly ID: string = 'workbench.editors.resourceEditorInput'; + + override get typeId(): string { + return TextResourceEditorInput.ID; + } + + private cachedModel: TextResourceEditorModel | undefined = undefined; + private modelReference: Promise> | undefined = undefined; + + constructor( + resource: URI, + private name: string | undefined, + private description: string | undefined, + private preferredMode: string | undefined, + private preferredContents: string | undefined, + @ITextModelService private readonly textModelResolverService: ITextModelService, + @ITextFileService textFileService: ITextFileService, + @IEditorService editorService: IEditorService, + @IFileService fileService: IFileService, + @ILabelService labelService: ILabelService + ) { + super(resource, undefined, editorService, textFileService, labelService, fileService); + } + + override getName(): string { + return this.name || super.getName(); + } + + setName(name: string): void { + if (this.name !== name) { + this.name = name; + + this._onDidChangeLabel.fire(); + } + } + + override getDescription(): string | undefined { + return this.description; + } + + setDescription(description: string): void { + if (this.description !== description) { + this.description = description; + + this._onDidChangeLabel.fire(); + } + } + + setMode(mode: string): void { + this.setPreferredMode(mode); + + if (this.cachedModel) { + this.cachedModel.setMode(mode); + } + } + + setPreferredMode(mode: string): void { + this.preferredMode = mode; + } + + setPreferredContents(contents: string): void { + this.preferredContents = contents; + } + + override async resolve(): Promise { + + // Unset preferred contents and mode after resolving + // once to prevent these properties to stick. We still + // want the user to change the language mode in the editor + // and want to show updated contents (if any) in future + // `resolve` calls. + const preferredContents = this.preferredContents; + const preferredMode = this.preferredMode; + this.preferredContents = undefined; + this.preferredMode = undefined; + + if (!this.modelReference) { + this.modelReference = this.textModelResolverService.createModelReference(this.resource); + } + + const ref = await this.modelReference; + + // Ensure the resolved model is of expected type + const model = ref.object; + if (!(model instanceof TextResourceEditorModel)) { + ref.dispose(); + this.modelReference = undefined; + + throw new Error(`Unexpected model for TextResourceEditorInput: ${this.resource}`); + } + + this.cachedModel = model; + + // Set contents and mode if preferred + if (typeof preferredContents === 'string' || typeof preferredMode === 'string') { + model.updateTextEditorModel(typeof preferredContents === 'string' ? createTextBufferFactory(preferredContents) : undefined, preferredMode); + } + + return model; + } + + override matches(otherInput: unknown): boolean { + if (super.matches(otherInput)) { + return true; + } + + if (otherInput instanceof TextResourceEditorInput) { + return isEqual(otherInput.resource, this.resource); + } + + return false; + } + + override dispose(): void { + if (this.modelReference) { + this.modelReference.then(ref => ref.dispose()); + this.modelReference = undefined; + } + + this.cachedModel = undefined; + + super.dispose(); + } +} diff --git a/lib/vscode/src/vs/workbench/common/editor/resourceEditorModel.ts b/src/vs/workbench/common/editor/textResourceEditorModel.ts similarity index 85% rename from lib/vscode/src/vs/workbench/common/editor/resourceEditorModel.ts rename to src/vs/workbench/common/editor/textResourceEditorModel.ts index 661bbe6496f3..6dab1e29f61b 100644 --- a/lib/vscode/src/vs/workbench/common/editor/resourceEditorModel.ts +++ b/src/vs/workbench/common/editor/textResourceEditorModel.ts @@ -9,9 +9,10 @@ import { IModeService } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; /** - * An editor model for in-memory, readonly content that is backed by an existing editor model. + * An editor model for in-memory, readonly text content that + * is backed by an existing editor model. */ -export class ResourceEditorModel extends BaseTextEditorModel { +export class TextResourceEditorModel extends BaseTextEditorModel { constructor( resource: URI, diff --git a/lib/vscode/src/vs/workbench/common/memento.ts b/src/vs/workbench/common/memento.ts similarity index 100% rename from lib/vscode/src/vs/workbench/common/memento.ts rename to src/vs/workbench/common/memento.ts diff --git a/lib/vscode/src/vs/workbench/common/notifications.ts b/src/vs/workbench/common/notifications.ts similarity index 99% rename from lib/vscode/src/vs/workbench/common/notifications.ts rename to src/vs/workbench/common/notifications.ts index fb465bf963ce..c718fbc18f90 100644 --- a/lib/vscode/src/vs/workbench/common/notifications.ts +++ b/src/vs/workbench/common/notifications.ts @@ -619,13 +619,17 @@ export class NotificationViewItem extends Disposable implements INotificationVie } updateSeverity(severity: Severity): void { + if (severity === this._severity) { + return; + } + this._severity = severity; this._onDidChangeContent.fire({ kind: NotificationViewItemContentChangeKind.SEVERITY }); } updateMessage(input: NotificationMessage): void { const message = NotificationViewItem.parseNotificationMessage(input); - if (!message) { + if (!message || message.raw === this._message.raw) { return; } diff --git a/lib/vscode/src/vs/workbench/common/panecomposite.ts b/src/vs/workbench/common/panecomposite.ts similarity index 100% rename from lib/vscode/src/vs/workbench/common/panecomposite.ts rename to src/vs/workbench/common/panecomposite.ts diff --git a/lib/vscode/src/vs/workbench/common/panel.ts b/src/vs/workbench/common/panel.ts similarity index 100% rename from lib/vscode/src/vs/workbench/common/panel.ts rename to src/vs/workbench/common/panel.ts diff --git a/lib/vscode/src/vs/workbench/common/resources.ts b/src/vs/workbench/common/resources.ts similarity index 97% rename from lib/vscode/src/vs/workbench/common/resources.ts rename to src/vs/workbench/common/resources.ts index 98001944a374..f99661f7ea79 100644 --- a/lib/vscode/src/vs/workbench/common/resources.ts +++ b/src/vs/workbench/common/resources.ts @@ -16,7 +16,6 @@ import { ParsedExpression, IExpression, parse } from 'vs/base/common/glob'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { withNullAsUndefined } from 'vs/base/common/types'; -import { Schemas } from 'vs/base/common/network'; export class ResourceContextKey extends Disposable implements IContextKey { @@ -76,8 +75,7 @@ export class ResourceContextKey extends Disposable implements IContextKey { if (!ResourceContextKey._uriEquals(this._resourceKey.get(), value)) { this._contextKeyService.bufferChangeEvents(() => { this._resourceKey.set(value); - // NOTE@coder: Fixes source control context menus (#1104). - this._schemeKey.set(value ? (value.scheme === Schemas.vscodeRemote ? Schemas.file : value.scheme) : null); + this._schemeKey.set(value ? value.scheme : null); this._filenameKey.set(value ? basename(value) : null); this._dirnameKey.set(value ? dirname(value).fsPath : null); this._pathKey.set(value ? value.fsPath : null); diff --git a/lib/vscode/src/vs/workbench/common/theme.ts b/src/vs/workbench/common/theme.ts similarity index 97% rename from lib/vscode/src/vs/workbench/common/theme.ts rename to src/vs/workbench/common/theme.ts index 272f767d2e8d..20a7eadb1199 100644 --- a/lib/vscode/src/vs/workbench/common/theme.ts +++ b/src/vs/workbench/common/theme.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { registerColor, editorBackground, contrastBorder, transparent, editorWidgetBackground, textLinkForeground, lighten, darken, focusBorder, activeContrastBorder, editorWidgetForeground, editorErrorForeground, editorWarningForeground, editorInfoForeground, treeIndentGuidesStroke, errorForeground } from 'vs/platform/theme/common/colorRegistry'; +import { registerColor, editorBackground, contrastBorder, transparent, editorWidgetBackground, textLinkForeground, lighten, darken, focusBorder, activeContrastBorder, editorWidgetForeground, editorErrorForeground, editorWarningForeground, editorInfoForeground, treeIndentGuidesStroke, errorForeground, listActiveSelectionBackground, listActiveSelectionForeground } from 'vs/platform/theme/common/colorRegistry'; import { IColorTheme } from 'vs/platform/theme/common/themeService'; import { Color } from 'vs/base/common/color'; @@ -249,14 +249,6 @@ export const EDITOR_DRAG_AND_DROP_BACKGROUND = registerColor('editorGroup.dropBa hc: null }, localize('editorDragAndDropBackground', "Background color when dragging editors around. The color should have transparency so that the editor contents can still shine through.")); -// < --- Resource Viewer --- > - -export const IMAGE_PREVIEW_BORDER = registerColor('imagePreview.border', { - dark: Color.fromHex('#808080').transparent(0.35), - light: Color.fromHex('#808080').transparent(0.35), - hc: contrastBorder -}, localize('imagePreviewBorder', "Border color for image in image preview.")); - // < --- Panels --- > export const PANEL_BACKGROUND = registerColor('panel.background', { @@ -332,6 +324,25 @@ export const PANEL_SECTION_BORDER = registerColor('panelSection.border', { hc: PANEL_BORDER }, localize('panelSectionBorder', "Panel section border color used when multiple views are stacked horizontally in the panel. Panels are shown below the editor area and contain views like output and integrated terminal. Panel sections are views nested within the panels.")); +// < --- Banner --- > + +export const BANNER_BACKGROUND = registerColor('banner.background', { + dark: listActiveSelectionBackground, + light: listActiveSelectionBackground, + hc: listActiveSelectionBackground +}, localize('banner.background', "Banner background color. The banner is shown under the title bar of the window.")); + +export const BANNER_FOREGROUND = registerColor('banner.foreground', { + dark: listActiveSelectionForeground, + light: listActiveSelectionForeground, + hc: listActiveSelectionForeground +}, localize('banner.foreground', "Banner foreground color. The banner is shown under the title bar of the window.")); + +export const BANNER_ICON_FOREGROUND = registerColor('banner.iconForeground', { + dark: editorInfoForeground, + light: editorInfoForeground, + hc: editorInfoForeground +}, localize('banner.iconForeground', "Banner icon color. The banner is shown under the title bar of the window.")); // < --- Status --- > diff --git a/lib/vscode/src/vs/workbench/common/viewlet.ts b/src/vs/workbench/common/viewlet.ts similarity index 100% rename from lib/vscode/src/vs/workbench/common/viewlet.ts rename to src/vs/workbench/common/viewlet.ts diff --git a/lib/vscode/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts similarity index 99% rename from lib/vscode/src/vs/workbench/common/views.ts rename to src/vs/workbench/common/views.ts index e7b8d1d61451..8a3fee85b94a 100644 --- a/lib/vscode/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -630,6 +630,8 @@ export interface ITreeView extends IDisposable { dataProvider: ITreeViewDataProvider | undefined; + dragAndDropController?: ITreeViewDragAndDropController; + showCollapseAllAction: boolean; canSelectMany: boolean; @@ -810,7 +812,10 @@ export interface ITreeViewDataProvider { readonly isTreeEmpty?: boolean; onDidChangeEmpty?: Event; getChildren(element?: ITreeItem): Promise; +} +export interface ITreeViewDragAndDropController { + onDrop(elements: ITreeItem[], target: ITreeItem): Promise; } export interface IEditableData { diff --git a/lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/bulkCellEdits.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkCellEdits.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/bulkCellEdits.ts rename to src/vs/workbench/contrib/bulkEdit/browser/bulkCellEdits.ts diff --git a/lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts similarity index 93% rename from lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts rename to src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts index 889c25a9193a..62fc63fa5e12 100644 --- a/lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditService.ts @@ -19,7 +19,7 @@ import { BulkCellEdits, ResourceNotebookCellEdit } from 'vs/workbench/contrib/bu import { UndoRedoGroup, UndoRedoSource } from 'vs/platform/undoRedo/common/undoRedo'; import { LinkedList } from 'vs/base/common/linkedList'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle'; +import { ILifecycleService, ShutdownReason } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; class BulkEdit { @@ -195,7 +195,7 @@ export class BulkEditService implements IBulkEditService { let listener: IDisposable | undefined; try { - listener = this._lifecycleService.onBeforeShutdown(e => e.veto(this.shouldVeto(label), 'veto.blukEditService')); + listener = this._lifecycleService.onBeforeShutdown(e => e.veto(this.shouldVeto(label, e.reason), 'veto.blukEditService')); await bulkEdit.perform(); return { ariaSummary: bulkEdit.ariaMessage() }; } catch (err) { @@ -209,11 +209,13 @@ export class BulkEditService implements IBulkEditService { } } - private async shouldVeto(label: string | undefined): Promise { + private async shouldVeto(label: string | undefined, reason: ShutdownReason): Promise { label = label || localize('fileOperation', "File operation"); + const reasonLabel = reason === ShutdownReason.CLOSE ? localize('closeTheWindow', "Close Window") : reason === ShutdownReason.LOAD ? localize('changeWorkspace', "Change Workspace") : + reason === ShutdownReason.RELOAD ? localize('reloadTheWindow', "Reload Window") : localize('quit', "Quit"); const result = await this._dialogService.confirm({ - message: localize('areYouSureQuiteBulkEdit', "Are you sure you want to quit? '{0}' is in progress.", label), - primaryButton: localize('quit', "Quit") + message: localize('areYouSureQuiteBulkEdit', "Are you sure you want to {0}? '{1}' is in progress.", reasonLabel.toLowerCase(), label), + primaryButton: reasonLabel }); return !result.confirmed; diff --git a/lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/bulkFileEdits.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkFileEdits.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/bulkFileEdits.ts rename to src/vs/workbench/contrib/bulkEdit/browser/bulkFileEdits.ts diff --git a/lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts similarity index 94% rename from lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts rename to src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts index b7c76933f5e0..db91d69b5b2b 100644 --- a/lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts @@ -102,7 +102,7 @@ class ModelEditTask implements IDisposable { class EditorEditTask extends ModelEditTask { - private _editor: ICodeEditor; + private readonly _editor: ICodeEditor; constructor(modelReference: IReference, editor: ICodeEditor) { super(modelReference); @@ -110,10 +110,18 @@ class EditorEditTask extends ModelEditTask { } override getBeforeCursorState(): Selection[] | null { - return this._editor.getSelections(); + return this._canUseEditor() ? this._editor.getSelections() : null; } override apply(): void { + + // Check that the editor is still for the wanted model. It might have changed in the + // meantime and that means we cannot use the editor anymore (instead we perform the edit through the model) + if (!this._canUseEditor()) { + super.apply(); + return; + } + if (this._edits.length > 0) { this._edits = this._edits.sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range)); this._editor.executeEdits('', this._edits); @@ -124,6 +132,10 @@ class EditorEditTask extends ModelEditTask { } } } + + private _canUseEditor(): boolean { + return this._editor?.getModel()?.uri.toString() === this.model.uri.toString(); + } } export class BulkTextEdits { diff --git a/lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/conflicts.ts b/src/vs/workbench/contrib/bulkEdit/browser/conflicts.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/conflicts.ts rename to src/vs/workbench/contrib/bulkEdit/browser/conflicts.ts diff --git a/lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEdit.contribution.ts b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEdit.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEdit.contribution.ts rename to src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEdit.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEdit.css b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEdit.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEdit.css rename to src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEdit.css diff --git a/lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts rename to src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts index 6cf35182be62..5964f380e318 100644 --- a/lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts @@ -353,8 +353,8 @@ export class BulkEditPane extends ViewPane { } this._editorService.openEditor({ - leftResource, - rightResource: previewUri, + originalInput: { resource: leftResource }, + modifiedInput: { resource: previewUri }, label, description: this._labelService.getUriLabel(dirname(leftResource), { relative: true }), options diff --git a/lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPreview.ts b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPreview.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPreview.ts rename to src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPreview.ts diff --git a/lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditTree.ts b/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditTree.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditTree.ts rename to src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditTree.ts diff --git a/lib/vscode/src/vs/workbench/contrib/bulkEdit/test/browser/bulkEditPreview.test.ts b/src/vs/workbench/contrib/bulkEdit/test/browser/bulkEditPreview.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/bulkEdit/test/browser/bulkEditPreview.test.ts rename to src/vs/workbench/contrib/bulkEdit/test/browser/bulkEditPreview.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts rename to src/vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts rename to src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts index 96f6d8628af6..a5970bac0a83 100644 --- a/lib/vscode/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts +++ b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts @@ -297,6 +297,7 @@ export class CallHierarchyTreePeekWidget extends peekView.PeekViewWidget { // update: editor and editor highlights const options: IModelDecorationOptions = { + description: 'call-hierarchy-decoration', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'call-decoration', overviewRuler: { diff --git a/lib/vscode/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts rename to src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts diff --git a/lib/vscode/src/vs/workbench/contrib/callHierarchy/browser/media/callHierarchy.css b/src/vs/workbench/contrib/callHierarchy/browser/media/callHierarchy.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/callHierarchy/browser/media/callHierarchy.css rename to src/vs/workbench/contrib/callHierarchy/browser/media/callHierarchy.css diff --git a/lib/vscode/src/vs/workbench/contrib/callHierarchy/common/callHierarchy.ts b/src/vs/workbench/contrib/callHierarchy/common/callHierarchy.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/callHierarchy/common/callHierarchy.ts rename to src/vs/workbench/contrib/callHierarchy/common/callHierarchy.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeActions/common/codeActions.contribution.ts b/src/vs/workbench/contrib/codeActions/common/codeActions.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeActions/common/codeActions.contribution.ts rename to src/vs/workbench/contrib/codeActions/common/codeActions.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeActions/common/codeActionsContribution.ts b/src/vs/workbench/contrib/codeActions/common/codeActionsContribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeActions/common/codeActionsContribution.ts rename to src/vs/workbench/contrib/codeActions/common/codeActionsContribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeActions/common/codeActionsExtensionPoint.ts b/src/vs/workbench/contrib/codeActions/common/codeActionsExtensionPoint.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeActions/common/codeActionsExtensionPoint.ts rename to src/vs/workbench/contrib/codeActions/common/codeActionsExtensionPoint.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeActions/common/documentationContribution.ts b/src/vs/workbench/contrib/codeActions/common/documentationContribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeActions/common/documentationContribution.ts rename to src/vs/workbench/contrib/codeActions/common/documentationContribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeActions/common/documentationExtensionPoint.ts b/src/vs/workbench/contrib/codeActions/common/documentationExtensionPoint.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeActions/common/documentationExtensionPoint.ts rename to src/vs/workbench/contrib/codeActions/common/documentationExtensionPoint.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css rename to src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.css diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts b/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts rename to src/vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/codeEditor.contribution.ts b/src/vs/workbench/contrib/codeEditor/browser/codeEditor.contribution.ts similarity index 96% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/codeEditor.contribution.ts rename to src/vs/workbench/contrib/codeEditor/browser/codeEditor.contribution.ts index 30a3c94fdf19..db38d82e5446 100644 --- a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/codeEditor.contribution.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/codeEditor.contribution.ts @@ -18,4 +18,5 @@ import './toggleMultiCursorModifier'; import './toggleRenderControlCharacter'; import './toggleRenderWhitespace'; import './toggleWordWrap'; +import './untitledTextEditorHint'; import './workbenchReferenceSearch'; diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/diffEditorHelper.ts b/src/vs/workbench/contrib/codeEditor/browser/diffEditorHelper.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/diffEditorHelper.ts rename to src/vs/workbench/contrib/codeEditor/browser/diffEditorHelper.ts index 2362766c7417..c97b25050d28 100644 --- a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/diffEditorHelper.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/diffEditorHelper.ts @@ -21,7 +21,7 @@ const enum WidgetState { class DiffEditorHelperContribution extends Disposable implements IDiffEditorContribution { - public static ID = 'editor.contrib.diffEditorHelper'; + public static readonly ID = 'editor.contrib.diffEditorHelper'; private _helperWidget: FloatingClickWidget | null; private _helperWidgetListener: IDisposable | null; diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindReplaceWidget.css b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindReplaceWidget.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindReplaceWidget.css rename to src/vs/workbench/contrib/codeEditor/browser/find/simpleFindReplaceWidget.css diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindReplaceWidget.ts b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindReplaceWidget.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindReplaceWidget.ts rename to src/vs/workbench/contrib/codeEditor/browser/find/simpleFindReplaceWidget.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.css b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.css rename to src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.css diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts similarity index 93% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts rename to src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts index dc1c0e064cbb..cb02f6275e5e 100644 --- a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts @@ -69,7 +69,7 @@ export abstract class SimpleFindWidget extends Widget { this._updateHistoryDelayer = new Delayer(500); this.oninput(this._findInput.domNode, (e) => { - this.foundMatch = this.onInputChanged(); + this.foundMatch = this._onInputChanged(); this.updateButtons(this.foundMatch); this._delayedUpdateHistory(); }); @@ -138,25 +138,25 @@ export abstract class SimpleFindWidget extends Widget { }); this._focusTracker = this._register(dom.trackFocus(this._innerDomNode)); - this._register(this._focusTracker.onDidFocus(this.onFocusTrackerFocus.bind(this))); - this._register(this._focusTracker.onDidBlur(this.onFocusTrackerBlur.bind(this))); + this._register(this._focusTracker.onDidFocus(this._onFocusTrackerFocus.bind(this))); + this._register(this._focusTracker.onDidBlur(this._onFocusTrackerBlur.bind(this))); this._findInputFocusTracker = this._register(dom.trackFocus(this._findInput.domNode)); - this._register(this._findInputFocusTracker.onDidFocus(this.onFindInputFocusTrackerFocus.bind(this))); - this._register(this._findInputFocusTracker.onDidBlur(this.onFindInputFocusTrackerBlur.bind(this))); + this._register(this._findInputFocusTracker.onDidFocus(this._onFindInputFocusTrackerFocus.bind(this))); + this._register(this._findInputFocusTracker.onDidBlur(this._onFindInputFocusTrackerBlur.bind(this))); this._register(dom.addDisposableListener(this._innerDomNode, 'click', (event) => { event.stopPropagation(); })); } - protected abstract onInputChanged(): boolean; + protected abstract _onInputChanged(): boolean; protected abstract find(previous: boolean): void; protected abstract findFirst(): void; - protected abstract onFocusTrackerFocus(): void; - protected abstract onFocusTrackerBlur(): void; - protected abstract onFindInputFocusTrackerFocus(): void; - protected abstract onFindInputFocusTrackerBlur(): void; + protected abstract _onFocusTrackerFocus(): void; + protected abstract _onFocusTrackerBlur(): void; + protected abstract _onFindInputFocusTrackerFocus(): void; + protected abstract _onFindInputFocusTrackerBlur(): void; protected get inputValue() { return this._findInput.getValue(); diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.css b/src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.css rename to src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.css diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.ts b/src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.ts rename to src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.ts index 3fd351fc49e1..33143587fca5 100644 --- a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/inspectEditorTokens/inspectEditorTokens.ts @@ -416,10 +416,17 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget { const fontStyleLabels = new Array(); function addStyle(key: 'bold' | 'italic' | 'underline') { + let label: HTMLElement | string | undefined; if (semantic && semantic[key]) { - fontStyleLabels.push($('span.tiw-metadata-semantic', undefined, key)); + label = $('span.tiw-metadata-semantic', undefined, key); } else if (tm && tm[key]) { - fontStyleLabels.push(key); + label = key; + } + if (label) { + if (fontStyleLabels.length) { + fontStyleLabels.push(' '); + } + fontStyleLabels.push(label); } } addStyle('bold'); @@ -428,7 +435,7 @@ class InspectEditorTokensWidget extends Disposable implements IContentWidget { if (fontStyleLabels.length) { elements.push($('tr', undefined, $('td.tiw-metadata-key', undefined, 'font style' as string), - $('td.tiw-metadata-value', undefined, fontStyleLabels.join(' ')) + $('td.tiw-metadata-value', undefined, ...fontStyleLabels) )); } return elements; diff --git a/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts b/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts new file mode 100644 index 000000000000..c80090eb8a70 --- /dev/null +++ b/src/vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts @@ -0,0 +1,54 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; + +class InspectKeyMap extends EditorAction { + + constructor() { + super({ + id: 'workbench.action.inspectKeyMappings', + label: localize('workbench.action.inspectKeyMap', "Developer: Inspect Key Mappings"), + alias: 'Developer: Inspect Key Mappings', + precondition: undefined + }); + } + + run(accessor: ServicesAccessor, editor: ICodeEditor): void { + const keybindingService = accessor.get(IKeybindingService); + const editorService = accessor.get(IEditorService); + + editorService.openEditor({ contents: keybindingService._dumpDebugInfo(), options: { pinned: true } }); + } +} + +registerEditorAction(InspectKeyMap); + +class InspectKeyMapJSON extends Action2 { + + constructor() { + super({ + id: 'workbench.action.inspectKeyMappingsJSON', + title: { value: localize('workbench.action.inspectKeyMapJSON', "Inspect Key Mappings (JSON)"), original: 'Inspect Key Mappings (JSON)' }, + category: CATEGORIES.Developer, + f1: true + }); + } + + override async run(accessor: ServicesAccessor): Promise { + const editorService = accessor.get(IEditorService); + const keybindingService = accessor.get(IKeybindingService); + + await editorService.openEditor({ contents: keybindingService._dumpDebugInfoJSON(), options: { pinned: true } }); + } +} + +registerAction2(InspectKeyMapJSON); diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts b/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts rename to src/vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/largeFileOptimizations.ts b/src/vs/workbench/contrib/codeEditor/browser/largeFileOptimizations.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/largeFileOptimizations.ts rename to src/vs/workbench/contrib/codeEditor/browser/largeFileOptimizations.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/menuPreventer.ts b/src/vs/workbench/contrib/codeEditor/browser/menuPreventer.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/menuPreventer.ts rename to src/vs/workbench/contrib/codeEditor/browser/menuPreventer.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts rename to src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts index bdb42efacd42..2a9776a9614c 100644 --- a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts @@ -233,6 +233,7 @@ class DocumentSymbolsOutline implements IOutline { const ids = this._editor.deltaDecorations([], [{ range: symbol.range, options: { + description: 'document-symbols-outline-range-highlight', className: 'rangeHighlight', isWholeLine: true } diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsTree.css b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsTree.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsTree.css rename to src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsTree.css diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsTree.ts b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsTree.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsTree.ts rename to src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsTree.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoLineQuickAccess.ts b/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoLineQuickAccess.ts similarity index 96% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoLineQuickAccess.ts rename to src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoLineQuickAccess.ts index 73843d65ff63..d2054e83e513 100644 --- a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoLineQuickAccess.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoLineQuickAccess.ts @@ -17,6 +17,7 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IQuickAccessTextEditorContext } from 'vs/editor/contrib/quickAccess/editorNavigationQuickAccess'; +import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; export class GotoLineQuickAccessProvider extends AbstractGotoLineQuickAccessProvider { @@ -47,11 +48,13 @@ export class GotoLineQuickAccessProvider extends AbstractGotoLineQuickAccessProv if ((options.keyMods.alt || (this.configuration.openEditorPinned && options.keyMods.ctrlCmd) || options.forceSideBySide) && this.editorService.activeEditor) { context.restoreViewState?.(); // since we open to the side, restore view state in this editor - this.editorService.openEditor(this.editorService.activeEditor, { + const editorOptions: ITextEditorOptions = { selection: options.range, pinned: options.keyMods.ctrlCmd || this.configuration.openEditorPinned, preserveFocus: options.preserveFocus - }, SIDE_GROUP); + }; + + this.editorService.openEditor(this.editorService.activeEditor, editorOptions, SIDE_GROUP); } // Otherwise let parent handle it diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts b/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts rename to src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts index 7766be44b3a0..c5772a73b67e 100644 --- a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts @@ -28,6 +28,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { IQuickAccessTextEditorContext } from 'vs/editor/contrib/quickAccess/editorNavigationQuickAccess'; import { IOutlineService, OutlineTarget } from 'vs/workbench/services/outline/browser/outline'; import { isCompositeEditor } from 'vs/editor/browser/editorBrowser'; +import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; export class GotoSymbolQuickAccessProvider extends AbstractGotoSymbolQuickAccessProvider { @@ -73,11 +74,13 @@ export class GotoSymbolQuickAccessProvider extends AbstractGotoSymbolQuickAccess if ((options.keyMods.alt || (this.configuration.openEditorPinned && options.keyMods.ctrlCmd) || options.forceSideBySide) && this.editorService.activeEditor) { context.restoreViewState?.(); // since we open to the side, restore view state in this editor - this.editorService.openEditor(this.editorService.activeEditor, { + const editorOptions: ITextEditorOptions = { selection: options.range, pinned: options.keyMods.ctrlCmd || this.configuration.openEditorPinned, preserveFocus: options.preserveFocus - }, SIDE_GROUP); + }; + + this.editorService.openEditor(this.editorService.activeEditor, editorOptions, SIDE_GROUP); } // Otherwise let parent handle it diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts b/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts rename to src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts b/src/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts rename to src/vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts b/src/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts rename to src/vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.css b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.css rename to src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.css diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts rename to src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts similarity index 60% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts rename to src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts index 5164467cd6d7..ea457ff5ca93 100644 --- a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleColumnSelection.ts @@ -3,13 +3,10 @@ * 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 { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { localize } from 'vs/nls'; +import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -17,34 +14,39 @@ import { CoreNavigationCommands } from 'vs/editor/browser/controller/coreCommand import { Position } from 'vs/editor/common/core/position'; import { Selection } from 'vs/editor/common/core/selection'; import { CursorColumns } from 'vs/editor/common/controller/cursorCommon'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -export class ToggleColumnSelectionAction extends Action { - public static readonly ID = 'editor.action.toggleColumnSelection'; - public static readonly LABEL = nls.localize('toggleColumnSelection', "Toggle Column Selection Mode"); +export class ToggleColumnSelectionAction extends Action2 { - constructor( - id: string, - label: string, - @IConfigurationService private readonly _configurationService: IConfigurationService, - @ICodeEditorService private readonly _codeEditorService: ICodeEditorService - ) { - super(id, label); - } + static readonly ID = 'editor.action.toggleColumnSelection'; - private _getCodeEditor(): ICodeEditor | null { - const codeEditor = this._codeEditorService.getFocusedCodeEditor(); - if (codeEditor) { - return codeEditor; - } - return this._codeEditorService.getActiveCodeEditor(); + constructor() { + super({ + id: ToggleColumnSelectionAction.ID, + title: { + value: localize('toggleColumnSelection', "Toggle Column Selection Mode"), + mnemonicTitle: localize({ key: 'miColumnSelection', comment: ['&& denotes a mnemonic'] }, "Column &&Selection Mode"), + original: 'Toggle Column Selection Mode' + }, + f1: true, + toggled: ContextKeyExpr.equals('config.editor.columnSelection', true), + menu: { + id: MenuId.MenubarSelectionMenu, + group: '4_config', + order: 2 + } + }); } - public override async run(): Promise { - const oldValue = this._configurationService.getValue('editor.columnSelection'); - const codeEditor = this._getCodeEditor(); - await this._configurationService.updateValue('editor.columnSelection', !oldValue); - const newValue = this._configurationService.getValue('editor.columnSelection'); - if (!codeEditor || codeEditor !== this._getCodeEditor() || oldValue === newValue || !codeEditor.hasModel()) { + override async run(accessor: ServicesAccessor): Promise { + const configurationService = accessor.get(IConfigurationService); + const codeEditorService = accessor.get(ICodeEditorService); + + const oldValue = configurationService.getValue('editor.columnSelection'); + const codeEditor = this._getCodeEditor(codeEditorService); + await configurationService.updateValue('editor.columnSelection', !oldValue); + const newValue = configurationService.getValue('editor.columnSelection'); + if (!codeEditor || codeEditor !== this._getCodeEditor(codeEditorService) || oldValue === newValue || !codeEditor.hasModel()) { return; } const viewModel = codeEditor._getViewModel(); @@ -76,17 +78,14 @@ export class ToggleColumnSelectionAction extends Action { codeEditor.setSelection(new Selection(fromPosition.lineNumber, fromPosition.column, toPosition.lineNumber, toPosition.column)); } } -} -const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleColumnSelectionAction), 'Toggle Column Selection Mode'); + private _getCodeEditor(codeEditorService: ICodeEditorService): ICodeEditor | null { + const codeEditor = codeEditorService.getFocusedCodeEditor(); + if (codeEditor) { + return codeEditor; + } + return codeEditorService.getActiveCodeEditor(); + } +} -MenuRegistry.appendMenuItem(MenuId.MenubarSelectionMenu, { - group: '4_config', - command: { - id: ToggleColumnSelectionAction.ID, - title: nls.localize({ key: 'miColumnSelection', comment: ['&& denotes a mnemonic'] }, "Column &&Selection Mode"), - toggled: ContextKeyExpr.equals('config.editor.columnSelection', true) - }, - order: 2 -}); +registerAction2(ToggleColumnSelectionAction); diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts new file mode 100644 index 000000000000..7dfdbb583c4b --- /dev/null +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { CATEGORIES } from 'vs/workbench/common/actions'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; + +export class ToggleMinimapAction extends Action2 { + + static readonly ID = 'editor.action.toggleMinimap'; + + constructor() { + super({ + id: ToggleMinimapAction.ID, + title: { + value: localize('toggleMinimap', "Toggle Minimap"), + original: 'Toggle Minimap', + mnemonicTitle: localize({ key: 'miShowMinimap', comment: ['&& denotes a mnemonic'] }, "Show &&Minimap") + }, + category: CATEGORIES.View, + f1: true, + toggled: ContextKeyExpr.equals('config.editor.minimap.enabled', true), + menu: { + id: MenuId.MenubarViewMenu, + group: '5_editor', + order: 2 + } + }); + } + + override async run(accessor: ServicesAccessor): Promise { + const configurationService = accessor.get(IConfigurationService); + + const newValue = !configurationService.getValue('editor.minimap.enabled'); + return configurationService.updateValue('editor.minimap.enabled', newValue); + } +} + +registerAction2(ToggleMinimapAction); diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts similarity index 63% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts rename to src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts index d271522e1074..fea60d0515ab 100644 --- a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts @@ -3,37 +3,37 @@ * 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 * as platform from 'vs/base/common/platform'; -import { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { localize } from 'vs/nls'; +import { isMacintosh } from 'vs/base/common/platform'; +import { Action2, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; -import { Extensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -export class ToggleMultiCursorModifierAction extends Action { +export class ToggleMultiCursorModifierAction extends Action2 { - public static readonly ID = 'workbench.action.toggleMultiCursorModifier'; - public static readonly LABEL = nls.localize('toggleLocation', "Toggle Multi-Cursor Modifier"); + static readonly ID = 'workbench.action.toggleMultiCursorModifier'; private static readonly multiCursorModifierConfigurationKey = 'editor.multiCursorModifier'; - constructor( - id: string, - label: string, - @IConfigurationService private readonly configurationService: IConfigurationService - ) { - super(id, label); + constructor() { + super({ + id: ToggleMultiCursorModifierAction.ID, + title: { value: localize('toggleLocation', "Toggle Multi-Cursor Modifier"), original: 'Toggle Multi-Cursor Modifier' }, + f1: true + }); } - public override run(): Promise { - const editorConf = this.configurationService.getValue<{ multiCursorModifier: 'ctrlCmd' | 'alt' }>('editor'); + override run(accessor: ServicesAccessor): Promise { + const configurationService = accessor.get(IConfigurationService); + + const editorConf = configurationService.getValue<{ multiCursorModifier: 'ctrlCmd' | 'alt' }>('editor'); const newValue: 'ctrlCmd' | 'alt' = (editorConf.multiCursorModifier === 'ctrlCmd' ? 'alt' : 'ctrlCmd'); - return this.configurationService.updateValue(ToggleMultiCursorModifierAction.multiCursorModifierConfigurationKey, newValue); + return configurationService.updateValue(ToggleMultiCursorModifierAction.multiCursorModifierConfigurationKey, newValue); } } @@ -66,14 +66,13 @@ class MultiCursorModifierContextKeyController implements IWorkbenchContribution Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(MultiCursorModifierContextKeyController, LifecyclePhase.Restored); +registerAction2(ToggleMultiCursorModifierAction); -const registry = Registry.as(Extensions.WorkbenchActions); -registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleMultiCursorModifierAction), 'Toggle Multi-Cursor Modifier'); MenuRegistry.appendMenuItem(MenuId.MenubarSelectionMenu, { group: '4_config', command: { id: ToggleMultiCursorModifierAction.ID, - title: nls.localize('miMultiCursorAlt', "Switch to Alt+Click for Multi-Cursor") + title: localize('miMultiCursorAlt', "Switch to Alt+Click for Multi-Cursor") }, when: multiCursorModifier.isEqualTo('ctrlCmd'), order: 1 @@ -83,9 +82,9 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSelectionMenu, { command: { id: ToggleMultiCursorModifierAction.ID, title: ( - platform.isMacintosh - ? nls.localize('miMultiCursorCmd', "Switch to Cmd+Click for Multi-Cursor") - : nls.localize('miMultiCursorCtrl', "Switch to Ctrl+Click for Multi-Cursor") + isMacintosh + ? localize('miMultiCursorCmd', "Switch to Cmd+Click for Multi-Cursor") + : localize('miMultiCursorCtrl', "Switch to Ctrl+Click for Multi-Cursor") ) }, when: multiCursorModifier.isEqualTo('altKey'), diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts new file mode 100644 index 000000000000..0990dd2f4547 --- /dev/null +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { CATEGORIES, } from 'vs/workbench/common/actions'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; + +export class ToggleRenderControlCharacterAction extends Action2 { + + static readonly ID = 'editor.action.toggleRenderControlCharacter'; + + constructor() { + super({ + id: ToggleRenderControlCharacterAction.ID, + title: { + value: localize('toggleRenderControlCharacters', "Toggle Control Characters"), + mnemonicTitle: localize({ key: 'miToggleRenderControlCharacters', comment: ['&& denotes a mnemonic'] }, "Render &&Control Characters"), + original: 'Toggle Control Characters' + }, + category: CATEGORIES.View, + f1: true, + toggled: ContextKeyExpr.equals('config.editor.renderControlCharacters', true), + menu: { + id: MenuId.MenubarViewMenu, + group: '5_editor', + order: 5 + } + }); + } + + override run(accessor: ServicesAccessor): Promise { + const configurationService = accessor.get(IConfigurationService); + + const newRenderControlCharacters = !configurationService.getValue('editor.renderControlCharacters'); + return configurationService.updateValue('editor.renderControlCharacters', newRenderControlCharacters); + } +} + +registerAction2(ToggleRenderControlCharacterAction); diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts new file mode 100644 index 000000000000..c8bab9f321f1 --- /dev/null +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts @@ -0,0 +1,52 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { CATEGORIES, } from 'vs/workbench/common/actions'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; + +class ToggleRenderWhitespaceAction extends Action2 { + + static readonly ID = 'editor.action.toggleRenderWhitespace'; + + constructor() { + super({ + id: ToggleRenderWhitespaceAction.ID, + title: { + value: localize('toggleRenderWhitespace', "Toggle Render Whitespace"), + mnemonicTitle: localize({ key: 'miToggleRenderWhitespace', comment: ['&& denotes a mnemonic'] }, "&&Render Whitespace"), + original: 'Toggle Render Whitespace' + }, + category: CATEGORIES.View, + f1: true, + toggled: ContextKeyExpr.notEquals('config.editor.renderWhitespace', 'none'), + menu: { + id: MenuId.MenubarViewMenu, + group: '5_editor', + order: 4 + } + }); + } + + override run(accessor: ServicesAccessor): Promise { + const configurationService = accessor.get(IConfigurationService); + + const renderWhitespace = configurationService.getValue('editor.renderWhitespace'); + + let newRenderWhitespace: string; + if (renderWhitespace === 'none') { + newRenderWhitespace = 'all'; + } else { + newRenderWhitespace = 'none'; + } + + return configurationService.updateValue('editor.renderWhitespace', newRenderWhitespace); + } +} + +registerAction2(ToggleRenderWhitespaceAction); diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts rename to src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts index beb9467303da..7fd09e34fee8 100644 --- a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts @@ -280,7 +280,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { group: '5_editor', command: { id: TOGGLE_WORD_WRAP_ID, - title: nls.localize({ key: 'miToggleWordWrap', comment: ['&& denotes a mnemonic'] }, "Toggle &&Word Wrap"), + title: nls.localize({ key: 'miToggleWordWrap', comment: ['&& denotes a mnemonic'] }, "&&Word Wrap"), toggled: EDITOR_WORD_WRAP, precondition: CAN_TOGGLE_WORD_WRAP }, diff --git a/lib/vscode/src/vs/workbench/browser/parts/editor/untitledHint.ts b/src/vs/workbench/contrib/codeEditor/browser/untitledTextEditorHint.ts similarity index 85% rename from lib/vscode/src/vs/workbench/browser/parts/editor/untitledHint.ts rename to src/vs/workbench/contrib/codeEditor/browser/untitledTextEditorHint.ts index 04a3dc37cee0..1e7a864680e4 100644 --- a/lib/vscode/src/vs/workbench/browser/parts/editor/untitledHint.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/untitledTextEditorHint.ts @@ -17,18 +17,19 @@ import { Schemas } from 'vs/base/common/network'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ITASExperimentService } from 'vs/workbench/services/experiment/common/experimentService'; import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; +import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; + const $ = dom.$; -const untitledHintSetting = 'workbench.editor.untitled.hint'; -export class UntitledHintContribution implements IEditorContribution { +const untitledTextEditorHintSetting = 'workbench.editor.untitled.hint'; +export class UntitledTextEditorHintContribution implements IEditorContribution { - public static readonly ID = 'editor.contrib.untitledHint'; + public static readonly ID = 'editor.contrib.untitledTextEditorHint'; private toDispose: IDisposable[]; - private untitledHintContentWidget: UntitledHintContentWidget | undefined; + private untitledTextHintContentWidget: UntitledTextEditorHintContentWidget | undefined; private experimentTreatment: 'text' | 'hidden' | undefined; - constructor( private editor: ICodeEditor, @ICommandService private readonly commandService: ICommandService, @@ -40,7 +41,7 @@ export class UntitledHintContribution implements IEditorContribution { this.toDispose.push(this.editor.onDidChangeModel(() => this.update())); this.toDispose.push(this.editor.onDidChangeModelLanguage(() => this.update())); this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration(untitledHintSetting)) { + if (e.affectsConfiguration(untitledTextEditorHintSetting)) { this.update(); } })); @@ -51,24 +52,24 @@ export class UntitledHintContribution implements IEditorContribution { } private update(): void { - this.untitledHintContentWidget?.dispose(); - const configValue = this.configurationService.getValue<'text' | 'hidden' | 'default'>(untitledHintSetting); + this.untitledTextHintContentWidget?.dispose(); + const configValue = this.configurationService.getValue<'text' | 'hidden' | 'default'>(untitledTextEditorHintSetting); const untitledHintMode = configValue === 'default' ? (this.experimentTreatment || 'text') : configValue; const model = this.editor.getModel(); if (model && model.uri.scheme === Schemas.untitled && model.getModeId() === PLAINTEXT_MODE_ID && untitledHintMode === 'text') { - this.untitledHintContentWidget = new UntitledHintContentWidget(this.editor, this.commandService, this.configurationService); + this.untitledTextHintContentWidget = new UntitledTextEditorHintContentWidget(this.editor, this.commandService, this.configurationService); } } dispose(): void { dispose(this.toDispose); - this.untitledHintContentWidget?.dispose(); + this.untitledTextHintContentWidget?.dispose(); } } -class UntitledHintContentWidget implements IContentWidget { +class UntitledTextEditorHintContentWidget implements IContentWidget { private static readonly ID = 'editor.widget.untitledHint'; @@ -99,7 +100,7 @@ class UntitledHintContentWidget implements IContentWidget { } getId(): string { - return UntitledHintContentWidget.ID; + return UntitledTextEditorHintContentWidget.ID; } // Select a language to get started. Start typing to dismiss, or don't show this again. @@ -133,7 +134,7 @@ class UntitledHintContentWidget implements IContentWidget { })); this.toDispose.push(dom.addDisposableListener(dontShow, 'click', () => { - this.configurationService.updateValue(untitledHintSetting, 'hidden'); + this.configurationService.updateValue(untitledTextEditorHintSetting, 'hidden'); this.dispose(); this.editor.focus(); })); @@ -173,3 +174,5 @@ registerThemingParticipant((theme, collector) => { collector.addRule(`.monaco-editor .contentWidgets .untitled-hint a { color: ${textLinkForegroundColor}; }`); } }); + +registerEditorContribution(UntitledTextEditorHintContribution.ID, UntitledTextEditorHintContribution); diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/browser/workbenchReferenceSearch.ts b/src/vs/workbench/contrib/codeEditor/browser/workbenchReferenceSearch.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/browser/workbenchReferenceSearch.ts rename to src/vs/workbench/contrib/codeEditor/browser/workbenchReferenceSearch.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/electron-sandbox/codeEditor.contribution.ts b/src/vs/workbench/contrib/codeEditor/electron-sandbox/codeEditor.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/electron-sandbox/codeEditor.contribution.ts rename to src/vs/workbench/contrib/codeEditor/electron-sandbox/codeEditor.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/electron-sandbox/displayChangeRemeasureFonts.ts b/src/vs/workbench/contrib/codeEditor/electron-sandbox/displayChangeRemeasureFonts.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/electron-sandbox/displayChangeRemeasureFonts.ts rename to src/vs/workbench/contrib/codeEditor/electron-sandbox/displayChangeRemeasureFonts.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/electron-sandbox/inputClipboardActions.ts b/src/vs/workbench/contrib/codeEditor/electron-sandbox/inputClipboardActions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/electron-sandbox/inputClipboardActions.ts rename to src/vs/workbench/contrib/codeEditor/electron-sandbox/inputClipboardActions.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/electron-sandbox/selectionClipboard.ts b/src/vs/workbench/contrib/codeEditor/electron-sandbox/selectionClipboard.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/electron-sandbox/selectionClipboard.ts rename to src/vs/workbench/contrib/codeEditor/electron-sandbox/selectionClipboard.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/electron-sandbox/sleepResumeRepaintMinimap.ts b/src/vs/workbench/contrib/codeEditor/electron-sandbox/sleepResumeRepaintMinimap.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/electron-sandbox/sleepResumeRepaintMinimap.ts rename to src/vs/workbench/contrib/codeEditor/electron-sandbox/sleepResumeRepaintMinimap.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/electron-sandbox/startDebugTextMate.ts b/src/vs/workbench/contrib/codeEditor/electron-sandbox/startDebugTextMate.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/electron-sandbox/startDebugTextMate.ts rename to src/vs/workbench/contrib/codeEditor/electron-sandbox/startDebugTextMate.ts diff --git a/lib/vscode/src/vs/workbench/contrib/codeEditor/test/browser/saveParticipant.test.ts b/src/vs/workbench/contrib/codeEditor/test/browser/saveParticipant.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/codeEditor/test/browser/saveParticipant.test.ts rename to src/vs/workbench/contrib/codeEditor/test/browser/saveParticipant.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/comments/browser/commentFormActions.ts b/src/vs/workbench/contrib/comments/browser/commentFormActions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/comments/browser/commentFormActions.ts rename to src/vs/workbench/contrib/comments/browser/commentFormActions.ts diff --git a/lib/vscode/src/vs/workbench/contrib/comments/browser/commentGlyphWidget.ts b/src/vs/workbench/contrib/comments/browser/commentGlyphWidget.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/comments/browser/commentGlyphWidget.ts rename to src/vs/workbench/contrib/comments/browser/commentGlyphWidget.ts index 12682d319d9d..8382e6c43187 100644 --- a/lib/vscode/src/vs/workbench/contrib/comments/browser/commentGlyphWidget.ts +++ b/src/vs/workbench/contrib/comments/browser/commentGlyphWidget.ts @@ -29,6 +29,7 @@ export class CommentGlyphWidget { private createDecorationOptions(): ModelDecorationOptions { const decorationOptions: IModelDecorationOptions = { + description: 'comment-glyph-widget', isWholeLine: true, overviewRuler: { color: themeColorFromId(overviewRulerCommentingRangeForeground), diff --git a/lib/vscode/src/vs/workbench/contrib/comments/browser/commentMenus.ts b/src/vs/workbench/contrib/comments/browser/commentMenus.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/comments/browser/commentMenus.ts rename to src/vs/workbench/contrib/comments/browser/commentMenus.ts diff --git a/lib/vscode/src/vs/workbench/contrib/comments/browser/commentNode.ts b/src/vs/workbench/contrib/comments/browser/commentNode.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/comments/browser/commentNode.ts rename to src/vs/workbench/contrib/comments/browser/commentNode.ts diff --git a/lib/vscode/src/vs/workbench/contrib/comments/browser/commentService.ts b/src/vs/workbench/contrib/comments/browser/commentService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/comments/browser/commentService.ts rename to src/vs/workbench/contrib/comments/browser/commentService.ts diff --git a/lib/vscode/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts rename to src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts index 42ab2bb49446..c53a055d6ba9 100644 --- a/lib/vscode/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts @@ -30,7 +30,7 @@ import { IMenu, MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/co import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { contrastBorder, editorForeground, focusBorder, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, textBlockQuoteBackground, textBlockQuoteBorder, textLinkActiveForeground, textLinkForeground, transparent } from 'vs/platform/theme/common/colorRegistry'; +import { contrastBorder, editorForeground, focusBorder, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, resolveColorValue, textBlockQuoteBackground, textBlockQuoteBorder, textLinkActiveForeground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry'; import { IColorTheme, IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { CommentFormActions } from 'vs/workbench/contrib/comments/browser/commentFormActions'; import { CommentGlyphWidget } from 'vs/workbench/contrib/comments/browser/commentGlyphWidget'; @@ -805,12 +805,12 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget renderOptions: { after: { contentText: placeholder, - color: `${transparent(editorForeground, 0.4)(this.themeService.getColorTheme())}` + color: `${resolveColorValue(editorForeground, this.themeService.getColorTheme())?.transparent(0.4)}` } } }]; - this._commentReplyComponent?.editor.setDecorations(COMMENTEDITOR_DECORATION_KEY, decorations); + this._commentReplyComponent?.editor.setDecorations('review-zone-widget', COMMENTEDITOR_DECORATION_KEY, decorations); } } diff --git a/lib/vscode/src/vs/workbench/contrib/comments/browser/comments.contribution.ts b/src/vs/workbench/contrib/comments/browser/comments.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/comments/browser/comments.contribution.ts rename to src/vs/workbench/contrib/comments/browser/comments.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts rename to src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts index ed8b5735426f..46c21f9860ed 100644 --- a/lib/vscode/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts @@ -102,6 +102,7 @@ class CommentingRangeDecorator { constructor() { const decorationOptions: IModelDecorationOptions = { + description: 'commenting-range-decorator', isWholeLine: true, linesDecorationsClassName: 'comment-range-glyph comment-diff-added' }; @@ -196,7 +197,7 @@ export class CommentController implements IEditorContribution { })); this.globalToDispose.add(this.editor.onDidChangeModel(e => this.onModelChanged(e))); - this.codeEditorService.registerDecorationType(COMMENTEDITOR_DECORATION_KEY, {}); + this.codeEditorService.registerDecorationType('comment-controller', COMMENTEDITOR_DECORATION_KEY, {}); this.beginCompute(); } diff --git a/lib/vscode/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts rename to src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts diff --git a/lib/vscode/src/vs/workbench/contrib/comments/browser/commentsView.ts b/src/vs/workbench/contrib/comments/browser/commentsView.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/comments/browser/commentsView.ts rename to src/vs/workbench/contrib/comments/browser/commentsView.ts diff --git a/lib/vscode/src/vs/workbench/contrib/comments/browser/media/panel.css b/src/vs/workbench/contrib/comments/browser/media/panel.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/comments/browser/media/panel.css rename to src/vs/workbench/contrib/comments/browser/media/panel.css diff --git a/lib/vscode/src/vs/workbench/contrib/comments/browser/media/review.css b/src/vs/workbench/contrib/comments/browser/media/review.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/comments/browser/media/review.css rename to src/vs/workbench/contrib/comments/browser/media/review.css diff --git a/lib/vscode/src/vs/workbench/contrib/comments/browser/reactionsAction.ts b/src/vs/workbench/contrib/comments/browser/reactionsAction.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/comments/browser/reactionsAction.ts rename to src/vs/workbench/contrib/comments/browser/reactionsAction.ts diff --git a/lib/vscode/src/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts b/src/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts rename to src/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts diff --git a/lib/vscode/src/vs/workbench/contrib/comments/common/commentContextKeys.ts b/src/vs/workbench/contrib/comments/common/commentContextKeys.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/comments/common/commentContextKeys.ts rename to src/vs/workbench/contrib/comments/common/commentContextKeys.ts diff --git a/lib/vscode/src/vs/workbench/contrib/comments/common/commentModel.ts b/src/vs/workbench/contrib/comments/common/commentModel.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/comments/common/commentModel.ts rename to src/vs/workbench/contrib/comments/common/commentModel.ts diff --git a/lib/vscode/src/vs/workbench/contrib/comments/common/commentThreadWidget.ts b/src/vs/workbench/contrib/comments/common/commentThreadWidget.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/comments/common/commentThreadWidget.ts rename to src/vs/workbench/contrib/comments/common/commentThreadWidget.ts diff --git a/lib/vscode/src/vs/workbench/contrib/configExporter/electron-sandbox/configurationExportHelper.contribution.ts b/src/vs/workbench/contrib/configExporter/electron-sandbox/configurationExportHelper.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/configExporter/electron-sandbox/configurationExportHelper.contribution.ts rename to src/vs/workbench/contrib/configExporter/electron-sandbox/configurationExportHelper.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/configExporter/electron-sandbox/configurationExportHelper.ts b/src/vs/workbench/contrib/configExporter/electron-sandbox/configurationExportHelper.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/configExporter/electron-sandbox/configurationExportHelper.ts rename to src/vs/workbench/contrib/configExporter/electron-sandbox/configurationExportHelper.ts diff --git a/lib/vscode/src/vs/workbench/contrib/customEditor/browser/customEditor.contribution.ts b/src/vs/workbench/contrib/customEditor/browser/customEditor.contribution.ts similarity index 72% rename from lib/vscode/src/vs/workbench/contrib/customEditor/browser/customEditor.contribution.ts rename to src/vs/workbench/contrib/customEditor/browser/customEditor.contribution.ts index 7fbc785144a4..dc4c64be579a 100644 --- a/lib/vscode/src/vs/workbench/contrib/customEditor/browser/customEditor.contribution.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditor.contribution.ts @@ -3,15 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Schemas } from 'vs/base/common/network'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Registry } from 'vs/platform/registry/common/platform'; import { EditorDescriptor, IEditorRegistry } from 'vs/workbench/browser/editor'; +import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { EditorExtensions, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor'; -import { customEditorInputFactory, CustomEditorInputSerializer } from 'vs/workbench/contrib/customEditor/browser/customEditorInputFactory'; +import { CustomEditorInputSerializer, ComplexCustomWorkingCopyEditorHandler as ComplexCustomWorkingCopyEditorHandler } from 'vs/workbench/contrib/customEditor/browser/customEditorInputFactory'; import { ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; import { WebviewEditor } from 'vs/workbench/contrib/webviewPanel/browser/webviewEditor'; +import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { CustomEditorInput } from './customEditorInput'; import { CustomEditorService } from './customEditors'; @@ -32,5 +33,5 @@ Registry.as(EditorExtensions.EditorInputFactories) CustomEditorInputSerializer.ID, CustomEditorInputSerializer); -Registry.as(EditorExtensions.EditorInputFactories) - .registerCustomEditorInputFactory(Schemas.vscodeCustomEditor, customEditorInputFactory); +Registry.as(WorkbenchExtensions.Workbench) + .registerWorkbenchContribution(ComplexCustomWorkingCopyEditorHandler, LifecyclePhase.Starting); diff --git a/lib/vscode/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts similarity index 63% rename from lib/vscode/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts rename to src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts index 08f1b94ef060..9c390babf049 100644 --- a/lib/vscode/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts @@ -4,22 +4,23 @@ *--------------------------------------------------------------------------------------------*/ import { VSBuffer } from 'vs/base/common/buffer'; -import { memoize } from 'vs/base/common/decorators'; import { IReference } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; import { basename } from 'vs/base/common/path'; -import { isEqual } from 'vs/base/common/resources'; +import { dirname, isEqual } from 'vs/base/common/resources'; import { assertIsDefined } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IResourceEditorInput } from 'vs/platform/editor/common/editor'; +import { FileSystemProviderCapabilities, IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILabelService } from 'vs/platform/label/common/label'; import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; -import { GroupIdentifier, IEditorInput, IRevertOptions, ISaveOptions, Verbosity } from 'vs/workbench/common/editor'; +import { EditorInputCapabilities, GroupIdentifier, IEditorInput, IRevertOptions, ISaveOptions, Verbosity } from 'vs/workbench/common/editor'; +import { decorateFileEditorLabel } from 'vs/workbench/common/editor/resourceEditorInput'; import { defaultCustomEditor } from 'vs/workbench/contrib/customEditor/common/contributedCustomEditors'; import { ICustomEditorModel, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; -import { decorateFileEditorLabel } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; import { IWebviewService, WebviewOverlay } from 'vs/workbench/contrib/webview/browser/webview'; import { IWebviewWorkbenchService, LazilyResolvedWebviewEditorInput } from 'vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -32,7 +33,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { resource: URI, viewType: string, group: GroupIdentifier | undefined, - options?: { readonly customClasses?: string }, + options?: { readonly customClasses?: string, readonly oldResource?: URI }, ): IEditorInput { return instantiationService.invokeFunction(accessor => { if (viewType === defaultCustomEditor.id) { @@ -43,11 +44,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { let untitledDocumentData = untitledString ? VSBuffer.fromString(untitledString) : undefined; const id = generateUuid(); const webview = accessor.get(IWebviewService).createWebviewOverlay(id, { customClasses: options?.customClasses }, {}, undefined); - const input = instantiationService.createInstance(CustomEditorInput, resource, viewType, id, webview, { untitledDocumentData: untitledDocumentData }); - // If we're loading untitled file data we should ensure it's dirty - if (untitledDocumentData) { - input._defaultDirtyState = true; - } + const input = instantiationService.createInstance(CustomEditorInput, resource, viewType, id, webview, { untitledDocumentData: untitledDocumentData, oldResource: options?.oldResource }); if (typeof group !== 'undefined') { input.updateGroup(group); } @@ -58,6 +55,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { public static override readonly typeId = 'workbench.editors.webviewEditor'; private readonly _editorResource: URI; + public readonly oldResource?: URI; private _defaultDirtyState: boolean | undefined; private readonly _backupId: string | undefined; @@ -73,7 +71,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { viewType: string, id: string, webview: WebviewOverlay, - options: { startsDirty?: boolean, backupId?: string, untitledDocumentData?: VSBuffer }, + options: { startsDirty?: boolean, backupId?: string, untitledDocumentData?: VSBuffer, readonly oldResource?: URI }, @IWebviewWorkbenchService webviewWorkbenchService: IWebviewWorkbenchService, @IInstantiationService private readonly instantiationService: IInstantiationService, @ILabelService private readonly labelService: ILabelService, @@ -81,20 +79,72 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { @IFileDialogService private readonly fileDialogService: IFileDialogService, @IEditorService private readonly editorService: IEditorService, @IUndoRedoService private readonly undoRedoService: IUndoRedoService, + @IFileService private readonly fileService: IFileService ) { super(id, viewType, '', webview, webviewWorkbenchService); this._editorResource = resource; + this.oldResource = options.oldResource; this._defaultDirtyState = options.startsDirty; this._backupId = options.backupId; this._untitledDocumentData = options.untitledDocumentData; + + this.registerListeners(); + } + + private registerListeners(): void { + + // Clear our labels on certain label related events + this._register(this.labelService.onDidChangeFormatters(e => this.onLabelEvent(e.scheme))); + this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(e => this.onLabelEvent(e.scheme))); + this._register(this.fileService.onDidChangeFileSystemProviderCapabilities(e => this.onLabelEvent(e.scheme))); + } + + private onLabelEvent(scheme: string): void { + if (scheme === this.resource.scheme) { + this.updateLabel(); + } + } + + private updateLabel(): void { + + // Clear any cached labels from before + this._shortDescription = undefined; + this._mediumDescription = undefined; + this._longDescription = undefined; + this._shortTitle = undefined; + this._mediumTitle = undefined; + this._longTitle = undefined; + + // Trigger recompute of label + this._onDidChangeLabel.fire(); } public override get typeId(): string { return CustomEditorInput.typeId; } - public override canSplit() { - return !!this.customEditorService.getCustomEditorCapabilities(this.viewType)?.supportsMultipleEditorsPerDocument; + public override get capabilities(): EditorInputCapabilities { + let capabilities = EditorInputCapabilities.None; + + if (!this.customEditorService.getCustomEditorCapabilities(this.viewType)?.supportsMultipleEditorsPerDocument) { + capabilities |= EditorInputCapabilities.Singleton; + } + + if (this._modelRef) { + if (this._modelRef.object.isReadonly()) { + capabilities |= EditorInputCapabilities.Readonly; + } + } else { + if (this.fileService.hasCapability(this.resource, FileSystemProviderCapabilities.Readonly)) { + capabilities |= EditorInputCapabilities.Readonly; + } + } + + if (this.resource.scheme === Schemas.untitled) { + capabilities |= EditorInputCapabilities.Untitled; + } + + return capabilities; } override getName(): string { @@ -102,62 +152,99 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { return this.decorateLabel(name); } - override matches(other: IEditorInput): boolean { - return this === other || (other instanceof CustomEditorInput - && this.viewType === other.viewType - && isEqual(this.resource, other.resource)); + override getDescription(verbosity = Verbosity.MEDIUM): string | undefined { + switch (verbosity) { + case Verbosity.SHORT: + return this.shortDescription; + case Verbosity.LONG: + return this.longDescription; + case Verbosity.MEDIUM: + default: + return this.mediumDescription; + } } - override copy(): IEditorInput { - return CustomEditorInput.create(this.instantiationService, this.resource, this.viewType, this.group, this.webview.options); + private _shortDescription: string | undefined = undefined; + private get shortDescription(): string { + if (typeof this._shortDescription !== 'string') { + this._shortDescription = this.labelService.getUriBasenameLabel(dirname(this.resource)); + } + + return this._shortDescription; + } + + private _mediumDescription: string | undefined = undefined; + private get mediumDescription(): string { + if (typeof this._mediumDescription !== 'string') { + this._mediumDescription = this.labelService.getUriLabel(dirname(this.resource), { relative: true }); + } + + return this._mediumDescription; + } + + private _longDescription: string | undefined = undefined; + private get longDescription(): string { + if (typeof this._longDescription !== 'string') { + this._longDescription = this.labelService.getUriLabel(dirname(this.resource)); + } + + return this._longDescription; } - @memoize + private _shortTitle: string | undefined = undefined; private get shortTitle(): string { - return this.getName(); + if (typeof this._shortTitle !== 'string') { + this._shortTitle = this.getName(); + } + + return this._shortTitle; } - @memoize + private _mediumTitle: string | undefined = undefined; private get mediumTitle(): string { - return this.labelService.getUriLabel(this.resource, { relative: true }); + if (typeof this._mediumTitle !== 'string') { + this._mediumTitle = this.labelService.getUriLabel(this.resource, { relative: true }); + } + + return this._mediumTitle; } - @memoize + private _longTitle: string | undefined = undefined; private get longTitle(): string { - return this.labelService.getUriLabel(this.resource); + if (typeof this._longTitle !== 'string') { + this._longTitle = this.labelService.getUriLabel(this.resource); + } + + return this._longTitle; } - public override getTitle(verbosity?: Verbosity): string { + override getTitle(verbosity?: Verbosity): string { switch (verbosity) { case Verbosity.SHORT: return this.decorateLabel(this.shortTitle); + case Verbosity.LONG: + return this.decorateLabel(this.longTitle); default: case Verbosity.MEDIUM: return this.decorateLabel(this.mediumTitle); - case Verbosity.LONG: - return this.decorateLabel(this.longTitle); } } private decorateLabel(label: string): string { + const readonly = this.hasCapability(EditorInputCapabilities.Readonly); const orphaned = !!this._modelRef?.object.isOrphaned(); - const readonly = this._modelRef - ? this._modelRef.object.isEditable() && this._modelRef.object.isOnReadonlyFileSystem() - : false; - - return decorateFileEditorLabel(label, { - orphaned, - readonly - }); + return decorateFileEditorLabel(label, { orphaned, readonly }); } - public override isReadonly(): boolean { - return this._modelRef ? !this._modelRef.object.isEditable() : false; + public override matches(other: IEditorInput): boolean { + return this === other || (other instanceof CustomEditorInput + && this.viewType === other.viewType + && isEqual(this.resource, other.resource)); } - public override isUntitled(): boolean { - return this.resource.scheme === Schemas.untitled; + public override copy(): IEditorInput { + return CustomEditorInput.create(this.instantiationService, this.resource, this.viewType, this.group, this.webview.options); } public override isDirty(): boolean { @@ -221,7 +308,11 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { this._modelRef = this._register(assertIsDefined(await this.customEditorService.models.tryRetain(this.resource, this.viewType))); this._register(this._modelRef.object.onDidChangeDirty(() => this._onDidChangeDirty.fire())); this._register(this._modelRef.object.onDidChangeOrphaned(() => this._onDidChangeLabel.fire())); - + this._register(this._modelRef.object.onDidChangeReadonly(() => this._onDidChangeCapabilities.fire())); + // If we're loading untitled file data we should ensure it's dirty + if (this._untitledDocumentData) { + this._defaultDirtyState = true; + } if (this.isDirty()) { this._onDidChangeDirty.fire(); } @@ -230,7 +321,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { return null; } - override rename(group: GroupIdentifier, newResource: URI): { editor: IEditorInput } | undefined { + public override rename(group: GroupIdentifier, newResource: URI): { editor: IEditorInput } | undefined { // See if we can keep using the same custom editor provider const editorInfo = this.customEditorService.getCustomEditor(this.viewType); if (editorInfo?.matches(newResource)) { @@ -242,7 +333,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { private doMove(group: GroupIdentifier, newResource: URI): IEditorInput { if (!this._moveHandler) { - return CustomEditorInput.create(this.instantiationService, newResource, this.viewType, group); + return CustomEditorInput.create(this.instantiationService, newResource, this.viewType, group, { oldResource: this.resource }); } this._moveHandler(newResource); @@ -284,14 +375,23 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { return other; } - get backupId(): string | undefined { + public get backupId(): string | undefined { if (this._modelRef) { return this._modelRef.object.backupId; } return this._backupId; } - get untitledDocumentData(): VSBuffer | undefined { + public get untitledDocumentData(): VSBuffer | undefined { return this._untitledDocumentData; } + + public override asResourceEditorInput(groupId: GroupIdentifier): IResourceEditorInput { + return { + resource: this.resource, + options: { + override: this.viewType + } + }; + } } diff --git a/lib/vscode/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts similarity index 58% rename from lib/vscode/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts rename to src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts index 23e5e9f0f664..43e86d2bb275 100644 --- a/lib/vscode/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts @@ -5,13 +5,18 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ICustomEditorInputFactory, IEditorInput } from 'vs/workbench/common/editor'; import { CustomEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput'; import { IWebviewService, WebviewContentOptions, WebviewContentPurpose, WebviewExtensionDescription, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; import { SerializedWebviewOptions, DeserializedWebview, reviveWebviewExtensionDescription, SerializedWebview, WebviewEditorInputSerializer, restoreWebviewContentOptions, restoreWebviewOptions } from 'vs/workbench/contrib/webviewPanel/browser/webviewEditorInputSerializer'; import { IWebviewWorkbenchService } from 'vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService'; import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/common/workingCopyBackup'; -import { IWorkingCopyBackupMeta, NO_TYPE_ID } from 'vs/workbench/services/workingCopy/common/workingCopy'; +import { IWorkingCopyBackupMeta } from 'vs/workbench/services/workingCopy/common/workingCopy'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { IWorkingCopyEditorService } from 'vs/workbench/services/workingCopy/common/workingCopyEditorService'; +import { ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; +import { Schemas } from 'vs/base/common/network'; +import { isEqual } from 'vs/base/common/resources'; export interface CustomDocumentBackupData extends IWorkingCopyBackupMeta { readonly viewType: string; @@ -36,14 +41,12 @@ interface SerializedCustomEditor extends SerializedWebview { readonly backupId?: string; } - interface DeserializedCustomEditor extends DeserializedWebview { readonly editorResource: URI; readonly dirty: boolean; readonly backupId?: string; } - export class CustomEditorInputSerializer extends WebviewEditorInputSerializer { public static override readonly ID = CustomEditorInput.typeId; @@ -104,41 +107,63 @@ function reviveWebview(webviewService: IWebviewService, data: { id: string, stat return webview; } -export const customEditorInputFactory = new class implements ICustomEditorInputFactory { - public createCustomEditorInput(resource: URI, instantiationService: IInstantiationService): Promise { - return instantiationService.invokeFunction(async accessor => { - const webviewService = accessor.get(IWebviewService); - const workingCopyBackupService = accessor.get(IWorkingCopyBackupService); +export class ComplexCustomWorkingCopyEditorHandler extends Disposable implements IWorkbenchContribution { - const backup = await workingCopyBackupService.resolve({ resource, typeId: NO_TYPE_ID }); - if (!backup?.meta) { - throw new Error(`No backup found for custom editor: ${resource}`); - } + constructor( + @IInstantiationService private readonly _instantiationService: IInstantiationService, + @IWorkingCopyEditorService private readonly _workingCopyEditorService: IWorkingCopyEditorService, + @IWorkingCopyBackupService private readonly _workingCopyBackupService: IWorkingCopyBackupService, + @IWebviewService private readonly _webviewService: IWebviewService, + @ICustomEditorService _customEditorService: ICustomEditorService // DO NOT REMOVE (needed on startup to register overrides properly) + ) { + super(); - const backupData = backup.meta; - const id = backupData.webview.id; - const extension = reviveWebviewExtensionDescription(backupData.extension?.id, backupData.extension?.location); - const webview = reviveWebview(webviewService, { - id, - webviewOptions: restoreWebviewOptions(backupData.webview.options), - contentOptions: restoreWebviewContentOptions(backupData.webview.options), - state: backupData.webview.state, - extension, - }); - - const editor = instantiationService.createInstance(CustomEditorInput, URI.revive(backupData.editorResource), backupData.viewType, id, webview, { backupId: backupData.backupId }); - editor.updateGroup(0); - return editor; - }); + this._installHandler(); } - public canResolveBackup(editorInput: IEditorInput, backupResource: URI): boolean { - if (editorInput instanceof CustomEditorInput) { - if (editorInput.resource.path === backupResource.path && backupResource.authority === editorInput.viewType) { - return true; + private _installHandler(): void { + this._register(this._workingCopyEditorService.registerHandler({ + handles: workingCopy => workingCopy.resource.scheme === Schemas.vscodeCustomEditor, + isOpen: (workingCopy, editor) => { + if (!(editor instanceof CustomEditorInput)) { + return false; + } + + if (workingCopy.resource.authority !== editor.viewType.replace(/[^a-z0-9\-_]/gi, '-').toLowerCase()) { + return false; + } + + // The working copy stores the uri of the original resource as its query param + try { + const data = JSON.parse(workingCopy.resource.query); + const workingCopyResource = URI.from(data); + return isEqual(workingCopyResource, editor.resource); + } catch { + return false; + } + }, + createEditor: async workingCopy => { + const backup = await this._workingCopyBackupService.resolve(workingCopy); + if (!backup?.meta) { + throw new Error(`No backup found for custom editor: ${workingCopy.resource}`); + } + + const backupData = backup.meta; + const id = backupData.webview.id; + const extension = reviveWebviewExtensionDescription(backupData.extension?.id, backupData.extension?.location); + const webview = reviveWebview(this._webviewService, { + id, + webviewOptions: restoreWebviewOptions(backupData.webview.options), + contentOptions: restoreWebviewContentOptions(backupData.webview.options), + state: backupData.webview.state, + extension, + }); + + const editor = this._instantiationService.createInstance(CustomEditorInput, URI.revive(backupData.editorResource), backupData.viewType, id, webview, { backupId: backupData.backupId }); + editor.updateGroup(0); + return editor; } - } - - return false; + })); } -}; +} + diff --git a/lib/vscode/src/vs/workbench/contrib/customEditor/browser/customEditors.ts b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts similarity index 95% rename from lib/vscode/src/vs/workbench/contrib/customEditor/browser/customEditors.ts rename to src/vs/workbench/contrib/customEditor/browser/customEditors.ts index 2824537bc4d8..ff0a67cfdea5 100644 --- a/lib/vscode/src/vs/workbench/contrib/customEditor/browser/customEditors.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts @@ -16,18 +16,19 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IStorageService } from 'vs/platform/storage/common/storage'; import * as colorRegistry from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { EditorInput, EditorExtensions, GroupIdentifier, IEditorInput, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor'; +import { EditorExtensions, GroupIdentifier, IEditorInput, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { CONTEXT_ACTIVE_CUSTOM_EDITOR_ID, CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE, CustomEditorCapabilities, CustomEditorInfo, CustomEditorInfoCollection, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; import { CustomEditorModelManager } from 'vs/workbench/contrib/customEditor/common/customEditorModelManager'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { ContributedEditorPriority, IEditorAssociationsRegistry, IEditorOverrideService, IEditorType, IEditorTypesHandler } from 'vs/workbench/services/editor/common/editorOverrideService'; +import { ContributedEditorPriority, IEditorOverrideService, IEditorType } from 'vs/workbench/services/editor/common/editorOverrideService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; import { ContributedCustomEditors } from '../common/contributedCustomEditors'; import { CustomEditorInput } from './customEditorInput'; -export class CustomEditorService extends Disposable implements ICustomEditorService, IEditorTypesHandler { +export class CustomEditorService extends Disposable implements ICustomEditorService { _serviceBrand: any; private readonly _contributedEditors: ContributedCustomEditors; @@ -67,7 +68,6 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ this.updateContexts(); this._onDidChangeEditorTypes.fire(); })); - this._register(Registry.as(EditorExtensions.Associations).registerEditorTypesHandler('Custom Editor', this)); this._register(this.editorService.onDidActiveEditorChange(() => this.updateContexts())); this._register(fileService.onDidRunOperation(e => { diff --git a/lib/vscode/src/vs/workbench/contrib/customEditor/common/contributedCustomEditors.ts b/src/vs/workbench/contrib/customEditor/common/contributedCustomEditors.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/customEditor/common/contributedCustomEditors.ts rename to src/vs/workbench/contrib/customEditor/common/contributedCustomEditors.ts diff --git a/lib/vscode/src/vs/workbench/contrib/customEditor/common/customEditor.ts b/src/vs/workbench/contrib/customEditor/common/customEditor.ts similarity index 97% rename from lib/vscode/src/vs/workbench/contrib/customEditor/common/customEditor.ts rename to src/vs/workbench/contrib/customEditor/common/customEditor.ts index c7aa1260e3f9..dbd675070a9a 100644 --- a/lib/vscode/src/vs/workbench/contrib/customEditor/common/customEditor.ts +++ b/src/vs/workbench/contrib/customEditor/common/customEditor.ts @@ -41,6 +41,8 @@ export interface ICustomEditorService { } export interface ICustomEditorModelManager { + getAllModels(resource: URI): Promise + get(resource: URI, viewType: string): Promise; tryRetain(resource: URI, viewType: string): Promise> | undefined; @@ -55,8 +57,8 @@ export interface ICustomEditorModel extends IDisposable { readonly resource: URI; readonly backupId: string | undefined; - isEditable(): boolean; - isOnReadonlyFileSystem(): boolean; + isReadonly(): boolean; + readonly onDidChangeReadonly: Event; isOrphaned(): boolean; readonly onDidChangeOrphaned: Event; diff --git a/lib/vscode/src/vs/workbench/contrib/customEditor/common/customEditorModelManager.ts b/src/vs/workbench/contrib/customEditor/common/customEditorModelManager.ts similarity index 88% rename from lib/vscode/src/vs/workbench/contrib/customEditor/common/customEditorModelManager.ts rename to src/vs/workbench/contrib/customEditor/common/customEditorModelManager.ts index b2b185ed874a..0d8176fadc43 100644 --- a/lib/vscode/src/vs/workbench/contrib/customEditor/common/customEditorModelManager.ts +++ b/src/vs/workbench/contrib/customEditor/common/customEditorModelManager.ts @@ -16,6 +16,16 @@ export class CustomEditorModelManager implements ICustomEditorModelManager { counter: number }>(); + public async getAllModels(resource: URI): Promise { + const keyStart = `${resource.toString()}@@@`; + const models = []; + for (const [key, entry] of this._references) { + if (key.startsWith(keyStart) && entry.model) { + models.push(await entry.model); + } + } + return models; + } public async get(resource: URI, viewType: string): Promise { const key = this.key(resource, viewType); const entry = this._references.get(key); diff --git a/lib/vscode/src/vs/workbench/contrib/customEditor/common/customTextEditorModel.ts b/src/vs/workbench/contrib/customEditor/common/customTextEditorModel.ts similarity index 90% rename from lib/vscode/src/vs/workbench/contrib/customEditor/common/customTextEditorModel.ts rename to src/vs/workbench/contrib/customEditor/common/customTextEditorModel.ts index c39fa2ce52c8..32c0e0189db7 100644 --- a/lib/vscode/src/vs/workbench/contrib/customEditor/common/customTextEditorModel.ts +++ b/src/vs/workbench/contrib/customEditor/common/customTextEditorModel.ts @@ -8,7 +8,6 @@ import { Disposable, IReference } from 'vs/base/common/lifecycle'; import { isEqual } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { IResolvedTextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; -import { FileSystemProviderCapabilities, IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IRevertOptions, ISaveOptions } from 'vs/workbench/common/editor'; import { ICustomEditorModel } from 'vs/workbench/contrib/customEditor/common/customEditor'; @@ -33,12 +32,14 @@ export class CustomTextEditorModel extends Disposable implements ICustomEditorMo private readonly _onDidChangeOrphaned = this._register(new Emitter()); public readonly onDidChangeOrphaned = this._onDidChangeOrphaned.event; + private readonly _onDidChangeReadonly = this._register(new Emitter()); + public readonly onDidChangeReadonly = this._onDidChangeReadonly.event; + constructor( public readonly viewType: string, private readonly _resource: URI, private readonly _model: IReference, - @ITextFileService private readonly textFileService: ITextFileService, - @IFileService private readonly _fileService: IFileService, + @ITextFileService private readonly textFileService: ITextFileService ) { super(); @@ -47,6 +48,7 @@ export class CustomTextEditorModel extends Disposable implements ICustomEditorMo this._textFileModel = this.textFileService.files.get(_resource); if (this._textFileModel) { this._register(this._textFileModel.onDidChangeOrphaned(() => this._onDidChangeOrphaned.fire())); + this._register(this._textFileModel.onDidChangeReadonly(() => this._onDidChangeReadonly.fire())); } this._register(this.textFileService.files.onDidChangeDirty(e => { @@ -61,12 +63,8 @@ export class CustomTextEditorModel extends Disposable implements ICustomEditorMo return this._resource; } - public isEditable(): boolean { - return !this._model.object.isReadonly(); - } - - public isOnReadonlyFileSystem(): boolean { - return this._fileService.hasCapability(this._resource, FileSystemProviderCapabilities.Readonly); + public isReadonly(): boolean { + return this._model.object.isReadonly(); } public get backupId() { diff --git a/lib/vscode/src/vs/workbench/contrib/customEditor/common/extensionPoint.ts b/src/vs/workbench/contrib/customEditor/common/extensionPoint.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/customEditor/common/extensionPoint.ts rename to src/vs/workbench/contrib/customEditor/common/extensionPoint.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/baseDebugView.ts b/src/vs/workbench/contrib/debug/browser/baseDebugView.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/baseDebugView.ts rename to src/vs/workbench/contrib/debug/browser/baseDebugView.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts rename to src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts index 41237a364a9f..2df6035afdd2 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts @@ -46,6 +46,7 @@ interface IBreakpointDecoration { } const breakpointHelperDecoration: IModelDecorationOptions = { + description: 'breakpoint-helper-decoration', glyphMarginClassName: ThemeIcon.asClassName(icons.debugBreakpointHint), stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges }; @@ -94,6 +95,7 @@ function getBreakpointDecorationOptions(model: ITextModel, breakpoint: IBreakpoi const renderInline = breakpoint.column && (breakpoint.column > model.getLineFirstNonWhitespaceColumn(breakpoint.lineNumber)); return { + description: 'breakpoint-decoration', glyphMarginClassName: ThemeIcon.asClassName(icon), glyphMarginHoverMessage, stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, @@ -128,6 +130,7 @@ async function createCandidateDecorations(model: ITextModel, breakpointDecoratio result.push({ range, options: { + description: 'breakpoint-placeholder-decoration', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, beforeContentClassName: breakpointAtPosition ? undefined : `debug-breakpoint-placeholder` }, diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts b/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts rename to src/vs/workbench/contrib/debug/browser/breakpointWidget.ts index f075b354d17d..7862fe95e3eb 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointWidget.ts @@ -27,7 +27,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { ITextModel } from 'vs/editor/common/model'; import { provideSuggestionItems, CompletionOptions } from 'vs/editor/contrib/suggest/suggest'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { transparent, editorForeground } from 'vs/platform/theme/common/colorRegistry'; +import { editorForeground } from 'vs/platform/theme/common/colorRegistry'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { IDecorationOptions } from 'vs/editor/common/editorCommon'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; @@ -57,7 +57,7 @@ function isCurlyBracketOpen(input: IActiveCodeEditor): boolean { } function createDecorations(theme: IColorTheme, placeHolder: string): IDecorationOptions[] { - const transparentForeground = transparent(editorForeground, 0.4)(theme); + const transparentForeground = theme.getColor(editorForeground)?.transparent(0.4); return [{ range: { startLineNumber: 0, @@ -125,7 +125,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi this.dispose(); } })); - this.codeEditorService.registerDecorationType(DECORATION_KEY, {}); + this.codeEditorService.registerDecorationType('breakpoint-widget', DECORATION_KEY, {}); this.create(); } @@ -229,7 +229,7 @@ export class BreakpointWidget extends ZoneWidget implements IPrivateBreakpointWi const setDecorations = () => { const value = this.input.getModel().getValue(); const decorations = !!value ? [] : createDecorations(this.themeService.getColorTheme(), this.placeholder); - this.input.setDecorations(DECORATION_KEY, decorations); + this.input.setDecorations('breakpoint-widget', DECORATION_KEY, decorations); }; this.input.getModel().onDidChangeContent(() => setDecorations()); this.themeService.onDidColorThemeChange(() => setDecorations()); diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/breakpointsView.ts b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/breakpointsView.ts rename to src/vs/workbench/contrib/debug/browser/breakpointsView.ts index e0f4fa1c42a4..bba2df5f6c2d 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/browser/breakpointsView.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts @@ -102,6 +102,7 @@ export class BreakpointsView extends ViewPane { this.breakpointSupportsCondition = CONTEXT_BREAKPOINT_SUPPORTS_CONDITION.bindTo(contextKeyService); this.breakpointInputFocused = CONTEXT_BREAKPOINT_INPUT_FOCUSED.bindTo(contextKeyService); this._register(this.debugService.getModel().onDidChangeBreakpoints(() => this.onBreakpointsChange())); + this._register(this.debugService.onDidChangeState(() => this.onStateChange())); } override renderBody(container: HTMLElement): void { @@ -254,6 +255,22 @@ export class BreakpointsView extends ViewPane { } } + private onStateChange(): void { + const thread = this.debugService.getViewModel().focusedThread; + if (thread && thread.stoppedDetails && thread.stoppedDetails.hitBreakpointIds && thread.stoppedDetails.hitBreakpointIds.length > 0) { + const hitBreakpointIds = thread.stoppedDetails.hitBreakpointIds; + const elements = this.elements; + const index = elements.findIndex(e => { + const id = e.getIdFromAdapter(thread.session.getId()); + return typeof id === 'number' && hitBreakpointIds.indexOf(id) !== -1; + }); + if (index >= 0) { + this.list.setFocus([index]); + this.list.setSelection([index]); + } + } + } + private get elements(): BreakpointItem[] { const model = this.debugService.getModel(); const elements = (>model.getExceptionBreakpoints()).concat(model.getFunctionBreakpoints()).concat(model.getDataBreakpoints()).concat(model.getBreakpoints()); diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts similarity index 96% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts rename to src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts index 08bf91ebc446..b94f3199510b 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts @@ -24,6 +24,7 @@ const stickiness = TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges; // we need a separate decoration for glyph margin, since we do not want it on each line of a multi line statement. const TOP_STACK_FRAME_MARGIN: IModelDecorationOptions = { + description: 'top-stack-frame-margin', glyphMarginClassName: ThemeIcon.asClassName(debugStackframe), stickiness, overviewRuler: { @@ -32,6 +33,7 @@ const TOP_STACK_FRAME_MARGIN: IModelDecorationOptions = { } }; const FOCUSED_STACK_FRAME_MARGIN: IModelDecorationOptions = { + description: 'focused-stack-frame-margin', glyphMarginClassName: ThemeIcon.asClassName(debugStackframeFocused), stickiness, overviewRuler: { @@ -40,14 +42,17 @@ const FOCUSED_STACK_FRAME_MARGIN: IModelDecorationOptions = { } }; const TOP_STACK_FRAME_DECORATION: IModelDecorationOptions = { + description: 'top-stack-frame-decoration', isWholeLine: true, className: 'debug-top-stack-frame-line', stickiness }; const TOP_STACK_FRAME_INLINE_DECORATION: IModelDecorationOptions = { + description: 'top-stack-frame-inline-decoration', beforeContentClassName: 'debug-top-stack-frame-column' }; const FOCUSED_STACK_FRAME_DECORATION: IModelDecorationOptions = { + description: 'focused-stack-frame-decoration', isWholeLine: true, className: 'debug-focused-stack-frame-line', stickiness diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/callStackView.ts b/src/vs/workbench/contrib/debug/browser/callStackView.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/callStackView.ts rename to src/vs/workbench/contrib/debug/browser/callStackView.ts index 94c7b595f3cb..51f7f931d44c 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/browser/callStackView.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackView.ts @@ -165,7 +165,7 @@ export class CallStackView extends ViewPane { const thread = sessions.length === 1 && sessions[0].getAllThreads().length === 1 ? sessions[0].getAllThreads()[0] : undefined; if (thread && thread.stoppedDetails) { this.stateMessageLabel.textContent = thread.stateLabel; - this.stateMessageLabel.title = thread.stateLabel; + this.stateMessageLabel.title = thread.stoppedDetails.text || thread.stateLabel; this.stateMessageLabel.classList.toggle('exception', thread.stoppedDetails.reason === 'exception'); this.stateMessage.hidden = false; } else if (sessions.length === 1 && sessions[0].state === State.Running) { @@ -603,6 +603,7 @@ class ThreadsRenderer implements ICompressibleTreeRenderer(JSONExtensions.JSONContribution); export class AdapterManager implements IAdapterManager { @@ -91,10 +92,46 @@ export class AdapterManager implements IAdapterManager { // update the schema to include all attributes, snippets and types from extensions. const items = (launchSchema.properties!['configurations'].items); + const taskSchema = TaskDefinitionRegistry.getJsonSchema(); + const definitions: IJSONSchemaMap = { + 'common': { + properties: { + 'name': { + type: 'string', + description: nls.localize('debugName', "Name of configuration; appears in the launch configuration dropdown menu."), + default: 'Launch' + }, + 'debugServer': { + type: 'number', + description: nls.localize('debugServer', "For debug extension development only: if a port is specified VS Code tries to connect to a debug adapter running in server mode"), + default: 4711 + }, + 'preLaunchTask': { + anyOf: [taskSchema, { + type: ['string'] + }], + default: '', + defaultSnippets: [{ body: { task: '', type: '' } }], + description: nls.localize('debugPrelaunchTask', "Task to run before debug session starts.") + }, + 'postDebugTask': { + anyOf: [taskSchema, { + type: ['string'], + }], + default: '', + defaultSnippets: [{ body: { task: '', type: '' } }], + description: nls.localize('debugPostDebugTask', "Task to run after debug session ends.") + }, + 'presentation': presentationSchema, + 'internalConsoleOptions': INTERNAL_CONSOLE_OPTIONS_SCHEMA, + } + } + }; + launchSchema.definitions = definitions; items.oneOf = []; items.defaultSnippets = []; this.debuggers.forEach(adapter => { - const schemaAttributes = adapter.getSchemaAttributes(); + const schemaAttributes = adapter.getSchemaAttributes(definitions); if (schemaAttributes && items.oneOf) { items.oneOf.push(...schemaAttributes); } @@ -247,7 +284,7 @@ export class AdapterManager implements IAdapterManager { } } - if (gettingConfigurations && candidates.length === 0) { + if ((!languageLabel || gettingConfigurations) && candidates.length === 0) { await this.activateDebuggers('onDebugInitialConfigurations'); candidates = this.debuggers.filter(dbg => dbg.hasInitialConfiguration() || dbg.hasConfigurationProvider()); } diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugColors.ts b/src/vs/workbench/contrib/debug/browser/debugColors.ts similarity index 96% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/debugColors.ts rename to src/vs/workbench/contrib/debug/browser/debugColors.ts index 0afeeb754e2f..63407735c935 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugColors.ts +++ b/src/vs/workbench/contrib/debug/browser/debugColors.ts @@ -135,15 +135,23 @@ export function registerColors() { * Only visible when there are more active debug sessions/threads running. */ .debug-pane .debug-call-stack .thread > .state.label, - .debug-pane .debug-call-stack .session > .state.label, - .debug-pane .monaco-list-row.selected .thread > .state.label, - .debug-pane .monaco-list-row.selected .session > .state.label { + .debug-pane .debug-call-stack .session > .state.label { background-color: ${debugViewStateLabelBackgroundColor}; color: ${debugViewStateLabelForegroundColor}; } + /* State "badge" displaying the active session's current state. + * Only visible when there are more active debug sessions/threads running + * and thread paused due to a thrown exception. + */ + .debug-pane .debug-call-stack .thread > .state.label.exception, + .debug-pane .debug-call-stack .session > .state.label.exception { + background-color: ${debugViewExceptionLabelBackgroundColor}; + color: ${debugViewExceptionLabelForegroundColor}; + } + /* Info "badge" shown when the debugger pauses due to a thrown exception. */ - .debug-pane .debug-call-stack-title > .pause-message > .label.exception { + .debug-pane .call-stack-state-message > .label.exception { background-color: ${debugViewExceptionLabelBackgroundColor}; color: ${debugViewExceptionLabelForegroundColor}; } diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugCommands.ts b/src/vs/workbench/contrib/debug/browser/debugCommands.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/debugCommands.ts rename to src/vs/workbench/contrib/debug/browser/debugCommands.ts index bc274a4f960a..c862f63c9cc5 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugCommands.ts +++ b/src/vs/workbench/contrib/debug/browser/debugCommands.ts @@ -66,7 +66,7 @@ export const STOP_LABEL = nls.localize('stop', "Stop"); export const CONTINUE_LABEL = nls.localize('continueDebug', "Continue"); export const FOCUS_SESSION_LABEL = nls.localize('focusSession', "Focus Session"); export const SELECT_AND_START_LABEL = nls.localize('selectAndStartDebugging', "Select and Start Debugging"); -export const DEBUG_CONFIGURE_LABEL = nls.localize('openLaunchJson', "Open {0}", 'launch.json'); +export const DEBUG_CONFIGURE_LABEL = nls.localize('openLaunchJson', "Open '{0}'", 'launch.json'); export const DEBUG_START_LABEL = nls.localize('startDebug', "Start Debugging"); export const DEBUG_RUN_LABEL = nls.localize('startWithoutDebugging', "Start Without Debugging"); @@ -338,7 +338,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ id: CONTINUE_ID, weight: KeybindingWeight.WorkbenchContrib + 10, // Use a stronger weight to get priority over start debugging F5 shortcut primary: KeyCode.F5, - when: CONTEXT_IN_DEBUG_MODE, + when: CONTEXT_DEBUG_STATE.isEqualTo('stopped'), handler: (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => { getThreadAndRun(accessor, context, thread => thread.continue()); } @@ -389,7 +389,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ id: DEBUG_START_COMMAND_ID, weight: KeybindingWeight.WorkbenchContrib, primary: KeyCode.F5, - when: ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing))), + when: ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.isEqualTo('inactive')), handler: async (accessor: ServicesAccessor, debugStartOptions?: { config?: Partial; noDebug?: boolean }) => { const debugService = accessor.get(IDebugService); let { launch, name, getConfig } = debugService.getConfigurationManager().selectedConfiguration; diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts b/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts rename to src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts b/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts rename to src/vs/workbench/contrib/debug/browser/debugEditorActions.ts index b3784e6901ca..51e666b94e2c 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorActions.ts @@ -33,7 +33,7 @@ class ToggleBreakpointAction extends EditorAction2 { id: 'editor.debug.action.toggleBreakpoint', title: { value: nls.localize('toggleBreakpointAction', "Debug: Toggle Breakpoint"), - original: 'Toggle Breakpoint', + original: 'Debug: Toggle Breakpoint', mnemonicTitle: nls.localize({ key: 'miToggleBreakpoint', comment: ['&& denotes a mnemonic'] }, "Toggle &&Breakpoint") }, f1: true, diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts similarity index 95% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts rename to src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts index c4a86e5c53c0..850045df6e87 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts @@ -30,7 +30,7 @@ import { ExceptionWidget } from 'vs/workbench/contrib/debug/browser/exceptionWid import { FloatingClickWidget } from 'vs/workbench/browser/codeeditor'; import { Position } from 'vs/editor/common/core/position'; import { CoreEditingCommands } from 'vs/editor/browser/controller/coreCommands'; -import { memoize, createMemoizer } from 'vs/base/common/decorators'; +import { memoize } from 'vs/base/common/decorators'; import { IEditorHoverOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { DebugHoverWidget } from 'vs/workbench/contrib/debug/browser/debugHover'; import { ITextModel } from 'vs/editor/common/model'; @@ -45,6 +45,8 @@ import { Event } from 'vs/base/common/event'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { Expression } from 'vs/workbench/contrib/debug/common/debugModel'; +import { themeColorFromId } from 'vs/platform/theme/common/themeService'; +import { registerColor } from 'vs/platform/theme/common/colorRegistry'; const LAUNCH_JSON_REGEX = /\.vscode\/launch\.json$/; const INLINE_VALUE_DECORATION_KEY = 'inlinevaluedecoration'; @@ -52,6 +54,18 @@ const MAX_NUM_INLINE_VALUES = 100; // JS Global scope can have 700+ entries. We const MAX_INLINE_DECORATOR_LENGTH = 150; // Max string length of each inline decorator when debugging. If exceeded ... is added const MAX_TOKENIZATION_LINE_LEN = 500; // If line is too long, then inline values for the line are skipped +export const debugInlineForeground = registerColor('editor.inlineValuesForeground', { + dark: '#ffffff80', + light: '#00000080', + hc: '#ffffff80' +}, nls.localize('editor.inlineValuesForeground', "Color for the debug inline value text.")); + +export const debugInlineBackground = registerColor('editor.inlineValuesBackground', { + dark: '#ffc80033', + light: '#ffc80033', + hc: '#ffc80033' +}, nls.localize('editor.inlineValuesBackground', "Color for the debug inline value background.")); + class InlineSegment { constructor(public column: number, public text: string) { } @@ -73,18 +87,9 @@ function createInlineValueDecoration(lineNumber: number, contentText: string, co renderOptions: { after: { contentText, - backgroundColor: 'rgba(255, 200, 0, 0.2)', - margin: '10px' - }, - dark: { - after: { - color: 'rgba(255, 255, 255, 0.5)', - } - }, - light: { - after: { - color: 'rgba(0, 0, 0, 0.5)', - } + backgroundColor: themeColorFromId(debugInlineBackground), + margin: '10px', + color: themeColorFromId(debugInlineForeground) } } }; @@ -185,7 +190,6 @@ export class DebugEditorContribution implements IDebugEditorContribution { private hoverRange: Range | null = null; private mouseDown = false; private exceptionWidgetVisible: IContextKey; - private static readonly MEMOIZER = createMemoizer(); private exceptionWidget: ExceptionWidget | undefined; private configurationWidget: FloatingClickWidget | undefined; @@ -208,7 +212,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { this.toDispose = []; this.registerListeners(); this.updateConfigurationWidgetVisibility(); - this.codeEditorService.registerDecorationType(INLINE_VALUE_DECORATION_KEY, {}); + this.codeEditorService.registerDecorationType('debug-inline-value-decoration', INLINE_VALUE_DECORATION_KEY, {}); this.exceptionWidgetVisible = CONTEXT_EXCEPTION_WIDGET_VISIBLE.bindTo(contextKeyService); this.toggleExceptionWidget(); } @@ -234,7 +238,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { })); this.toDispose.push(this.editor.onKeyDown((e: IKeyboardEvent) => this.onKeyDown(e))); this.toDispose.push(this.editor.onDidChangeModelContent(() => { - DebugEditorContribution.MEMOIZER.clear(); + this._wordToLineNumbersMap = undefined; this.updateInlineValuesScheduler.schedule(); })); this.toDispose.push(this.debugService.getViewModel().onWillUpdateViews(() => this.updateInlineValuesScheduler.schedule())); @@ -247,7 +251,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { this.toggleExceptionWidget(); this.hideHoverWidget(); this.updateConfigurationWidgetVisibility(); - DebugEditorContribution.MEMOIZER.clear(); + this._wordToLineNumbersMap = undefined; await this.updateInlineValueDecorations(stackFrame); })); this.toDispose.push(this.editor.onDidScrollChange(() => { @@ -266,9 +270,12 @@ export class DebugEditorContribution implements IDebugEditorContribution { })); } - @DebugEditorContribution.MEMOIZER + private _wordToLineNumbersMap: Map | undefined = undefined; private get wordToLineNumbersMap(): Map { - return getWordToLineNumbersMap(this.editor.getModel()); + if (!this._wordToLineNumbersMap) { + this._wordToLineNumbersMap = getWordToLineNumbersMap(this.editor.getModel()); + } + return this._wordToLineNumbersMap; } private applyHoverConfiguration(model: ITextModel, stackFrame: IStackFrame | undefined): void { @@ -708,7 +715,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { allDecorations = decorationsPerScope.reduce((previous, current) => previous.concat(current), []); } - this.editor.setDecorations(INLINE_VALUE_DECORATION_KEY, allDecorations); + this.editor.setDecorations('debug-inline-value-decoration', INLINE_VALUE_DECORATION_KEY, allDecorations); } dispose(): void { diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugHover.ts b/src/vs/workbench/contrib/debug/browser/debugHover.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/debugHover.ts rename to src/vs/workbench/contrib/debug/browser/debugHover.ts index 60febd20d81e..5f1f4d1123ff 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugHover.ts +++ b/src/vs/workbench/contrib/debug/browser/debugHover.ts @@ -262,6 +262,7 @@ export class DebugHoverWidget implements IContentWidget { } private static readonly _HOVER_HIGHLIGHT_DECORATION_OPTIONS = ModelDecorationOptions.register({ + description: 'bdebug-hover-highlight', className: 'hoverHighlight' }); diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugIcons.ts b/src/vs/workbench/contrib/debug/browser/debugIcons.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/debugIcons.ts rename to src/vs/workbench/contrib/debug/browser/debugIcons.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugProgress.ts b/src/vs/workbench/contrib/debug/browser/debugProgress.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/debugProgress.ts rename to src/vs/workbench/contrib/debug/browser/debugProgress.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugQuickAccess.ts b/src/vs/workbench/contrib/debug/browser/debugQuickAccess.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/debugQuickAccess.ts rename to src/vs/workbench/contrib/debug/browser/debugQuickAccess.ts index 3c920d1366f8..e29b61897e2e 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugQuickAccess.ts +++ b/src/vs/workbench/contrib/debug/browser/debugQuickAccess.ts @@ -33,7 +33,7 @@ export class StartDebugQuickAccessProvider extends PickerQuickAccessProvider { + protected async _getPicks(filter: string): Promise<(IQuickPickSeparator | IPickerQuickAccessItem)[]> { const picks: Array = []; picks.push({ type: 'separator', label: 'launch.json' }); diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugService.ts b/src/vs/workbench/contrib/debug/browser/debugService.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/debugService.ts rename to src/vs/workbench/contrib/debug/browser/debugService.ts index 0a8d34ec3635..a0c444ab666a 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/browser/debugService.ts @@ -276,11 +276,7 @@ export class DebugService implements IDebugService { */ async startDebugging(launch: ILaunch | undefined, configOrName?: IConfig | string, options?: IDebugSessionOptions): Promise { const message = options && options.noDebug ? nls.localize('runTrust', "Running executes build tasks and program code from your workspace.") : nls.localize('debugTrust', "Debugging executes build tasks and program code from your workspace."); - const trust = await this.workspaceTrustRequestService.requestWorkspaceTrust({ - modal: true, - message, - - }); + const trust = await this.workspaceTrustRequestService.requestWorkspaceTrust({ message }); if (!trust) { return false; } @@ -289,8 +285,7 @@ export class DebugService implements IDebugService { // make sure to save all files and that the configuration is up to date await this.extensionService.activateByEvent('onDebug'); if (!options?.parentSession) { - const saveBeforeStartConfig: string = this.configurationService.getValue('debug.saveBeforeStart'); - + const saveBeforeStartConfig: string = this.configurationService.getValue('debug.saveBeforeStart', { overrideIdentifier: this.editorService.activeTextEditorMode }); if (saveBeforeStartConfig !== 'none') { await this.editorService.saveAll(); if (saveBeforeStartConfig === 'allEditorsInActiveGroup') { diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugSession.ts b/src/vs/workbench/contrib/debug/browser/debugSession.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/debugSession.ts rename to src/vs/workbench/contrib/debug/browser/debugSession.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugStatus.ts b/src/vs/workbench/contrib/debug/browser/debugStatus.ts similarity index 96% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/debugStatus.ts rename to src/vs/workbench/contrib/debug/browser/debugStatus.ts index a83612abdcae..91806d765195 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugStatus.ts +++ b/src/vs/workbench/contrib/debug/browser/debugStatus.ts @@ -23,7 +23,7 @@ export class DebugStatusContribution implements IWorkbenchContribution { ) { const addStatusBarEntry = () => { - this.entryAccessor = this.statusBarService.addEntry(this.entry, 'status.debug', nls.localize('status.debug', "Debug"), StatusbarAlignment.LEFT, 30 /* Low Priority */); + this.entryAccessor = this.statusBarService.addEntry(this.entry, 'status.debug', StatusbarAlignment.LEFT, 30 /* Low Priority */); }; const setShowInStatusBar = () => { @@ -65,6 +65,7 @@ export class DebugStatusContribution implements IWorkbenchContribution { } return { + name: nls.localize('status.debug', "Debug"), text: '$(debug-alt-small) ' + text, ariaLabel: nls.localize('debugTarget', "Debug: {0}", text), tooltip: nls.localize('selectAndStartDebug', "Select and start debug configuration"), diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugTaskRunner.ts b/src/vs/workbench/contrib/debug/browser/debugTaskRunner.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/debugTaskRunner.ts rename to src/vs/workbench/contrib/debug/browser/debugTaskRunner.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugTitle.ts b/src/vs/workbench/contrib/debug/browser/debugTitle.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/debugTitle.ts rename to src/vs/workbench/contrib/debug/browser/debugTitle.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugToolBar.ts b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/debugToolBar.ts rename to src/vs/workbench/contrib/debug/browser/debugToolBar.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/debugViewlet.ts b/src/vs/workbench/contrib/debug/browser/debugViewlet.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/debugViewlet.ts rename to src/vs/workbench/contrib/debug/browser/debugViewlet.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts b/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts rename to src/vs/workbench/contrib/debug/browser/exceptionWidget.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts b/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts rename to src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/linkDetector.ts b/src/vs/workbench/contrib/debug/browser/linkDetector.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/linkDetector.ts rename to src/vs/workbench/contrib/debug/browser/linkDetector.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts b/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts rename to src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/media/breakpointWidget.css b/src/vs/workbench/contrib/debug/browser/media/breakpointWidget.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/media/breakpointWidget.css rename to src/vs/workbench/contrib/debug/browser/media/breakpointWidget.css diff --git a/src/vs/workbench/contrib/debug/browser/media/continue-tb.png b/src/vs/workbench/contrib/debug/browser/media/continue-tb.png new file mode 100644 index 0000000000000000000000000000000000000000..8e2d11acd7bafe0ee1345b347dfcb03aa38dec61 GIT binary patch literal 668 zcmV;N0%QG&P)DpEq?K*0 zKa9_)9dp)ZJ;Nc?X8+LgU7LOI3179n4JK6kqPfIc+v{MmnQY?v)f-g%3K(j8A51pX z2GyQ&)DB|siT|nH&}(l|LQsRrd9^KY86^Zam<;RyN0`O#zWOFAb^!sQp$A_NFy0^C z*V?q*TliE>cLVu zMeKvA>c~~q=bY7Mk6)lNqgeo~qt;Rfk~4eI2H%FP7KUAw1x`EP1P1RB2%YO=ofX*VEps7S-@| zX*bfy+t7;sC6k3vl?4q?Cuymhbs>ZhLI@#5IDP{lp>&hWCgG6)0000b>GDMP+il+*UP^pt2*G2}9I=mMyZzJ;w|#BWONk|Oar}1d6t`o3xE)9z4$|$w z2Cbmn4otA(TKp4o`#tcX|%LT)3)bS@pMLfPOPLrn(~U=;emmnMz# zZWj6=BQsEiY7FD*2{Ei zzwPSfD>DK$VbTkoV&u@pS` z^8u?LmfyV=2Xm4cC%*Bl@H?{@`x3Vhj4nd)7MM7Cr?89cK%cl0Of}BAc#4J3^2?X! z>W8%%&SA@bT*N}mIr}N5*C{Lp!2Y+r;LX6rw(b+dM^;e*O76dr`0H zOcR^-9#|)sP5e|9){2oZN-zMf`Y>bSXFTXM9blo!HC;Wk3vW8p(ZGS_+U68QqjH~6U+$cfTmAR{G~;|8JaW}ZkMl6s9TyVZV^^%yJ0HAR z-IsMOlEu@{ymHlvE5W$DYaXj`cytdHELcJm&dMu+#Wl{-o$sRcGV#yH3`X)+c3)T@ zdF84TSAuCROGnPMab+xtb+cr|ZUD+)u0=ktT4mjSWHf)Z=3~!=DqIO}FWh@+#a+M^ z7`|)TzA_*H-1cFo(n09$DFfSb=|NUXAW{+(_^$WLW4`5&KU3+JR3VLB~`|5 zeis)hY@(GO@^6fem=G|o1=Dm=;}ru>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{sB)H$B+ufw>LNP9x@Pcdw5^4+ki>BA) literal 0 HcmV?d00001 diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/media/repl.css b/src/vs/workbench/contrib/debug/browser/media/repl.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/media/repl.css rename to src/vs/workbench/contrib/debug/browser/media/repl.css diff --git a/src/vs/workbench/contrib/debug/browser/media/restart-tb.png b/src/vs/workbench/contrib/debug/browser/media/restart-tb.png new file mode 100644 index 0000000000000000000000000000000000000000..9ec0196946a09745c8db987bfffde35bf27cb605 GIT binary patch literal 1276 zcmVb*w2m-GuXIM+ylatMMnWoe3$IRH82TH_vbh-g26 zO>W%mv>Yl`YPM2UAq6!kstfjdXZnr}WpQm{X2({M<|i4vv-ZwBo_Xi}Gl0cnu~;k? zi^XEGbOA#jSt%_gd>|3wxa;e|};!3`M1s9+_Q zb5U&0R0pIi(}ZuFyyOiW_tmK&|1>%P#Y3RY&$zuqNHT`D!k2hww`;Q z!|wj?DGoLX&Th8cRbA+-w@lH{SA5R|t`wOWxl?7Zha? z+vV*zhwrozE+N>=Y;t}bAuzL~n@c!;x{Ylf2rt>KSj9LS$6RvG9eVSvNngmBmfH+m zt~ORu2#jx9O=NyHG5?vaU%m709b6t9SrY=cT5d7P@hw8o3&HMzs81s#x3Awu3~%Jf zBwFn@k$slA2~Et{Z~&T>w2GX9ZDFFQm7NtP>Ry4dlbxRiUAjAV??Y%{e1kO_AU!_f6d>w2fPmoZ74K(PH4Vxo9nnq+WN^Xrj!3m6UOh5xI!7=#CHI&gO zV$qnSSp0`z8wdXw8fXdrg6#2<@WzjRb+?OGD6Unnp$@hcY*Wh`8uT?i)I~}M>t&48 z_~4(xW+A+{&zoHQ?`>GYn4{LUkzDyg2sX)u5iF`*Wz?_bLI{4m^B9Lx{%4cYDGpo+ z!Mo92%420J*v2&7qLF-9<+CphR4Z0Ko@e~?_nqjrnRIE$M z`*_W-ta;*aRkfK!{g^;K6^x~!Je9yEGzcZw^?pf6;T0%eE>N;MMZ=h;wxmOT(-eEJ z{$TX{)|AktJiGrhJP6Na5@W%(M!rfx0t}FSmSqA=Wo7YT7i7T>GzlGPWlG;nM>tzM z^-zWlCNJIk=!1$J*Bo2+=PX0jr@U9@T5kP1J9h6KXcBsto=<+cPBC>c*hbfrf_YE2 z%NTvM^9bib)wNc4GK^KlR2#7>ocshKFcM22m1hg|cC_V|OI<9o$UuG=!}7&@FW_{T zakV+^z1m~GsK1VHlfWoJ|ClZLr^eLs4}k!x`KBTX^5~>a4i$2jX;I5*Me+GyFN(=x_Zx m5Vu$?7K_DVu~;mYuJ{MSH1*Nk80Jy{0000_YP)6;g%h37T*OwjkW%xNEnWH2US6bq+J zZ+e0oh6^t{F1+lx@Ur8=S7rTMeI?bE&4Tf|h*Q=)QH9?W{31zFY<%ZFuE18o^bhD0 zV^7LNM4|~x!QH7aF)zJJ~^cLH4wykp3if zAOcZ@cXFCgiJXB+?ZPFb&yhtab4-NCQU@Xs?UCMoLI+)?n`F0hIzS|%4q9ELEoG-o zQDEaMuW*JU6kdPtWKg5JSV9XC!S>i^%>7Utu%9 zdB$a#mR{WjK3hnu&%+I}!hMNq{4TKy1Js2>Y^ryG>JG@US6USdn00v94AZ zuEMJ&o}aZfJVA!$VG6v50cQK*jPNiV${$*I_Ni_{=-ETUBdcB0wQUc>??#iuTNuR( iuse?9IF92u*Uf+Da}`KLJQmIX00002}8PN>P+HPP8+vqWPpqmc7#E^VqvP;{_bYaU92S932S8yedMc1Uhou21ajl8o>}# z;a(B8LqNfuZq}!cQ6fKhLcd@{1|#Ok3Y#3}qu%$h4I@kl=zi%6>rH;|2( zNUI7jAsbPbRuf)9Hlix6GH6{U8-UNVZRecZ(j3T=3tuJsu1mYK?KcQ7ETxkQFDonb za|)Ky$%I#tjaW*ji*Uf#S=sY|!6Mm6ExpS(Z7_35q`x2$>4Zx>53*FO5!v^TsgEUK zX>4TZPfG_GwFx^&L^5HSMu^wNBE5=iWLjEeiFk_2(@jxH2Q85<3HMi(jYR1-;Xz7S z!8|?e9dYcYIOvk;e=y6IZVE2E?zr%}WA zcPymU=ivpi!WLiq^smGt7@#hE%AZEBkc|+v@KN4zZPbO!b3ALD!ua+7!9~PJhR=@hI!r>X=;l9ys9`m~NYuUC`qC-5Go!!Ey jdIB8BaU92SoHgJA;XwguL{kH!00000NkvXXu0mjfj+rm$ literal 0 HcmV?d00001 diff --git a/src/vs/workbench/contrib/debug/browser/media/stepover-tb.png b/src/vs/workbench/contrib/debug/browser/media/stepover-tb.png new file mode 100644 index 0000000000000000000000000000000000000000..f492f89557121d9291b6c7317b53385ba88bf233 GIT binary patch literal 914 zcmV;D18w|?P)NZdpyQ-eDB;lcLI1k9*@W4@pwEQ6BKR;tys_lqIBEahDuNn zr-IjFi7Kf<2SD!xNI39b-m_0*QGG!_)g&hh^F>96u!t5o11yW6Er( zOX$I6-J?tQc<&v@3 zdl|R%Tx>B2?P3CS+WAe3pVFNqXVVl(Z=N7SPqAbqqj>mGU(DvS)0)@ZigM;n7u&^r1Aqm6cbKFdDfcr!LL}lk-i*zfT z-zH1X!h%^4=%^f}+i2l$aEGy2P2oJ;jJYym?oGFCFQ^++R~HUix_;$SZ}sw8Nx5mm z=>Fl<}dx`mG} zwrisax<)@8SlPN@=}#;|u?m~CuQApI7jRG+99FR(w74H_rLQ4Q(h`4u`OZIcIo-M} zGv{F$Cuxa!_7TRrtLR(|2RIS@>VfJ|kltt3=_xH-pLcn$!9E9Yfb+HVlh0DeWi;lT o)gJ>MkH_Qjcsw4D$8+8I2cIY!4gUklJ^%m!07*qoM6N<$g2A($ApigX literal 0 HcmV?d00001 diff --git a/src/vs/workbench/contrib/debug/browser/media/stop-tb.png b/src/vs/workbench/contrib/debug/browser/media/stop-tb.png new file mode 100644 index 0000000000000000000000000000000000000000..f4ae35a946ddc5e1cf16cc17ce2d1c05852a9456 GIT binary patch literal 310 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{%KDa$B+ufw>J&>nj8e&9@cj*y~mh;XyO`^ zkZDJ}`j2?_lp9=hDGB$;c$3m7(Dq%mW!iMvS+bl!tqlJjh&+sYV^or zEkQk2*HquF;AEAb6~3}hNcYU6rpIo-uIJ93zg_C)W{VyDadEbWm#zus$R5N&+!YZ2 zST*Ncp!ZI_RUgVc1M;0&mfs5x@6A~eDD$Kxdu3YEy8i_k^Upo<+Y#rs{rAn4EzhJ` cK#ocN$&_ZJ;(szA{1}Mq>FVdQ&MBb@06PA4t^fc4 literal 0 HcmV?d00001 diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts rename to src/vs/workbench/contrib/debug/browser/rawDebugSession.ts index f9c3477a8a5d..125cc091e2e3 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts @@ -692,7 +692,7 @@ export class RawDebugSession implements IDisposable { const label = error.urlLabel ? error.urlLabel : nls.localize('moreInfo', "More Info"); return errors.createErrorWithActions(userMessage, { actions: [new Action('debug.moreInfo', label, undefined, true, async () => { - this.openerService.open(URI.parse(url)); + this.openerService.open(URI.parse(url), { allowCommands: true }); })] }); } diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts similarity index 97% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/repl.ts rename to src/vs/workbench/contrib/debug/browser/repl.ts index 4a4ded5663da..0653e7f174d4 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -33,7 +33,7 @@ import { createAndBindHistoryNavigationWidgetScopedContextKeyService } from 'vs/ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { getSimpleEditorOptions, getSimpleCodeEditorWidgetOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; import { IDecorationOptions } from 'vs/editor/common/editorCommon'; -import { transparent, editorForeground } from 'vs/platform/theme/common/colorRegistry'; +import { editorForeground, resolveColorValue } from 'vs/platform/theme/common/colorRegistry'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/debugActionViewItems'; import { CompletionContext, CompletionList, CompletionProviderRegistry, CompletionItem, completionKindFromString, CompletionItemKind, CompletionItemInsertTextRule } from 'vs/editor/common/modes'; @@ -68,6 +68,7 @@ const $ = dom.$; const HISTORY_STORAGE_KEY = 'debug.repl.history'; const FILTER_HISTORY_STORAGE_KEY = 'debug.repl.filterHistory'; +const FILTER_VALUE_STORAGE_KEY = 'debug.repl.filterValue'; const DECORATION_KEY = 'replinputdecoration'; const FILTER_ACTION_ID = `workbench.actions.treeView.repl.filter`; @@ -132,10 +133,11 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { this.history = new HistoryNavigator(JSON.parse(this.storageService.get(HISTORY_STORAGE_KEY, StorageScope.WORKSPACE, '[]')), 50); this.filter = new ReplFilter(); this.filterState = new ReplFilterState(this); + this.filter.filterQuery = this.filterState.filterText = this.storageService.get(FILTER_VALUE_STORAGE_KEY, StorageScope.WORKSPACE, ''); this.multiSessionRepl = CONTEXT_MULTI_SESSION_REPL.bindTo(contextKeyService); this.multiSessionRepl.set(this.isMultiSessionView); - codeEditorService.registerDecorationType(DECORATION_KEY, {}); + codeEditorService.registerDecorationType('repl-decoration', DECORATION_KEY, {}); this.registerListeners(); } @@ -271,9 +273,10 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { } getFilterStats(): { total: number, filtered: number } { + // This could be called before the tree is created when setting this.filterState.filterText value return { - total: this.tree.getNode().children.length, - filtered: this.tree.getNode().children.filter(c => c.visible).length + total: this.tree?.getNode().children.length ?? 0, + filtered: this.tree?.getNode().children.filter(c => c.visible).length ?? 0 }; } @@ -657,7 +660,7 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { const decorations: IDecorationOptions[] = []; if (this.isReadonly && this.replInput.hasTextFocus() && !this.replInput.getValue()) { - const transparentForeground = transparent(editorForeground, 0.4)(this.themeService.getColorTheme()); + const transparentForeground = resolveColorValue(editorForeground, this.themeService.getColorTheme())?.transparent(0.4); decorations.push({ range: { startLineNumber: 0, @@ -674,7 +677,7 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { }); } - this.replInput.setDecorations(DECORATION_KEY, decorations); + this.replInput.setDecorations('repl-decoration', DECORATION_KEY, decorations); } override saveState(): void { @@ -691,6 +694,12 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { } else { this.storageService.remove(FILTER_HISTORY_STORAGE_KEY, StorageScope.WORKSPACE); } + const filterValue = this.filterState.filterText; + if (filterValue) { + this.storageService.store(FILTER_VALUE_STORAGE_KEY, filterValue, StorageScope.WORKSPACE, StorageTarget.USER); + } else { + this.storageService.remove(FILTER_VALUE_STORAGE_KEY, StorageScope.WORKSPACE); + } } super.saveState(); diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/replFilter.ts b/src/vs/workbench/contrib/debug/browser/replFilter.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/replFilter.ts rename to src/vs/workbench/contrib/debug/browser/replFilter.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/replViewer.ts b/src/vs/workbench/contrib/debug/browser/replViewer.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/replViewer.ts rename to src/vs/workbench/contrib/debug/browser/replViewer.ts index d393d97ca5f7..794e917ad7c1 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/browser/replViewer.ts +++ b/src/vs/workbench/contrib/debug/browser/replViewer.ts @@ -394,7 +394,7 @@ export class ReplAccessibilityProvider implements IListAccessibilityProvider 1 ? localize({ key: 'occurred', comment: ['Front will the value of the debug console element. Placeholder will be replaced by a number which represents occurrance count.'] }, - ", occured {0} times", element.count) : ''); + ", occurred {0} times", element.count) : ''); } if (element instanceof RawObjectReplElement) { return localize('replRawObjectAriaLabel', "Debug console variable {0}, value {1}", element.name, element.value); diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts b/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts rename to src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/variablesView.ts b/src/vs/workbench/contrib/debug/browser/variablesView.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/variablesView.ts rename to src/vs/workbench/contrib/debug/browser/variablesView.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts b/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts rename to src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/browser/welcomeView.ts b/src/vs/workbench/contrib/debug/browser/welcomeView.ts similarity index 97% rename from lib/vscode/src/vs/workbench/contrib/debug/browser/welcomeView.ts rename to src/vs/workbench/contrib/debug/browser/welcomeView.ts index e5b63d8da09b..5fb19d85d79a 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/browser/welcomeView.ts +++ b/src/vs/workbench/contrib/debug/browser/welcomeView.ts @@ -32,8 +32,8 @@ const CONTEXT_DEBUGGER_INTERESTED_IN_ACTIVE_EDITOR = new RawContextKey( export class WelcomeView extends ViewPane { - static ID = 'workbench.debug.welcome'; - static LABEL = localize('run', "Run"); + static readonly ID = 'workbench.debug.welcome'; + static readonly LABEL = localize('run', "Run"); private debugStartLanguageContext: IContextKey; private debuggerInterestedContext: IContextKey; @@ -123,7 +123,7 @@ viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, { viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, { content: localize({ key: 'detectThenRunAndDebug', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] }, - "[Show](command:{0}) all automatic debug configurations.", SELECT_AND_START_ID), + "[Show all automatic debug configurations](command:{0}).", SELECT_AND_START_ID), when: CONTEXT_DEBUGGERS_AVAILABLE, group: ViewContentGroups.Debug, order: 10 diff --git a/lib/vscode/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts b/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts rename to src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/debug/common/debug.ts rename to src/vs/workbench/contrib/debug/common/debug.ts index c005f81bd2aa..3a46f18c937d 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -106,6 +106,7 @@ export interface IRawStoppedDetails { totalFrames?: number; allThreadsStopped?: boolean; framesErrorMessage?: string; + hitBreakpointIds?: number[]; } // model diff --git a/lib/vscode/src/vs/workbench/contrib/debug/common/debugCompoundRoot.ts b/src/vs/workbench/contrib/debug/common/debugCompoundRoot.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/common/debugCompoundRoot.ts rename to src/vs/workbench/contrib/debug/common/debugCompoundRoot.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/common/debugContentProvider.ts b/src/vs/workbench/contrib/debug/common/debugContentProvider.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/common/debugContentProvider.ts rename to src/vs/workbench/contrib/debug/common/debugContentProvider.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/common/debugModel.ts b/src/vs/workbench/contrib/debug/common/debugModel.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/common/debugModel.ts rename to src/vs/workbench/contrib/debug/common/debugModel.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts b/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts rename to src/vs/workbench/contrib/debug/common/debugProtocol.d.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/common/debugSchemas.ts b/src/vs/workbench/contrib/debug/common/debugSchemas.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/common/debugSchemas.ts rename to src/vs/workbench/contrib/debug/common/debugSchemas.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/common/debugSource.ts b/src/vs/workbench/contrib/debug/common/debugSource.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/common/debugSource.ts rename to src/vs/workbench/contrib/debug/common/debugSource.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/common/debugStorage.ts b/src/vs/workbench/contrib/debug/common/debugStorage.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/common/debugStorage.ts rename to src/vs/workbench/contrib/debug/common/debugStorage.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/common/debugTelemetry.ts b/src/vs/workbench/contrib/debug/common/debugTelemetry.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/common/debugTelemetry.ts rename to src/vs/workbench/contrib/debug/common/debugTelemetry.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/common/debugUtils.ts b/src/vs/workbench/contrib/debug/common/debugUtils.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/common/debugUtils.ts rename to src/vs/workbench/contrib/debug/common/debugUtils.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/common/debugViewModel.ts b/src/vs/workbench/contrib/debug/common/debugViewModel.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/common/debugViewModel.ts rename to src/vs/workbench/contrib/debug/common/debugViewModel.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/common/debugger.ts b/src/vs/workbench/contrib/debug/common/debugger.ts similarity index 78% rename from lib/vscode/src/vs/workbench/contrib/debug/common/debugger.ts rename to src/vs/workbench/contrib/debug/common/debugger.ts index d021319ffc4c..bf3633def3fb 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/common/debugger.ts +++ b/src/vs/workbench/contrib/debug/common/debugger.ts @@ -4,21 +4,18 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import * as objects from 'vs/base/common/objects'; import { isObject } from 'vs/base/common/types'; -import { IJSONSchema, IJSONSchemaSnippet } from 'vs/base/common/jsonSchema'; +import { IJSONSchema, IJSONSchemaMap, IJSONSchemaSnippet } from 'vs/base/common/jsonSchema'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { IConfig, IDebuggerContribution, INTERNAL_CONSOLE_OPTIONS_SCHEMA, IDebugAdapter, IDebugger, IDebugSession, IAdapterManager, IDebugService } from 'vs/workbench/contrib/debug/common/debug'; +import { IConfig, IDebuggerContribution, IDebugAdapter, IDebugger, IDebugSession, IAdapterManager, IDebugService } from 'vs/workbench/contrib/debug/common/debug'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import * as ConfigurationResolverUtils from 'vs/workbench/services/configurationResolver/common/configurationResolverUtils'; -import { TaskDefinitionRegistry } from 'vs/workbench/contrib/tasks/common/taskDefinitionRegistry'; import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; import { isDebuggerMainContribution } from 'vs/workbench/contrib/debug/common/debugUtils'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { presentationSchema } from 'vs/workbench/contrib/debug/common/debugSchemas'; import { ITelemetryEndpoint } from 'vs/platform/telemetry/common/telemetry'; import { cleanRemoteAuthority } from 'vs/platform/telemetry/common/telemetryUtils'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -194,15 +191,15 @@ export class Debugger implements IDebugger { }; } - getSchemaAttributes(): IJSONSchema[] | null { + getSchemaAttributes(definitions: IJSONSchemaMap): IJSONSchema[] | null { if (!this.debuggerContribution.configurationAttributes) { return null; } // fill in the default configuration attributes shared by all adapters. - const taskSchema = TaskDefinitionRegistry.getJsonSchema(); return Object.keys(this.debuggerContribution.configurationAttributes).map(request => { + const definitionId = `${this.type}:${request}`; const attributes: IJSONSchema = this.debuggerContribution.configurationAttributes[request]; const defaultRequired = ['name', 'type', 'request']; attributes.required = attributes.required && attributes.required.length ? defaultRequired.concat(attributes.required) : defaultRequired; @@ -219,64 +216,44 @@ export class Debugger implements IDebugger { errorMessage: nls.localize('debugTypeNotRecognised', "The debug type is not recognized. Make sure that you have a corresponding debug extension installed and that it is enabled."), patternErrorMessage: nls.localize('node2NotSupported', "\"node2\" is no longer supported, use \"node\" instead and set the \"protocol\" attribute to \"inspector\".") }; - properties['name'] = { - type: 'string', - description: nls.localize('debugName', "Name of configuration; appears in the launch configuration dropdown menu."), - default: 'Launch' - }; properties['request'] = { enum: [request], description: nls.localize('debugRequest', "Request type of configuration. Can be \"launch\" or \"attach\"."), }; - properties['debugServer'] = { - type: 'number', - description: nls.localize('debugServer', "For debug extension development only: if a port is specified VS Code tries to connect to a debug adapter running in server mode"), - default: 4711 - }; - properties['preLaunchTask'] = { - anyOf: [taskSchema, { - type: ['string'] - }], - default: '', - defaultSnippets: [{ body: { task: '', type: '' } }], - description: nls.localize('debugPrelaunchTask', "Task to run before debug session starts.") - }; - properties['postDebugTask'] = { - anyOf: [taskSchema, { - type: ['string'], - }], - default: '', - defaultSnippets: [{ body: { task: '', type: '' } }], - description: nls.localize('debugPostDebugTask', "Task to run after debug session ends.") - }; - properties['presentation'] = presentationSchema; - properties['internalConsoleOptions'] = INTERNAL_CONSOLE_OPTIONS_SCHEMA; - // Clear out windows, linux and osx fields to not have cycles inside the properties object - delete properties['windows']; - delete properties['osx']; - delete properties['linux']; - - const osProperties = objects.deepClone(properties); - properties['windows'] = { - type: 'object', - description: nls.localize('debugWindowsConfiguration', "Windows specific launch configuration attributes."), - properties: osProperties - }; - properties['osx'] = { - type: 'object', - description: nls.localize('debugOSXConfiguration', "OS X specific launch configuration attributes."), - properties: osProperties - }; - properties['linux'] = { - type: 'object', - description: nls.localize('debugLinuxConfiguration', "Linux specific launch configuration attributes."), - properties: osProperties - }; + for (const prop in definitions['common'].properties) { + properties[prop] = { + $ref: `#/definitions/common/properties/${prop}` + }; + } + definitions[definitionId] = attributes; + Object.keys(properties).forEach(name => { // Use schema allOf property to get independent error reporting #21113 ConfigurationResolverUtils.applyDeprecatedVariableMessage(properties[name]); }); - return attributes; + + const result = { + allOf: [{ + $ref: `#/definitions/${definitionId}` + }, { + properties: { + windows: { + $ref: `#/definitions/${definitionId}`, + description: nls.localize('debugWindowsConfiguration', "Windows specific launch configuration attributes.") + }, + osx: { + $ref: `#/definitions/${definitionId}`, + description: nls.localize('debugOSXConfiguration', "OS X specific launch configuration attributes.") + }, + linux: { + $ref: `#/definitions/${definitionId}`, + description: nls.localize('debugLinuxConfiguration', "Linux specific launch configuration attributes.") + } + } + }] + }; + + return result; }); } } diff --git a/lib/vscode/src/vs/workbench/contrib/debug/common/replModel.ts b/src/vs/workbench/contrib/debug/common/replModel.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/common/replModel.ts rename to src/vs/workbench/contrib/debug/common/replModel.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/electron-sandbox/extensionHostDebugService.ts b/src/vs/workbench/contrib/debug/electron-sandbox/extensionHostDebugService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/electron-sandbox/extensionHostDebugService.ts rename to src/vs/workbench/contrib/debug/electron-sandbox/extensionHostDebugService.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/node/debugAdapter.ts b/src/vs/workbench/contrib/debug/node/debugAdapter.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/node/debugAdapter.ts rename to src/vs/workbench/contrib/debug/node/debugAdapter.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/node/telemetryApp.ts b/src/vs/workbench/contrib/debug/node/telemetryApp.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/node/telemetryApp.ts rename to src/vs/workbench/contrib/debug/node/telemetryApp.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/node/terminals.ts b/src/vs/workbench/contrib/debug/node/terminals.ts similarity index 91% rename from lib/vscode/src/vs/workbench/contrib/debug/node/terminals.ts rename to src/vs/workbench/contrib/debug/node/terminals.ts index 03c4fc8f6c5d..a4ef4b4c84f4 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/node/terminals.ts +++ b/src/vs/workbench/contrib/debug/node/terminals.ts @@ -5,29 +5,13 @@ import * as cp from 'child_process'; import * as platform from 'vs/base/common/platform'; -import { WindowsExternalTerminalService, MacExternalTerminalService, LinuxExternalTerminalService } from 'vs/workbench/contrib/externalTerminal/node/externalTerminalService'; +import { getDriveLetter } from 'vs/base/common/extpath'; +import { LinuxExternalTerminalService, MacExternalTerminalService, WindowsExternalTerminalService } from 'vs/platform/externalTerminal/node/externalTerminalService'; +import { IExternalTerminalService } from 'vs/platform/externalTerminal/common/externalTerminal'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IExternalTerminalService } from 'vs/workbench/contrib/externalTerminal/common/externalTerminal'; import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration'; -import { getDriveLetter } from 'vs/base/common/extpath'; -let externalTerminalService: IExternalTerminalService | undefined = undefined; -export function runInExternalTerminal(args: DebugProtocol.RunInTerminalRequestArguments, configProvider: ExtHostConfigProvider): Promise { - if (!externalTerminalService) { - if (platform.isWindows) { - externalTerminalService = new WindowsExternalTerminalService(undefined); - } else if (platform.isMacintosh) { - externalTerminalService = new MacExternalTerminalService(undefined); - } else if (platform.isLinux) { - externalTerminalService = new LinuxExternalTerminalService(undefined); - } else { - throw new Error('external terminals not supported on this platform'); - } - } - const config = configProvider.getConfiguration('terminal'); - return externalTerminalService.runInTerminal(args.title!, args.cwd, args.args, args.env || {}, config.external || {}); -} function spawnAsPromised(command: string, args: string[]): Promise { return new Promise((resolve, reject) => { @@ -47,15 +31,35 @@ function spawnAsPromised(command: string, args: string[]): Promise { }); } +let externalTerminalService: IExternalTerminalService | undefined = undefined; + +export function runInExternalTerminal(args: DebugProtocol.RunInTerminalRequestArguments, configProvider: ExtHostConfigProvider): Promise { + if (!externalTerminalService) { + if (platform.isWindows) { + externalTerminalService = new WindowsExternalTerminalService(undefined); + } else if (platform.isMacintosh) { + externalTerminalService = new MacExternalTerminalService(undefined); + } else if (platform.isLinux) { + externalTerminalService = new LinuxExternalTerminalService(undefined); + } else { + throw new Error('external terminals not supported on this platform'); + } + } + const config = configProvider.getConfiguration('terminal'); + return externalTerminalService.runInTerminal(args.title!, args.cwd, args.args, args.env || {}, config.external || {}); +} + export function hasChildProcesses(processId: number | undefined): Promise { if (processId) { + // if shell has at least one child process, assume that shell is busy if (platform.isWindows) { - return spawnAsPromised('wmic', ['process', 'get', 'ParentProcessId']).then(stdout => { - const pids = stdout.split('\r\n'); - return pids.some(p => parseInt(p) === processId); - }, error => { - return true; + return new Promise(async (resolve) => { + // See #123296 + const windowsProcessTree = await import('windows-process-tree'); + windowsProcessTree.getProcessTree(processId, (processTree) => { + resolve(processTree.children.length > 0); + }); }); } else { return spawnAsPromised('/usr/bin/pgrep', ['-lP', String(processId)]).then(stdout => { diff --git a/lib/vscode/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts b/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts rename to src/vs/workbench/contrib/debug/test/browser/baseDebugView.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/test/browser/breakpoints.test.ts b/src/vs/workbench/contrib/debug/test/browser/breakpoints.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/test/browser/breakpoints.test.ts rename to src/vs/workbench/contrib/debug/test/browser/breakpoints.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/test/browser/callStack.test.ts b/src/vs/workbench/contrib/debug/test/browser/callStack.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/test/browser/callStack.test.ts rename to src/vs/workbench/contrib/debug/test/browser/callStack.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts b/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts rename to src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/test/browser/debugHover.test.ts b/src/vs/workbench/contrib/debug/test/browser/debugHover.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/test/browser/debugHover.test.ts rename to src/vs/workbench/contrib/debug/test/browser/debugHover.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/test/browser/debugSource.test.ts b/src/vs/workbench/contrib/debug/test/browser/debugSource.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/test/browser/debugSource.test.ts rename to src/vs/workbench/contrib/debug/test/browser/debugSource.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/test/browser/debugUtils.test.ts b/src/vs/workbench/contrib/debug/test/browser/debugUtils.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/test/browser/debugUtils.test.ts rename to src/vs/workbench/contrib/debug/test/browser/debugUtils.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/test/browser/debugViewModel.test.ts b/src/vs/workbench/contrib/debug/test/browser/debugViewModel.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/test/browser/debugViewModel.test.ts rename to src/vs/workbench/contrib/debug/test/browser/debugViewModel.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/test/browser/linkDetector.test.ts b/src/vs/workbench/contrib/debug/test/browser/linkDetector.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/test/browser/linkDetector.test.ts rename to src/vs/workbench/contrib/debug/test/browser/linkDetector.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/test/browser/mockDebug.ts b/src/vs/workbench/contrib/debug/test/browser/mockDebug.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/test/browser/mockDebug.ts rename to src/vs/workbench/contrib/debug/test/browser/mockDebug.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/test/browser/rawDebugSession.test.ts b/src/vs/workbench/contrib/debug/test/browser/rawDebugSession.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/test/browser/rawDebugSession.test.ts rename to src/vs/workbench/contrib/debug/test/browser/rawDebugSession.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/test/browser/repl.test.ts b/src/vs/workbench/contrib/debug/test/browser/repl.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/test/browser/repl.test.ts rename to src/vs/workbench/contrib/debug/test/browser/repl.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/test/browser/watch.test.ts b/src/vs/workbench/contrib/debug/test/browser/watch.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/test/browser/watch.test.ts rename to src/vs/workbench/contrib/debug/test/browser/watch.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/debug/test/node/debugger.test.ts b/src/vs/workbench/contrib/debug/test/node/debugger.test.ts similarity index 87% rename from lib/vscode/src/vs/workbench/contrib/debug/test/node/debugger.test.ts rename to src/vs/workbench/contrib/debug/test/node/debugger.test.ts index c66810f43cb1..fb93786d406a 100644 --- a/lib/vscode/src/vs/workbench/contrib/debug/test/node/debugger.test.ts +++ b/src/vs/workbench/contrib/debug/test/node/debugger.test.ts @@ -149,20 +149,6 @@ suite('Debug - Debugger', () => { assert.deepStrictEqual(ae!.args, debuggerContribution.args); }); - test('schema attributes', () => { - const schemaAttribute = _debugger.getSchemaAttributes()![0]; - assert.notDeepStrictEqual(schemaAttribute, debuggerContribution.configurationAttributes); - Object.keys(debuggerContribution.configurationAttributes.launch).forEach(key => { - assert.deepStrictEqual((schemaAttribute)[key], (debuggerContribution.configurationAttributes.launch)[key]); - }); - - assert.strictEqual(schemaAttribute['additionalProperties'], false); - assert.strictEqual(!!schemaAttribute['properties']!['request'], true); - assert.strictEqual(!!schemaAttribute['properties']!['name'], true); - assert.strictEqual(!!schemaAttribute['properties']!['type'], true); - assert.strictEqual(!!schemaAttribute['properties']!['preLaunchTask'], true); - }); - test('merge platform specific attributes', () => { const ae = ExecutableDebugAdapter.platformAdapterExecutable([extensionDescriptor1, extensionDescriptor2], 'mock')!; assert.strictEqual(ae.command, platform.isLinux ? 'linuxRuntime' : (platform.isMacintosh ? 'osxRuntime' : 'winRuntime')); diff --git a/lib/vscode/src/vs/workbench/contrib/debug/test/node/streamDebugAdapter.test.ts b/src/vs/workbench/contrib/debug/test/node/streamDebugAdapter.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/debug/test/node/streamDebugAdapter.test.ts rename to src/vs/workbench/contrib/debug/test/node/streamDebugAdapter.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/emmet/browser/actions/expandAbbreviation.ts b/src/vs/workbench/contrib/emmet/browser/actions/expandAbbreviation.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/emmet/browser/actions/expandAbbreviation.ts rename to src/vs/workbench/contrib/emmet/browser/actions/expandAbbreviation.ts diff --git a/lib/vscode/src/vs/workbench/contrib/emmet/browser/emmet.contribution.ts b/src/vs/workbench/contrib/emmet/browser/emmet.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/emmet/browser/emmet.contribution.ts rename to src/vs/workbench/contrib/emmet/browser/emmet.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/emmet/browser/emmetActions.ts b/src/vs/workbench/contrib/emmet/browser/emmetActions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/emmet/browser/emmetActions.ts rename to src/vs/workbench/contrib/emmet/browser/emmetActions.ts diff --git a/lib/vscode/src/vs/workbench/contrib/emmet/test/browser/emmetAction.test.ts b/src/vs/workbench/contrib/emmet/test/browser/emmetAction.test.ts similarity index 86% rename from lib/vscode/src/vs/workbench/contrib/emmet/test/browser/emmetAction.test.ts rename to src/vs/workbench/contrib/emmet/test/browser/emmetAction.test.ts index 508337608c4d..25a6a9fc255b 100644 --- a/lib/vscode/src/vs/workbench/contrib/emmet/test/browser/emmetAction.test.ts +++ b/src/vs/workbench/contrib/emmet/test/browser/emmetAction.test.ts @@ -8,24 +8,6 @@ import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor'; import * as assert from 'assert'; import { LanguageId, LanguageIdentifier } from 'vs/editor/common/modes'; -// -// To run the emmet tests only change .vscode/launch.json -// { -// "name": "Stacks Tests", -// "type": "node", -// "request": "launch", -// "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", -// "stopOnEntry": false, -// "args": [ -// "--timeout", -// "999999", -// "--colors", -// "-g", -// "Stacks" <<<--- Emmet -// ], -// Select the 'Stacks Tests' launch config and F5 -// - class MockGrammarContributions implements IGrammarContributions { private scopeName: string; diff --git a/lib/vscode/src/vs/workbench/contrib/experiments/browser/experimentalPrompt.ts b/src/vs/workbench/contrib/experiments/browser/experimentalPrompt.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/experiments/browser/experimentalPrompt.ts rename to src/vs/workbench/contrib/experiments/browser/experimentalPrompt.ts diff --git a/lib/vscode/src/vs/workbench/contrib/experiments/browser/experiments.contribution.ts b/src/vs/workbench/contrib/experiments/browser/experiments.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/experiments/browser/experiments.contribution.ts rename to src/vs/workbench/contrib/experiments/browser/experiments.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/experiments/common/experimentService.ts b/src/vs/workbench/contrib/experiments/common/experimentService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/experiments/common/experimentService.ts rename to src/vs/workbench/contrib/experiments/common/experimentService.ts diff --git a/lib/vscode/src/vs/workbench/contrib/experiments/test/electron-browser/experimentService.test.ts b/src/vs/workbench/contrib/experiments/test/electron-browser/experimentService.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/experiments/test/electron-browser/experimentService.test.ts rename to src/vs/workbench/contrib/experiments/test/electron-browser/experimentService.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/experiments/test/electron-browser/experimentalPrompts.test.ts b/src/vs/workbench/contrib/experiments/test/electron-browser/experimentalPrompts.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/experiments/test/electron-browser/experimentalPrompts.test.ts rename to src/vs/workbench/contrib/experiments/test/electron-browser/experimentalPrompts.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/abstractRuntimeExtensionsEditor.ts b/src/vs/workbench/contrib/extensions/browser/abstractRuntimeExtensionsEditor.ts similarity index 91% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/abstractRuntimeExtensionsEditor.ts rename to src/vs/workbench/contrib/extensions/browser/abstractRuntimeExtensionsEditor.ts index 9fb0cfc9dfac..ba3363c265b6 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/browser/abstractRuntimeExtensionsEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/abstractRuntimeExtensionsEditor.ts @@ -8,7 +8,7 @@ import * as nls from 'vs/nls'; import { Action, IAction, Separator } from 'vs/base/common/actions'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionsWorkbenchService, IExtension } from 'vs/workbench/contrib/extensions/common/extensions'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IExtensionService, IExtensionsStatus, IExtensionHostProfile } from 'vs/workbench/services/extensions/common/extensions'; @@ -36,6 +36,9 @@ import { domEvent } from 'vs/base/browser/event'; import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/common/runtimeExtensionsInput'; +import { Action2 } from 'vs/platform/actions/common/actions'; +import { CATEGORIES } from 'vs/workbench/common/actions'; +import { DefaultIconPath } from 'vs/platform/extensionManagement/common/extensionManagement'; interface IExtensionProfileInformation { /** @@ -54,7 +57,7 @@ interface IExtensionProfileInformation { export interface IRuntimeExtension { originalIndex: number; description: IExtensionDescription; - marketplaceInfo: IExtension; + marketplaceInfo: IExtension | undefined; status: IExtensionsStatus; profileInfo?: IExtensionProfileInformation; unresponsiveProfile?: IExtensionHostProfile; @@ -265,8 +268,8 @@ export abstract class AbstractRuntimeExtensionsEditor extends EditorPane { data.root.classList.toggle('odd', index % 2 === 1); const onError = Event.once(domEvent(data.icon, 'error')); - onError(() => data.icon.src = element.marketplaceInfo.iconUrlFallback, null, data.elementDisposables); - data.icon.src = element.marketplaceInfo.iconUrl; + onError(() => data.icon.src = element.marketplaceInfo?.iconUrlFallback || DefaultIconPath, null, data.elementDisposables); + data.icon.src = element.marketplaceInfo?.iconUrl || DefaultIconPath; if (!data.icon.complete) { data.icon.style.visibility = 'hidden'; @@ -274,7 +277,7 @@ export abstract class AbstractRuntimeExtensionsEditor extends EditorPane { } else { data.icon.style.visibility = 'inherit'; } - data.name.textContent = element.marketplaceInfo.displayName; + data.name.textContent = element.marketplaceInfo?.displayName || element.description.identifier.value; data.version.textContent = element.description.version; const activationTimes = element.status.activationTimes!; @@ -427,8 +430,10 @@ export abstract class AbstractRuntimeExtensionsEditor extends EditorPane { actions.push(new Separator()); } - actions.push(new Action('runtimeExtensionsEditor.action.disableWorkspace', nls.localize('disable workspace', "Disable (Workspace)"), undefined, true, () => this._extensionsWorkbenchService.setEnablement(e.element!.marketplaceInfo, EnablementState.DisabledWorkspace))); - actions.push(new Action('runtimeExtensionsEditor.action.disable', nls.localize('disable', "Disable"), undefined, true, () => this._extensionsWorkbenchService.setEnablement(e.element!.marketplaceInfo, EnablementState.DisabledGlobally))); + if (e.element!.marketplaceInfo) { + actions.push(new Action('runtimeExtensionsEditor.action.disableWorkspace', nls.localize('disable workspace', "Disable (Workspace)"), undefined, true, () => this._extensionsWorkbenchService.setEnablement(e.element!.marketplaceInfo!, EnablementState.DisabledWorkspace))); + actions.push(new Action('runtimeExtensionsEditor.action.disable', nls.localize('disable', "Disable"), undefined, true, () => this._extensionsWorkbenchService.setEnablement(e.element!.marketplaceInfo!, EnablementState.DisabledGlobally))); + } actions.push(new Separator()); const profileAction = this._createProfileAction(); @@ -466,18 +471,18 @@ export abstract class AbstractRuntimeExtensionsEditor extends EditorPane { protected abstract _createProfileAction(): Action | null; } -export class ShowRuntimeExtensionsAction extends Action { - static readonly ID = 'workbench.action.showRuntimeExtensions'; - static readonly LABEL = nls.localize('showRuntimeExtensions', "Show Running Extensions"); +export class ShowRuntimeExtensionsAction extends Action2 { - constructor( - id: string, label: string, - @IEditorService private readonly _editorService: IEditorService - ) { - super(id, label); + constructor() { + super({ + id: 'workbench.action.showRuntimeExtensions', + title: { value: nls.localize('showRuntimeExtensions', "Show Running Extensions"), original: 'Show Running Extensions' }, + category: CATEGORIES.Developer, + f1: true + }); } - public override async run(e?: any): Promise { - await this._editorService.openEditor(RuntimeExtensionsInput.instance, { revealIfOpened: true, pinned: true }); + async run(accessor: ServicesAccessor): Promise { + await accessor.get(IEditorService).openEditor(RuntimeExtensionsInput.instance, { revealIfOpened: true, pinned: true }); } } diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/browserRuntimeExtensionsEditor.ts b/src/vs/workbench/contrib/extensions/browser/browserRuntimeExtensionsEditor.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/browserRuntimeExtensionsEditor.ts rename to src/vs/workbench/contrib/extensions/browser/browserRuntimeExtensionsEditor.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/configBasedRecommendations.ts b/src/vs/workbench/contrib/extensions/browser/configBasedRecommendations.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/configBasedRecommendations.ts rename to src/vs/workbench/contrib/extensions/browser/configBasedRecommendations.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/dynamicWorkspaceRecommendations.ts b/src/vs/workbench/contrib/extensions/browser/dynamicWorkspaceRecommendations.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/dynamicWorkspaceRecommendations.ts rename to src/vs/workbench/contrib/extensions/browser/dynamicWorkspaceRecommendations.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/exeBasedRecommendations.ts b/src/vs/workbench/contrib/extensions/browser/exeBasedRecommendations.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/exeBasedRecommendations.ts rename to src/vs/workbench/contrib/extensions/browser/exeBasedRecommendations.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/experimentalRecommendations.ts b/src/vs/workbench/contrib/extensions/browser/experimentalRecommendations.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/experimentalRecommendations.ts rename to src/vs/workbench/contrib/extensions/browser/experimentalRecommendations.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts rename to src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index 3f99c17d6385..ecc8962769eb 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -25,7 +25,7 @@ import { ResolvedKeybinding, KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; import { IExtensionsWorkbenchService, IExtensionsViewPaneContainer, VIEWLET_ID, IExtension, ExtensionContainers } from 'vs/workbench/contrib/extensions/common/extensions'; import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets'; -import { EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor'; +import { IEditorOpenContext } from 'vs/workbench/common/editor'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { UpdateAction, ReloadAction, MaliciousStatusLabelAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction, @@ -69,6 +69,7 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { Delegate } from 'vs/workbench/contrib/extensions/browser/extensionsList'; import { renderMarkdown } from 'vs/base/browser/markdownRenderer'; import { attachKeybindingLabelStyler } from 'vs/platform/theme/common/styler'; +import { IEditorOptions } from 'vs/platform/editor/common/editor'; class NavBar extends Disposable { @@ -325,7 +326,7 @@ export class ExtensionEditor extends EditorPane { return disposables; } - override async setInput(input: ExtensionsInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + override async setInput(input: ExtensionsInput, options: IEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { await super.setInput(input, options, context, token); if (this.template) { await this.updateTemplate(input, this.template, !!options?.preserveFocus); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEnablementWorkspaceTrustTransitionParticipant.ts b/src/vs/workbench/contrib/extensions/browser/extensionEnablementWorkspaceTrustTransitionParticipant.ts new file mode 100644 index 000000000000..606d019fe0e1 --- /dev/null +++ b/src/vs/workbench/contrib/extensions/browser/extensionEnablementWorkspaceTrustTransitionParticipant.ts @@ -0,0 +1,53 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { IWorkspaceTrustManagementService, IWorkspaceTrustTransitionParticipant } from 'vs/platform/workspace/common/workspaceTrust'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; + +export class ExtensionEnablementWorkspaceTrustTransitionParticipant extends Disposable implements IWorkbenchContribution { + constructor( + @IExtensionService extensionService: IExtensionService, + @IHostService hostService: IHostService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IWorkbenchExtensionEnablementService extensionEnablementService: IWorkbenchExtensionEnablementService, + @IWorkspaceTrustManagementService workspaceTrustManagementService: IWorkspaceTrustManagementService, + ) { + super(); + + if (workspaceTrustManagementService.workspaceTrustEnabled) { + // The extension enablement participant will be registered only after the + // workspace trust state has been initialized. There is no need to execute + // the participant as part of the initialization process, as the workspace + // trust state is initialized before starting the extension host. + workspaceTrustManagementService.workspaceTrustInitialized.then(() => { + const workspaceTrustTransitionParticipant = new class implements IWorkspaceTrustTransitionParticipant { + async participate(trusted: boolean): Promise { + if (trusted) { + // Untrusted -> Trusted + await extensionEnablementService.updateEnablementByWorkspaceTrustRequirement(); + } else { + // Trusted -> Untrusted + if (environmentService.remoteAuthority) { + hostService.reload(); + } else { + extensionService.stopExtensionHosts(); + await extensionEnablementService.updateEnablementByWorkspaceTrustRequirement(); + extensionService.startExtensionHosts(); + } + } + } + }; + + // Execute BEFORE the workspace trust transition completes + this._register(workspaceTrustManagementService.addWorkspaceTrustTransitionParticipant(workspaceTrustTransitionParticipant)); + }); + } + } +} diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionRecommendationNotificationService.ts b/src/vs/workbench/contrib/extensions/browser/extensionRecommendationNotificationService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionRecommendationNotificationService.ts rename to src/vs/workbench/contrib/extensions/browser/extensionRecommendationNotificationService.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionRecommendations.ts b/src/vs/workbench/contrib/extensions/browser/extensionRecommendations.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionRecommendations.ts rename to src/vs/workbench/contrib/extensions/browser/extensionRecommendations.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionRecommendationsService.ts b/src/vs/workbench/contrib/extensions/browser/extensionRecommendationsService.ts similarity index 94% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionRecommendationsService.ts rename to src/vs/workbench/contrib/extensions/browser/extensionRecommendationsService.ts index 5477d2147cf1..104d7ffc6e0a 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionRecommendationsService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionRecommendationsService.ts @@ -18,9 +18,11 @@ import { ExperimentalRecommendations } from 'vs/workbench/contrib/extensions/bro import { WorkspaceRecommendations } from 'vs/workbench/contrib/extensions/browser/workspaceRecommendations'; import { FileBasedRecommendations } from 'vs/workbench/contrib/extensions/browser/fileBasedRecommendations'; import { KeymapRecommendations } from 'vs/workbench/contrib/extensions/browser/keymapRecommendations'; +import { LanguageRecommendations } from 'vs/workbench/contrib/extensions/browser/languageRecommendations'; import { ExtensionRecommendation } from 'vs/workbench/contrib/extensions/browser/extensionRecommendations'; import { ConfigBasedRecommendations } from 'vs/workbench/contrib/extensions/browser/configBasedRecommendations'; import { IExtensionRecommendationNotificationService } from 'vs/platform/extensionRecommendations/common/extensionRecommendations'; +import { timeout } from 'vs/base/common/async'; type IgnoreRecommendationClassification = { recommendationReason: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; @@ -39,6 +41,7 @@ export class ExtensionRecommendationsService extends Disposable implements IExte private readonly exeBasedRecommendations: ExeBasedRecommendations; private readonly dynamicWorkspaceRecommendations: DynamicWorkspaceRecommendations; private readonly keymapRecommendations: KeymapRecommendations; + private readonly languageRecommendations: LanguageRecommendations; public readonly activationPromise: Promise; private sessionSeed: number; @@ -65,6 +68,7 @@ export class ExtensionRecommendationsService extends Disposable implements IExte this.exeBasedRecommendations = instantiationService.createInstance(ExeBasedRecommendations); this.dynamicWorkspaceRecommendations = instantiationService.createInstance(DynamicWorkspaceRecommendations); this.keymapRecommendations = instantiationService.createInstance(KeymapRecommendations); + this.languageRecommendations = instantiationService.createInstance(LanguageRecommendations); if (!this.isEnabled()) { this.sessionSeed = 0; @@ -89,6 +93,7 @@ export class ExtensionRecommendationsService extends Disposable implements IExte this.fileBasedRecommendations.activate(), this.experimentalRecommendations.activate(), this.keymapRecommendations.activate(), + this.languageRecommendations.activate(), ]); this._register(Event.any(this.workspaceRecommendations.onDidChangeRecommendations, this.configBasedRecommendations.onDidChangeRecommendations, this.extensionRecommendationsManagementService.onDidChangeIgnoredRecommendations)(() => this._onDidChangeRecommendations.fire())); @@ -126,6 +131,7 @@ export class ExtensionRecommendationsService extends Disposable implements IExte ...this.fileBasedRecommendations.recommendations, ...this.workspaceRecommendations.recommendations, ...this.keymapRecommendations.recommendations, + ...this.languageRecommendations.recommendations, ]; for (const { extensionId, reason } of allRecommendations) { @@ -184,6 +190,10 @@ export class ExtensionRecommendationsService extends Disposable implements IExte return this.toExtensionRecommendations(this.keymapRecommendations.recommendations); } + getLanguageRecommendations(): string[] { + return this.toExtensionRecommendations(this.languageRecommendations.recommendations); + } + async getWorkspaceRecommendations(): Promise { if (!this.isEnabled()) { return []; @@ -232,16 +242,20 @@ export class ExtensionRecommendationsService extends Disposable implements IExte return !this.extensionRecommendationsManagementService.ignoredRecommendations.includes(extensionId.toLowerCase()); } + // for testing + protected get workbenchRecommendationDelay() { + // remote extensions might still being installed #124119 + return 5000; + } + private async promptWorkspaceRecommendations(): Promise { const allowedRecommendations = [...this.workspaceRecommendations.recommendations, ...this.configBasedRecommendations.importantRecommendations] .map(({ extensionId }) => extensionId) .filter(extensionId => this.isExtensionAllowedToBeRecommended(extensionId)); if (allowedRecommendations.length) { + await timeout(this.workbenchRecommendationDelay); await this.extensionRecommendationNotificationService.promptWorkspaceRecommendations(allowedRecommendations); } } - - - } diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts similarity index 94% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts rename to src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index 41e39af95a13..4232ee5f9e3b 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -6,7 +6,7 @@ import { localize } from 'vs/nls'; import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; import { Registry } from 'vs/platform/registry/common/platform'; -import { MenuRegistry, MenuId, registerAction2, Action2, SyncActionDescriptor, ISubmenuItem, IMenuItem, IAction2Options } from 'vs/platform/actions/common/actions'; +import { MenuRegistry, MenuId, registerAction2, Action2, ISubmenuItem, IMenuItem, IAction2Options } from 'vs/platform/actions/common/actions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ExtensionsLabel, ExtensionsLocalizedLabel, ExtensionsChannelId, IExtensionManagementService, IExtensionGalleryService, PreferencesLocalizedLabel, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; import { EnablementState, IExtensionManagementServerService, IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; @@ -14,7 +14,7 @@ import { IExtensionIgnoredRecommendationsService, IExtensionRecommendationsServi import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/services/output/common/output'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { VIEWLET_ID, IExtensionsWorkbenchService, IExtensionsViewPaneContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, DefaultViewsContext, ExtensionsSortByContext, WORKSPACE_RECOMMENDATIONS_VIEW_ID, IWorkspaceRecommendedExtensionsView, AutoUpdateConfigurationKey, HasOutdatedExtensionsContext, SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID } from 'vs/workbench/contrib/extensions/common/extensions'; +import { VIEWLET_ID, IExtensionsWorkbenchService, IExtensionsViewPaneContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, DefaultViewsContext, ExtensionsSortByContext, WORKSPACE_RECOMMENDATIONS_VIEW_ID, IWorkspaceRecommendedExtensionsView, AutoUpdateConfigurationKey, HasOutdatedExtensionsContext, SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID } from 'vs/workbench/contrib/extensions/common/extensions'; import { ReinstallAction, InstallSpecificVersionOfExtensionAction, ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, PromptExtensionInstallFailureAction, SearchExtensionsAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; import { ExtensionEditor } from 'vs/workbench/contrib/extensions/browser/extensionEditor'; @@ -23,7 +23,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions, Configur import * as jsonContributionRegistry from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { ExtensionsConfigurationSchema, ExtensionsConfigurationSchemaId } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; -import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor, optional } from 'vs/platform/instantiation/common/instantiation'; import { KeymapExtensions } from 'vs/workbench/contrib/extensions/common/extensionsUtils'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { EditorDescriptor, IEditorRegistry } from 'vs/workbench/browser/editor'; @@ -49,7 +49,7 @@ import { Webview } from 'vs/workbench/contrib/webview/browser/webview'; import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/browser/extensionsWorkbenchService'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { WorkbenchStateContext } from 'vs/workbench/browser/contextkeys'; -import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions, CATEGORIES } from 'vs/workbench/common/actions'; +import { CATEGORIES } from 'vs/workbench/common/actions'; import { IExtensionRecommendationNotificationService } from 'vs/platform/extensionRecommendations/common/extensionRecommendations'; import { ExtensionRecommendationNotificationService } from 'vs/workbench/contrib/extensions/browser/extensionRecommendationNotificationService'; import { IExtensionService, toExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; @@ -60,7 +60,7 @@ import { IAction } from 'vs/base/common/actions'; import { IWorkpsaceExtensionsConfigService } from 'vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig'; import { Schemas } from 'vs/base/common/network'; import { ShowRuntimeExtensionsAction } from 'vs/workbench/contrib/extensions/browser/abstractRuntimeExtensionsEditor'; -import { ExtensionEnablementByWorkspaceTrustRequirement } from 'vs/workbench/contrib/extensions/browser/extensionEnablementByWorkspaceTrustRequirement'; +import { ExtensionEnablementWorkspaceTrustTransitionParticipant } from 'vs/workbench/contrib/extensions/browser/extensionEnablementWorkspaceTrustTransitionParticipant'; import { clearSearchResultsIcon, configureRecommendedIcon, extensionsViewIcon, filterIcon, installWorkspaceRecommendedIcon, refreshIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons'; import { EXTENSION_CATEGORIES } from 'vs/platform/extensions/common/extensions'; import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; @@ -72,6 +72,8 @@ import { Query } from 'vs/workbench/contrib/extensions/common/extensionQuery'; import { Promises } from 'vs/base/common/async'; import { EditorExtensions } from 'vs/workbench/common/editor'; import { WORKSPACE_TRUST_EXTENSION_SUPPORT } from 'vs/workbench/services/workspaces/common/workspaceTrust'; +import { ExtensionsCompletionItemsProvider } from 'vs/workbench/contrib/extensions/browser/extensionsCompletionItemsProvider'; +import { ITASExperimentService } from 'vs/workbench/services/experiment/common/experimentService'; // Singletons registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService); @@ -249,14 +251,29 @@ CommandsRegistry.registerCommand({ description: localize('workbench.extensions.installExtension.description', "Install the given extension"), args: [ { - name: localize('workbench.extensions.installExtension.arg.name', "Extension id or VSIX resource uri"), + name: 'extensionIdOrVSIXUri', + description: localize('workbench.extensions.installExtension.arg.decription', "Extension id or VSIX resource uri"), + constraint: (value: any) => typeof value === 'string' || value instanceof URI, + }, + { + name: 'options', + description: '(optional) Options for installing the extension. Object with the following properties: ' + + '`installOnlyNewlyAddedFromExtensionPackVSIX`: When enabled, VS Code installs only newly added extensions from the extension pack VSIX. This option is considered only when installing VSIX. ', + isOptional: true, schema: { - 'type': ['object', 'string'] + 'type': 'object', + 'properties': { + 'installOnlyNewlyAddedFromExtensionPackVSIX': { + 'type': 'boolean', + 'description': localize('workbench.extensions.installExtension.option.installOnlyNewlyAddedFromExtensionPackVSIX', "When enabled, VS Code installs only newly added extensions from the extension pack VSIX. This option is considered only while installing a VSIX."), + default: false + } + } } } ] }, - handler: async (accessor, arg: string | UriComponents) => { + handler: async (accessor, arg: string | UriComponents, options?: { installOnlyNewlyAddedFromExtensionPackVSIX?: boolean }) => { const extensionManagementService = accessor.get(IExtensionManagementService); const extensionGalleryService = accessor.get(IExtensionGalleryService); try { @@ -269,7 +286,7 @@ CommandsRegistry.registerCommand({ } } else { const vsix = URI.revive(arg); - await extensionManagementService.install(vsix); + await extensionManagementService.install(vsix, { installOnlyNewlyAddedFromExtensionPack: options?.installOnlyNewlyAddedFromExtensionPackVSIX }); } } catch (e) { onUnexpectedError(e); @@ -377,6 +394,8 @@ interface IExtensionActionOptions extends IAction2Options { class ExtensionsContributions extends Disposable implements IWorkbenchContribution { + private tasExperimentService?: ITASExperimentService; + constructor( @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @IExtensionGalleryService extensionGalleryService: IExtensionGalleryService, @@ -387,6 +406,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi @IInstantiationService private readonly instantiationService: IInstantiationService, @IDialogService private readonly dialogService: IDialogService, @ICommandService private readonly commandService: ICommandService, + @optional(ITASExperimentService) tasExperimentService: ITASExperimentService, ) { super(); const hasGalleryContext = CONTEXT_HAS_GALLERY.bindTo(contextKeyService); @@ -409,6 +429,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi hasWebServerContext.set(true); } + this.tasExperimentService = tasExperimentService; this.registerGlobalActions(); this.registerContextMenuActions(); this.registerQuickAccessProvider(); @@ -500,7 +521,10 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi id: MenuId.CommandPalette, when: CONTEXT_HAS_GALLERY }, - run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@category:"programming languages" @sort:installs ')) + run: async () => { + const recommended = await this.tasExperimentService?.getTreatment('recommendedLanguages'); + runAction(this.instantiationService.createInstance(SearchExtensionsAction, recommended ? '@recommended:languages ' : '@category:"programming languages" @sort:installs ')); + } }); this.registerExtensionAction({ @@ -876,10 +900,21 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi }); this.registerExtensionAction({ - id: 'workbench.extensions.action.listTrustRequiredExtensions', - title: { value: localize('showTrustRequiredExtensions', "Show Extensions Requiring Trust"), original: 'Show Extensions Requiring Trust' }, + id: LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID, + title: { value: localize('showWorkspaceUnsupportedExtensions', "Show Extensions Unsupported By Workspace"), original: 'Show Extensions Unsupported By Workspace' }, category: ExtensionsLocalizedLabel, - run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@trustRequired')) + menu: [{ + id: MenuId.CommandPalette, + when: ContextKeyOrExpr.create([CONTEXT_HAS_LOCAL_SERVER, CONTEXT_HAS_REMOTE_SERVER, CONTEXT_HAS_WEB_SERVER]) + }, { + id: extensionsFilterSubMenu, + group: '3_installed', + order: 6, + }], + menuTitles: { + [extensionsFilterSubMenu.id]: localize('workspace unsupported filter', "Workspace Unsupported") + }, + run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@workspaceUnsupported')) }); this.registerExtensionAction({ @@ -1325,8 +1360,8 @@ workbenchRegistry.registerWorkbenchContribution(KeymapExtensions, LifecyclePhase workbenchRegistry.registerWorkbenchContribution(ExtensionsViewletViewsContribution, LifecyclePhase.Starting); workbenchRegistry.registerWorkbenchContribution(ExtensionActivationProgress, LifecyclePhase.Eventually); workbenchRegistry.registerWorkbenchContribution(ExtensionDependencyChecker, LifecyclePhase.Eventually); -workbenchRegistry.registerWorkbenchContribution(ExtensionEnablementByWorkspaceTrustRequirement, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(ExtensionEnablementWorkspaceTrustTransitionParticipant, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(ExtensionsCompletionItemsProvider, LifecyclePhase.Restored); // Running Extensions -const actionRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); -actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(ShowRuntimeExtensionsAction), 'Show Running Extensions', CATEGORIES.Developer.value); +registerAction2(ShowRuntimeExtensionsAction); diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensions.web.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.web.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/extensions.web.contribution.ts rename to src/vs/workbench/contrib/extensions/browser/extensions.web.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index 458801de1eee..c1dbb44158a3 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -18,7 +18,7 @@ import { IGalleryExtension, IExtensionGalleryService, INSTALL_ERROR_MALICIOUS, I import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer, IWorkbenchExtensionManagementService, IWebExtensionsScannerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ExtensionRecommendationReason, IExtensionIgnoredRecommendationsService, IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { ExtensionType, ExtensionIdentifier, IExtensionDescription, IExtensionManifest, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions'; +import { ExtensionType, ExtensionIdentifier, IExtensionDescription, IExtensionManifest, isLanguagePackExtension, getWorkpaceSupportTypeMessage } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IFileService, IFileContent } from 'vs/platform/files/common/files'; @@ -59,8 +59,9 @@ import { ILogService } from 'vs/platform/log/common/log'; import * as Constants from 'vs/workbench/contrib/logs/common/logConstants'; import { infoIcon, manageExtensionIcon, syncEnabledIcon, syncIgnoredIcon, trustIcon, warningIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons'; import { isWeb } from 'vs/base/common/platform'; -import { isWorkspaceTrustEnabled } from 'vs/workbench/services/workspaces/common/workspaceTrust'; import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; +import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; +import { isVirtualWorkspace } from 'vs/platform/remote/common/remoteHosts'; function getRelativeDateLabel(date: Date): string { const delta = new Date().getTime() - date.getTime(); @@ -2085,10 +2086,12 @@ export class SystemDisabledWarningAction extends ExtensionAction { constructor( @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @ILabelService private readonly labelService: ILabelService, + @ICommandService private readonly commandService: ICommandService, + @IWorkspaceTrustManagementService private readonly workspaceTrustService: IWorkspaceTrustManagementService, @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionService private readonly extensionService: IExtensionService, - @IConfigurationService private readonly configurationService: IConfigurationService, @IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService, + @IWorkspaceContextService private readonly contextService: IWorkspaceContextService ) { super('extensions.install', '', `${SystemDisabledWarningAction.CLASS} hide`, false); this._register(this.labelService.onDidChangeFormatters(() => this.update(), this)); @@ -2104,6 +2107,7 @@ export class SystemDisabledWarningAction extends ExtensionAction { update(): void { this.class = `${SystemDisabledWarningAction.CLASS} hide`; this.tooltip = ''; + this.enabled = false; if ( !this.extension || !this.extension.local || @@ -2113,10 +2117,17 @@ export class SystemDisabledWarningAction extends ExtensionAction { ) { return; } - if (this.extension.enablementState === EnablementState.DisabledByVirtualWorkspace) { - this.class = `${SystemDisabledWarningAction.INFO_CLASS}`; - this.tooltip = localize('disabled because of virtual workspace', "This extension has been disabled because it does not support virtual workspaces."); - return; + + if (isVirtualWorkspace(this.contextService.getWorkspace())) { + const virtualSupportType = this.extensionManifestPropertiesService.getExtensionVirtualWorkspaceSupportType(this.extension.local.manifest); + if (virtualSupportType !== true) { + this.class = `${SystemDisabledWarningAction.INFO_CLASS}`; + const details = getWorkpaceSupportTypeMessage(this.extension.local.manifest.capabilities?.virtualWorkspaces); + this.tooltip = details || (virtualSupportType === 'limited' ? + localize('extension limited because of virtual workspace', "This extension has limited features because the current workspace is virtual.") : + localize('disabled because of virtual workspace', "This extension has been disabled because it does not support virtual workspaces.")); + return; + } } if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { if (isLanguagePackExtension(this.extension.local.manifest)) { @@ -2159,14 +2170,25 @@ export class SystemDisabledWarningAction extends ExtensionAction { return; } } - if (isWorkspaceTrustEnabled(this.configurationService) && this.extension.enablementState === EnablementState.DisabledByTrustRequirement) { + + const untrustedSupportType = this.extensionManifestPropertiesService.getExtensionUntrustedWorkspaceSupportType(this.extension.local.manifest); + if (this.workspaceTrustService.workspaceTrustEnabled && untrustedSupportType !== true && !this.workspaceTrustService.isWorkpaceTrusted()) { + const untrustedDetails = getWorkpaceSupportTypeMessage(this.extension.local.manifest.capabilities?.untrustedWorkspaces); + this.enabled = true; this.class = `${SystemDisabledWarningAction.TRUST_CLASS}`; - this.tooltip = localize('extension disabled because of trust requirement', "This extension has been disabled because the current workspace is not trusted"); + this.tooltip = untrustedDetails || (untrustedSupportType === 'limited' ? + localize('extension limited because of trust requirement', "This extension has limited features because the current workspace is not trusted.") : + localize('extension disabled because of trust requirement', "This extension has been disabled because the current workspace is not trusted.")); return; } } override run(): Promise { + // Only enabled by the workspace trust version of this action + // If other actions enable, add a new member to control this + if (this.enabled) { + this.commandService.executeCommand('workbench.trust.manage'); + } return Promise.resolve(null); } } diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsActivationProgress.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActivationProgress.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsActivationProgress.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsActivationProgress.ts diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsCompletionItemsProvider.ts b/src/vs/workbench/contrib/extensions/browser/extensionsCompletionItemsProvider.ts new file mode 100644 index 000000000000..fa1c28987541 --- /dev/null +++ b/src/vs/workbench/contrib/extensions/browser/extensionsCompletionItemsProvider.ts @@ -0,0 +1,66 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { CancellationToken } from 'vs/base/common/cancellation'; +import { getLocation, parse } from 'vs/base/common/json'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { Position } from 'vs/editor/common/core/position'; +import { ITextModel } from 'vs/editor/common/model'; +import { CompletionContext, CompletionList, CompletionProviderRegistry, CompletionItemKind, CompletionItem } from 'vs/editor/common/modes'; +import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { Range } from 'vs/editor/common/core/range'; + + +export class ExtensionsCompletionItemsProvider extends Disposable implements IWorkbenchContribution { + constructor( + @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, + ) { + super(); + + this._register(CompletionProviderRegistry.register({ language: 'jsonc', pattern: '**/settings.json' }, { + provideCompletionItems: async (model: ITextModel, position: Position, _context: CompletionContext, token: CancellationToken): Promise => { + const getWordRangeAtPosition = (model: ITextModel, position: Position): Range | null => { + const wordAtPosition = model.getWordAtPosition(position); + return wordAtPosition ? new Range(position.lineNumber, wordAtPosition.startColumn, position.lineNumber, wordAtPosition.endColumn) : null; + }; + + const location = getLocation(model.getValue(), model.getOffsetAt(position)); + const range = getWordRangeAtPosition(model, position) ?? Range.fromPositions(position, position); + + // extensions.supportUntrustedWorkspaces + if (location.path[0] === 'extensions.supportUntrustedWorkspaces' && location.path.length === 2 && location.isAtPropertyKey) { + let alreadyConfigured: string[] = []; + try { + alreadyConfigured = Object.keys(parse(model.getValue())['extensions.supportUntrustedWorkspaces']); + } catch (e) {/* ignore error */ } + + return { suggestions: await this.provideSupportUntrustedWorkspacesExtensionProposals(alreadyConfigured, range) }; + } + + return { suggestions: [] }; + } + })); + } + + private async provideSupportUntrustedWorkspacesExtensionProposals(alreadyConfigured: string[], range: Range): Promise { + const suggestions: CompletionItem[] = []; + const installedExtensions = (await this.extensionManagementService.getInstalled()).filter(e => e.manifest.main); + const proposedExtensions = installedExtensions.filter(e => alreadyConfigured.indexOf(e.identifier.id) === -1); + + if (proposedExtensions.length) { + suggestions.push(...proposedExtensions.map(e => { + const text = `"${e.identifier.id}": {\n\t"supported": true,\n\t"version": "${e.manifest.version}"\n},`; + return { label: e.identifier.id, kind: CompletionItemKind.Value, insertText: text, filterText: text, range }; + })); + } else { + const text = '"vscode.csharp": {\n\t"supported": true,\n\t"version": "0.0.0"\n},'; + suggestions.push({ label: localize('exampleExtension', "Example"), kind: CompletionItemKind.Value, insertText: text, filterText: text, range }); + } + + return suggestions; + } +} diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsDependencyChecker.ts b/src/vs/workbench/contrib/extensions/browser/extensionsDependencyChecker.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsDependencyChecker.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsDependencyChecker.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsIcons.ts b/src/vs/workbench/contrib/extensions/browser/extensionsIcons.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsIcons.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsIcons.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsList.ts b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsList.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsList.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsQuickAccess.ts b/src/vs/workbench/contrib/extensions/browser/extensionsQuickAccess.ts similarity index 93% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsQuickAccess.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsQuickAccess.ts index 921231f3f869..8aecf0ed0c35 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsQuickAccess.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsQuickAccess.ts @@ -28,7 +28,7 @@ export class InstallExtensionQuickAccessProvider extends PickerQuickAccessProvid super(InstallExtensionQuickAccessProvider.PREFIX); } - protected getPicks(filter: string, disposables: DisposableStore, token: CancellationToken): Array | Promise> { + protected _getPicks(filter: string, disposables: DisposableStore, token: CancellationToken): Array | Promise> { // Nothing typed if (!filter) { @@ -100,7 +100,7 @@ export class ManageExtensionsQuickAccessProvider extends PickerQuickAccessProvid super(ManageExtensionsQuickAccessProvider.PREFIX); } - protected getPicks(): Array { + protected _getPicks(): Array { return [{ label: localize('manage', "Press Enter to manage your extensions."), accept: () => openExtensionsViewlet(this.viewletService) diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts similarity index 89% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index e09a04de0c79..9cba26e46839 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -22,12 +22,12 @@ import { InstallLocalExtensionsInRemoteAction, InstallRemoteExtensionsInLocalAct import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IWorkbenchExtensionEnablementService, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; -import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInFeatureExtensionsView, BuiltInThemesExtensionsView, BuiltInProgrammingLanguageExtensionsView, ServerInstalledExtensionsView, DefaultRecommendedExtensionsView, TrustRequiredOnStartExtensionsView, TrustRequiredOnDemandExtensionsView } from 'vs/workbench/contrib/extensions/browser/extensionsViews'; +import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInFeatureExtensionsView, BuiltInThemesExtensionsView, BuiltInProgrammingLanguageExtensionsView, ServerInstalledExtensionsView, DefaultRecommendedExtensionsView, UntrustedWorkspaceUnsupportedExtensionsView, UntrustedWorkspacePartiallySupportedExtensionsView, VirtualWorkspaceUnsupportedExtensionsView, VirtualWorkspacePartiallySupportedExtensionsView } from 'vs/workbench/contrib/extensions/browser/extensionsViews'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import Severity from 'vs/base/common/severity'; import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; -import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IViewsRegistry, IViewDescriptor, Extensions, ViewContainer, IViewDescriptorService, IAddedViewDescriptorRef } from 'vs/workbench/common/views'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; @@ -54,12 +54,12 @@ import { DragAndDropObserver } from 'vs/workbench/browser/dnd'; import { URI } from 'vs/base/common/uri'; import { SIDE_BAR_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { WorkbenchStateContext } from 'vs/workbench/browser/contextkeys'; +import { VirtualWorkspaceContext, WorkbenchStateContext } from 'vs/workbench/browser/contextkeys'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { textLinkForeground } from 'vs/platform/theme/common/colorRegistry'; -import { isWeb } from 'vs/base/common/platform'; +import { isIOS, isWeb } from 'vs/base/common/platform'; import { installLocalInRemoteIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons'; import { registerAction2, Action2, MenuId } from 'vs/platform/actions/common/actions'; +import { WorkspaceTrustContext } from 'vs/workbench/services/workspaces/common/workspaceTrust'; const SearchMarketplaceExtensionsContext = new RawContextKey('searchMarketplaceExtensions', false); const SearchIntalledExtensionsContext = new RawContextKey('searchInstalledExtensions', false); @@ -70,8 +70,7 @@ const HasInstalledExtensionsContext = new RawContextKey('hasInstalledEx const HasInstalledWebExtensionsContext = new RawContextKey('hasInstalledWebExtensions', false); const BuiltInExtensionsContext = new RawContextKey('builtInExtensions', false); const SearchBuiltInExtensionsContext = new RawContextKey('searchBuiltInExtensions', false); -const TrustRequiredExtensionsContext = new RawContextKey('trustRequiredExtensions', false); -const SearchTrustRequiredExtensionsContext = new RawContextKey('searchTrustRequiredExtensions', false); +const SearchUnsupportedWorkspaceExtensionsContext = new RawContextKey('searchUnsupportedWorkspaceExtensions', false); const RecommendedExtensionsContext = new RawContextKey('recommendedExtensions', false); export class ExtensionsViewletViewsContribution implements IWorkbenchContribution { @@ -104,7 +103,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio viewDescriptors.push(...this.createBuiltinExtensionsViewDescriptors()); /* Trust Required extensions views */ - viewDescriptors.push(...this.createTrustRequiredExtensionsViewDescriptors()); + viewDescriptors.push(...this.createUnsupportedWorkspaceExtensionsViewDescriptors()); Registry.as(Extensions.ViewsRegistry).registerViews(viewDescriptors, this.container); } @@ -344,13 +343,13 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio }); /* - * View used for searching trustRequired extensions + * View used for searching workspace unsupported extensions */ viewDescriptors.push({ - id: 'workbench.views.extensions.searchTrustRequired', - name: localize('trustRequired', "Trust Required"), + id: 'workbench.views.extensions.searchWorkspaceUnsupported', + name: localize('workspaceUnsupported', "Workspace Unsupported"), ctorDescriptor: new SyncDescriptor(ExtensionsListView, [{}]), - when: ContextKeyExpr.and(ContextKeyExpr.has('searchTrustRequiredExtensions')), + when: ContextKeyExpr.and(ContextKeyExpr.has('searchWorkspaceUnsupportedExtensions')), }); return viewDescriptors; @@ -405,21 +404,35 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio return viewDescriptors; } - private createTrustRequiredExtensionsViewDescriptors(): IViewDescriptor[] { + private createUnsupportedWorkspaceExtensionsViewDescriptors(): IViewDescriptor[] { const viewDescriptors: IViewDescriptor[] = []; viewDescriptors.push({ - id: 'workbench.views.extensions.trustRequiredOnStartExtensions', - name: localize('trustRequiredOnStartExtensions', "Trust Required To Enable"), - ctorDescriptor: new SyncDescriptor(TrustRequiredOnStartExtensionsView, [{}]), - when: ContextKeyExpr.has('trustRequiredExtensions'), + id: 'workbench.views.extensions.untrustedUnsupportedExtensions', + name: localize('untrustedUnsupportedExtensions', "Disabled in Restricted Mode"), + ctorDescriptor: new SyncDescriptor(UntrustedWorkspaceUnsupportedExtensionsView, [{}]), + when: ContextKeyExpr.and(WorkspaceTrustContext.IsTrusted.negate(), SearchUnsupportedWorkspaceExtensionsContext), }); viewDescriptors.push({ - id: 'workbench.views.extensions.trustRequiredOnDemandExtensions', - name: localize('trustRequiredOnDemandExtensions', "Trust Required For Features"), - ctorDescriptor: new SyncDescriptor(TrustRequiredOnDemandExtensionsView, [{}]), - when: ContextKeyExpr.has('trustRequiredExtensions'), + id: 'workbench.views.extensions.untrustedPartiallySupportedExtensions', + name: localize('untrustedPartiallySupportedExtensions', "Limited in Restricted Mode"), + ctorDescriptor: new SyncDescriptor(UntrustedWorkspacePartiallySupportedExtensionsView, [{}]), + when: ContextKeyExpr.and(WorkspaceTrustContext.IsTrusted.negate(), SearchUnsupportedWorkspaceExtensionsContext), + }); + + viewDescriptors.push({ + id: 'workbench.views.extensions.virtualUnsupportedExtensions', + name: localize('virtualUnsupportedExtensions', "Disabled in Virtual Workspaces"), + ctorDescriptor: new SyncDescriptor(VirtualWorkspaceUnsupportedExtensionsView, [{}]), + when: ContextKeyExpr.and(VirtualWorkspaceContext, SearchUnsupportedWorkspaceExtensionsContext), + }); + + viewDescriptors.push({ + id: 'workbench.views.extensions.virtualPartiallySupportedExtensions', + name: localize('virtualPartiallySupportedExtensions', "Limited in Virtual Workspaces"), + ctorDescriptor: new SyncDescriptor(VirtualWorkspacePartiallySupportedExtensionsView, [{}]), + when: ContextKeyExpr.and(VirtualWorkspaceContext, SearchUnsupportedWorkspaceExtensionsContext), }); return viewDescriptors; @@ -440,8 +453,7 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE private hasInstalledWebExtensionsContextKey: IContextKey; private builtInExtensionsContextKey: IContextKey; private searchBuiltInExtensionsContextKey: IContextKey; - private trustRequiredExtensionsContextKey: IContextKey; - private searchTrustRequiredExtensionsContextKey: IContextKey; + private searchWorkspaceUnsupportedExtensionsContextKey: IContextKey; private recommendedExtensionsContextKey: IContextKey; private searchDelayer: Delayer; @@ -477,8 +489,7 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE this.sortByContextKey = ExtensionsSortByContext.bindTo(contextKeyService); this.searchMarketplaceExtensionsContextKey = SearchMarketplaceExtensionsContext.bindTo(contextKeyService); this.searchInstalledExtensionsContextKey = SearchIntalledExtensionsContext.bindTo(contextKeyService); - this.trustRequiredExtensionsContextKey = TrustRequiredExtensionsContext.bindTo(contextKeyService); - this.searchTrustRequiredExtensionsContextKey = SearchTrustRequiredExtensionsContext.bindTo(contextKeyService); + this.searchWorkspaceUnsupportedExtensionsContextKey = SearchUnsupportedWorkspaceExtensionsContext.bindTo(contextKeyService); this.searchOutdatedExtensionsContextKey = SearchOutdatedExtensionsContext.bindTo(contextKeyService); this.searchEnabledExtensionsContextKey = SearchEnabledExtensionsContext.bindTo(contextKeyService); this.searchDisabledExtensionsContextKey = SearchDisabledExtensionsContext.bindTo(contextKeyService); @@ -514,49 +525,9 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE overlay.style.backgroundColor = overlayBackgroundColor; hide(overlay); - // NOTE@coder this UI element helps users understand the extension marketplace divergence - const extensionHelperLocalStorageKey = 'coder.extension-help-message'; - - if (localStorage.getItem(extensionHelperLocalStorageKey) === null) { - const helperHeader = append(this.root, $('.header')); - helperHeader.id = 'codeServerMarketplaceHelper'; - helperHeader.style.height = 'auto'; - helperHeader.style.fontWeight = '600'; - helperHeader.style.padding = 'padding: 5px 16px'; - helperHeader.style.position = 'relative'; - - const helperText = append(helperHeader, $('div')); - - // We call this function because it gives us access to the current theme - // Then we can apply the link color to the links in the helper header - registerThemingParticipant((theme) => { - const linkColor = theme.getColor(textLinkForeground); - helperText.innerHTML = ` -
    -

    WARNING

    -

    - These extensions are not official. Find additional open-source extensions - here. - See docs. -

    -
    - `; - }); - - const dismiss = append(helperHeader, $('span')); - dismiss.innerHTML = 'Dismiss'; - dismiss.style.display = 'block'; - dismiss.style.textAlign = 'right'; - dismiss.style.cursor = 'pointer'; - dismiss.tabIndex = 0; - dismiss.onclick = () => { - helperHeader.remove(); - localStorage.setItem(extensionHelperLocalStorageKey, 'viewed'); - }; - } - const header = append(this.root, $('.header')); const placeholder = localize('searchExtensions', "Search Extensions in Marketplace"); + const searchValue = this.searchViewletState['query.value'] ? this.searchViewletState['query.value'] : ''; this.searchBox = this._register(this.instantiationService.createInstance(SuggestEnabledInput, `${VIEWLET_ID}.searchbox`, header, { @@ -585,7 +556,7 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE this._register(this.searchBox.onShouldFocusResults(() => this.focusListView(), this)); this._register(this.onDidChangeVisibility(visible => { - if (visible) { + if (visible && !isIOS) { this.searchBox!.focus(); } })); @@ -637,7 +608,7 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE } override focus(): void { - if (this.searchBox) { + if (this.searchBox && !isIOS) { this.searchBox.focus(); } } @@ -711,8 +682,7 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE this.searchEnabledExtensionsContextKey.set(ExtensionsListView.isEnabledExtensionsQuery(value)); this.searchDisabledExtensionsContextKey.set(ExtensionsListView.isDisabledExtensionsQuery(value)); this.searchBuiltInExtensionsContextKey.set(ExtensionsListView.isSearchBuiltInExtensionsQuery(value)); - this.trustRequiredExtensionsContextKey.set(ExtensionsListView.isTrustRequiredExtensionsQuery(value)); - this.searchTrustRequiredExtensionsContextKey.set(ExtensionsListView.isSearchTrustRequiredExtensionsQuery(value)); + this.searchWorkspaceUnsupportedExtensionsContextKey.set(ExtensionsListView.isSearchWorkspaceUnsupportedExtensionsQuery(value)); this.builtInExtensionsContextKey.set(ExtensionsListView.isBuiltInExtensionsQuery(value)); this.recommendedExtensionsContextKey.set(isRecommendedExtensionsQuery); this.searchMarketplaceExtensionsContextKey.set(!!value && !ExtensionsListView.isLocalExtensionsQuery(value) && !isRecommendedExtensionsQuery); diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts similarity index 89% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsViews.ts index 67e0af117291..7ee9c0358268 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts @@ -37,7 +37,7 @@ import { alert } from 'vs/base/browser/ui/aria/aria'; import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IAction, Action, Separator, ActionRunner } from 'vs/base/common/actions'; -import { ExtensionIdentifier, IExtensionDescription, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions'; +import { ExtensionIdentifier, ExtensionUntrustedWorkpaceSupportType, ExtensionVirtualWorkpaceSupportType, IExtensionDescription, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions'; import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; import { IProductService } from 'vs/platform/product/common/productService'; import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon'; @@ -49,6 +49,8 @@ import { IPreferencesService } from 'vs/workbench/services/preferences/common/pr import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; +import { isVirtualWorkspace } from 'vs/platform/remote/common/remoteHosts'; +import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; // Extensions that are automatically classified as Programming Language extensions, but should be Feature extensions const FORCE_FEATURE_EXTENSIONS = ['vscode.git', 'vscode.search-result']; @@ -121,12 +123,14 @@ export class ExtensionsListView extends ViewPane { @IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService, @IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService, @IWorkbenchExtensionManagementService protected readonly extensionManagementService: IWorkbenchExtensionManagementService, + @IWorkspaceContextService protected readonly workspaceService: IWorkspaceContextService, @IProductService protected readonly productService: IProductService, @IContextKeyService contextKeyService: IContextKeyService, @IViewDescriptorService viewDescriptorService: IViewDescriptorService, @IOpenerService openerService: IOpenerService, @IPreferencesService private readonly preferencesService: IPreferencesService, @IStorageService private readonly storageService: IStorageService, + @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService ) { super({ ...(viewletViewOptions as IViewPaneOptions), @@ -394,8 +398,8 @@ export class ExtensionsListView extends ViewPane { extensions = this.filterEnabledExtensions(local, runningExtensions, query, options); } - else if (/@trustRequired/i.test(value)) { - extensions = this.filterTrustRequiredExtensions(local, query, options); + else if (/@workspaceUnsupported/i.test(value)) { + extensions = this.filterWorkspaceUnsupportedExtensions(local, query, options); } return { extensions, canIncludeInstalledExtensions }; @@ -548,32 +552,44 @@ export class ExtensionsListView extends ViewPane { return this.sortExtensions(result, options); } - private filterTrustRequiredExtensions(local: IExtension[], query: Query, options: IQueryOptions): IExtension[] { - let value = query.value; - const onStartOnly = /@trustRequired:onStart/i.test(value); - if (onStartOnly) { - value = value.replace(/@trustRequired:onStart/g, ''); - } - const onDemandOnly = /@trustRequired:onDemand/i.test(value); - if (onDemandOnly) { - value = value.replace(/@trustRequired:onDemand/g, ''); - } + private filterWorkspaceUnsupportedExtensions(local: IExtension[], query: Query, options: IQueryOptions): IExtension[] { - value = value.replace(/@trustRequired/g, '').replace(/@sort:(\w+)(-\w*)?/g, '').trim().toLowerCase(); + // shows local extensions which are restricted or disabled in the current workspace because of the extension's capability + + const inVirtualWorkspace = isVirtualWorkspace(this.workspaceService.getWorkspace()); + const inRestrictedWorkspace = !this.workspaceTrustManagementService.isWorkpaceTrusted(); + if (!inVirtualWorkspace && !inRestrictedWorkspace) { + return []; + } - const result = local.filter(extension => extension.local && this.extensionManifestPropertiesService.getExtensionUntrustedWorkspaceSupportType(extension.local.manifest) !== true && (extension.name.toLowerCase().indexOf(value) > -1 || extension.displayName.toLowerCase().indexOf(value) > -1)); + let queryString = query.value; // @sortby is already filtered out - if (onStartOnly) { - const onStartExtensions = result.filter(extension => extension.local && this.extensionManifestPropertiesService.getExtensionUntrustedWorkspaceSupportType(extension.local.manifest) === false); - return this.sortExtensions(onStartExtensions, options); + const match = queryString.match(/^\s*@workspaceUnsupported(?::(untrusted|virtual)(Partial)?)?(?:\s+([^\s]*))?/i); + if (!match) { + return []; } + const type = match[1]?.toLowerCase(); + const partial = !!match[2]; + const nameFilter = match[3]?.toLowerCase(); - if (onDemandOnly) { - const onDemandExtensions = result.filter(extension => extension.local && this.extensionManifestPropertiesService.getExtensionUntrustedWorkspaceSupportType(extension.local.manifest) === 'limited'); - return this.sortExtensions(onDemandExtensions, options); + if (nameFilter) { + local = local.filter(extension => extension.name.toLowerCase().indexOf(nameFilter) > -1 || extension.displayName.toLowerCase().indexOf(nameFilter) > -1); } - return this.sortExtensions(result, options); + const hasVirtualSupportType = (extension: IExtension, supportType: ExtensionVirtualWorkpaceSupportType) => extension.local && this.extensionManifestPropertiesService.getExtensionVirtualWorkspaceSupportType(extension.local.manifest) === supportType; + const hasRestrictedSupportType = (extension: IExtension, supportType: ExtensionUntrustedWorkpaceSupportType) => extension.local && this.extensionManifestPropertiesService.getExtensionUntrustedWorkspaceSupportType(extension.local.manifest) === supportType; + + if (type === 'virtual') { + // show limited and disabled extensions unless disabled because of a untrusted workspace + local = local.filter(extension => inVirtualWorkspace && hasVirtualSupportType(extension, partial ? 'limited' : false) && !(inRestrictedWorkspace && hasRestrictedSupportType(extension, false))); + } else if (type === 'untrusted') { + // show limited and disabled extensions unless disabled because of a virtual workspace + local = local.filter(extension => inRestrictedWorkspace && hasRestrictedSupportType(extension, partial ? 'limited' : false) && !(inVirtualWorkspace && hasVirtualSupportType(extension, false))); + } else { + // show extensions that are restricted or disabled in the current workspace + local = local.filter(extension => inVirtualWorkspace && !hasVirtualSupportType(extension, true) || inRestrictedWorkspace && !hasRestrictedSupportType(extension, true)); + } + return this.sortExtensions(local, options); } @@ -706,6 +722,7 @@ export class ExtensionsListView extends ViewPane { private isRecommendationsQuery(query: Query): boolean { return ExtensionsListView.isWorkspaceRecommendedExtensionsQuery(query.value) || ExtensionsListView.isKeymapsRecommendedExtensionsQuery(query.value) + || ExtensionsListView.isLanguageRecommendedExtensionsQuery(query.value) || ExtensionsListView.isExeRecommendedExtensionsQuery(query.value) || /@recommended:all/i.test(query.value) || ExtensionsListView.isSearchRecommendedExtensionsQuery(query.value) @@ -723,6 +740,11 @@ export class ExtensionsListView extends ViewPane { return this.getKeymapRecommendationsModel(query, options, token); } + // Language recommendations + if (ExtensionsListView.isLanguageRecommendedExtensionsQuery(query.value)) { + return this.getLanguageRecommendationsModel(query, options, token); + } + // Exe recommendations if (ExtensionsListView.isExeRecommendedExtensionsQuery(query.value)) { return this.getExeRecommendationsModel(query, options, token); @@ -787,6 +809,14 @@ export class ExtensionsListView extends ViewPane { return new PagedModel(installableRecommendations); } + private async getLanguageRecommendationsModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise> { + const value = query.value.replace(/@recommended:languages/g, '').trim().toLowerCase(); + const recommendations = this.extensionRecommendationsService.getLanguageRecommendations(); + const installableRecommendations = (await this.getInstallableRecommendations(recommendations, { ...options, source: 'recommendations-languages' }, token)) + .filter(extension => extension.identifier.id.toLowerCase().indexOf(value) > -1); + return new PagedModel(installableRecommendations); + } + private async getExeRecommendationsModel(query: Query, options: IQueryOptions, token: CancellationToken): Promise> { const exe = query.value.replace(/@exe:/g, '').trim().toLowerCase(); const { important, others } = await this.extensionRecommendationsService.getExeBasedRecommendations(exe.startsWith('"') ? exe.substring(1, exe.length - 1) : exe); @@ -964,9 +994,7 @@ export class ExtensionsListView extends ViewPane { || this.isBuiltInExtensionsQuery(query) || this.isSearchBuiltInExtensionsQuery(query) || this.isBuiltInGroupExtensionsQuery(query) - || this.isSearchTrustRequiredExtensionsQuery(query) - || this.isTrustRequiredExtensionsQuery(query) - || this.isTrustRequiredGroupExtensionsQuery(query); + || this.isSearchWorkspaceUnsupportedExtensionsQuery(query); } static isSearchBuiltInExtensionsQuery(query: string): boolean { @@ -981,16 +1009,8 @@ export class ExtensionsListView extends ViewPane { return /^\s*@builtin:.+$/i.test(query.trim()); } - static isSearchTrustRequiredExtensionsQuery(query: string): boolean { - return /@trustRequired\s.+/i.test(query); - } - - static isTrustRequiredExtensionsQuery(query: string): boolean { - return /^\s*@trustRequired$/i.test(query.trim()); - } - - static isTrustRequiredGroupExtensionsQuery(query: string): boolean { - return /^\s*@trustRequired:.+$/i.test(query.trim()); + static isSearchWorkspaceUnsupportedExtensionsQuery(query: string): boolean { + return /^\s*@workspaceUnsupported(:(untrusted|virtual)(Partial)?)?(\s|$)/i.test(query); } static isInstalledExtensionsQuery(query: string): boolean { @@ -1029,6 +1049,10 @@ export class ExtensionsListView extends ViewPane { return /@recommended:keymaps/i.test(query); } + static isLanguageRecommendedExtensionsQuery(query: string): boolean { + return /@recommended:languages/i.test(query); + } + override focus(): void { super.focus(); if (!this.list) { @@ -1088,15 +1112,46 @@ export class BuiltInProgrammingLanguageExtensionsView extends ExtensionsListView } } -export class TrustRequiredOnStartExtensionsView extends ExtensionsListView { +function toSpecificWorkspaceUnsupportedQuery(query: string, qualifier: string): string | undefined { + if (!query) { + return '@workspaceUnsupported:' + qualifier; + } + const match = query.match(new RegExp(`@workspaceUnsupported(:${qualifier})?(\\s|$)`, 'i')); + if (match) { + if (!match[1]) { + return query.replace(/@workspaceUnsupported/gi, '@workspaceUnsupported:' + qualifier); + } + return query; + } + return undefined; +} + + +export class UntrustedWorkspaceUnsupportedExtensionsView extends ExtensionsListView { + override async show(query: string): Promise> { + const updatedQuery = toSpecificWorkspaceUnsupportedQuery(query, 'untrusted'); + return updatedQuery ? super.show(updatedQuery) : this.showEmptyModel(); + } +} + +export class UntrustedWorkspacePartiallySupportedExtensionsView extends ExtensionsListView { + override async show(query: string): Promise> { + const updatedQuery = toSpecificWorkspaceUnsupportedQuery(query, 'untrustedPartial'); + return updatedQuery ? super.show(updatedQuery) : this.showEmptyModel(); + } +} + +export class VirtualWorkspaceUnsupportedExtensionsView extends ExtensionsListView { override async show(query: string): Promise> { - return (query && query.trim() !== '@trustRequired') ? this.showEmptyModel() : super.show('@trustRequired:onStart'); + const updatedQuery = toSpecificWorkspaceUnsupportedQuery(query, 'virtual'); + return updatedQuery ? super.show(updatedQuery) : this.showEmptyModel(); } } -export class TrustRequiredOnDemandExtensionsView extends ExtensionsListView { +export class VirtualWorkspacePartiallySupportedExtensionsView extends ExtensionsListView { override async show(query: string): Promise> { - return (query && query.trim() !== '@trustRequired') ? this.showEmptyModel() : super.show('@trustRequired:onDemand'); + const updatedQuery = toSpecificWorkspaceUnsupportedQuery(query, 'virtualPartial'); + return updatedQuery ? super.show(updatedQuery) : this.showEmptyModel(); } } diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts rename to src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts b/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts rename to src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/keymapRecommendations.ts b/src/vs/workbench/contrib/extensions/browser/keymapRecommendations.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/keymapRecommendations.ts rename to src/vs/workbench/contrib/extensions/browser/keymapRecommendations.ts diff --git a/src/vs/workbench/contrib/extensions/browser/languageRecommendations.ts b/src/vs/workbench/contrib/extensions/browser/languageRecommendations.ts new file mode 100644 index 000000000000..9258305b84aa --- /dev/null +++ b/src/vs/workbench/contrib/extensions/browser/languageRecommendations.ts @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ExtensionRecommendations, ExtensionRecommendation } from 'vs/workbench/contrib/extensions/browser/extensionRecommendations'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { ExtensionRecommendationReason } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations'; + +export class LanguageRecommendations extends ExtensionRecommendations { + + private _recommendations: ExtensionRecommendation[] = []; + get recommendations(): ReadonlyArray { return this._recommendations; } + + constructor( + @IProductService private readonly productService: IProductService, + ) { + super(); + } + + protected async doActivate(): Promise { + if (this.productService.languageExtensionTips) { + this._recommendations = this.productService.languageExtensionTips.map(extensionId => ({ + extensionId: extensionId.toLowerCase(), + reason: { + reasonId: ExtensionRecommendationReason.Application, + reasonText: '' + } + })); + } + } + +} + diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/media/extension.css b/src/vs/workbench/contrib/extensions/browser/media/extension.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/media/extension.css rename to src/vs/workbench/contrib/extensions/browser/media/extension.css diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/media/extensionActions.css b/src/vs/workbench/contrib/extensions/browser/media/extensionActions.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/media/extensionActions.css rename to src/vs/workbench/contrib/extensions/browser/media/extensionActions.css diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css b/src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css rename to src/vs/workbench/contrib/extensions/browser/media/extensionEditor.css diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css b/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css rename to src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/media/extensionsWidgets.css b/src/vs/workbench/contrib/extensions/browser/media/extensionsWidgets.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/media/extensionsWidgets.css rename to src/vs/workbench/contrib/extensions/browser/media/extensionsWidgets.css diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/media/language-icon.svg b/src/vs/workbench/contrib/extensions/browser/media/language-icon.svg similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/media/language-icon.svg rename to src/vs/workbench/contrib/extensions/browser/media/language-icon.svg diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/media/loading.svg b/src/vs/workbench/contrib/extensions/browser/media/loading.svg similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/media/loading.svg rename to src/vs/workbench/contrib/extensions/browser/media/loading.svg diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/media/runtimeExtensionsEditor.css b/src/vs/workbench/contrib/extensions/browser/media/runtimeExtensionsEditor.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/media/runtimeExtensionsEditor.css rename to src/vs/workbench/contrib/extensions/browser/media/runtimeExtensionsEditor.css diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/media/theme-icon.png b/src/vs/workbench/contrib/extensions/browser/media/theme-icon.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/media/theme-icon.png rename to src/vs/workbench/contrib/extensions/browser/media/theme-icon.png diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/browser/workspaceRecommendations.ts b/src/vs/workbench/contrib/extensions/browser/workspaceRecommendations.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/browser/workspaceRecommendations.ts rename to src/vs/workbench/contrib/extensions/browser/workspaceRecommendations.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/common/extensionQuery.ts b/src/vs/workbench/contrib/extensions/common/extensionQuery.ts similarity index 95% rename from lib/vscode/src/vs/workbench/contrib/extensions/common/extensionQuery.ts rename to src/vs/workbench/contrib/extensions/common/extensionQuery.ts index e1cac15cc906..fe3716f36d47 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/common/extensionQuery.ts +++ b/src/vs/workbench/contrib/extensions/common/extensionQuery.ts @@ -13,7 +13,7 @@ export class Query { } static suggestions(query: string): string[] { - const commands = ['installed', 'outdated', 'enabled', 'disabled', 'builtin', 'recommended', 'trustRequired', 'sort', 'category', 'tag', 'ext', 'id'] as const; + const commands = ['installed', 'outdated', 'enabled', 'disabled', 'builtin', 'recommended', 'workspaceUnsupported', 'sort', 'category', 'tag', 'ext', 'id'] as const; const subcommands = { 'sort': ['installs', 'rating', 'name'], 'category': EXTENSION_CATEGORIES.map(c => `"${c.toLowerCase()}"`), diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/common/extensions.ts b/src/vs/workbench/contrib/extensions/common/extensions.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/extensions/common/extensions.ts rename to src/vs/workbench/contrib/extensions/common/extensions.ts index 127ae556dae8..adc2776375b5 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/common/extensions.ts +++ b/src/vs/workbench/contrib/extensions/common/extensions.ts @@ -156,6 +156,8 @@ export const TOGGLE_IGNORE_EXTENSION_ACTION_ID = 'workbench.extensions.action.to export const SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID = 'workbench.extensions.action.installVSIX'; export const INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID = 'workbench.extensions.command.installFromVSIX'; +export const LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID = 'workbench.extensions.action.listWorkspaceUnsupportedExtensions'; + // Context Keys export const DefaultViewsContext = new RawContextKey('defaultExtensionViews', true); export const ExtensionsSortByContext = new RawContextKey('extensionsSortByValue', ''); diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/common/extensionsFileTemplate.ts b/src/vs/workbench/contrib/extensions/common/extensionsFileTemplate.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/common/extensionsFileTemplate.ts rename to src/vs/workbench/contrib/extensions/common/extensionsFileTemplate.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/common/extensionsInput.ts b/src/vs/workbench/contrib/extensions/common/extensionsInput.ts similarity index 83% rename from lib/vscode/src/vs/workbench/contrib/extensions/common/extensionsInput.ts rename to src/vs/workbench/contrib/extensions/common/extensionsInput.ts index ad1f9febec2b..2c142d26a6b1 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/common/extensionsInput.ts +++ b/src/vs/workbench/contrib/extensions/common/extensionsInput.ts @@ -6,7 +6,8 @@ import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; -import { EditorInput } from 'vs/workbench/common/editor'; +import { EditorInputCapabilities } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { IExtension } from 'vs/workbench/contrib/extensions/common/extensions'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { join } from 'vs/base/common/path'; @@ -19,6 +20,10 @@ export class ExtensionsInput extends EditorInput { return ExtensionsInput.ID; } + override get capabilities(): EditorInputCapabilities { + return EditorInputCapabilities.Readonly | EditorInputCapabilities.Singleton; + } + override get resource() { return URI.from({ scheme: Schemas.extension, @@ -36,10 +41,6 @@ export class ExtensionsInput extends EditorInput { return localize('extensionsInputName', "Extension: {0}", this.extension.displayName); } - override canSplit(): boolean { - return false; - } - override matches(other: unknown): boolean { if (super.matches(other)) { return true; diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/common/extensionsUtils.ts b/src/vs/workbench/contrib/extensions/common/extensionsUtils.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/common/extensionsUtils.ts rename to src/vs/workbench/contrib/extensions/common/extensionsUtils.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/common/runtimeExtensionsInput.ts b/src/vs/workbench/contrib/extensions/common/runtimeExtensionsInput.ts similarity index 81% rename from lib/vscode/src/vs/workbench/contrib/extensions/common/runtimeExtensionsInput.ts rename to src/vs/workbench/contrib/extensions/common/runtimeExtensionsInput.ts index e5ff9281fd03..c153c41d1071 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/common/runtimeExtensionsInput.ts +++ b/src/vs/workbench/contrib/extensions/common/runtimeExtensionsInput.ts @@ -5,7 +5,8 @@ import * as nls from 'vs/nls'; import { URI } from 'vs/base/common/uri'; -import { EditorInput } from 'vs/workbench/common/editor'; +import { EditorInputCapabilities } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; export class RuntimeExtensionsInput extends EditorInput { @@ -15,6 +16,10 @@ export class RuntimeExtensionsInput extends EditorInput { return RuntimeExtensionsInput.ID; } + override get capabilities(): EditorInputCapabilities { + return EditorInputCapabilities.Readonly | EditorInputCapabilities.Singleton; + } + static _instance: RuntimeExtensionsInput; static get instance() { if (!RuntimeExtensionsInput._instance || RuntimeExtensionsInput._instance.isDisposed()) { @@ -33,10 +38,6 @@ export class RuntimeExtensionsInput extends EditorInput { return nls.localize('extensionsInputName', "Running Extensions"); } - override canSplit(): boolean { - return false; - } - override matches(other: unknown): boolean { return other instanceof RuntimeExtensionsInput; } diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts similarity index 96% rename from lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts rename to src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts index ff347a59dc57..ac64051f0aaa 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts @@ -10,11 +10,11 @@ import { IExtensionHostProfile, ProfileSession, IExtensionService } from 'vs/wor import { Disposable, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { onUnexpectedError } from 'vs/base/common/errors'; import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar'; -import { IExtensionHostProfileService, ProfileSessionState } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor'; +import { IExtensionHostProfileService, ProfileSessionState } from 'vs/workbench/contrib/extensions/electron-sandbox/runtimeExtensionsEditor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { randomPort } from 'vs/base/node/ports'; +import { randomPort } from 'vs/base/common/ports'; import { IProductService } from 'vs/platform/product/common/productService'; import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/common/runtimeExtensionsInput'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; @@ -82,6 +82,7 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio if (visible) { const indicator: IStatusbarEntry = { + name: nls.localize('status.profiler', "Extension Profiler"), text: nls.localize('profilingExtensionHost', "Profiling Extension Host"), showProgress: true, ariaLabel: nls.localize('profilingExtensionHost', "Profiling Extension Host"), @@ -98,7 +99,7 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio this.profilingStatusBarIndicatorLabelUpdater.value = toDisposable(() => clearInterval(handle)); if (!this.profilingStatusBarIndicator) { - this.profilingStatusBarIndicator = this._statusbarService.addEntry(indicator, 'status.profiler', nls.localize('status.profiler', "Extension Profiler"), StatusbarAlignment.RIGHT); + this.profilingStatusBarIndicator = this._statusbarService.addEntry(indicator, 'status.profiler', StatusbarAlignment.RIGHT); } else { this.profilingStatusBarIndicator.update(indicator); } diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts new file mode 100644 index 000000000000..555bb6af1163 --- /dev/null +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts @@ -0,0 +1,18 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Registry } from 'vs/platform/registry/common/platform'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; +import { IExtensionHostProfileService } from 'vs/workbench/contrib/extensions/electron-sandbox/runtimeExtensionsEditor'; +import { ExtensionHostProfileService } from 'vs/workbench/contrib/extensions/electron-browser/extensionProfileService'; +import { ExtensionsAutoProfiler } from 'vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler'; + +// Singletons +registerSingleton(IExtensionHostProfileService, ExtensionHostProfileService, true); + +const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); +workbenchRegistry.registerWorkbenchContribution(ExtensionsAutoProfiler, LifecyclePhase.Eventually); diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts rename to src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts index 96b09731b4e6..0320b2f08b7f 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts @@ -11,14 +11,14 @@ import { ILogService } from 'vs/platform/log/common/log'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { onUnexpectedError } from 'vs/base/common/errors'; import { joinPath } from 'vs/base/common/resources'; -import { IExtensionHostProfileService } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor'; +import { IExtensionHostProfileService } from 'vs/workbench/contrib/extensions/electron-sandbox/runtimeExtensionsEditor'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { localize } from 'vs/nls'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/common/runtimeExtensionsInput'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { createSlowExtensionAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions'; +import { createSlowExtensionAction } from 'vs/workbench/contrib/extensions/electron-sandbox/extensionsSlowActions'; import { ExtensionHostProfiler } from 'vs/workbench/services/extensions/electron-browser/extensionHostProfiler'; import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; import { IFileService } from 'vs/platform/files/common/files'; diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/debugExtensionHostAction.ts b/src/vs/workbench/contrib/extensions/electron-sandbox/debugExtensionHostAction.ts similarity index 97% rename from lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/debugExtensionHostAction.ts rename to src/vs/workbench/contrib/extensions/electron-sandbox/debugExtensionHostAction.ts index 45eb957a3791..6787e95d718a 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/debugExtensionHostAction.ts +++ b/src/vs/workbench/contrib/extensions/electron-sandbox/debugExtensionHostAction.ts @@ -10,7 +10,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { IDebugService } from 'vs/workbench/contrib/debug/common/debug'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { randomPort } from 'vs/base/node/ports'; +import { randomPort } from 'vs/base/common/ports'; export class DebugExtensionHostAction extends Action { static readonly ID = 'workbench.extensions.action.debugExtensionHost'; diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts similarity index 76% rename from lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts rename to src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts index 2c5810945595..560131188671 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution.ts @@ -5,35 +5,25 @@ import { localize } from 'vs/nls'; 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 { MenuRegistry, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; 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'; import { EditorDescriptor, IEditorRegistry } from 'vs/workbench/browser/editor'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { RuntimeExtensionsEditor, IExtensionHostProfileService, StartExtensionHostProfileAction, StopExtensionHostProfileAction, CONTEXT_PROFILE_SESSION_STATE, CONTEXT_EXTENSION_HOST_PROFILE_RECORDED, SaveExtensionHostProfileAction } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor'; -import { DebugExtensionHostAction } from 'vs/workbench/contrib/extensions/electron-browser/debugExtensionHostAction'; -import { EditorInput, IEditorInputSerializer, IEditorInputFactoryRegistry, ActiveEditorContext, EditorExtensions } from 'vs/workbench/common/editor'; -import { ExtensionHostProfileService } from 'vs/workbench/contrib/extensions/electron-browser/extensionProfileService'; +import { RuntimeExtensionsEditor, StartExtensionHostProfileAction, StopExtensionHostProfileAction, CONTEXT_PROFILE_SESSION_STATE, CONTEXT_EXTENSION_HOST_PROFILE_RECORDED, SaveExtensionHostProfileAction } from 'vs/workbench/contrib/extensions/electron-sandbox/runtimeExtensionsEditor'; +import { DebugExtensionHostAction } from 'vs/workbench/contrib/extensions/electron-sandbox/debugExtensionHostAction'; +import { IEditorInputSerializer, IEditorInputFactoryRegistry, ActiveEditorContext, EditorExtensions } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/common/runtimeExtensionsInput'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { ExtensionsAutoProfiler } from 'vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler'; import { OpenExtensionsFolderAction } from 'vs/workbench/contrib/extensions/electron-sandbox/extensionsActions'; -import { ExtensionsLabel } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionRecommendationNotificationService } from 'vs/platform/extensionRecommendations/common/extensionRecommendations'; import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services'; import { ExtensionRecommendationNotificationServiceChannel } from 'vs/platform/extensionRecommendations/electron-sandbox/extensionRecommendationsIpc'; import { Codicon } from 'vs/base/common/codicons'; -// Singletons -registerSingleton(IExtensionHostProfileService, ExtensionHostProfileService, true); - -const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(ExtensionsAutoProfiler, LifecyclePhase.Eventually); - // Running Extensions Editor Registry.as(EditorExtensions.Editors).registerEditor( EditorDescriptor.create(RuntimeExtensionsEditor, RuntimeExtensionsEditor.ID, localize('runtimeExtension', "Running Extensions")), @@ -47,7 +37,7 @@ class RuntimeExtensionsInputSerializer implements IEditorInputSerializer { serialize(editorInput: EditorInput): string { return ''; } - deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput { + deserialize(instantiationService: IInstantiationService): EditorInput { return RuntimeExtensionsInput.instance; } } @@ -56,7 +46,6 @@ Registry.as(EditorExtensions.EditorInputFactories). // Global actions -const actionRegistry = Registry.as(WorkbenchActionExtensions.WorkbenchActions); class ExtensionsContributions implements IWorkbenchContribution { @@ -65,11 +54,11 @@ class ExtensionsContributions implements IWorkbenchContribution { @ISharedProcessService sharedProcessService: ISharedProcessService, ) { sharedProcessService.registerChannel('extensionRecommendationNotification', new ExtensionRecommendationNotificationServiceChannel(extensionRecommendationNotificationService)); - const openExtensionsFolderActionDescriptor = SyncActionDescriptor.from(OpenExtensionsFolderAction); - actionRegistry.registerWorkbenchAction(openExtensionsFolderActionDescriptor, 'Extensions: Open Extensions Folder', ExtensionsLabel); + registerAction2(OpenExtensionsFolderAction); } } +const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, LifecyclePhase.Starting); // Register Commands diff --git a/src/vs/workbench/contrib/extensions/electron-sandbox/extensionsActions.ts b/src/vs/workbench/contrib/extensions/electron-sandbox/extensionsActions.ts new file mode 100644 index 000000000000..2f86974b1427 --- /dev/null +++ b/src/vs/workbench/contrib/extensions/electron-sandbox/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 { IFileService } from 'vs/platform/files/common/files'; +import { URI } from 'vs/base/common/uri'; +import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; +import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; +import { Schemas } from 'vs/base/common/network'; +import { Action2 } from 'vs/platform/actions/common/actions'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { ExtensionsLocalizedLabel } from 'vs/platform/extensionManagement/common/extensionManagement'; + +export class OpenExtensionsFolderAction extends Action2 { + + constructor() { + super({ + id: 'workbench.extensions.action.openExtensionsFolder', + title: { value: localize('openExtensionsFolder', "Open Extensions Folder"), original: 'Open Extensions Folder' }, + category: ExtensionsLocalizedLabel, + f1: true + }); + } + + async run(accessor: ServicesAccessor): Promise { + const nativeHostService = accessor.get(INativeHostService); + const fileService = accessor.get(IFileService); + const environmentService = accessor.get(INativeWorkbenchEnvironmentService); + + const extensionsHome = URI.file(environmentService.extensionsPath); + const file = await 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 nativeHostService.showItemInFolder(itemToShow.fsPath); + } + } +} + diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts b/src/vs/workbench/contrib/extensions/electron-sandbox/extensionsSlowActions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions.ts rename to src/vs/workbench/contrib/extensions/electron-sandbox/extensionsSlowActions.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/reportExtensionIssueAction.ts b/src/vs/workbench/contrib/extensions/electron-sandbox/reportExtensionIssueAction.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/reportExtensionIssueAction.ts rename to src/vs/workbench/contrib/extensions/electron-sandbox/reportExtensionIssueAction.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts b/src/vs/workbench/contrib/extensions/electron-sandbox/runtimeExtensionsEditor.ts similarity index 95% rename from lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts rename to src/vs/workbench/contrib/extensions/electron-sandbox/runtimeExtensionsEditor.ts index a5c303f843a1..ea3f8ed3b89e 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-sandbox/runtimeExtensionsEditor.ts @@ -17,9 +17,9 @@ import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/cont import { IStorageService } from 'vs/platform/storage/common/storage'; import { ILabelService } from 'vs/platform/label/common/label'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; -import { SlowExtensionAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsSlowActions'; +import { SlowExtensionAction } from 'vs/workbench/contrib/extensions/electron-sandbox/extensionsSlowActions'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { ReportExtensionIssueAction } from 'vs/workbench/contrib/extensions/electron-browser/reportExtensionIssueAction'; +import { ReportExtensionIssueAction } from 'vs/workbench/contrib/extensions/electron-sandbox/reportExtensionIssueAction'; import { AbstractRuntimeExtensionsEditor, IRuntimeExtension } from 'vs/workbench/contrib/extensions/browser/abstractRuntimeExtensionsEditor'; import { VSBuffer } from 'vs/base/common/buffer'; import { URI } from 'vs/base/common/uri'; @@ -105,7 +105,15 @@ export class RuntimeExtensionsEditor extends AbstractRuntimeExtensionsEditor { } protected _createReportExtensionIssueAction(element: IRuntimeExtension): Action | null { - return this._instantiationService.createInstance(ReportExtensionIssueAction, element); + if (element.marketplaceInfo) { + return this._instantiationService.createInstance(ReportExtensionIssueAction, { + description: element.description, + marketplaceInfo: element.marketplaceInfo, + status: element.status, + unresponsiveProfile: element.unresponsiveProfile + }); + } + return null; } protected _createSaveExtensionHostProfileAction(): Action | null { diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/test/common/extensionQuery.test.ts b/src/vs/workbench/contrib/extensions/test/common/extensionQuery.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/test/common/extensionQuery.test.ts rename to src/vs/workbench/contrib/extensions/test/common/extensionQuery.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts similarity index 96% rename from lib/vscode/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts rename to src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts index efedc1c28dd4..9798f435ebf0 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts @@ -175,6 +175,12 @@ function aGalleryExtension(name: string, properties: any = {}, galleryExtensionP return galleryExtension; } +class TestExtensionRecommendationsService extends ExtensionRecommendationsService { + protected override get workbenchRecommendationDelay() { + return 0; + } +} + suite('ExtensionRecommendationsService Test', () => { let workspaceService: IWorkspaceContextService; let instantiationService: TestInstantiationService; @@ -311,7 +317,7 @@ suite('ExtensionRecommendationsService Test', () => { function testNoPromptForValidRecommendations(recommendations: string[]) { return setUpFolderWorkspace('myFolder', recommendations).then(() => { - testObject = instantiationService.createInstance(ExtensionRecommendationsService); + testObject = instantiationService.createInstance(TestExtensionRecommendationsService); return testObject.activationPromise.then(() => { assert.strictEqual(Object.keys(testObject.getAllRecommendationsWithReason()).length, recommendations.length); assert.ok(!prompted); @@ -321,7 +327,7 @@ suite('ExtensionRecommendationsService Test', () => { function testNoPromptOrRecommendationsForValidRecommendations(recommendations: string[]) { return setUpFolderWorkspace('myFolder', mockTestData.validRecommendedExtensions).then(() => { - testObject = instantiationService.createInstance(ExtensionRecommendationsService); + testObject = instantiationService.createInstance(TestExtensionRecommendationsService); assert.ok(!prompted); return testObject.getWorkspaceRecommendations().then(() => { @@ -350,7 +356,7 @@ suite('ExtensionRecommendationsService Test', () => { test('ExtensionRecommendationsService: Prompt for valid workspace recommendations', async () => { await setUpFolderWorkspace('myFolder', mockTestData.recommendedExtensions); - testObject = instantiationService.createInstance(ExtensionRecommendationsService); + testObject = instantiationService.createInstance(TestExtensionRecommendationsService); await Event.toPromise(promptedEmitter.event); const recommendations = Object.keys(testObject.getAllRecommendationsWithReason()); @@ -379,7 +385,7 @@ suite('ExtensionRecommendationsService Test', () => { test('ExtensionRecommendationsService: No Prompt for valid workspace recommendations if ignoreRecommendations is set', () => { testConfigurationService.setUserConfiguration(ConfigurationKey, { ignoreRecommendations: true }); return setUpFolderWorkspace('myFolder', mockTestData.validRecommendedExtensions).then(() => { - testObject = instantiationService.createInstance(ExtensionRecommendationsService); + testObject = instantiationService.createInstance(TestExtensionRecommendationsService); return testObject.activationPromise.then(() => { assert.ok(!prompted); }); @@ -389,7 +395,7 @@ suite('ExtensionRecommendationsService Test', () => { test('ExtensionRecommendationsService: No Prompt for valid workspace recommendations if showRecommendationsOnlyOnDemand is set', () => { testConfigurationService.setUserConfiguration(ConfigurationKey, { showRecommendationsOnlyOnDemand: true }); return setUpFolderWorkspace('myFolder', mockTestData.validRecommendedExtensions).then(() => { - testObject = instantiationService.createInstance(ExtensionRecommendationsService); + testObject = instantiationService.createInstance(TestExtensionRecommendationsService); return testObject.activationPromise.then(() => { assert.ok(!prompted); }); @@ -407,7 +413,7 @@ suite('ExtensionRecommendationsService Test', () => { instantiationService.get(IStorageService).store('extensionsAssistant/ignored_recommendations', '["ms-dotnettools.csharp", "mockpublisher2.mockextension2"]', StorageScope.GLOBAL, StorageTarget.MACHINE); return setUpFolderWorkspace('myFolder', mockTestData.validRecommendedExtensions).then(() => { - testObject = instantiationService.createInstance(ExtensionRecommendationsService); + testObject = instantiationService.createInstance(TestExtensionRecommendationsService); return testObject.activationPromise.then(() => { const recommendations = testObject.getAllRecommendationsWithReason(); assert.ok(!recommendations['ms-dotnettools.csharp']); // stored recommendation that has been globally ignored @@ -425,7 +431,7 @@ suite('ExtensionRecommendationsService Test', () => { instantiationService.get(IStorageService).store('extensionsAssistant/recommendations', storedRecommendations, StorageScope.GLOBAL, StorageTarget.MACHINE); return setUpFolderWorkspace('myFolder', mockTestData.validRecommendedExtensions, ignoredRecommendations).then(() => { - testObject = instantiationService.createInstance(ExtensionRecommendationsService); + testObject = instantiationService.createInstance(TestExtensionRecommendationsService); return testObject.activationPromise.then(() => { const recommendations = testObject.getAllRecommendationsWithReason(); assert.ok(!recommendations['ms-dotnettools.csharp']); // stored recommendation that has been workspace ignored @@ -447,7 +453,7 @@ suite('ExtensionRecommendationsService Test', () => { storageService.store('extensionsAssistant/ignored_recommendations', globallyIgnoredRecommendations, StorageScope.GLOBAL, StorageTarget.MACHINE); await setUpFolderWorkspace('myFolder', mockTestData.validRecommendedExtensions, workspaceIgnoredRecommendations); - testObject = instantiationService.createInstance(ExtensionRecommendationsService); + testObject = instantiationService.createInstance(TestExtensionRecommendationsService); await testObject.activationPromise; const recommendations = testObject.getAllRecommendationsWithReason(); @@ -467,7 +473,7 @@ suite('ExtensionRecommendationsService Test', () => { await setUpFolderWorkspace('myFolder', mockTestData.validRecommendedExtensions); const extensionIgnoredRecommendationsService = instantiationService.get(IExtensionIgnoredRecommendationsService); - testObject = instantiationService.createInstance(ExtensionRecommendationsService); + testObject = instantiationService.createInstance(TestExtensionRecommendationsService); await testObject.activationPromise; let recommendations = testObject.getAllRecommendationsWithReason(); @@ -499,7 +505,7 @@ suite('ExtensionRecommendationsService Test', () => { storageService.store('extensionsAssistant/ignored_recommendations', '["ms-vscode.vscode"]', StorageScope.GLOBAL, StorageTarget.MACHINE); await setUpFolderWorkspace('myFolder', []); - testObject = instantiationService.createInstance(ExtensionRecommendationsService); + testObject = instantiationService.createInstance(TestExtensionRecommendationsService); const extensionIgnoredRecommendationsService = instantiationService.get(IExtensionIgnoredRecommendationsService); extensionIgnoredRecommendationsService.onDidChangeGlobalIgnoredRecommendation(changeHandlerTarget); extensionIgnoredRecommendationsService.toggleGlobalIgnoredRecommendation(ignoredExtensionId, true); @@ -514,7 +520,7 @@ suite('ExtensionRecommendationsService Test', () => { instantiationService.get(IStorageService).store('extensionsAssistant/recommendations', storedRecommendations, StorageScope.GLOBAL, StorageTarget.MACHINE); return setUpFolderWorkspace('myFolder', []).then(() => { - testObject = instantiationService.createInstance(ExtensionRecommendationsService); + testObject = instantiationService.createInstance(TestExtensionRecommendationsService); return testObject.activationPromise.then(() => { const recommendations = testObject.getFileBasedRecommendations(); assert.strictEqual(recommendations.length, 2); @@ -533,7 +539,7 @@ suite('ExtensionRecommendationsService Test', () => { instantiationService.get(IStorageService).store('extensionsAssistant/recommendations', storedRecommendations, StorageScope.GLOBAL, StorageTarget.MACHINE); return setUpFolderWorkspace('myFolder', []).then(() => { - testObject = instantiationService.createInstance(ExtensionRecommendationsService); + testObject = instantiationService.createInstance(TestExtensionRecommendationsService); return testObject.activationPromise.then(() => { const recommendations = testObject.getFileBasedRecommendations(); assert.strictEqual(recommendations.length, 2); diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts rename to src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts rename to src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts rename to src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts index 36890e2ac3d0..33cd340d10fb 100644 --- a/lib/vscode/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts @@ -176,14 +176,14 @@ suite('ExtensionsWorkbenchServiceTest', () => { assert.strictEqual(4, actual.rating); assert.strictEqual(100, actual.ratingCount); assert.strictEqual(false, actual.outdated); - assert.deepEqual(['pub.1', 'pub.2'], actual.dependencies); + assert.deepStrictEqual(['pub.1', 'pub.2'], actual.dependencies); }); }); test('test for empty installed extensions', async () => { testObject = await aWorkbenchService(); - assert.deepEqual([], testObject.local); + assert.deepStrictEqual([], testObject.local); }); test('test for installed extensions', async () => { @@ -233,7 +233,7 @@ suite('ExtensionsWorkbenchServiceTest', () => { assert.strictEqual(undefined, actual.rating); assert.strictEqual(undefined, actual.ratingCount); assert.strictEqual(false, actual.outdated); - assert.deepEqual(['pub.1', 'pub.2'], actual.dependencies); + assert.deepStrictEqual(['pub.1', 'pub.2'], actual.dependencies); actual = actuals[1]; assert.strictEqual(ExtensionType.System, actual.type); @@ -251,7 +251,7 @@ suite('ExtensionsWorkbenchServiceTest', () => { assert.strictEqual(undefined, actual.rating); assert.strictEqual(undefined, actual.ratingCount); assert.strictEqual(false, actual.outdated); - assert.deepEqual([], actual.dependencies); + assert.deepStrictEqual([], actual.dependencies); }); test('test installed extensions get syncs with gallery', async () => { @@ -327,7 +327,7 @@ suite('ExtensionsWorkbenchServiceTest', () => { assert.strictEqual(4, actual.rating); assert.strictEqual(100, actual.ratingCount); assert.strictEqual(true, actual.outdated); - assert.deepEqual(['pub.1'], actual.dependencies); + assert.deepStrictEqual(['pub.1'], actual.dependencies); actual = actuals[1]; assert.strictEqual(ExtensionType.System, actual.type); @@ -345,7 +345,7 @@ suite('ExtensionsWorkbenchServiceTest', () => { assert.strictEqual(undefined, actual.rating); assert.strictEqual(undefined, actual.ratingCount); assert.strictEqual(false, actual.outdated); - assert.deepEqual([], actual.dependencies); + assert.deepStrictEqual([], actual.dependencies); }); }); diff --git a/lib/vscode/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts b/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts rename to src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts index 148401905f6d..d817ac641700 100644 --- a/lib/vscode/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts +++ b/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts @@ -6,7 +6,6 @@ import * as nls from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { URI } from 'vs/base/common/uri'; -import { IExternalTerminalConfiguration, IExternalTerminalService } from 'vs/workbench/contrib/externalTerminal/common/externalTerminal'; import { MenuId, MenuRegistry, IMenuItem } from 'vs/platform/actions/common/actions'; import { ITerminalService as IIntegratedTerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { ResourceContextKey } from 'vs/workbench/common/resources'; @@ -26,6 +25,7 @@ import { isWeb, isWindows } from 'vs/base/common/platform'; import { dirname, basename } from 'vs/base/common/path'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; +import { IExternalTerminalConfiguration, IExternalTerminalService } from 'vs/platform/externalTerminal/common/externalTerminal'; const OPEN_IN_TERMINAL_COMMAND_ID = 'openInTerminal'; CommandsRegistry.registerCommand({ @@ -44,11 +44,7 @@ CommandsRegistry.registerCommand({ // Always use integrated terminal when using a remote const useIntegratedTerminal = remoteAgentService.getConnection() || configurationService.getValue().terminal.explorerKind === 'integrated'; if (useIntegratedTerminal) { - - // TODO: Use uri for cwd in createterminal - - const opened: { [path: string]: boolean } = {}; targets.map(({ stat }) => { const resource = stat!.resource; @@ -121,8 +117,7 @@ export class ExternalTerminalContribution extends Disposable implements IWorkben this._openInTerminalMenuItem.command.title = nls.localize('scopedConsoleAction.integrated', "Open in Integrated Terminal"); return; } - - if (isWindows && config.external.windowsExec) { + if (isWindows && config.external?.windowsExec) { const file = basename(config.external.windowsExec); if (file === 'wt' || file === 'wt.exe') { this._openInTerminalMenuItem.command.title = nls.localize('scopedConsoleAction.wt', "Open in Windows Terminal"); diff --git a/lib/vscode/src/vs/workbench/contrib/externalTerminal/node/externalTerminal.contribution.ts b/src/vs/workbench/contrib/externalTerminal/electron-sandbox/externalTerminal.contribution.ts similarity index 50% rename from lib/vscode/src/vs/workbench/contrib/externalTerminal/node/externalTerminal.contribution.ts rename to src/vs/workbench/contrib/externalTerminal/electron-sandbox/externalTerminal.contribution.ts index 84e406323bec..e63a96b7c60c 100644 --- a/lib/vscode/src/vs/workbench/contrib/externalTerminal/node/externalTerminal.contribution.ts +++ b/src/vs/workbench/contrib/externalTerminal/electron-sandbox/externalTerminal.contribution.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import * as paths from 'vs/base/common/path'; -import { IExternalTerminalService } from 'vs/workbench/contrib/externalTerminal/common/externalTerminal'; +import { DEFAULT_TERMINAL_OSX, IExternalTerminalService } from 'vs/platform/externalTerminal/common/externalTerminal'; import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { KEYBINDING_CONTEXT_TERMINAL_NOT_FOCUSED } from 'vs/workbench/contrib/terminal/common/terminal'; @@ -13,12 +13,10 @@ import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { Schemas } from 'vs/base/common/network'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; -import { WindowsExternalTerminalService, MacExternalTerminalService, LinuxExternalTerminalService } from 'vs/workbench/contrib/externalTerminal/node/externalTerminalService'; import { IConfigurationRegistry, Extensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Registry } from 'vs/platform/registry/common/platform'; -import { isWindows, isMacintosh, isLinux } from 'vs/base/common/platform'; -import { DEFAULT_TERMINAL_OSX } from 'vs/workbench/contrib/externalTerminal/node/externalTerminal'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { IExternalTerminalMainService } from 'vs/platform/externalTerminal/electron-sandbox/externalTerminalMainService'; const OPEN_NATIVE_CONSOLE_COMMAND_ID = 'workbench.action.terminal.openNativeConsole'; KeybindingsRegistry.registerCommandAndKeybindingRule({ @@ -54,53 +52,54 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, { } }); -if (isWindows) { - registerSingleton(IExternalTerminalService, WindowsExternalTerminalService, true); -} else if (isMacintosh) { - registerSingleton(IExternalTerminalService, MacExternalTerminalService, true); -} else if (isLinux) { - registerSingleton(IExternalTerminalService, LinuxExternalTerminalService, true); -} +export class ExternalTerminalContribution implements IWorkbenchContribution { + + public _serviceBrand: undefined; + constructor(@IExternalTerminalMainService private readonly _externalTerminalService: IExternalTerminalMainService) { + this._updateConfiguration(); + } -LinuxExternalTerminalService.getDefaultTerminalLinuxReady().then(defaultTerminalLinux => { - let configurationRegistry = Registry.as(Extensions.Configuration); - configurationRegistry.registerConfiguration({ - id: 'externalTerminal', - order: 100, - title: nls.localize('terminalConfigurationTitle', "External Terminal"), - type: 'object', - properties: { - 'terminal.explorerKind': { - type: 'string', - enum: [ - 'integrated', - 'external' - ], - enumDescriptions: [ - nls.localize('terminal.explorerKind.integrated', "Use VS Code's integrated terminal."), - nls.localize('terminal.explorerKind.external', "Use the configured external terminal.") - ], - description: nls.localize('explorer.openInTerminalKind', "Customizes what kind of terminal to launch."), - default: 'integrated' - }, - 'terminal.external.windowsExec': { - type: 'string', - description: nls.localize('terminal.external.windowsExec', "Customizes which terminal to run on Windows."), - default: WindowsExternalTerminalService.getDefaultTerminalWindows(), - scope: ConfigurationScope.APPLICATION - }, - 'terminal.external.osxExec': { - type: 'string', - description: nls.localize('terminal.external.osxExec', "Customizes which terminal application to run on macOS."), - default: DEFAULT_TERMINAL_OSX, - scope: ConfigurationScope.APPLICATION - }, - 'terminal.external.linuxExec': { - type: 'string', - description: nls.localize('terminal.external.linuxExec', "Customizes which terminal to run on Linux."), - default: defaultTerminalLinux, - scope: ConfigurationScope.APPLICATION + private async _updateConfiguration(): Promise { + const terminals = await this._externalTerminalService.getDefaultTerminalForPlatforms(); + let configurationRegistry = Registry.as(Extensions.Configuration); + configurationRegistry.registerConfiguration({ + id: 'externalTerminal', + order: 100, + title: nls.localize('terminalConfigurationTitle', "External Terminal"), + type: 'object', + properties: { + 'terminal.explorerKind': { + type: 'string', + enum: [ + 'integrated', + 'external' + ], + enumDescriptions: [ + nls.localize('terminal.explorerKind.integrated', "Use VS Code's integrated terminal."), + nls.localize('terminal.explorerKind.external', "Use the configured external terminal.") + ], + description: nls.localize('explorer.openInTerminalKind', "Customizes what kind of terminal to launch."), + default: 'integrated' + }, + 'terminal.external.windowsExec': { + type: 'string', + description: nls.localize('terminal.external.windowsExec', "Customizes which terminal to run on Windows."), + default: terminals.windows, + scope: ConfigurationScope.APPLICATION + }, + 'terminal.external.osxExec': { + type: 'string', + description: nls.localize('terminal.external.osxExec', "Customizes which terminal application to run on macOS."), + default: DEFAULT_TERMINAL_OSX, + scope: ConfigurationScope.APPLICATION + }, + 'terminal.external.linuxExec': { + type: 'string', + description: nls.localize('terminal.external.linuxExec', "Customizes which terminal to run on Linux."), + default: terminals.linux, + scope: ConfigurationScope.APPLICATION + } } - } - }); -}); + }); + } +} diff --git a/lib/vscode/src/vs/workbench/contrib/externalTerminal/node/TerminalHelper.scpt b/src/vs/workbench/contrib/externalTerminal/node/TerminalHelper.scpt similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/externalTerminal/node/TerminalHelper.scpt rename to src/vs/workbench/contrib/externalTerminal/node/TerminalHelper.scpt diff --git a/lib/vscode/src/vs/workbench/contrib/externalTerminal/node/iTermHelper.scpt b/src/vs/workbench/contrib/externalTerminal/node/iTermHelper.scpt similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/externalTerminal/node/iTermHelper.scpt rename to src/vs/workbench/contrib/externalTerminal/node/iTermHelper.scpt diff --git a/lib/vscode/src/vs/workbench/contrib/externalUriOpener/common/configuration.ts b/src/vs/workbench/contrib/externalUriOpener/common/configuration.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/externalUriOpener/common/configuration.ts rename to src/vs/workbench/contrib/externalUriOpener/common/configuration.ts diff --git a/lib/vscode/src/vs/workbench/contrib/externalUriOpener/common/contributedOpeners.ts b/src/vs/workbench/contrib/externalUriOpener/common/contributedOpeners.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/externalUriOpener/common/contributedOpeners.ts rename to src/vs/workbench/contrib/externalUriOpener/common/contributedOpeners.ts diff --git a/lib/vscode/src/vs/workbench/contrib/externalUriOpener/common/externalUriOpener.contribution.ts b/src/vs/workbench/contrib/externalUriOpener/common/externalUriOpener.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/externalUriOpener/common/externalUriOpener.contribution.ts rename to src/vs/workbench/contrib/externalUriOpener/common/externalUriOpener.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/externalUriOpener/common/externalUriOpenerService.ts b/src/vs/workbench/contrib/externalUriOpener/common/externalUriOpenerService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/externalUriOpener/common/externalUriOpenerService.ts rename to src/vs/workbench/contrib/externalUriOpener/common/externalUriOpenerService.ts diff --git a/lib/vscode/src/vs/workbench/contrib/externalUriOpener/test/common/externalUriOpenerService.test.ts b/src/vs/workbench/contrib/externalUriOpener/test/common/externalUriOpenerService.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/externalUriOpener/test/common/externalUriOpenerService.test.ts rename to src/vs/workbench/contrib/externalUriOpener/test/common/externalUriOpenerService.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/feedback/browser/feedback.contribution.ts b/src/vs/workbench/contrib/feedback/browser/feedback.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/feedback/browser/feedback.contribution.ts rename to src/vs/workbench/contrib/feedback/browser/feedback.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/feedback/browser/feedback.ts b/src/vs/workbench/contrib/feedback/browser/feedback.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/feedback/browser/feedback.ts rename to src/vs/workbench/contrib/feedback/browser/feedback.ts index 9bd1c3ba1081..08dc43a8a56e 100644 --- a/lib/vscode/src/vs/workbench/contrib/feedback/browser/feedback.ts +++ b/src/vs/workbench/contrib/feedback/browser/feedback.ts @@ -13,7 +13,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity'; import { IThemeService, registerThemingParticipant, IColorTheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { attachButtonStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; -import { editorWidgetBackground, editorWidgetForeground, widgetShadow, inputBorder, inputForeground, inputBackground, inputActiveOptionBorder, editorBackground, textLinkForeground, contrastBorder, darken } from 'vs/platform/theme/common/colorRegistry'; +import { editorWidgetBackground, editorWidgetForeground, widgetShadow, inputBorder, inputForeground, inputBackground, inputActiveOptionBorder, editorBackground, textLinkForeground, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { IAnchor } from 'vs/base/browser/ui/contextview/contextview'; import { Button } from 'vs/base/browser/ui/button/button'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -142,7 +142,7 @@ export class FeedbackWidget extends Dropdown { if (darkenFactor) { const backgroundBaseColor = theme.getColor(editorWidgetBackground); if (backgroundBaseColor) { - const backgroundColor = darken(backgroundBaseColor, darkenFactor)(theme); + const backgroundColor = backgroundBaseColor.darken(darkenFactor); if (backgroundColor) { closeBtn.style.backgroundColor = backgroundColor.toString(); } diff --git a/lib/vscode/src/vs/workbench/contrib/feedback/browser/feedbackStatusbarItem.ts b/src/vs/workbench/contrib/feedback/browser/feedbackStatusbarItem.ts similarity index 95% rename from lib/vscode/src/vs/workbench/contrib/feedback/browser/feedbackStatusbarItem.ts rename to src/vs/workbench/contrib/feedback/browser/feedbackStatusbarItem.ts index a53db17373f8..7708f4a8f65b 100644 --- a/lib/vscode/src/vs/workbench/contrib/feedback/browser/feedbackStatusbarItem.ts +++ b/src/vs/workbench/contrib/feedback/browser/feedbackStatusbarItem.ts @@ -19,6 +19,7 @@ import { CATEGORIES } from 'vs/workbench/common/actions'; import { assertIsDefined } from 'vs/base/common/types'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { HIDE_NOTIFICATIONS_CENTER, HIDE_NOTIFICATION_TOAST } from 'vs/workbench/browser/parts/notifications/notificationsCommands'; +import { isIOS } from 'vs/base/common/platform'; class TwitterFeedbackService implements IFeedbackDelegate { @@ -70,7 +71,7 @@ export class FeedbackStatusbarConribution extends Disposable implements IWorkben ) { super(); - if (productService.sendASmile) { + if (productService.sendASmile && !isIOS) { this.createFeedbackStatusEntry(); this.registerListeners(); } @@ -79,7 +80,7 @@ export class FeedbackStatusbarConribution extends Disposable implements IWorkben private createFeedbackStatusEntry(): void { // Status entry - this.entry = this._register(this.statusbarService.addEntry(this.getStatusEntry(), 'status.feedback', localize('status.feedback', "Tweet Feedback"), StatusbarAlignment.RIGHT, -100 /* towards the end of the right hand side */)); + this.entry = this._register(this.statusbarService.addEntry(this.getStatusEntry(), 'status.feedback', StatusbarAlignment.RIGHT, -100 /* towards the end of the right hand side */)); // Command to toggle CommandsRegistry.registerCommand(FeedbackStatusbarConribution.TOGGLE_FEEDBACK_COMMAND, () => this.toggleFeedback()); @@ -135,6 +136,7 @@ export class FeedbackStatusbarConribution extends Disposable implements IWorkben private getStatusEntry(showBeak?: boolean): IStatusbarEntry { return { + name: localize('status.feedback.name', "Feedback"), text: '$(feedback)', ariaLabel: localize('status.feedback', "Tweet Feedback"), tooltip: localize('status.feedback', "Tweet Feedback"), diff --git a/lib/vscode/src/vs/workbench/contrib/feedback/browser/media/feedback.css b/src/vs/workbench/contrib/feedback/browser/media/feedback.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/feedback/browser/media/feedback.css rename to src/vs/workbench/contrib/feedback/browser/media/feedback.css diff --git a/lib/vscode/src/vs/workbench/contrib/feedback/browser/media/happy.svg b/src/vs/workbench/contrib/feedback/browser/media/happy.svg similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/feedback/browser/media/happy.svg rename to src/vs/workbench/contrib/feedback/browser/media/happy.svg diff --git a/lib/vscode/src/vs/workbench/contrib/feedback/browser/media/sad.svg b/src/vs/workbench/contrib/feedback/browser/media/sad.svg similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/feedback/browser/media/sad.svg rename to src/vs/workbench/contrib/feedback/browser/media/sad.svg diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts b/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts similarity index 83% rename from lib/vscode/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts rename to src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts index 7eed77c03abc..15845c6758dc 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts +++ b/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts @@ -7,12 +7,12 @@ import { localize } from 'vs/nls'; import { BaseBinaryResourceEditor } from 'vs/workbench/browser/parts/editor/binaryEditor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { EditorInput, EditorOptions } from 'vs/workbench/common/editor'; -import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; +import { FileEditorInput } from 'vs/workbench/contrib/files/browser/editors/fileEditorInput'; import { BINARY_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { EditorOverride } from 'vs/platform/editor/common/editor'; +import { EditorOverride, IEditorOptions } from 'vs/platform/editor/common/editor'; import { IEditorOverrideService } from 'vs/workbench/services/editor/common/editorOverrideService'; /** @@ -40,7 +40,7 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor { ); } - private async openInternal(input: EditorInput, options: EditorOptions | undefined): Promise { + private async openInternal(input: EditorInput, options: IEditorOptions | undefined): Promise { if (input instanceof FileEditorInput && this.group) { // Enforce to open the input as text to enable our text based viewer @@ -49,13 +49,14 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor { // Try to let the user pick an override if there is one availabe const overridenInput = await this.editorOverrideService.resolveEditorOverride(input, { ...options, override: EditorOverride.PICK, }, this.group); - let newOptions = overridenInput?.options ?? options; - newOptions = { ...newOptions, override: EditorOverride.DISABLED }; // Replace the overrriden input, with the text based input await this.editorService.replaceEditors([{ editor: input, replacement: overridenInput?.editor ?? input, - options: newOptions, + options: { + ...overridenInput?.options ?? options, + override: EditorOverride.DISABLED + } }], overridenInput?.group ?? this.group); } } diff --git a/src/vs/workbench/contrib/files/browser/editors/fileEditorHandler.ts b/src/vs/workbench/contrib/files/browser/editors/fileEditorHandler.ts new file mode 100644 index 000000000000..7d1270d53b90 --- /dev/null +++ b/src/vs/workbench/contrib/files/browser/editors/fileEditorHandler.ts @@ -0,0 +1,92 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { URI, UriComponents } from 'vs/base/common/uri'; +import { IEditorInputSerializer } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { isEqual } from 'vs/base/common/resources'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { NO_TYPE_ID } from 'vs/workbench/services/workingCopy/common/workingCopy'; +import { IWorkingCopyEditorService } from 'vs/workbench/services/workingCopy/common/workingCopyEditorService'; +import { FileEditorInput } from 'vs/workbench/contrib/files/browser/editors/fileEditorInput'; +import { IFileService } from 'vs/platform/files/common/files'; + +interface ISerializedFileEditorInput { + resourceJSON: UriComponents; + preferredResourceJSON?: UriComponents; + name?: string; + description?: string; + encoding?: string; + modeId?: string; +} + +export class FileEditorInputSerializer implements IEditorInputSerializer { + + canSerialize(editorInput: EditorInput): boolean { + return true; + } + + serialize(editorInput: EditorInput): string { + const fileEditorInput = editorInput as FileEditorInput; + const resource = fileEditorInput.resource; + const preferredResource = fileEditorInput.preferredResource; + const serializedFileEditorInput: ISerializedFileEditorInput = { + resourceJSON: resource.toJSON(), + preferredResourceJSON: isEqual(resource, preferredResource) ? undefined : preferredResource, // only storing preferredResource if it differs from the resource + name: fileEditorInput.getPreferredName(), + description: fileEditorInput.getPreferredDescription(), + encoding: fileEditorInput.getEncoding(), + modeId: fileEditorInput.getPreferredMode() // only using the preferred user associated mode here if available to not store redundant data + }; + + return JSON.stringify(serializedFileEditorInput); + } + + deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): FileEditorInput { + return instantiationService.invokeFunction(accessor => { + const serializedFileEditorInput: ISerializedFileEditorInput = JSON.parse(serializedEditorInput); + const resource = URI.revive(serializedFileEditorInput.resourceJSON); + const preferredResource = URI.revive(serializedFileEditorInput.preferredResourceJSON); + const name = serializedFileEditorInput.name; + const description = serializedFileEditorInput.description; + const encoding = serializedFileEditorInput.encoding; + const mode = serializedFileEditorInput.modeId; + + const fileEditorInput = accessor.get(IEditorService).createEditorInput({ resource, label: name, description, encoding, mode, forceFile: true }) as FileEditorInput; + if (preferredResource) { + fileEditorInput.setPreferredResource(preferredResource); + } + + return fileEditorInput; + }); + } +} + +export class FileEditorWorkingCopyEditorHandler extends Disposable implements IWorkbenchContribution { + + constructor( + @IWorkingCopyEditorService private readonly workingCopyEditorService: IWorkingCopyEditorService, + @IEditorService private readonly editorService: IEditorService, + @IFileService private readonly fileService: IFileService + ) { + super(); + + this.installHandler(); + } + + private installHandler(): void { + this._register(this.workingCopyEditorService.registerHandler({ + handles: workingCopy => workingCopy.typeId === NO_TYPE_ID && this.fileService.canHandleResource(workingCopy.resource), + // Naturally it would make sense here to check for `instanceof FileEditorInput` + // but because some custom editors also leverage text file based working copies + // we need to do a weaker check by only comparing for the resource + isOpen: (workingCopy, editor) => isEqual(workingCopy.resource, editor.resource), + createEditor: workingCopy => this.editorService.createEditorInput({ resource: workingCopy.resource, forceFile: true }) + })); + } +} diff --git a/lib/vscode/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts b/src/vs/workbench/contrib/files/browser/editors/fileEditorInput.ts similarity index 75% rename from lib/vscode/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts rename to src/vs/workbench/contrib/files/browser/editors/fileEditorInput.ts index 342eaecd6055..488441ba5e39 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/contrib/files/browser/editors/fileEditorInput.ts @@ -3,25 +3,24 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { localize } from 'vs/nls'; import { URI } from 'vs/base/common/uri'; -import { IFileEditorInput, Verbosity, GroupIdentifier, IMoveResult, isTextEditorPane } from 'vs/workbench/common/editor'; +import { IFileEditorInput, Verbosity, GroupIdentifier, IMoveResult, EditorInputCapabilities, IEditorDescriptor, IEditorPane } from 'vs/workbench/common/editor'; import { AbstractTextResourceEditorInput } from 'vs/workbench/common/editor/textResourceEditorInput'; +import { EditorOverride, ITextResourceEditorInput } from 'vs/platform/editor/common/editor'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; -import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files'; +import { FileOperationError, FileOperationResult, FileSystemProviderCapabilities, IFileService } from 'vs/platform/files/common/files'; import { ITextFileService, TextFileEditorModelState, TextFileResolveReason, TextFileOperationError, TextFileOperationResult, ITextFileEditorModel, EncodingMode } from 'vs/workbench/services/textfile/common/textfiles'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IReference, dispose, DisposableStore } from 'vs/base/common/lifecycle'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { FILE_EDITOR_INPUT_ID, TEXT_FILE_EDITOR_ID, BINARY_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files'; import { ILabelService } from 'vs/platform/label/common/label'; -import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; +import { AutoSaveMode, IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { isEqual } from 'vs/base/common/resources'; import { Event } from 'vs/base/common/event'; -import { IEditorViewState } from 'vs/editor/common/editorCommon'; import { Schemas } from 'vs/base/common/network'; +import { createTextBufferFactory } from 'vs/editor/common/model/textModel'; const enum ForceOpenAs { None, @@ -38,10 +37,31 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements return FILE_EDITOR_INPUT_ID; } + override get capabilities(): EditorInputCapabilities { + let capabilities = EditorInputCapabilities.None; + + if (this.model) { + if (this.model.isReadonly()) { + capabilities |= EditorInputCapabilities.Readonly; + } + } else { + if (this.fileService.canHandleResource(this.resource)) { + if (this.fileService.hasCapability(this.resource, FileSystemProviderCapabilities.Readonly)) { + capabilities |= EditorInputCapabilities.Readonly; + } + } else { + capabilities |= EditorInputCapabilities.Untitled; + } + } + + return capabilities; + } + private preferredName: string | undefined; private preferredDescription: string | undefined; private preferredEncoding: string | undefined; private preferredMode: string | undefined; + private preferredContents: string | undefined; private forceOpenAs: ForceOpenAs = ForceOpenAs.None; @@ -57,16 +77,16 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements preferredDescription: string | undefined, preferredEncoding: string | undefined, preferredMode: string | undefined, + preferredContents: string | undefined, @IInstantiationService private readonly instantiationService: IInstantiationService, @ITextFileService textFileService: ITextFileService, @ITextModelService private readonly textModelResolverService: ITextModelService, @ILabelService labelService: ILabelService, @IFileService fileService: IFileService, - @IFilesConfigurationService filesConfigurationService: IFilesConfigurationService, - @IEditorService editorService: IEditorService, - @IEditorGroupsService editorGroupService: IEditorGroupsService + @IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService, + @IEditorService editorService: IEditorService ) { - super(resource, preferredResource, editorService, editorGroupService, textFileService, labelService, fileService, filesConfigurationService); + super(resource, preferredResource, editorService, textFileService, labelService, fileService); this.model = this.textFileService.files.get(resource); @@ -86,17 +106,17 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements this.setPreferredMode(preferredMode); } - // If a file model already exists, make sure to wire it in - if (this.model) { - this.registerModelListeners(this.model); + if (typeof preferredContents === 'string') { + this.setPreferredContents(preferredContents); } - } - - protected override registerListeners(): void { - super.registerListeners(); // Attach to model that matches our resource once created this._register(this.textFileService.files.onDidCreate(model => this.onDidCreateTextFileModel(model))); + + // If a file model already exists, make sure to wire it in + if (this.model) { + this.registerModelListeners(this.model); + } } private onDidCreateTextFileModel(model: ITextFileEditorModel): void { @@ -118,6 +138,7 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements // re-emit some events from the model this.modelListeners.add(model.onDidChangeDirty(() => this._onDidChangeDirty.fire())); this.modelListeners.add(model.onDidChangeOrphaned(() => this._onDidChangeLabel.fire())); + this.modelListeners.add(model.onDidChangeReadonly(() => this._onDidChangeCapabilities.fire())); // important: treat save errors as potential dirty change because // a file that is in save conflict or error will report dirty even @@ -132,7 +153,7 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements } override getName(): string { - return this.preferredName || this.decorateLabel(super.getName()); + return this.preferredName || super.getName(); } setPreferredName(name: string): void { @@ -175,22 +196,6 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements return this.preferredDescription; } - override getTitle(verbosity: Verbosity): string { - switch (verbosity) { - case Verbosity.SHORT: - return this.decorateLabel(super.getName()); - case Verbosity.MEDIUM: - case Verbosity.LONG: - return this.decorateLabel(super.getTitle(verbosity)); - } - } - - private decorateLabel(label: string): string { - const orphaned = this.model?.hasState(TextFileEditorModelState.ORPHAN); - const readonly = this.isReadonly(); - return decorateFileEditorLabel(label, { orphaned: !!orphaned, readonly }); - } - getEncoding(): string | undefined { if (this.model) { return this.model.getEncoding(); @@ -216,6 +221,14 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements this.setForceOpenAsText(); } + getMode(): string | undefined { + if (this.model) { + return this.model.getMode(); + } + + return this.preferredMode; + } + getPreferredMode(): string | undefined { return this.preferredMode; } @@ -233,6 +246,13 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements this.setForceOpenAsText(); } + setPreferredContents(contents: string): void { + this.preferredContents = contents; + + // contents is a good hint to open the file as text + this.setForceOpenAsText(); + } + setForceOpenAsText(): void { this.forceOpenAs = ForceOpenAs.Text; } @@ -245,12 +265,12 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements return !!(this.model?.isDirty()); } - override isReadonly(): boolean { + override isOrphaned(): boolean { if (this.model) { - return this.model.isReadonly(); + return this.model.hasState(TextFileEditorModelState.ORPHAN); } - return super.isReadonly(); + return super.isOrphaned(); } override isSaving(): boolean { @@ -263,11 +283,19 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements // and it could result in bad UX where an editor can be closed even though // it shows up as dirty and has not finished saving yet. + if (this.filesConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { + return true; // a short auto save is configured, treat this as being saved + } + return super.isSaving(); } - override getPreferredEditorId(candidates: string[]): string { - return this.forceOpenAs === ForceOpenAs.Binary ? BINARY_FILE_EDITOR_ID : TEXT_FILE_EDITOR_ID; + override prefersEditor>(editors: T[]): T | undefined { + if (this.forceOpenAs === ForceOpenAs.Binary) { + return editors.find(editor => editor.typeId === BINARY_FILE_EDITOR_ID); + } + + return editors.find(editor => editor.typeId === TEXT_FILE_EDITOR_ID); } override resolve(): Promise { @@ -284,11 +312,18 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements private async doResolveAsText(): Promise { try { + // Unset preferred contents after having applied it once + // to prevent this property to stick. We still want future + // `resolve` calls to fetch the contents from disk. + const preferredContents = this.preferredContents; + this.preferredContents = undefined; + // Resolve resource via text file service and only allow // to open binary files if we are instructed so await this.textFileService.files.resolve(this.resource, { mode: this.preferredMode, encoding: this.preferredEncoding, + contents: typeof preferredContents === 'string' ? createTextBufferFactory(preferredContents) : undefined, reload: { async: true }, // trigger a reload of the model if it exists already but do not wait to show the model allowBinary: this.forceOpenAs === ForceOpenAs.Text, reason: TextFileResolveReason.EDITOR @@ -350,20 +385,29 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements }; } - private getViewStateFor(group: GroupIdentifier): IEditorViewState | undefined { - for (const editorPane of this.editorService.visibleEditorPanes) { - if (editorPane.group.id === group && this.matches(editorPane.input)) { - if (isTextEditorPane(editorPane)) { - return editorPane.getViewState(); + override asResourceEditorInput(group: GroupIdentifier): ITextResourceEditorInput { + return { + resource: this.preferredResource, + forceFile: true, + encoding: this.getEncoding(), + mode: this.getMode(), + contents: (() => { + const model = this.textFileService.files.get(this.resource); + if (model && model.isDirty()) { + return model.textEditorModel.getValue(); // only if dirty } - } - } - return undefined; + return undefined; + })(), + options: { + viewState: this.getViewStateFor(group), + override: EditorOverride.DISABLED + } + }; } override matches(otherInput: unknown): boolean { - if (otherInput === this) { + if (super.matches(otherInput)) { return true; } @@ -390,19 +434,3 @@ export class FileEditorInput extends AbstractTextResourceEditorInput implements this.cachedTextFileModelReference = undefined; } } - -export function decorateFileEditorLabel(label: string, state: { orphaned: boolean, readonly: boolean }): string { - if (state.orphaned && state.readonly) { - return localize('orphanedReadonlyFile', "{0} (deleted, read-only)", label); - } - - if (state.orphaned) { - return localize('orphanedFile', "{0} (deleted)", label); - } - - if (state.readonly) { - return localize('readonlyFile', "{0} (read-only)", label); - } - - return label; -} diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts similarity index 81% rename from lib/vscode/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts rename to src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts index 0d0bac8499d1..6e6705404424 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts @@ -5,16 +5,17 @@ import { localize } from 'vs/nls'; import { toErrorMessage } from 'vs/base/common/errorMessage'; -import { isFunction, assertIsDefined } from 'vs/base/common/types'; +import { assertIsDefined } from 'vs/base/common/types'; import { isValidBasename } from 'vs/base/common/extpath'; import { basename } from 'vs/base/common/resources'; import { toAction } from 'vs/base/common/actions'; import { VIEWLET_ID, TEXT_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files'; import { ITextFileService, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles'; import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor'; -import { EditorOptions, TextEditorOptions, IEditorInput, IEditorOpenContext } from 'vs/workbench/common/editor'; +import { IEditorInput, IEditorOpenContext, EditorInputCapabilities } from 'vs/workbench/common/editor'; +import { applyTextEditorOptions } from 'vs/workbench/common/editor/editorOptions'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; -import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; +import { FileEditorInput } from 'vs/workbench/contrib/files/browser/editors/fileEditorInput'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { FileOperationError, FileOperationResult, FileChangesEvent, IFileService, FileOperationEvent, FileOperation } from 'vs/platform/files/common/files'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -28,9 +29,10 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { CancellationToken } from 'vs/base/common/cancellation'; import { createErrorWithActions } from 'vs/base/common/errors'; -import { EditorActivation, EditorOverride, IEditorOptions } from 'vs/platform/editor/common/editor'; +import { EditorActivation, EditorOverride, ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; import { IExplorerService } from 'vs/workbench/contrib/files/browser/files'; +import { MutableDisposable } from 'vs/base/common/lifecycle'; /** * An implementation of editor for file system resources. @@ -39,6 +41,8 @@ export class TextFileEditor extends BaseTextEditor { static readonly ID = TEXT_FILE_EDITOR_ID; + private readonly inputListener = this._register(new MutableDisposable()); + constructor( @ITelemetryService telemetryService: ITelemetryService, @IFileService private readonly fileService: IFileService, @@ -63,8 +67,8 @@ export class TextFileEditor extends BaseTextEditor { this._register(this.fileService.onDidRunOperation(e => this.onDidRunOperation(e))); // Listen to file system provider changes - this._register(this.fileService.onDidChangeFileSystemProviderCapabilities(e => this.onDidFileSystemProviderChange(e.scheme))); - this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(e => this.onDidFileSystemProviderChange(e.scheme))); + this._register(this.fileService.onDidChangeFileSystemProviderCapabilities(e => this.onDidChangeFileSystemProvider(e.scheme))); + this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(e => this.onDidChangeFileSystemProvider(e.scheme))); } private onDidFilesChange(e: FileChangesEvent): void { @@ -80,11 +84,22 @@ export class TextFileEditor extends BaseTextEditor { } } - private onDidFileSystemProviderChange(scheme: string): void { + private onDidChangeFileSystemProvider(scheme: string): void { + if (this.input?.resource.scheme === scheme) { + this.updateReadonly(this.input); + } + } + + private onDidChangeInputCapabilities(input: FileEditorInput): void { + if (this.input === input) { + this.updateReadonly(input); + } + } + + private updateReadonly(input: FileEditorInput): void { const control = this.getControl(); - const input = this.input; - if (control && input?.resource.scheme === scheme) { - control.updateOptions({ readOnly: input.isReadonly() }); + if (control) { + control.updateOptions({ readOnly: input.hasCapability(EditorInputCapabilities.Readonly) }); } } @@ -104,7 +119,10 @@ export class TextFileEditor extends BaseTextEditor { return this._input as FileEditorInput; } - override async setInput(input: FileEditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + override async setInput(input: FileEditorInput, options: ITextEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + + // Update our listener for input capabilities + this.inputListener.value = input.onDidChangeCapabilities(() => this.onDidChangeInputCapabilities(input)); // Update/clear view settings if input changes this.doSaveOrClearTextEditorViewState(this.input); @@ -140,9 +158,9 @@ export class TextFileEditor extends BaseTextEditor { } } - // TextOptions (avoiding instanceof here for a reason, do not change!) - if (options && isFunction((options).apply)) { - (options).apply(textEditor, ScrollType.Immediate); + // Apply options to editor if any + if (options) { + applyTextEditorOptions(options, textEditor, ScrollType.Immediate); } // Since the resolved model provides information about being readonly @@ -156,7 +174,7 @@ export class TextFileEditor extends BaseTextEditor { } } - protected handleSetInputError(error: Error, input: FileEditorInput, options: EditorOptions | undefined): void { + protected handleSetInputError(error: Error, input: FileEditorInput, options: ITextEditorOptions | undefined): void { // In case we tried to open a file inside the text editor and the response // indicates that this is not a text file, reopen the file through the binary @@ -196,21 +214,18 @@ export class TextFileEditor extends BaseTextEditor { throw error; } - private openAsBinary(input: FileEditorInput, options: EditorOptions | undefined): void { + private openAsBinary(input: FileEditorInput, options: ITextEditorOptions | undefined): void { input.setForceOpenAsBinary(); - // Make sure to not steal away the currently active group - // because we are triggering another openEditor() call - // and do not control the initial intent that resulted - // in us now opening as binary. - const preservingOptions: IEditorOptions = { activation: EditorActivation.PRESERVE, override: EditorOverride.DISABLED }; - if (options) { - options.overwrite(preservingOptions); - } else { - options = EditorOptions.create(preservingOptions); - } - - this.editorService.openEditor(input, options, this.group); + this.editorService.openEditor(input, { + ...options, + // Make sure to not steal away the currently active group + // because we are triggering another openEditor() call + // and do not control the initial intent that resulted + // in us now opening as binary. + activation: EditorActivation.PRESERVE, + override: EditorOverride.DISABLED + }, this.group); } private async openAsFolder(input: FileEditorInput): Promise { @@ -231,6 +246,9 @@ export class TextFileEditor extends BaseTextEditor { override clearInput(): void { + // Clear input listener + this.inputListener.clear(); + // Update/clear editor view state in settings this.doSaveOrClearTextEditorViewState(this.input); diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/editors/textFileEditorTracker.ts b/src/vs/workbench/contrib/files/browser/editors/textFileEditorTracker.ts similarity index 86% rename from lib/vscode/src/vs/workbench/contrib/files/browser/editors/textFileEditorTracker.ts rename to src/vs/workbench/contrib/files/browser/editors/textFileEditorTracker.ts index 20ed5ecfea8b..51bc0067083e 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/browser/editors/textFileEditorTracker.ts +++ b/src/vs/workbench/contrib/files/browser/editors/textFileEditorTracker.ts @@ -17,6 +17,7 @@ import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/ import { FILE_EDITOR_INPUT_ID } from 'vs/workbench/contrib/files/common/files'; import { Schemas } from 'vs/base/common/network'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput'; +import { IWorkingCopyEditorService } from 'vs/workbench/services/workingCopy/common/workingCopyEditorService'; export class TextFileEditorTracker extends Disposable implements IWorkbenchContribution { @@ -26,7 +27,8 @@ export class TextFileEditorTracker extends Disposable implements IWorkbenchContr @ILifecycleService private readonly lifecycleService: ILifecycleService, @IHostService private readonly hostService: IHostService, @ICodeEditorService private readonly codeEditorService: ICodeEditorService, - @IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService + @IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService, + @IWorkingCopyEditorService private readonly workingCopyEditorService: IWorkingCopyEditorService ) { super(); @@ -57,19 +59,24 @@ export class TextFileEditorTracker extends Disposable implements IWorkbenchContr return false; // resource must be dirty } - const model = this.textFileService.files.get(resource); - if (model?.hasState(TextFileEditorModelState.PENDING_SAVE)) { + const fileModel = this.textFileService.files.get(resource); + if (fileModel?.hasState(TextFileEditorModelState.PENDING_SAVE)) { return false; // resource must not be pending to save } - if (this.filesConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY && !model?.hasState(TextFileEditorModelState.ERROR)) { + if (this.filesConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY && !fileModel?.hasState(TextFileEditorModelState.ERROR)) { // leave models auto saved after short delay unless // the save resulted in an error return false; } if (this.editorService.isOpened({ resource, typeId: resource.scheme === Schemas.untitled ? UntitledTextEditorInput.ID : FILE_EDITOR_INPUT_ID })) { - return false; // model must not be opened already as file + return false; // model must not be opened already as file (fast check via editor type) + } + + const model = fileModel ?? this.textFileService.untitled.get(resource); + if (model && this.workingCopyEditorService.findEditor(model)) { + return false; // model must not be opened already as file (slower check via working copy) } return true; diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts b/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts rename to src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts index c9c2651dc2e6..24192e1198a5 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts +++ b/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts @@ -18,7 +18,7 @@ import { ResourceMap } from 'vs/base/common/map'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { TextFileContentProvider } from 'vs/workbench/contrib/files/common/files'; -import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; +import { FileEditorInput } from 'vs/workbench/contrib/files/browser/editors/fileEditorInput'; import { SAVE_FILE_AS_LABEL } from 'vs/workbench/contrib/files/browser/fileCommands'; import { INotificationService, INotificationHandle, INotificationActions, Severity } from 'vs/platform/notification/common/notification'; import { IOpenerService } from 'vs/platform/opener/common/opener'; diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/explorerService.ts b/src/vs/workbench/contrib/files/browser/explorerService.ts similarity index 92% rename from lib/vscode/src/vs/workbench/contrib/files/browser/explorerService.ts rename to src/vs/workbench/contrib/files/browser/explorerService.ts index 9a5d39685f9a..55c934a4e36b 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/browser/explorerService.ts +++ b/src/vs/workbench/contrib/files/browser/explorerService.ts @@ -6,7 +6,7 @@ import { Event } from 'vs/base/common/event'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { DisposableStore } from 'vs/base/common/lifecycle'; -import { IFilesConfiguration, SortOrder } from 'vs/workbench/contrib/files/common/files'; +import { IFilesConfiguration, ISortOrderConfiguration, SortOrder, LexicographicOptions } from 'vs/workbench/contrib/files/common/files'; import { ExplorerItem, ExplorerModel } from 'vs/workbench/contrib/files/common/explorerModel'; import { URI } from 'vs/base/common/uri'; import { FileOperationEvent, FileOperation, IFileService, FileChangesEvent, FileChangeType, IResolveFileOptions } from 'vs/platform/files/common/files'; @@ -33,6 +33,7 @@ export class ExplorerService implements IExplorerService { private readonly disposables = new DisposableStore(); private editable: { stat: ExplorerItem, data: IEditableData } | undefined; private _sortOrder: SortOrder; + private _lexicographicOptions: LexicographicOptions; private cutItems: ExplorerItem[] | undefined; private view: IExplorerView | undefined; private model: ExplorerModel; @@ -50,6 +51,7 @@ export class ExplorerService implements IExplorerService { @IProgressService private readonly progressService: IProgressService ) { this._sortOrder = this.configurationService.getValue('explorer.sortOrder'); + this._lexicographicOptions = this.configurationService.getValue('explorer.sortOrderLexicographicOptions'); this.model = new ExplorerModel(this.contextService, this.uriIdentityService, this.fileService); this.disposables.add(this.model); @@ -125,8 +127,11 @@ export class ExplorerService implements IExplorerService { return this.model.roots; } - get sortOrder(): SortOrder { - return this._sortOrder; + get sortOrderConfiguration(): ISortOrderConfiguration { + return { + sortOrder: this._sortOrder, + lexicographicOptions: this._lexicographicOptions, + }; } registerView(contextProvider: IExplorerView): void { @@ -226,7 +231,7 @@ export class ExplorerService implements IExplorerService { } // Stat needs to be resolved first and then revealed - const options: IResolveFileOptions = { resolveTo: [resource], resolveMetadata: this.sortOrder === SortOrder.Modified }; + const options: IResolveFileOptions = { resolveTo: [resource], resolveMetadata: this._sortOrder === SortOrder.Modified }; const root = this.findClosestRoot(resource); if (!root) { return undefined; @@ -278,7 +283,7 @@ export class ExplorerService implements IExplorerService { // Add the new file to its parent (Model) await Promise.all(parents.map(async p => { // We have to check if the parent is resolved #29177 - const resolveMetadata = this.sortOrder === `modified`; + const resolveMetadata = this._sortOrder === `modified`; if (!p.isDirectoryResolved) { const stat = await this.fileService.resolve(p.resource, { resolveMetadata }); if (stat) { @@ -348,13 +353,22 @@ export class ExplorerService implements IExplorerService { } private async onConfigurationUpdated(configuration: IFilesConfiguration, event?: IConfigurationChangeEvent): Promise { - const configSortOrder = configuration?.explorer?.sortOrder || 'default'; + let shouldRefresh = false; + + const configSortOrder = configuration?.explorer?.sortOrder || SortOrder.Default; if (this._sortOrder !== configSortOrder) { - const shouldRefresh = this._sortOrder !== undefined; + shouldRefresh = this._sortOrder !== undefined; this._sortOrder = configSortOrder; - if (shouldRefresh) { - await this.refresh(); - } + } + + const configLexicographicOptions = configuration?.explorer?.sortOrderLexicographicOptions || LexicographicOptions.Default; + if (this._lexicographicOptions !== configLexicographicOptions) { + shouldRefresh = shouldRefresh || this._lexicographicOptions !== undefined; + this._lexicographicOptions = configLexicographicOptions; + } + + if (shouldRefresh) { + await this.refresh(); } } diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/explorerViewlet.ts b/src/vs/workbench/contrib/files/browser/explorerViewlet.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/files/browser/explorerViewlet.ts rename to src/vs/workbench/contrib/files/browser/explorerViewlet.ts index ebdde76ffdce..f752b8790e5a 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/browser/explorerViewlet.ts +++ b/src/vs/workbench/contrib/files/browser/explorerViewlet.ts @@ -37,7 +37,7 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { WorkbenchStateContext, RemoteNameContext } from 'vs/workbench/browser/contextkeys'; import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; import { AddRootFolderAction, OpenFolderAction, OpenFileFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; -import { isMacintosh } from 'vs/base/common/platform'; +import { isMacintosh, isWeb } from 'vs/base/common/platform'; import { Codicon } from 'vs/base/common/codicons'; import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; @@ -294,7 +294,7 @@ viewsRegistry.registerViewWelcomeContent(EmptyView.ID, { order: 1 }); -const commandId = isMacintosh ? OpenFileFolderAction.ID : OpenFolderAction.ID; +const commandId = (isMacintosh && !isWeb) ? OpenFileFolderAction.ID : OpenFolderAction.ID; viewsRegistry.registerViewWelcomeContent(EmptyView.ID, { content: localize({ key: 'remoteNoFolderHelp', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] }, "Connected to remote.\n[Open Folder](command:{0})", commandId), diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts similarity index 97% rename from lib/vscode/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts rename to src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index ab99f725f5a2..17fa76012f26 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; -import { ToggleAutoSaveAction, FocusFilesExplorer, GlobalCompareResourcesAction, ShowActiveFileInExplorer, CompareWithClipboardAction, NEW_FILE_COMMAND_ID, NEW_FILE_LABEL, NEW_FOLDER_COMMAND_ID, NEW_FOLDER_LABEL, TRIGGER_RENAME_LABEL, MOVE_FILE_TO_TRASH_LABEL, COPY_FILE_LABEL, PASTE_FILE_LABEL, FileCopiedContext, renameHandler, moveFileToTrashHandler, copyFileHandler, pasteFileHandler, deleteFileHandler, cutFileHandler, DOWNLOAD_COMMAND_ID, openFilePreserveFocusHandler, DOWNLOAD_LABEL, ShowOpenedFileInNewWindow } from 'vs/workbench/contrib/files/browser/fileActions'; +import { ToggleAutoSaveAction, FocusFilesExplorer, GlobalCompareResourcesAction, ShowActiveFileInExplorer, CompareWithClipboardAction, NEW_FILE_COMMAND_ID, NEW_FILE_LABEL, NEW_FOLDER_COMMAND_ID, NEW_FOLDER_LABEL, TRIGGER_RENAME_LABEL, MOVE_FILE_TO_TRASH_LABEL, COPY_FILE_LABEL, PASTE_FILE_LABEL, FileCopiedContext, renameHandler, moveFileToTrashHandler, copyFileHandler, pasteFileHandler, deleteFileHandler, cutFileHandler, DOWNLOAD_COMMAND_ID, openFilePreserveFocusHandler, DOWNLOAD_LABEL, ShowOpenedFileInNewWindow, UPLOAD_COMMAND_ID, UPLOAD_LABEL } from 'vs/workbench/contrib/files/browser/fileActions'; import { revertLocalChangesCommand, acceptLocalChangesCommand, CONFLICT_RESOLUTION_CONTEXT } from 'vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler'; import { SyncActionDescriptor, MenuId, MenuRegistry, ILocalizedString } from 'vs/platform/actions/common/actions'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; @@ -112,7 +112,7 @@ const CUT_FILE_ID = 'filesExplorer.cut'; KeybindingsRegistry.registerCommandAndKeybindingRule({ id: CUT_FILE_ID, weight: KeybindingWeight.WorkbenchContrib + explorerCommandsWeightBonus, - when: ContextKeyExpr.and(FilesExplorerFocusCondition, ExplorerRootContext.toNegated()), + when: ContextKeyExpr.and(FilesExplorerFocusCondition, ExplorerRootContext.toNegated(), ExplorerResourceNotReadonlyContext), primary: KeyMod.CtrlCmd | KeyCode.KEY_X, handler: cutFileHandler, }); @@ -460,7 +460,7 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { id: CUT_FILE_ID, title: nls.localize('cut', "Cut") }, - when: ExplorerRootContext.toNegated() + when: ContextKeyExpr.and(ExplorerRootContext.toNegated(), ExplorerResourceNotReadonlyContext) }); MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { @@ -485,8 +485,8 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { }); MenuRegistry.appendMenuItem(MenuId.ExplorerContext, ({ - group: '5_cutcopypaste', - order: 30, + group: '5b_importexport', + order: 10, command: { id: DOWNLOAD_COMMAND_ID, title: DOWNLOAD_LABEL, @@ -501,16 +501,33 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, ({ ) })); +MenuRegistry.appendMenuItem(MenuId.ExplorerContext, ({ + group: '5b_importexport', + order: 20, + command: { + id: UPLOAD_COMMAND_ID, + title: UPLOAD_LABEL, + }, + when: ContextKeyExpr.and( + // only in web + IsWebContext, + // only on folders + ExplorerFolderContext, + // only on editable folders + ExplorerResourceNotReadonlyContext + ) +})); + MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { group: '6_copypath', - order: 30, + order: 10, command: copyPathCommand, when: ResourceContextKey.IsFileSystemResource }); MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { group: '6_copypath', - order: 30, + order: 20, command: copyRelativePathCommand, when: ResourceContextKey.IsFileSystemResource }); diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/fileActions.ts b/src/vs/workbench/contrib/files/browser/fileActions.ts similarity index 77% rename from lib/vscode/src/vs/workbench/contrib/files/browser/fileActions.ts rename to src/vs/workbench/contrib/files/browser/fileActions.ts index 1a9407c20ab8..258000894b2f 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.ts @@ -4,16 +4,16 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import { isWindows, isWeb } from 'vs/base/common/platform'; +import { isWindows } from 'vs/base/common/platform'; import * as extpath from 'vs/base/common/extpath'; import { extname, basename } from 'vs/base/common/path'; import * as resources from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Action } from 'vs/base/common/actions'; -import { DisposableStore, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { VIEWLET_ID, IFilesConfiguration, VIEW_ID } from 'vs/workbench/contrib/files/common/files'; -import { ByteSize, IFileService, IFileStatWithMetadata } from 'vs/platform/files/common/files'; +import { IFileService } from 'vs/platform/files/common/files'; import { EditorResourceAccessor, SideBySideEditor } from 'vs/workbench/common/editor'; import { IQuickInputService, ItemActivation } from 'vs/platform/quickinput/common/quickInput'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; @@ -28,8 +28,8 @@ import { IModeService } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { FileAccess, Schemas } from 'vs/base/common/network'; -import { IDialogService, IConfirmationResult, getFileNamesMessage, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { Schemas } from 'vs/base/common/network'; +import { IDialogService, IConfirmationResult, getFileNamesMessage } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Constants } from 'vs/base/common/uint'; @@ -37,26 +37,19 @@ import { CLOSE_EDITORS_AND_GROUP_COMMAND_ID } from 'vs/workbench/browser/parts/e import { coalesce } from 'vs/base/common/arrays'; import { ExplorerItem, NewExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel'; import { getErrorMessage } from 'vs/base/common/errors'; -import { WebFileSystemAccess, triggerDownload } from 'vs/base/browser/dom'; -import { mnemonicButtonLabel } from 'vs/base/common/labels'; +import { triggerUpload } from 'vs/base/browser/dom'; import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopy'; -import { RunOnceWorker, sequence, timeout } from 'vs/base/common/async'; +import { timeout } from 'vs/base/common/async'; import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService'; -import { once } from 'vs/base/common/functional'; import { Codicon } from 'vs/base/common/codicons'; import { IViewsService } from 'vs/workbench/common/views'; import { trim, rtrim } from 'vs/base/common/strings'; -import { IProgressService, IProgressStep, ProgressLocation } from 'vs/platform/progress/common/progress'; -import { CancellationTokenSource } from 'vs/base/common/cancellation'; -import { ILogService } from 'vs/platform/log/common/log'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; import { ResourceFileEdit } from 'vs/editor/browser/services/bulkEditService'; import { IExplorerService } from 'vs/workbench/contrib/files/browser/files'; -import { listenStream } from 'vs/base/common/stream'; -import { EditorOverride } from 'vs/platform/editor/common/editor'; -import { ContributedEditorPriority, IEditorOverrideService } from 'vs/workbench/services/editor/common/editorOverrideService'; +import { BrowserFileUpload, FileDownload } from 'vs/workbench/contrib/files/browser/fileImportExport'; export const NEW_FILE_COMMAND_ID = 'explorer.newFile'; export const NEW_FILE_LABEL = nls.localize('newFile', "New File"); @@ -67,7 +60,10 @@ export const MOVE_FILE_TO_TRASH_LABEL = nls.localize('delete', "Delete"); export const COPY_FILE_LABEL = nls.localize('copyFile', "Copy"); export const PASTE_FILE_LABEL = nls.localize('pasteFile', "Paste"); export const FileCopiedContext = new RawContextKey('fileCopied', false); +export const DOWNLOAD_COMMAND_ID = 'explorer.download'; export const DOWNLOAD_LABEL = nls.localize('download', "Download..."); +export const UPLOAD_COMMAND_ID = 'explorer.upload'; +export const UPLOAD_LABEL = nls.localize('upload', "Upload..."); const CONFIRM_DELETE_SETTING_KEY = 'explorer.confirmDelete'; const MAX_UNDO_FILE_SIZE = 5000000; // 5mb @@ -444,8 +440,7 @@ export class GlobalCompareResourcesAction extends Action { label: string, @IQuickInputService private readonly quickInputService: IQuickInputService, @IEditorService private readonly editorService: IEditorService, - @ITextModelService private readonly textModelService: ITextModelService, - @IEditorOverrideService private readonly editorOverrideService: IEditorOverrideService + @ITextModelService private readonly textModelService: ITextModelService ) { super(id, label); } @@ -454,49 +449,17 @@ export class GlobalCompareResourcesAction extends Action { const activeInput = this.editorService.activeEditor; const activeResource = EditorResourceAccessor.getOriginalUri(activeInput); if (activeResource && this.textModelService.canHandleResource(activeResource)) { - - // Define a one-time override that has highest priority - // and matches every resource to be able to create a - // diff editor to show the comparison. - const editorOverrideDisposable = this.editorOverrideService.registerContributionPoint('*', { - id: GlobalCompareResourcesAction.ID, - label: GlobalCompareResourcesAction.LABEL, - priority: ContributedEditorPriority.exclusive, - detail: '', - describes: () => false - }, {}, resource => { - - // Only once! - editorOverrideDisposable.dispose(); - - // Open editor as diff if the selected editor resource - // can be handled by the text model service - if (this.textModelService.canHandleResource(resource)) { - return { - editor: this.editorService.createEditorInput({ - leftResource: activeResource, - rightResource: resource, - options: { override: EditorOverride.DISABLED, pinned: true } - }) - }; + const picks = await this.quickInputService.quickAccess.pick('', { itemActivation: ItemActivation.SECOND }); + if (picks?.length === 1) { + const resource = (picks[0] as unknown as { resource: unknown }).resource; + if (URI.isUri(resource) && this.textModelService.canHandleResource(resource)) { + this.editorService.openEditor({ + originalInput: { resource: activeResource }, + modifiedInput: { resource: resource }, + options: { pinned: true } + }); } - - // Otherwise stay on current resource - return { - editor: this.editorService.createEditorInput({ - resource: activeResource, - options: { override: EditorOverride.DISABLED, pinned: true } - }) - }; - }); - - once(this.quickInputService.onHide)((async () => { - await timeout(0); // prevent race condition with editor - editorOverrideDisposable.dispose(); - })); - - // Bring up quick access - this.quickInputService.quickAccess.show('', { itemActivation: ItemActivation.SECOND }); + } } } } @@ -639,7 +602,7 @@ export class ShowOpenedFileInNewWindow extends Action { label: string, @IEditorService private readonly editorService: IEditorService, @IHostService private readonly hostService: IHostService, - @INotificationService private readonly notificationService: INotificationService, + @IDialogService private readonly dialogService: IDialogService, @IFileService private readonly fileService: IFileService ) { super(id, label); @@ -651,7 +614,7 @@ export class ShowOpenedFileInNewWindow extends Action { if (this.fileService.canHandleResource(fileResource)) { this.hostService.openWindow([{ fileUri: fileResource }], { forceNewWindow: true }); } else { - this.notificationService.info(nls.localize('openFileToShowInNewWindow.unsupportedschema', "The active editor must contain an openable resource.")); + this.dialogService.show(Severity.Error, nls.localize('openFileToShowInNewWindow.unsupportedschema', "The active editor must contain an openable resource."), [nls.localize('ok', 'OK')]); } } } @@ -718,7 +681,7 @@ function trimLongName(name: string): string { return name; } -export function getWellFormedFileName(filename: string): string { +function getWellFormedFileName(filename: string): string { if (!filename) { return filename; } @@ -726,8 +689,7 @@ export function getWellFormedFileName(filename: string): string { // Trim tabs filename = trim(filename, '\t'); - // Remove trailing dots and slashes - filename = rtrim(filename, '.'); + // Remove trailing slashes filename = rtrim(filename, '/'); filename = rtrim(filename, '\\'); @@ -768,8 +730,9 @@ export class CompareWithClipboardAction extends Action { const editorLabel = nls.localize('clipboardComparisonLabel', "Clipboard ↔ {0}", name); await this.editorService.openEditor({ - leftResource: resource.with({ scheme }), - rightResource: resource, label: editorLabel, + originalInput: { resource: resource.with({ scheme }) }, + modifiedInput: { resource: resource }, + label: editorLabel, options: { pinned: true } }).finally(() => { dispose(this.registrationDisposal); @@ -965,245 +928,39 @@ export const cutFileHandler = async (accessor: ServicesAccessor) => { } }; -export const DOWNLOAD_COMMAND_ID = 'explorer.download'; const downloadFileHandler = async (accessor: ServicesAccessor) => { - const logService = accessor.get(ILogService); - const fileService = accessor.get(IFileService); - const fileDialogService = accessor.get(IFileDialogService); const explorerService = accessor.get(IExplorerService); - const progressService = accessor.get(IProgressService); + const instantiationService = accessor.get(IInstantiationService); const context = explorerService.getContext(true); const explorerItems = context.length ? context : explorerService.roots; - const cts = new CancellationTokenSource(); - - await progressService.withProgress({ - location: ProgressLocation.Window, - delay: 800, - cancellable: isWeb, - title: nls.localize('downloadingFiles', "Downloading") - }, async progress => { - return sequence(explorerItems.map(explorerItem => async () => { - if (cts.token.isCancellationRequested) { - return; - } - - // Web: use DOM APIs to download files with optional support - // for folders and large files - if (isWeb) { - const stat = await fileService.resolve(explorerItem.resource, { resolveMetadata: true }); - - if (cts.token.isCancellationRequested) { - return; - } - - const maxBlobDownloadSize = 32 * ByteSize.MB; // avoid to download via blob-trick >32MB to avoid memory pressure - const preferFileSystemAccessWebApis = stat.isDirectory || stat.size > maxBlobDownloadSize; - - // Folder: use FS APIs to download files and folders if available and preferred - if (preferFileSystemAccessWebApis && WebFileSystemAccess.supported(window)) { - - interface IDownloadOperation { - startTime: number; - progressScheduler: RunOnceWorker; - - filesTotal: number; - filesDownloaded: number; - - totalBytesDownloaded: number; - fileBytesDownloaded: number; - } - - async function downloadFileBuffered(resource: URI, target: FileSystemWritableFileStream, operation: IDownloadOperation): Promise { - const contents = await fileService.readFileStream(resource); - if (cts.token.isCancellationRequested) { - target.close(); - return; - } - - return new Promise((resolve, reject) => { - const sourceStream = contents.value; - - const disposables = new DisposableStore(); - disposables.add(toDisposable(() => target.close())); - - let disposed = false; - disposables.add(toDisposable(() => disposed = true)); - - disposables.add(once(cts.token.onCancellationRequested)(() => { - disposables.dispose(); - reject(); - })); - - listenStream(sourceStream, { - onData: data => { - if (!disposed) { - target.write(data.buffer); - reportProgress(contents.name, contents.size, data.byteLength, operation); - } - }, - onError: error => { - disposables.dispose(); - reject(error); - }, - onEnd: () => { - disposables.dispose(); - resolve(); - } - }); - }); - } - - async function downloadFileUnbuffered(resource: URI, target: FileSystemWritableFileStream, operation: IDownloadOperation): Promise { - const contents = await fileService.readFile(resource); - if (!cts.token.isCancellationRequested) { - target.write(contents.value.buffer); - reportProgress(contents.name, contents.size, contents.value.byteLength, operation); - } - - target.close(); - } - - async function downloadFile(targetFolder: FileSystemDirectoryHandle, file: IFileStatWithMetadata, operation: IDownloadOperation): Promise { - - // Report progress - operation.filesDownloaded++; - operation.fileBytesDownloaded = 0; // reset for this file - reportProgress(file.name, 0, 0, operation); - - // Start to download - const targetFile = await targetFolder.getFileHandle(file.name, { create: true }); - const targetFileWriter = await targetFile.createWritable(); - - // For large files, write buffered using streams - if (file.size > ByteSize.MB) { - return downloadFileBuffered(file.resource, targetFileWriter, operation); - } - - // For small files prefer to write unbuffered to reduce overhead - return downloadFileUnbuffered(file.resource, targetFileWriter, operation); - } - - async function downloadFolder(folder: IFileStatWithMetadata, targetFolder: FileSystemDirectoryHandle, operation: IDownloadOperation): Promise { - if (folder.children) { - operation.filesTotal += (folder.children.map(child => child.isFile)).length; - - for (const child of folder.children) { - if (cts.token.isCancellationRequested) { - return; - } - - if (child.isFile) { - await downloadFile(targetFolder, child, operation); - } else { - const childFolder = await targetFolder.getDirectoryHandle(child.name, { create: true }); - const resolvedChildFolder = await fileService.resolve(child.resource, { resolveMetadata: true }); - - await downloadFolder(resolvedChildFolder, childFolder, operation); - } - } - } - } - - function reportProgress(name: string, fileSize: number, bytesDownloaded: number, operation: IDownloadOperation): void { - operation.fileBytesDownloaded += bytesDownloaded; - operation.totalBytesDownloaded += bytesDownloaded; - - const bytesDownloadedPerSecond = operation.totalBytesDownloaded / ((Date.now() - operation.startTime) / 1000); - - // Small file - let message: string; - if (fileSize < ByteSize.MB) { - if (operation.filesTotal === 1) { - message = name; - } else { - message = nls.localize('downloadProgressSmallMany', "{0} of {1} files ({2}/s)", operation.filesDownloaded, operation.filesTotal, ByteSize.formatSize(bytesDownloadedPerSecond)); - } - } - - // Large file - else { - message = nls.localize('downloadProgressLarge', "{0} ({1} of {2}, {3}/s)", name, ByteSize.formatSize(operation.fileBytesDownloaded), ByteSize.formatSize(fileSize), ByteSize.formatSize(bytesDownloadedPerSecond)); - } - - // Report progress but limit to update only once per second - operation.progressScheduler.work({ message }); - } + const downloadHandler = instantiationService.createInstance(FileDownload); + return downloadHandler.download(explorerItems); +}; - try { - const parentFolder: FileSystemDirectoryHandle = await window.showDirectoryPicker(); - const operation: IDownloadOperation = { - startTime: Date.now(), - progressScheduler: new RunOnceWorker(steps => { progress.report(steps[steps.length - 1]); }, 1000), - - filesTotal: stat.isDirectory ? 0 : 1, // folders increment filesTotal within downloadFolder method - filesDownloaded: 0, - - totalBytesDownloaded: 0, - fileBytesDownloaded: 0 - }; - - if (stat.isDirectory) { - const targetFolder = await parentFolder.getDirectoryHandle(stat.name, { create: true }); - await downloadFolder(stat, targetFolder, operation); - } else { - await downloadFile(parentFolder, stat, operation); - } - - operation.progressScheduler.dispose(); - } catch (error) { - logService.warn(error); - cts.cancel(); // `showDirectoryPicker` will throw an error when the user cancels - } - } +CommandsRegistry.registerCommand({ + id: DOWNLOAD_COMMAND_ID, + handler: downloadFileHandler +}); - // File: use traditional download to circumvent browser limitations - else if (stat.isFile) { - let bufferOrUri: Uint8Array | URI; - try { - bufferOrUri = (await fileService.readFile(stat.resource, { limits: { size: maxBlobDownloadSize } })).value.buffer; - } catch (error) { - bufferOrUri = FileAccess.asBrowserUri(stat.resource); - } +const uploadFileHandler = async (accessor: ServicesAccessor) => { + const explorerService = accessor.get(IExplorerService); + const instantiationService = accessor.get(IInstantiationService); - if (!cts.token.isCancellationRequested) { - triggerDownload(bufferOrUri, stat.name); - } - } - } + const context = explorerService.getContext(true); + const element = context.length ? context[0] : explorerService.roots[0]; - // Native: use working copy file service to get at the contents - else { - progress.report({ message: explorerItem.name }); - - let defaultUri = explorerItem.isDirectory ? await fileDialogService.defaultFolderPath(Schemas.file) : await fileDialogService.defaultFilePath(Schemas.file); - defaultUri = resources.joinPath(defaultUri, explorerItem.name); - - const destination = await fileDialogService.showSaveDialog({ - availableFileSystems: [Schemas.file], - saveLabel: mnemonicButtonLabel(nls.localize('downloadButton', "Download")), - title: nls.localize('chooseWhereToDownload', "Choose Where to Download"), - defaultUri - }); - - if (destination) { - await explorerService.applyBulkEdit([new ResourceFileEdit(explorerItem.resource, destination, { overwrite: true, copy: true })], { - undoLabel: nls.localize('downloadBulkEdit', "Download {0}", explorerItem.name), - progressLabel: nls.localize('downloadingBulkEdit', "Downloading {0}", explorerItem.name), - progressLocation: ProgressLocation.Explorer - }); - } else { - cts.cancel(); // User canceled a download. In case there were multiple files selected we should cancel the remainder of the prompts #86100 - } - } - })); - }, () => cts.dispose(true)); + const files = await triggerUpload(); + if (files) { + const browserUpload = instantiationService.createInstance(BrowserFileUpload); + return browserUpload.upload(element, files); + } }; CommandsRegistry.registerCommand({ - id: DOWNLOAD_COMMAND_ID, - handler: downloadFileHandler + id: UPLOAD_COMMAND_ID, + handler: uploadFileHandler }); export const pasteFileHandler = async (accessor: ServicesAccessor) => { diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/fileCommands.ts b/src/vs/workbench/contrib/files/browser/fileCommands.ts similarity index 97% rename from lib/vscode/src/vs/workbench/contrib/files/browser/fileCommands.ts rename to src/vs/workbench/contrib/files/browser/fileCommands.ts index f2894496f223..f078cb142bb4 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/browser/fileCommands.ts +++ b/src/vs/workbench/contrib/files/browser/fileCommands.ts @@ -5,7 +5,8 @@ import * as nls from 'vs/nls'; import { URI } from 'vs/base/common/uri'; -import { EditorResourceAccessor, IEditorCommandsContext, SideBySideEditor, IEditorIdentifier, SaveReason, SideBySideEditorInput, EditorsOrder } from 'vs/workbench/common/editor'; +import { EditorResourceAccessor, IEditorCommandsContext, SideBySideEditor, IEditorIdentifier, SaveReason, EditorsOrder, EditorInputCapabilities } from 'vs/workbench/common/editor'; +import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput'; import { IWindowOpenable, IOpenWindowOptions, isWorkspaceToOpen, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -243,8 +244,8 @@ CommandsRegistry.registerCommand({ if (resources.length === 2) { return editorService.openEditor({ - leftResource: resources[0], - rightResource: resources[1], + originalInput: { resource: resources[0] }, + modifiedInput: { resource: resources[1] }, options: { pinned: true } }); } @@ -262,8 +263,8 @@ CommandsRegistry.registerCommand({ const rightResource = getResourceForCommand(resource, listService, editorService); if (globalResourceToCompare && rightResource) { editorService.openEditor({ - leftResource: globalResourceToCompare, - rightResource, + originalInput: { resource: globalResourceToCompare }, + modifiedInput: { resource: rightResource }, options: { pinned: true } }); } @@ -386,7 +387,7 @@ async function saveSelectedEditors(accessor: ServicesAccessor, options?: ISaveEd // See also https://github.com/microsoft/vscode/issues/106330 if ( activeGroup.activeEditor instanceof SideBySideEditorInput && - !options?.saveAs && !(activeGroup.activeEditor.primary.isUntitled() || activeGroup.activeEditor.secondary.isUntitled()) + !options?.saveAs && !(activeGroup.activeEditor.primary.hasCapability(EditorInputCapabilities.Untitled) || activeGroup.activeEditor.secondary.hasCapability(EditorInputCapabilities.Untitled)) ) { editors.push({ groupId: activeGroup.id, editor: activeGroup.activeEditor.primary }); editors.push({ groupId: activeGroup.id, editor: activeGroup.activeEditor.secondary }); @@ -550,7 +551,7 @@ CommandsRegistry.registerCommand({ } try { - await editorService.revert(editors.filter(({ editor }) => !editor.isUntitled() /* all except untitled */), { force: true }); + await editorService.revert(editors.filter(({ editor }) => !editor.hasCapability(EditorInputCapabilities.Untitled) /* all except untitled */), { force: true }); } catch (error) { notificationService.error(nls.localize('genericRevertError', "Failed to revert '{0}': {1}", editors.map(({ editor }) => editor.getName()).join(', '), toErrorMessage(error, false))); } diff --git a/src/vs/workbench/contrib/files/browser/fileImportExport.ts b/src/vs/workbench/contrib/files/browser/fileImportExport.ts new file mode 100644 index 000000000000..bf558d47c9b4 --- /dev/null +++ b/src/vs/workbench/contrib/files/browser/fileImportExport.ts @@ -0,0 +1,825 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; +import { getFileNamesMessage, IConfirmation, IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { ByteSize, FileSystemProviderCapabilities, IFileService, IFileStatWithMetadata } from 'vs/platform/files/common/files'; +import { Severity } from 'vs/platform/notification/common/notification'; +import { IProgress, IProgressService, IProgressStep, ProgressLocation } from 'vs/platform/progress/common/progress'; +import { IExplorerService } from 'vs/workbench/contrib/files/browser/files'; +import { VIEW_ID } from 'vs/workbench/contrib/files/common/files'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { Limiter, Promises, RunOnceWorker } from 'vs/base/common/async'; +import { newWriteableBufferStream, VSBuffer } from 'vs/base/common/buffer'; +import { basename, joinPath } from 'vs/base/common/resources'; +import { ResourceFileEdit } from 'vs/editor/browser/services/bulkEditService'; +import { ExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel'; +import { URI } from 'vs/base/common/uri'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { extractEditorsDropData } from 'vs/workbench/browser/dnd'; +import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; +import { isWeb } from 'vs/base/common/platform'; +import { triggerDownload, WebFileSystemAccess } from 'vs/base/browser/dom'; +import { ILogService } from 'vs/platform/log/common/log'; +import { FileAccess, Schemas } from 'vs/base/common/network'; +import { mnemonicButtonLabel } from 'vs/base/common/labels'; +import { listenStream } from 'vs/base/common/stream'; +import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; +import { once } from 'vs/base/common/functional'; +import { coalesce } from 'vs/base/common/arrays'; + +//#region Browser File Upload (drag and drop, input element) + +interface IBrowserUploadOperation { + startTime: number; + progressScheduler: RunOnceWorker; + + filesTotal: number; + filesUploaded: number; + + totalBytesUploaded: number; +} + +interface IWebkitDataTransfer { + items: IWebkitDataTransferItem[]; +} + +interface IWebkitDataTransferItem { + webkitGetAsEntry(): IWebkitDataTransferItemEntry; +} + +interface IWebkitDataTransferItemEntry { + name: string | undefined; + isFile: boolean; + isDirectory: boolean; + + file(resolve: (file: File) => void, reject: () => void): void; + createReader(): IWebkitDataTransferItemEntryReader; +} + +interface IWebkitDataTransferItemEntryReader { + readEntries(resolve: (file: IWebkitDataTransferItemEntry[]) => void, reject: () => void): void +} + +export class BrowserFileUpload { + + private static readonly MAX_PARALLEL_UPLOADS = 20; + + constructor( + @IProgressService private readonly progressService: IProgressService, + @IDialogService private readonly dialogService: IDialogService, + @IExplorerService private readonly explorerService: IExplorerService, + @IEditorService private readonly editorService: IEditorService, + @IFileService private readonly fileService: IFileService + ) { + } + + upload(target: ExplorerItem, source: DragEvent | FileList): Promise { + const cts = new CancellationTokenSource(); + + // Indicate progress globally + const uploadPromise = this.progressService.withProgress( + { + location: ProgressLocation.Window, + delay: 800, + cancellable: true, + title: localize('uploadingFiles', "Uploading") + }, + async progress => this.doUpload(target, this.toTransfer(source), progress, cts.token), + () => cts.dispose(true) + ); + + // Also indicate progress in the files view + this.progressService.withProgress({ location: VIEW_ID, delay: 500 }, () => uploadPromise); + + return uploadPromise; + } + + private toTransfer(source: DragEvent | FileList): IWebkitDataTransfer { + if (source instanceof DragEvent) { + return source.dataTransfer as unknown as IWebkitDataTransfer; + } + + const transfer: IWebkitDataTransfer = { items: [] }; + + // We want to reuse the same code for uploading from + // Drag & Drop as well as input element based upload + // so we convert into webkit data transfer when the + // input element approach is used (simplified). + for (const file of source) { + transfer.items.push({ + webkitGetAsEntry: () => { + return { + name: file.name, + isDirectory: false, + isFile: true, + createReader: () => { throw new Error('Unsupported for files'); }, + file: resolve => resolve(file) + }; + } + }); + } + + return transfer; + } + + private async doUpload(target: ExplorerItem, source: IWebkitDataTransfer, progress: IProgress, token: CancellationToken): Promise { + const items = source.items; + + // Somehow the items thing is being modified at random, maybe as a security + // measure since this is a DND operation. As such, we copy the items into + // an array we own as early as possible before using it. + const entries: IWebkitDataTransferItemEntry[] = []; + for (const item of items) { + entries.push(item.webkitGetAsEntry()); + } + + const results: { isFile: boolean, resource: URI }[] = []; + const operation: IBrowserUploadOperation = { + startTime: Date.now(), + progressScheduler: new RunOnceWorker(steps => { progress.report(steps[steps.length - 1]); }, 1000), + + filesTotal: entries.length, + filesUploaded: 0, + + totalBytesUploaded: 0 + }; + + // Upload all entries in parallel up to a + // certain maximum leveraging the `Limiter` + const uploadLimiter = new Limiter(BrowserFileUpload.MAX_PARALLEL_UPLOADS); + await Promises.settled(entries.map(entry => { + return uploadLimiter.queue(async () => { + if (token.isCancellationRequested) { + return; + } + + // Confirm overwrite as needed + if (target && entry.name && target.getChild(entry.name)) { + const { confirmed } = await this.dialogService.confirm(getFileOverwriteConfirm(entry.name)); + if (!confirmed) { + return; + } + + await this.explorerService.applyBulkEdit([new ResourceFileEdit(joinPath(target.resource, entry.name), undefined, { recursive: true, folder: target.getChild(entry.name)?.isDirectory })], { + undoLabel: localize('overwrite', "Overwrite {0}", entry.name), + progressLabel: localize('overwriting', "Overwriting {0}", entry.name), + }); + + if (token.isCancellationRequested) { + return; + } + } + + // Upload entry + const result = await this.doUploadEntry(entry, target.resource, target, progress, operation, token); + if (result) { + results.push(result); + } + }); + })); + + operation.progressScheduler.dispose(); + + // Open uploaded file in editor only if we upload just one + const firstUploadedFile = results[0]; + if (!token.isCancellationRequested && firstUploadedFile?.isFile) { + await this.editorService.openEditor({ resource: firstUploadedFile.resource, options: { pinned: true } }); + } + } + + private async doUploadEntry(entry: IWebkitDataTransferItemEntry, parentResource: URI, target: ExplorerItem | undefined, progress: IProgress, operation: IBrowserUploadOperation, token: CancellationToken): Promise<{ isFile: boolean, resource: URI } | undefined> { + if (token.isCancellationRequested || !entry.name || (!entry.isFile && !entry.isDirectory)) { + return undefined; + } + + // Report progress + let fileBytesUploaded = 0; + const reportProgress = (fileSize: number, bytesUploaded: number): void => { + fileBytesUploaded += bytesUploaded; + operation.totalBytesUploaded += bytesUploaded; + + const bytesUploadedPerSecond = operation.totalBytesUploaded / ((Date.now() - operation.startTime) / 1000); + + // Small file + let message: string; + if (fileSize < ByteSize.MB) { + if (operation.filesTotal === 1) { + message = `${entry.name}`; + } else { + message = localize('uploadProgressSmallMany', "{0} of {1} files ({2}/s)", operation.filesUploaded, operation.filesTotal, ByteSize.formatSize(bytesUploadedPerSecond)); + } + } + + // Large file + else { + message = localize('uploadProgressLarge', "{0} ({1} of {2}, {3}/s)", entry.name, ByteSize.formatSize(fileBytesUploaded), ByteSize.formatSize(fileSize), ByteSize.formatSize(bytesUploadedPerSecond)); + } + + // Report progress but limit to update only once per second + operation.progressScheduler.work({ message }); + }; + operation.filesUploaded++; + reportProgress(0, 0); + + // Handle file upload + const resource = joinPath(parentResource, entry.name); + if (entry.isFile) { + const file = await new Promise((resolve, reject) => entry.file(resolve, reject)); + + if (token.isCancellationRequested) { + return undefined; + } + + // Chrome/Edge/Firefox support stream method, but only use it for + // larger files to reduce the overhead of the streaming approach + if (typeof file.stream === 'function' && file.size > ByteSize.MB) { + await this.doUploadFileBuffered(resource, file, reportProgress, token); + } + + // Fallback to unbuffered upload for other browsers or small files + else { + await this.doUploadFileUnbuffered(resource, file, reportProgress); + } + + return { isFile: true, resource }; + } + + // Handle folder upload + else { + + // Create target folder + await this.fileService.createFolder(resource); + + if (token.isCancellationRequested) { + return undefined; + } + + // Recursive upload files in this directory + const dirReader = entry.createReader(); + const childEntries: IWebkitDataTransferItemEntry[] = []; + let done = false; + do { + const childEntriesChunk = await new Promise((resolve, reject) => dirReader.readEntries(resolve, reject)); + if (childEntriesChunk.length > 0) { + childEntries.push(...childEntriesChunk); + } else { + done = true; // an empty array is a signal that all entries have been read + } + } while (!done && !token.isCancellationRequested); + + // Update operation total based on new counts + operation.filesTotal += childEntries.length; + + // Split up files from folders to upload + const folderTarget = target && target.getChild(entry.name) || undefined; + const fileChildEntries: IWebkitDataTransferItemEntry[] = []; + const folderChildEntries: IWebkitDataTransferItemEntry[] = []; + for (const childEntry of childEntries) { + if (childEntry.isFile) { + fileChildEntries.push(childEntry); + } else if (childEntry.isDirectory) { + folderChildEntries.push(childEntry); + } + } + + // Upload files (up to `MAX_PARALLEL_UPLOADS` in parallel) + const fileUploadQueue = new Limiter(BrowserFileUpload.MAX_PARALLEL_UPLOADS); + await Promises.settled(fileChildEntries.map(fileChildEntry => { + return fileUploadQueue.queue(() => this.doUploadEntry(fileChildEntry, resource, folderTarget, progress, operation, token)); + })); + + // Upload folders (sequentially give we don't know their sizes) + for (const folderChildEntry of folderChildEntries) { + await this.doUploadEntry(folderChildEntry, resource, folderTarget, progress, operation, token); + } + + return { isFile: false, resource }; + } + } + + private async doUploadFileBuffered(resource: URI, file: File, progressReporter: (fileSize: number, bytesUploaded: number) => void, token: CancellationToken): Promise { + const writeableStream = newWriteableBufferStream({ + // Set a highWaterMark to prevent the stream + // for file upload to produce large buffers + // in-memory + highWaterMark: 10 + }); + const writeFilePromise = this.fileService.writeFile(resource, writeableStream); + + // Read the file in chunks using File.stream() web APIs + try { + const reader: ReadableStreamDefaultReader = file.stream().getReader(); + + let res = await reader.read(); + while (!res.done) { + if (token.isCancellationRequested) { + return undefined; + } + + // Write buffer into stream but make sure to wait + // in case the highWaterMark is reached + const buffer = VSBuffer.wrap(res.value); + await writeableStream.write(buffer); + + if (token.isCancellationRequested) { + return undefined; + } + + // Report progress + progressReporter(file.size, buffer.byteLength); + + res = await reader.read(); + } + writeableStream.end(undefined); + } catch (error) { + writeableStream.error(error); + writeableStream.end(); + } + + if (token.isCancellationRequested) { + return undefined; + } + + // Wait for file being written to target + await writeFilePromise; + } + + private doUploadFileUnbuffered(resource: URI, file: File, progressReporter: (fileSize: number, bytesUploaded: number) => void): Promise { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = async event => { + try { + if (event.target?.result instanceof ArrayBuffer) { + const buffer = VSBuffer.wrap(new Uint8Array(event.target.result)); + await this.fileService.writeFile(resource, buffer); + + // Report progress + progressReporter(file.size, buffer.byteLength); + } else { + throw new Error('Could not read from dropped file.'); + } + + resolve(); + } catch (error) { + reject(error); + } + }; + + // Start reading the file to trigger `onload` + reader.readAsArrayBuffer(file); + }); + } +} + +//#endregion + +//#region Native File Import (drag and drop) + +export class NativeFileImport { + + constructor( + @IFileService private readonly fileService: IFileService, + @IHostService private readonly hostService: IHostService, + @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, + @IDialogService private readonly dialogService: IDialogService, + @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService, + @IExplorerService private readonly explorerService: IExplorerService, + @IEditorService private readonly editorService: IEditorService, + @IProgressService private readonly progressService: IProgressService + ) { + } + + async import(target: ExplorerItem, source: DragEvent): Promise { + const cts = new CancellationTokenSource(); + + // Indicate progress globally + const importPromise = this.progressService.withProgress( + { + location: ProgressLocation.Window, + delay: 800, + cancellable: true, + title: localize('copyingFiles', "Copying...") + }, + async () => await this.doImport(target, source, cts.token), + () => cts.dispose(true) + ); + + // Also indicate progress in the files view + this.progressService.withProgress({ location: VIEW_ID, delay: 500 }, () => importPromise); + + return importPromise; + } + + private async doImport(target: ExplorerItem, source: DragEvent, token: CancellationToken): Promise { + + // Check for dropped external files to be folders + const files = coalesce(extractEditorsDropData(source, true).filter(editor => URI.isUri(editor.resource) && this.fileService.canHandleResource(editor.resource)).map(editor => editor.resource)); + const resolvedFiles = await this.fileService.resolveAll(files.map(file => ({ resource: file }))); + + if (token.isCancellationRequested) { + return; + } + + // Pass focus to window + this.hostService.focus(); + + // Handle folders by adding to workspace if we are in workspace context and if dropped on top + const folders = resolvedFiles.filter(resolvedFile => resolvedFile.success && resolvedFile.stat?.isDirectory).map(resolvedFile => ({ uri: resolvedFile.stat!.resource })); + if (folders.length > 0 && target.isRoot) { + const buttons = [ + folders.length > 1 ? + localize('copyFolders', "&&Copy Folders") : + localize('copyFolder', "&&Copy Folder"), + localize('cancel', "Cancel") + ]; + + let message: string; + + // We only allow to add a folder to the workspace if there is already a workspace folder with that scheme + const workspaceFolderSchemas = this.contextService.getWorkspace().folders.map(folder => folder.uri.scheme); + if (folders.some(folder => workspaceFolderSchemas.indexOf(folder.uri.scheme) >= 0)) { + buttons.unshift(folders.length > 1 ? localize('addFolders', "&&Add Folders to Workspace") : localize('addFolder', "&&Add Folder to Workspace")); + message = folders.length > 1 ? + localize('dropFolders', "Do you want to copy the folders or add the folders to the workspace?") : + localize('dropFolder', "Do you want to copy '{0}' or add '{0}' as a folder to the workspace?", basename(folders[0].uri)); + } else { + message = folders.length > 1 ? + localize('copyfolders', "Are you sure to want to copy folders?") : + localize('copyfolder', "Are you sure to want to copy '{0}'?", basename(folders[0].uri)); + } + + const { choice } = await this.dialogService.show(Severity.Info, message, buttons); + + // Add folders + if (choice === buttons.length - 3) { + return this.workspaceEditingService.addFolders(folders); + } + + // Copy resources + if (choice === buttons.length - 2) { + return this.importResources(target, files, token); + } + } + + // Handle dropped files (only support FileStat as target) + else if (target instanceof ExplorerItem) { + return this.importResources(target, files, token); + } + } + + private async importResources(target: ExplorerItem, resources: URI[], token: CancellationToken): Promise { + if (resources && resources.length > 0) { + + // Resolve target to check for name collisions and ask user + const targetStat = await this.fileService.resolve(target.resource); + + if (token.isCancellationRequested) { + return; + } + + // Check for name collisions + const targetNames = new Set(); + const caseSensitive = this.fileService.hasCapability(target.resource, FileSystemProviderCapabilities.PathCaseSensitive); + if (targetStat.children) { + targetStat.children.forEach(child => { + targetNames.add(caseSensitive ? child.name : child.name.toLowerCase()); + }); + } + + const resourcesFiltered = coalesce((await Promises.settled(resources.map(async resource => { + if (targetNames.has(caseSensitive ? basename(resource) : basename(resource).toLowerCase())) { + const confirmationResult = await this.dialogService.confirm(getFileOverwriteConfirm(basename(resource))); + if (!confirmationResult.confirmed) { + return undefined; + } + } + + return resource; + })))); + + // Copy resources through bulk edit API + const resourceFileEdits = resourcesFiltered.map(resource => { + const sourceFileName = basename(resource); + const targetFile = joinPath(target.resource, sourceFileName); + + return new ResourceFileEdit(resource, targetFile, { overwrite: true, copy: true }); + }); + + await this.explorerService.applyBulkEdit(resourceFileEdits, { + undoLabel: resourcesFiltered.length === 1 ? + localize('copyFile', "Copy {0}", basename(resourcesFiltered[0])) : + localize('copynFile', "Copy {0} resources", resourcesFiltered.length), + progressLabel: resourcesFiltered.length === 1 ? + localize('copyingFile', "Copying {0}", basename(resourcesFiltered[0])) : + localize('copyingnFile', "Copying {0} resources", resourcesFiltered.length), + progressLocation: ProgressLocation.Window + }); + + // if we only add one file, just open it directly + if (resourceFileEdits.length === 1) { + const item = this.explorerService.findClosest(resourceFileEdits[0].newResource!); + if (item && !item.isDirectory) { + this.editorService.openEditor({ resource: item.resource, options: { pinned: true } }); + } + } + } + } +} + +//#endregion + +//#region Download (web, native) + +interface IDownloadOperation { + startTime: number; + progressScheduler: RunOnceWorker; + + filesTotal: number; + filesDownloaded: number; + + totalBytesDownloaded: number; + fileBytesDownloaded: number; +} + +export class FileDownload { + + constructor( + @IFileService private readonly fileService: IFileService, + @IExplorerService private readonly explorerService: IExplorerService, + @IProgressService private readonly progressService: IProgressService, + @ILogService private readonly logService: ILogService, + @IFileDialogService private readonly fileDialogService: IFileDialogService + ) { + } + + download(source: ExplorerItem[]): Promise { + const cts = new CancellationTokenSource(); + + // Indicate progress globally + const downloadPromise = this.progressService.withProgress( + { + location: ProgressLocation.Window, + delay: 800, + cancellable: isWeb, + title: localize('downloadingFiles', "Downloading") + }, + async progress => this.doDownload(source, progress, cts), + () => cts.dispose(true) + ); + + // Also indicate progress in the files view + this.progressService.withProgress({ location: VIEW_ID, delay: 500 }, () => downloadPromise); + + return downloadPromise; + } + + private async doDownload(sources: ExplorerItem[], progress: IProgress, cts: CancellationTokenSource): Promise { + for (const source of sources) { + if (cts.token.isCancellationRequested) { + return; + } + + // Web: use DOM APIs to download files with optional support + // for folders and large files + if (isWeb) { + await this.doDownloadBrowser(source.resource, progress, cts); + } + + // Native: use working copy file service to get at the contents + else { + await this.doDownloadNative(source, progress, cts); + } + } + } + + private async doDownloadBrowser(resource: URI, progress: IProgress, cts: CancellationTokenSource): Promise { + const stat = await this.fileService.resolve(resource, { resolveMetadata: true }); + + if (cts.token.isCancellationRequested) { + return; + } + + const maxBlobDownloadSize = 32 * ByteSize.MB; // avoid to download via blob-trick >32MB to avoid memory pressure + const preferFileSystemAccessWebApis = stat.isDirectory || stat.size > maxBlobDownloadSize; + + // Folder: use FS APIs to download files and folders if available and preferred + if (preferFileSystemAccessWebApis && WebFileSystemAccess.supported(window)) { + try { + const parentFolder: FileSystemDirectoryHandle = await window.showDirectoryPicker(); + const operation: IDownloadOperation = { + startTime: Date.now(), + progressScheduler: new RunOnceWorker(steps => { progress.report(steps[steps.length - 1]); }, 1000), + + filesTotal: stat.isDirectory ? 0 : 1, // folders increment filesTotal within downloadFolder method + filesDownloaded: 0, + + totalBytesDownloaded: 0, + fileBytesDownloaded: 0 + }; + + if (stat.isDirectory) { + const targetFolder = await parentFolder.getDirectoryHandle(stat.name, { create: true }); + await this.downloadFolderBrowser(stat, targetFolder, operation, cts.token); + } else { + await this.downloadFileBrowser(parentFolder, stat, operation, cts.token); + } + + operation.progressScheduler.dispose(); + } catch (error) { + this.logService.warn(error); + cts.cancel(); // `showDirectoryPicker` will throw an error when the user cancels + } + } + + // File: use traditional download to circumvent browser limitations + else if (stat.isFile) { + let bufferOrUri: Uint8Array | URI; + try { + bufferOrUri = (await this.fileService.readFile(stat.resource, { limits: { size: maxBlobDownloadSize } })).value.buffer; + } catch (error) { + bufferOrUri = FileAccess.asBrowserUri(stat.resource); + } + + if (!cts.token.isCancellationRequested) { + triggerDownload(bufferOrUri, stat.name); + } + } + } + + private async downloadFileBufferedBrowser(resource: URI, target: FileSystemWritableFileStream, operation: IDownloadOperation, token: CancellationToken): Promise { + const contents = await this.fileService.readFileStream(resource); + if (token.isCancellationRequested) { + target.close(); + return; + } + + return new Promise((resolve, reject) => { + const sourceStream = contents.value; + + const disposables = new DisposableStore(); + disposables.add(toDisposable(() => target.close())); + + let disposed = false; + disposables.add(toDisposable(() => disposed = true)); + + disposables.add(once(token.onCancellationRequested)(() => { + disposables.dispose(); + reject(); + })); + + listenStream(sourceStream, { + onData: data => { + if (!disposed) { + target.write(data.buffer); + this.reportProgress(contents.name, contents.size, data.byteLength, operation); + } + }, + onError: error => { + disposables.dispose(); + reject(error); + }, + onEnd: () => { + disposables.dispose(); + resolve(); + } + }); + }); + } + + private async downloadFileUnbufferedBrowser(resource: URI, target: FileSystemWritableFileStream, operation: IDownloadOperation, token: CancellationToken): Promise { + const contents = await this.fileService.readFile(resource); + if (!token.isCancellationRequested) { + target.write(contents.value.buffer); + this.reportProgress(contents.name, contents.size, contents.value.byteLength, operation); + } + + target.close(); + } + + private async downloadFileBrowser(targetFolder: FileSystemDirectoryHandle, file: IFileStatWithMetadata, operation: IDownloadOperation, token: CancellationToken): Promise { + + // Report progress + operation.filesDownloaded++; + operation.fileBytesDownloaded = 0; // reset for this file + this.reportProgress(file.name, 0, 0, operation); + + // Start to download + const targetFile = await targetFolder.getFileHandle(file.name, { create: true }); + const targetFileWriter = await targetFile.createWritable(); + + // For large files, write buffered using streams + if (file.size > ByteSize.MB) { + return this.downloadFileBufferedBrowser(file.resource, targetFileWriter, operation, token); + } + + // For small files prefer to write unbuffered to reduce overhead + return this.downloadFileUnbufferedBrowser(file.resource, targetFileWriter, operation, token); + } + + private async downloadFolderBrowser(folder: IFileStatWithMetadata, targetFolder: FileSystemDirectoryHandle, operation: IDownloadOperation, token: CancellationToken): Promise { + if (folder.children) { + operation.filesTotal += (folder.children.map(child => child.isFile)).length; + + for (const child of folder.children) { + if (token.isCancellationRequested) { + return; + } + + if (child.isFile) { + await this.downloadFileBrowser(targetFolder, child, operation, token); + } else { + const childFolder = await targetFolder.getDirectoryHandle(child.name, { create: true }); + const resolvedChildFolder = await this.fileService.resolve(child.resource, { resolveMetadata: true }); + + await this.downloadFolderBrowser(resolvedChildFolder, childFolder, operation, token); + } + } + } + } + + private reportProgress(name: string, fileSize: number, bytesDownloaded: number, operation: IDownloadOperation): void { + operation.fileBytesDownloaded += bytesDownloaded; + operation.totalBytesDownloaded += bytesDownloaded; + + const bytesDownloadedPerSecond = operation.totalBytesDownloaded / ((Date.now() - operation.startTime) / 1000); + + // Small file + let message: string; + if (fileSize < ByteSize.MB) { + if (operation.filesTotal === 1) { + message = name; + } else { + message = localize('downloadProgressSmallMany', "{0} of {1} files ({2}/s)", operation.filesDownloaded, operation.filesTotal, ByteSize.formatSize(bytesDownloadedPerSecond)); + } + } + + // Large file + else { + message = localize('downloadProgressLarge', "{0} ({1} of {2}, {3}/s)", name, ByteSize.formatSize(operation.fileBytesDownloaded), ByteSize.formatSize(fileSize), ByteSize.formatSize(bytesDownloadedPerSecond)); + } + + // Report progress but limit to update only once per second + operation.progressScheduler.work({ message }); + } + + private async doDownloadNative(explorerItem: ExplorerItem, progress: IProgress, cts: CancellationTokenSource): Promise { + progress.report({ message: explorerItem.name }); + + const defaultUri = joinPath( + explorerItem.isDirectory ? + await this.fileDialogService.defaultFolderPath(Schemas.file) : + await this.fileDialogService.defaultFilePath(Schemas.file), + explorerItem.name + ); + + const destination = await this.fileDialogService.showSaveDialog({ + availableFileSystems: [Schemas.file], + saveLabel: mnemonicButtonLabel(localize('downloadButton', "Download")), + title: localize('chooseWhereToDownload', "Choose Where to Download"), + defaultUri + }); + + if (destination) { + await this.explorerService.applyBulkEdit([new ResourceFileEdit(explorerItem.resource, destination, { overwrite: true, copy: true })], { + undoLabel: localize('downloadBulkEdit', "Download {0}", explorerItem.name), + progressLabel: localize('downloadingBulkEdit', "Downloading {0}", explorerItem.name), + progressLocation: ProgressLocation.Window + }); + } else { + cts.cancel(); // User canceled a download. In case there were multiple files selected we should cancel the remainder of the prompts #86100 + } + } +} + +//#endregion + +//#region Helpers + +export function getFileOverwriteConfirm(name: string): IConfirmation { + return { + message: localize('confirmOverwrite', "A file or folder with the name '{0}' already exists in the destination folder. Do you want to replace it?", name), + detail: localize('irreversible', "This action is irreversible!"), + primaryButton: localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), + type: 'warning' + }; +} + +export function getMultipleFilesOverwriteConfirm(files: URI[]): IConfirmation { + if (files.length > 1) { + return { + message: localize('confirmManyOverwrites', "The following {0} files and/or folders already exist in the destination folder. Do you want to replace them?", files.length), + detail: getFileNamesMessage(files) + '\n' + localize('irreversible', "This action is irreversible!"), + primaryButton: localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), + type: 'warning' + }; + } + + return getFileOverwriteConfirm(basename(files[0])); +} + +//#endregion diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts similarity index 87% rename from lib/vscode/src/vs/workbench/contrib/files/browser/files.contribution.ts rename to src/vs/workbench/contrib/files/browser/files.contribution.ts index 196ff12fa9e1..b9ff354280e3 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -8,16 +8,16 @@ import { sep } from 'vs/base/common/path'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { EditorInput, IFileEditorInput, IEditorInputFactoryRegistry, EditorExtensions } from 'vs/workbench/common/editor'; +import { IFileEditorInput, IEditorInputFactoryRegistry, EditorExtensions } from 'vs/workbench/common/editor'; import { AutoSaveConfiguration, HotExitConfiguration, FILES_EXCLUDE_CONFIG, FILES_ASSOCIATIONS_CONFIG } from 'vs/platform/files/common/files'; -import { SortOrder, FILE_EDITOR_INPUT_ID } from 'vs/workbench/contrib/files/common/files'; +import { SortOrder, LexicographicOptions, FILE_EDITOR_INPUT_ID } from 'vs/workbench/contrib/files/common/files'; import { TextFileEditorTracker } from 'vs/workbench/contrib/files/browser/editors/textFileEditorTracker'; import { TextFileSaveErrorHandler } from 'vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler'; -import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; +import { FileEditorInput } from 'vs/workbench/contrib/files/browser/editors/fileEditorInput'; import { BinaryFileEditor } from 'vs/workbench/contrib/files/browser/editors/binaryFileEditor'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import * as platform from 'vs/base/common/platform'; +import { isNative, isWeb, isWindows } from 'vs/base/common/platform'; import { ExplorerViewletViewsContribution } from 'vs/workbench/contrib/files/browser/explorerViewlet'; import { IEditorRegistry, EditorDescriptor } from 'vs/workbench/browser/editor'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; @@ -31,7 +31,8 @@ import { editorConfigurationBaseNode } from 'vs/editor/common/config/commonEdito import { DirtyFilesIndicator } from 'vs/workbench/contrib/files/common/dirtyFilesIndicator'; import { UndoCommand, RedoCommand } from 'vs/editor/browser/editorExtensions'; import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; -import { FileEditorInputSerializer, IExplorerService } from 'vs/workbench/contrib/files/browser/files'; +import { IExplorerService } from 'vs/workbench/contrib/files/browser/files'; +import { FileEditorInputSerializer, FileEditorWorkingCopyEditorHandler } from 'vs/workbench/contrib/files/browser/editors/fileEditorHandler'; class FileUriLabelContribution implements IWorkbenchContribution { @@ -41,8 +42,8 @@ class FileUriLabelContribution implements IWorkbenchContribution { formatting: { label: '${authority}${path}', separator: sep, - tildify: !platform.isWindows, - normalizeDriveLetter: platform.isWindows, + tildify: !isWindows, + normalizeDriveLetter: isWindows, authorityPrefix: sep + sep, workspaceSuffix: '' } @@ -60,7 +61,7 @@ Registry.as(EditorExtensions.Editors).registerEditor( nls.localize('binaryFileEditor', "Binary File Editor") ), [ - new SyncDescriptor(FileEditorInput) + new SyncDescriptor(FileEditorInput) ] ); @@ -69,8 +70,8 @@ Registry.as(EditorExtensions.EditorInputFactories). typeId: FILE_EDITOR_INPUT_ID, - createFileEditorInput: (resource, preferredResource, preferredName, preferredDescription, preferredEncoding, preferredMode, instantiationService): IFileEditorInput => { - return instantiationService.createInstance(FileEditorInput, resource, preferredResource, preferredName, preferredDescription, preferredEncoding, preferredMode); + createFileEditorInput: (resource, preferredResource, preferredName, preferredDescription, preferredEncoding, preferredMode, preferredContents, instantiationService): IFileEditorInput => { + return instantiationService.createInstance(FileEditorInput, resource, preferredResource, preferredName, preferredDescription, preferredEncoding, preferredMode, preferredContents); }, isFileEditorInput: (obj): obj is IFileEditorInput => { @@ -78,8 +79,9 @@ Registry.as(EditorExtensions.EditorInputFactories). } }); -// Register Editor Input Serializer +// Register Editor Input Serializer & Handler Registry.as(EditorExtensions.EditorInputFactories).registerEditorInputSerializer(FILE_EDITOR_INPUT_ID, FileEditorInputSerializer); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(FileEditorWorkingCopyEditorHandler, LifecyclePhase.Ready); // Register Explorer views Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ExplorerViewletViewsContribution, LifecyclePhase.Starting); @@ -102,7 +104,7 @@ Registry.as(WorkbenchExtensions.Workbench).regi // Configuration const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); -const hotExitConfiguration: IConfigurationPropertySchema = platform.isNative ? +const hotExitConfiguration: IConfigurationPropertySchema = isNative ? { 'type': 'string', 'scope': ConfigurationScope.APPLICATION, @@ -227,7 +229,7 @@ configurationRegistry.registerConfiguration({ nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'files.autoSave.onFocusChange' }, "A dirty editor is automatically saved when the editor loses focus."), nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'files.autoSave.onWindowChange' }, "A dirty editor is automatically saved when the window loses focus.") ], - 'default': platform.isWeb ? AutoSaveConfiguration.AFTER_DELAY : AutoSaveConfiguration.OFF, + 'default': isWeb ? AutoSaveConfiguration.AFTER_DELAY : AutoSaveConfiguration.OFF, 'markdownDescription': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'autoSave' }, "Controls auto save of dirty editors. Read more about autosave [here](https://code.visualstudio.com/docs/editor/codebasics#_save-auto-save).", AutoSaveConfiguration.OFF, AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE, AutoSaveConfiguration.ON_WINDOW_CHANGE, AutoSaveConfiguration.AFTER_DELAY) }, 'files.autoSaveDelay': { @@ -237,7 +239,7 @@ configurationRegistry.registerConfiguration({ }, 'files.watcherExclude': { 'type': 'object', - 'default': platform.isWindows /* https://github.com/microsoft/vscode/issues/23954 */ ? { '**/.git/objects/**': true, '**/.git/subtree-cache/**': true, '**/node_modules/*/**': true, '**/.hg/store/**': true } : { '**/.git/objects/**': true, '**/.git/subtree-cache/**': true, '**/node_modules/**': true, '**/.hg/store/**': true }, + 'default': isWindows /* https://github.com/microsoft/vscode/issues/23954 */ ? { '**/.git/objects/**': true, '**/.git/subtree-cache/**': true, '**/node_modules/*/**': true, '**/.hg/store/**': true } : { '**/.git/objects/**': true, '**/.git/subtree-cache/**': true, '**/node_modules/**': true, '**/.hg/store/**': true }, 'description': nls.localize('watcherExclude', "Configure glob patterns of file paths to exclude from file watching. Patterns must match on absolute paths (i.e. prefix with ** or the full path to match properly). Changing this setting requires a restart. When you experience Code consuming lots of CPU time on startup, you can exclude large folders to reduce the initial load."), 'scope': ConfigurationScope.RESOURCE }, @@ -250,7 +252,7 @@ configurationRegistry.registerConfiguration({ 'type': 'number', 'default': 4096, 'markdownDescription': nls.localize('maxMemoryForLargeFilesMB', "Controls the memory available to VS Code after restart when trying to open large files. Same effect as specifying `--max-memory=NEWSIZE` on the command line."), - included: platform.isNative + included: isNative }, 'files.restoreUndoStack': { 'type': 'boolean', @@ -356,13 +358,25 @@ configurationRegistry.registerConfiguration({ 'enum': [SortOrder.Default, SortOrder.Mixed, SortOrder.FilesFirst, SortOrder.Type, SortOrder.Modified], 'default': SortOrder.Default, 'enumDescriptions': [ - nls.localize('sortOrder.default', 'Files and folders are sorted by their names, in alphabetical order. Folders are displayed before files.'), - nls.localize('sortOrder.mixed', 'Files and folders are sorted by their names, in alphabetical order. Files are interwoven with folders.'), - nls.localize('sortOrder.filesFirst', 'Files and folders are sorted by their names, in alphabetical order. Files are displayed before folders.'), - nls.localize('sortOrder.type', 'Files and folders are sorted by their extensions, in alphabetical order. Folders are displayed before files.'), - nls.localize('sortOrder.modified', 'Files and folders are sorted by last modified date, in descending order. Folders are displayed before files.') + nls.localize('sortOrder.default', 'Files and folders are sorted by their names. Folders are displayed before files.'), + nls.localize('sortOrder.mixed', 'Files and folders are sorted by their names. Files are interwoven with folders.'), + nls.localize('sortOrder.filesFirst', 'Files and folders are sorted by their names. Files are displayed before folders.'), + nls.localize('sortOrder.type', 'Files and folders are grouped by extension type then sorted by their names. Folders are displayed before files.'), + nls.localize('sortOrder.modified', 'Files and folders are sorted by last modified date in descending order. Folders are displayed before files.') ], - 'description': nls.localize('sortOrder', "Controls sorting order of files and folders in the explorer.") + 'description': nls.localize('sortOrder', "Controls the property-based sorting of files and folders in the explorer.") + }, + 'explorer.sortOrderLexicographicOptions': { + 'type': 'string', + 'enum': [LexicographicOptions.Default, LexicographicOptions.Upper, LexicographicOptions.Lower, LexicographicOptions.Unicode], + 'default': LexicographicOptions.Default, + 'enumDescriptions': [ + nls.localize('sortOrderLexicographicOptions.default', 'Uppercase and lowercase names are mixed together.'), + nls.localize('sortOrderLexicographicOptions.upper', 'Uppercase names are grouped together before lowercase names.'), + nls.localize('sortOrderLexicographicOptions.lower', 'Lowercase names are grouped together before uppercase names.'), + nls.localize('sortOrderLexicographicOptions.unicode', 'Names are sorted in unicode order.') + ], + 'description': nls.localize('sortOrderLexicographicOptions', "Controls the lexicographic sorting of file and folder names in the explorer.") }, 'explorer.decorations.colors': { type: 'boolean', diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/files.ts b/src/vs/workbench/contrib/files/browser/files.ts similarity index 71% rename from lib/vscode/src/vs/workbench/contrib/files/browser/files.ts rename to src/vs/workbench/contrib/files/browser/files.ts index 0cf9348d3d2b..ad2dd9354d51 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/browser/files.ts +++ b/src/vs/workbench/contrib/files/browser/files.ts @@ -3,10 +3,10 @@ * 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 { IListService } from 'vs/platform/list/browser/listService'; -import { OpenEditor, SortOrder } from 'vs/workbench/contrib/files/common/files'; -import { EditorResourceAccessor, SideBySideEditor, IEditorIdentifier, EditorInput, IEditorInputSerializer } from 'vs/workbench/common/editor'; +import { OpenEditor, ISortOrderConfiguration } from 'vs/workbench/contrib/files/common/files'; +import { EditorResourceAccessor, SideBySideEditor, IEditorIdentifier } from 'vs/workbench/common/editor'; import { List } from 'vs/base/browser/ui/list/listWidget'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel'; @@ -14,67 +14,14 @@ import { coalesce } from 'vs/base/common/arrays'; import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditableData } from 'vs/workbench/common/views'; -import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ResourceFileEdit } from 'vs/editor/browser/services/bulkEditService'; import { ProgressLocation } from 'vs/platform/progress/common/progress'; -import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; -import { isEqual } from 'vs/base/common/resources'; - -interface ISerializedFileEditorInput { - resourceJSON: UriComponents; - preferredResourceJSON?: UriComponents; - name?: string; - description?: string; - encoding?: string; - modeId?: string; -} - -export class FileEditorInputSerializer implements IEditorInputSerializer { - - canSerialize(editorInput: EditorInput): boolean { - return true; - } - - serialize(editorInput: EditorInput): string { - const fileEditorInput = editorInput as FileEditorInput; - const resource = fileEditorInput.resource; - const preferredResource = fileEditorInput.preferredResource; - const serializedFileEditorInput: ISerializedFileEditorInput = { - resourceJSON: resource.toJSON(), - preferredResourceJSON: isEqual(resource, preferredResource) ? undefined : preferredResource, // only storing preferredResource if it differs from the resource - name: fileEditorInput.getPreferredName(), - description: fileEditorInput.getPreferredDescription(), - encoding: fileEditorInput.getEncoding(), - modeId: fileEditorInput.getPreferredMode() // only using the preferred user associated mode here if available to not store redundant data - }; - - return JSON.stringify(serializedFileEditorInput); - } - - deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): FileEditorInput { - return instantiationService.invokeFunction(accessor => { - const serializedFileEditorInput: ISerializedFileEditorInput = JSON.parse(serializedEditorInput); - const resource = URI.revive(serializedFileEditorInput.resourceJSON); - const preferredResource = URI.revive(serializedFileEditorInput.preferredResourceJSON); - const name = serializedFileEditorInput.name; - const description = serializedFileEditorInput.description; - const encoding = serializedFileEditorInput.encoding; - const mode = serializedFileEditorInput.modeId; - - const fileEditorInput = accessor.get(IEditorService).createEditorInput({ resource, label: name, description, encoding, mode, forceFile: true }) as FileEditorInput; - if (preferredResource) { - fileEditorInput.setPreferredResource(preferredResource); - } - - return fileEditorInput; - }); - } -} export interface IExplorerService { readonly _serviceBrand: undefined; readonly roots: ExplorerItem[]; - readonly sortOrder: SortOrder; + readonly sortOrderConfiguration: ISortOrderConfiguration; getContext(respectMultiSelection: boolean): ExplorerItem[]; hasViewFocus(): boolean; diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/files.web.contribution.ts b/src/vs/workbench/contrib/files/browser/files.web.contribution.ts similarity index 73% rename from lib/vscode/src/vs/workbench/contrib/files/browser/files.web.contribution.ts rename to src/vs/workbench/contrib/files/browser/files.web.contribution.ts index 729150402ca3..b91ef6e6e063 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/browser/files.web.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.web.contribution.ts @@ -3,10 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; +import { localize } from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; -import { EditorExtensions, EditorInput } from 'vs/workbench/common/editor'; -import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; +import { EditorExtensions } from 'vs/workbench/common/editor'; +import { FileEditorInput } from 'vs/workbench/contrib/files/browser/editors/fileEditorInput'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IEditorRegistry, EditorDescriptor } from 'vs/workbench/browser/editor'; import { TextFileEditor } from 'vs/workbench/contrib/files/browser/editors/textFileEditor'; @@ -16,9 +16,9 @@ Registry.as(EditorExtensions.Editors).registerEditor( EditorDescriptor.create( TextFileEditor, TextFileEditor.ID, - nls.localize('textFileEditor', "Text File Editor") + localize('textFileEditor', "Text File Editor") ), [ - new SyncDescriptor(FileEditorInput) + new SyncDescriptor(FileEditorInput) ] ); diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css b/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css rename to src/vs/workbench/contrib/files/browser/media/explorerviewlet.css diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/views/emptyView.ts b/src/vs/workbench/contrib/files/browser/views/emptyView.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/files/browser/views/emptyView.ts rename to src/vs/workbench/contrib/files/browser/views/emptyView.ts diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/views/explorerDecorationsProvider.ts b/src/vs/workbench/contrib/files/browser/views/explorerDecorationsProvider.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/files/browser/views/explorerDecorationsProvider.ts rename to src/vs/workbench/contrib/files/browser/views/explorerDecorationsProvider.ts diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/files/browser/views/explorerView.ts rename to src/vs/workbench/contrib/files/browser/views/explorerView.ts index a519921ad8e0..91d8c0d79328 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -8,7 +8,7 @@ import { URI } from 'vs/base/common/uri'; import * as perf from 'vs/base/common/performance'; import { IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; import { memoize } from 'vs/base/common/decorators'; -import { IFilesConfiguration, ExplorerFolderContext, FilesExplorerFocusedContext, ExplorerFocusedContext, ExplorerRootContext, ExplorerResourceReadonlyContext, ExplorerResourceCut, ExplorerResourceMoveableToTrash, ExplorerCompressedFocusContext, ExplorerCompressedFirstFocusContext, ExplorerCompressedLastFocusContext, ExplorerResourceAvailableEditorIdsContext, VIEW_ID, VIEWLET_ID } from 'vs/workbench/contrib/files/common/files'; +import { IFilesConfiguration, ExplorerFolderContext, FilesExplorerFocusedContext, ExplorerFocusedContext, ExplorerRootContext, ExplorerResourceReadonlyContext, ExplorerResourceCut, ExplorerResourceMoveableToTrash, ExplorerCompressedFocusContext, ExplorerCompressedFirstFocusContext, ExplorerCompressedLastFocusContext, ExplorerResourceAvailableEditorIdsContext, VIEW_ID, VIEWLET_ID, ExplorerResourceNotReadonlyContext } from 'vs/workbench/contrib/files/common/files'; import { FileCopiedContext, NEW_FILE_COMMAND_ID, NEW_FOLDER_COMMAND_ID } from 'vs/workbench/contrib/files/browser/fileActions'; import * as DOM from 'vs/base/browser/dom'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; @@ -55,6 +55,7 @@ import { IExplorerService } from 'vs/workbench/contrib/files/browser/files'; import { Codicon } from 'vs/base/common/codicons'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; +import { IEditorOverrideService } from 'vs/workbench/services/editor/common/editorOverrideService'; interface IExplorerViewColors extends IColorMapping { listDropBackground?: ColorValue | undefined; @@ -169,6 +170,7 @@ export class ExplorerView extends ViewPane { @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IProgressService private readonly progressService: IProgressService, @IEditorService private readonly editorService: IEditorService, + @IEditorOverrideService private readonly editorOverrideService: IEditorOverrideService, @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, @IKeybindingService keybindingService: IKeybindingService, @IContextKeyService contextKeyService: IContextKeyService, @@ -493,8 +495,8 @@ export class ExplorerView extends ViewPane { this.rootContext.set(!stat || (stat && stat.isRoot)); if (resource) { - const overrides = resource ? this.editorService.getEditorOverrides(resource, undefined, undefined) : []; - this.availableEditorIdsContext.set(overrides.map(([, entry]) => entry.id).join(',')); + const overrides = resource ? this.editorOverrideService.getEditorIds(resource) : []; + this.availableEditorIdsContext.set(overrides.join(',')); } else { this.availableEditorIdsContext.reset(); } @@ -863,6 +865,7 @@ registerAction2(class extends Action2 { title: nls.localize('createNewFile', "New File"), f1: false, icon: Codicon.newFile, + precondition: ExplorerResourceNotReadonlyContext, menu: { id: MenuId.ViewTitle, group: 'navigation', @@ -885,6 +888,7 @@ registerAction2(class extends Action2 { title: nls.localize('createNewFolder', "New Folder"), f1: false, icon: Codicon.newFolder, + precondition: ExplorerResourceNotReadonlyContext, menu: { id: MenuId.ViewTitle, group: 'navigation', diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts similarity index 70% rename from lib/vscode/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts rename to src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index 5ef31be6d7d1..aa024f8993a4 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -7,9 +7,9 @@ import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; import * as DOM from 'vs/base/browser/dom'; import * as glob from 'vs/base/common/glob'; import { IListVirtualDelegate, ListDragOverEffect } from 'vs/base/browser/ui/list/list'; -import { IProgressService, ProgressLocation, IProgressStep, IProgress } from 'vs/platform/progress/common/progress'; +import { IProgressService, ProgressLocation, } from 'vs/platform/progress/common/progress'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; -import { IFileService, FileKind, FileOperationError, FileOperationResult, FileSystemProviderCapabilities, ByteSize } from 'vs/platform/files/common/files'; +import { IFileService, FileKind, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IDisposable, Disposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; @@ -19,8 +19,8 @@ import { ITreeNode, ITreeFilter, TreeVisibility, IAsyncDataSource, ITreeSorter, import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IFilesConfiguration, VIEW_ID } from 'vs/workbench/contrib/files/common/files'; -import { dirname, joinPath, basename, distinctParents } from 'vs/base/common/resources'; +import { IFilesConfiguration } from 'vs/workbench/contrib/files/common/files'; +import { dirname, joinPath, distinctParents } from 'vs/base/common/resources'; import { InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; import { localize } from 'vs/nls'; import { attachInputBoxStyler } from 'vs/platform/theme/common/styler'; @@ -29,18 +29,16 @@ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { equals, deepClone } from 'vs/base/common/objects'; import * as path from 'vs/base/common/path'; import { ExplorerItem, NewExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel'; -import { compareFileNamesDefault, compareFileExtensionsDefault } from 'vs/base/common/comparers'; -import { fillResourceDataTransfers, CodeDataTransfers, extractResources, containsDragType } from 'vs/workbench/browser/dnd'; +import { compareFileExtensionsDefault, compareFileNamesDefault, compareFileNamesUpper, compareFileExtensionsUpper, compareFileNamesLower, compareFileExtensionsLower, compareFileNamesUnicode, compareFileExtensionsUnicode } from 'vs/base/common/comparers'; +import { fillEditorsDragData, CodeDataTransfers, containsDragType } from 'vs/workbench/browser/dnd'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IDragAndDropData, DataTransfers } from 'vs/base/browser/dnd'; import { Schemas } from 'vs/base/common/network'; import { NativeDragAndDropData, ExternalElementsDragAndDropData, ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView'; import { isMacintosh, isWeb } from 'vs/base/common/platform'; -import { IDialogService, IConfirmation, getFileNamesMessage } from 'vs/platform/dialogs/common/dialogs'; -import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IDialogService, getFileNamesMessage } from 'vs/platform/dialogs/common/dialogs'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; import { URI } from 'vs/base/common/uri'; -import { RunOnceWorker } from 'vs/base/common/async'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; import { findValidPasteFileTarget } from 'vs/workbench/contrib/files/browser/fileActions'; @@ -49,16 +47,16 @@ import { Emitter, Event, EventMultiplexer } from 'vs/base/common/event'; import { ITreeCompressionDelegate } from 'vs/base/browser/ui/tree/asyncDataTree'; import { ICompressibleTreeRenderer } from 'vs/base/browser/ui/tree/objectTree'; import { ICompressedTreeNode } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; -import { VSBuffer, newWriteableBufferStream } from 'vs/base/common/buffer'; import { ILabelService } from 'vs/platform/label/common/label'; import { isNumber } from 'vs/base/common/types'; import { domEvent } from 'vs/base/browser/event'; import { IEditableData } from 'vs/workbench/common/views'; import { IEditorInput } from 'vs/workbench/common/editor'; -import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; import { ResourceFileEdit } from 'vs/editor/browser/services/bulkEditService'; import { IExplorerService } from 'vs/workbench/contrib/files/browser/files'; +import { BrowserFileUpload, NativeFileImport, getMultipleFilesOverwriteConfirm } from 'vs/workbench/contrib/files/browser/fileImportExport'; +import { toErrorMessage } from 'vs/base/common/errorMessage'; export class ExplorerDelegate implements IListVirtualDelegate { @@ -94,7 +92,7 @@ export class ExplorerDataSource implements IAsyncDataSource { if (element instanceof ExplorerItem && element.isRoot) { @@ -669,7 +667,29 @@ export class FileSorter implements ITreeSorter { return 1; } - const sortOrder = this.explorerService.sortOrder; + const sortOrder = this.explorerService.sortOrderConfiguration.sortOrder; + const lexicographicOptions = this.explorerService.sortOrderConfiguration.lexicographicOptions; + + let compareFileNames; + let compareFileExtensions; + switch (lexicographicOptions) { + case 'upper': + compareFileNames = compareFileNamesUpper; + compareFileExtensions = compareFileExtensionsUpper; + break; + case 'lower': + compareFileNames = compareFileNamesLower; + compareFileExtensions = compareFileExtensionsLower; + break; + case 'unicode': + compareFileNames = compareFileNamesUnicode; + compareFileExtensions = compareFileExtensionsUnicode; + break; + default: + // 'default' + compareFileNames = compareFileNamesDefault; + compareFileExtensions = compareFileExtensionsDefault; + } // Sort Directories switch (sortOrder) { @@ -683,7 +703,7 @@ export class FileSorter implements ITreeSorter { } if (statA.isDirectory && statB.isDirectory) { - return compareFileNamesDefault(statA.name, statB.name); + return compareFileNames(statA.name, statB.name); } break; @@ -717,74 +737,21 @@ export class FileSorter implements ITreeSorter { // Sort Files switch (sortOrder) { case 'type': - return compareFileExtensionsDefault(statA.name, statB.name); + return compareFileExtensions(statA.name, statB.name); case 'modified': if (statA.mtime !== statB.mtime) { return (statA.mtime && statB.mtime && statA.mtime < statB.mtime) ? 1 : -1; } - return compareFileNamesDefault(statA.name, statB.name); + return compareFileNames(statA.name, statB.name); default: /* 'default', 'mixed', 'filesFirst' */ - return compareFileNamesDefault(statA.name, statB.name); + return compareFileNames(statA.name, statB.name); } } } -function getFileOverwriteConfirm(name: string): IConfirmation { - return { - message: localize('confirmOverwrite', "A file or folder with the name '{0}' already exists in the destination folder. Do you want to replace it?", name), - detail: localize('irreversible', "This action is irreversible!"), - primaryButton: localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), - type: 'warning' - }; -} - -function getMultipleFilesOverwriteConfirm(files: URI[]): IConfirmation { - if (files.length > 1) { - return { - message: localize('confirmManyOverwrites', "The following {0} files and/or folders already exist in the destination folder. Do you want to replace them?", files.length), - detail: getFileNamesMessage(files) + '\n' + localize('irreversible', "This action is irreversible!"), - primaryButton: localize({ key: 'replaceButtonLabel', comment: ['&& denotes a mnemonic'] }, "&&Replace"), - type: 'warning' - }; - } - - return getFileOverwriteConfirm(basename(files[0])); -} - -interface IWebkitDataTransfer { - items: IWebkitDataTransferItem[]; -} - -interface IWebkitDataTransferItem { - webkitGetAsEntry(): IWebkitDataTransferItemEntry; -} - -interface IWebkitDataTransferItemEntry { - name: string | undefined; - isFile: boolean; - isDirectory: boolean; - - file(resolve: (file: File) => void, reject: () => void): void; - createReader(): IWebkitDataTransferItemEntryReader; -} - -interface IWebkitDataTransferItemEntryReader { - readEntries(resolve: (file: IWebkitDataTransferItemEntry[]) => void, reject: () => void): void -} - -interface IUploadOperation { - startTime: number; - progressScheduler: RunOnceWorker; - - filesTotal: number; - filesUploaded: number; - - totalBytesUploaded: number; -} - export class FileDragAndDrop implements ITreeDragAndDrop { private static readonly CONFIRM_DND_SETTING_KEY = 'explorer.confirmDragAndDrop'; @@ -795,7 +762,6 @@ export class FileDragAndDrop implements ITreeDragAndDrop { private dropEnabled = false; constructor( - @INotificationService private notificationService: INotificationService, @IExplorerService private explorerService: IExplorerService, @IEditorService private editorService: IEditorService, @IDialogService private dialogService: IDialogService, @@ -803,9 +769,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop { @IFileService private fileService: IFileService, @IConfigurationService private configurationService: IConfigurationService, @IInstantiationService private instantiationService: IInstantiationService, - @IHostService private hostService: IHostService, @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService, - @IProgressService private readonly progressService: IProgressService, @IUriIdentityService private readonly uriIdentityService: IUriIdentityService ) { this.toDispose = []; @@ -867,6 +831,10 @@ export class FileDragAndDrop implements ITreeDragAndDrop { if (!containsDragType(originalEvent, DataTransfers.FILES, CodeDataTransfers.FILES, DataTransfers.RESOURCES)) { return false; } + if (isWeb && originalEvent.dataTransfer?.types.indexOf('Files') === -1) { + // DnD from vscode to web is not supported #115535. Only if we are dragging from native finder / explorer then the "Files" data transfer will be set + return false; + } } // Other-Tree DND @@ -964,7 +932,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop { const items = FileDragAndDrop.getStatsFromDragAndDropData(data as ElementsDragAndDropData, originalEvent); if (items && items.length && originalEvent.dataTransfer) { // Apply some datatransfer types to allow for dragging the element outside of the application - this.instantiationService.invokeFunction(fillResourceDataTransfers, items, undefined, originalEvent); + this.instantiationService.invokeFunction(accessor => fillEditorsDragData(accessor, items, originalEvent)); // The only custom data transfer we set from the explorer is a file transfer // to be able to DND between multiple code file explorers across windows @@ -1002,358 +970,25 @@ export class FileDragAndDrop implements ITreeDragAndDrop { return; } - // Desktop DND (Import file) - if (data instanceof NativeDragAndDropData) { - const cts = new CancellationTokenSource(); - - if (isWeb) { - // Indicate progress globally - const dropPromise = this.progressService.withProgress({ - location: ProgressLocation.Window, - delay: 800, - cancellable: true, - title: localize('uploadingFiles', "Uploading") - }, async progress => { - try { - await this.handleWebExternalDrop(resolvedTarget, originalEvent, progress, cts.token); - } catch (error) { - this.notificationService.warn(error); - } - }, () => cts.dispose(true)); - // Also indicate progress in the files view - this.progressService.withProgress({ location: VIEW_ID, delay: 500 }, () => dropPromise); - } else { - try { - await this.handleExternalDrop(resolvedTarget, originalEvent, cts.token); - } catch (error) { - this.notificationService.warn(error); - } - } - } - // In-Explorer DND (Move/Copy file) - else { - this.handleExplorerDrop(data as ElementsDragAndDropData, resolvedTarget, originalEvent).then(undefined, e => this.notificationService.warn(e)); - } - } - - private async handleWebExternalDrop(target: ExplorerItem, originalEvent: DragEvent, progress: IProgress, token: CancellationToken): Promise { - const items = (originalEvent.dataTransfer as unknown as IWebkitDataTransfer).items; - - // Somehow the items thing is being modified at random, maybe as a security - // measure since this is a DND operation. As such, we copy the items into - // an array we own as early as possible before using it. - const entries: IWebkitDataTransferItemEntry[] = []; - for (const item of items) { - entries.push(item.webkitGetAsEntry()); - } - - const results: { isFile: boolean, resource: URI }[] = []; - const operation: IUploadOperation = { - startTime: Date.now(), - progressScheduler: new RunOnceWorker(steps => { progress.report(steps[steps.length - 1]); }, 1000), - - filesTotal: entries.length, - filesUploaded: 0, - - totalBytesUploaded: 0 - }; - - for (let entry of entries) { - if (token.isCancellationRequested) { - break; - } - - // Confirm overwrite as needed - if (target && entry.name && target.getChild(entry.name)) { - const { confirmed } = await this.dialogService.confirm(getFileOverwriteConfirm(entry.name)); - if (!confirmed) { - continue; - } - - await this.explorerService.applyBulkEdit([new ResourceFileEdit(joinPath(target.resource, entry.name), undefined, { recursive: true })], { - undoLabel: localize('overwrite', "Overwrite {0}", entry.name), - progressLabel: localize('overwriting', "Overwriting {0}", entry.name), - }); - - if (token.isCancellationRequested) { - break; - } - } - - // Upload entry - const result = await this.doUploadWebFileEntry(entry, target.resource, target, progress, operation, token); - if (result) { - results.push(result); - } - } - - operation.progressScheduler.dispose(); - - // Open uploaded file in editor only if we upload just one - const firstUploadedFile = results[0]; - if (!token.isCancellationRequested && firstUploadedFile?.isFile) { - await this.editorService.openEditor({ resource: firstUploadedFile.resource, options: { pinned: true } }); - } - } - - private async doUploadWebFileEntry(entry: IWebkitDataTransferItemEntry, parentResource: URI, target: ExplorerItem | undefined, progress: IProgress, operation: IUploadOperation, token: CancellationToken): Promise<{ isFile: boolean, resource: URI } | undefined> { - if (token.isCancellationRequested || !entry.name || (!entry.isFile && !entry.isDirectory)) { - return undefined; - } - - // Report progress - let fileBytesUploaded = 0; - const reportProgress = (fileSize: number, bytesUploaded: number): void => { - fileBytesUploaded += bytesUploaded; - operation.totalBytesUploaded += bytesUploaded; - - const bytesUploadedPerSecond = operation.totalBytesUploaded / ((Date.now() - operation.startTime) / 1000); + try { - // Small file - let message: string; - if (fileSize < ByteSize.MB) { - if (operation.filesTotal === 1) { - message = `${entry.name}`; + // Desktop DND (Import file) + if (data instanceof NativeDragAndDropData) { + if (isWeb) { + const browserUpload = this.instantiationService.createInstance(BrowserFileUpload); + await browserUpload.upload(target, originalEvent); } else { - message = localize('uploadProgressSmallMany', "{0} of {1} files ({2}/s)", operation.filesUploaded, operation.filesTotal, ByteSize.formatSize(bytesUploadedPerSecond)); + const nativeImport = this.instantiationService.createInstance(NativeFileImport); + await nativeImport.import(resolvedTarget, originalEvent); } } - // Large file + // In-Explorer DND (Move/Copy file) else { - message = localize('uploadProgressLarge', "{0} ({1} of {2}, {3}/s)", entry.name, ByteSize.formatSize(fileBytesUploaded), ByteSize.formatSize(fileSize), ByteSize.formatSize(bytesUploadedPerSecond)); + await this.handleExplorerDrop(data as ElementsDragAndDropData, resolvedTarget, originalEvent); } - - // Report progress but limit to update only once per second - operation.progressScheduler.work({ message }); - }; - operation.filesUploaded++; - reportProgress(0, 0); - - // Handle file upload - const resource = joinPath(parentResource, entry.name); - if (entry.isFile) { - const file = await new Promise((resolve, reject) => entry.file(resolve, reject)); - - if (token.isCancellationRequested) { - return undefined; - } - - // Chrome/Edge/Firefox support stream method, but only use it for - // larger files to reduce the overhead of the streaming approach - if (typeof file.stream === 'function' && file.size > ByteSize.MB) { - await this.doUploadWebFileEntryBuffered(resource, file, reportProgress, token); - } - - // Fallback to unbuffered upload for other browsers or small files - else { - await this.doUploadWebFileEntryUnbuffered(resource, file, reportProgress); - } - - return { isFile: true, resource }; - } - - // Handle folder upload - else { - - // Create target folder - await this.fileService.createFolder(resource); - - if (token.isCancellationRequested) { - return undefined; - } - - // Recursive upload files in this directory - const dirReader = entry.createReader(); - const childEntries: IWebkitDataTransferItemEntry[] = []; - let done = false; - do { - const childEntriesChunk = await new Promise((resolve, reject) => dirReader.readEntries(resolve, reject)); - if (childEntriesChunk.length > 0) { - childEntries.push(...childEntriesChunk); - } else { - done = true; // an empty array is a signal that all entries have been read - } - } while (!done && !token.isCancellationRequested); - - // Update operation total based on new counts - operation.filesTotal += childEntries.length; - - // Upload all entries as files to target - const folderTarget = target && target.getChild(entry.name) || undefined; - for (let childEntry of childEntries) { - await this.doUploadWebFileEntry(childEntry, resource, folderTarget, progress, operation, token); - } - - return { isFile: false, resource }; - } - } - - private async doUploadWebFileEntryBuffered(resource: URI, file: File, progressReporter: (fileSize: number, bytesUploaded: number) => void, token: CancellationToken): Promise { - const writeableStream = newWriteableBufferStream({ - // Set a highWaterMark to prevent the stream - // for file upload to produce large buffers - // in-memory - highWaterMark: 10 - }); - const writeFilePromise = this.fileService.writeFile(resource, writeableStream); - - // Read the file in chunks using File.stream() web APIs - try { - const reader: ReadableStreamDefaultReader = file.stream().getReader(); - - let res = await reader.read(); - while (!res.done) { - if (token.isCancellationRequested) { - return undefined; - } - - // Write buffer into stream but make sure to wait - // in case the highWaterMark is reached - const buffer = VSBuffer.wrap(res.value); - await writeableStream.write(buffer); - - if (token.isCancellationRequested) { - return undefined; - } - - // Report progress - progressReporter(file.size, buffer.byteLength); - - res = await reader.read(); - } - writeableStream.end(undefined); } catch (error) { - writeableStream.error(error); - writeableStream.end(); - } - - if (token.isCancellationRequested) { - return undefined; - } - - // Wait for file being written to target - await writeFilePromise; - } - - private doUploadWebFileEntryUnbuffered(resource: URI, file: File, progressReporter: (fileSize: number, bytesUploaded: number) => void): Promise { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onload = async event => { - try { - if (event.target?.result instanceof ArrayBuffer) { - const buffer = VSBuffer.wrap(new Uint8Array(event.target.result)); - await this.fileService.writeFile(resource, buffer); - - // Report progress - progressReporter(file.size, buffer.byteLength); - } else { - throw new Error('Could not read from dropped file.'); - } - - resolve(); - } catch (error) { - reject(error); - } - }; - - // Start reading the file to trigger `onload` - reader.readAsArrayBuffer(file); - }); - } - - private async handleExternalDrop(target: ExplorerItem, originalEvent: DragEvent, token: CancellationToken): Promise { - - // Check for dropped external files to be folders - const droppedResources = extractResources(originalEvent, true); - const result = await this.fileService.resolveAll(droppedResources.map(droppedResource => ({ resource: droppedResource.resource }))); - - if (token.isCancellationRequested) { - return; - } - - // Pass focus to window - this.hostService.focus(); - - // Handle folders by adding to workspace if we are in workspace context and if dropped on top - const folders = result.filter(r => r.success && r.stat && r.stat.isDirectory).map(result => ({ uri: result.stat!.resource })); - if (folders.length > 0 && target.isRoot) { - const buttons = [ - folders.length > 1 ? localize('copyFolders', "&&Copy Folders") : localize('copyFolder', "&&Copy Folder"), - localize('cancel', "Cancel") - ]; - const workspaceFolderSchemas = this.contextService.getWorkspace().folders.map(f => f.uri.scheme); - let message = folders.length > 1 ? localize('copyfolders', "Are you sure to want to copy folders?") : localize('copyfolder', "Are you sure to want to copy '{0}'?", basename(folders[0].uri)); - if (folders.some(f => workspaceFolderSchemas.indexOf(f.uri.scheme) >= 0)) { - // We only allow to add a folder to the workspace if there is already a workspace folder with that scheme - buttons.unshift(folders.length > 1 ? localize('addFolders', "&&Add Folders to Workspace") : localize('addFolder', "&&Add Folder to Workspace")); - message = folders.length > 1 ? localize('dropFolders', "Do you want to copy the folders or add the folders to the workspace?") - : localize('dropFolder', "Do you want to copy '{0}' or add '{0}' as a folder to the workspace?", basename(folders[0].uri)); - } - - const { choice } = await this.dialogService.show(Severity.Info, message, buttons); - if (choice === buttons.length - 3) { - return this.workspaceEditingService.addFolders(folders); - } - if (choice === buttons.length - 2) { - return this.addResources(target, droppedResources.map(res => res.resource), token); - } - - return undefined; - } - - // Handle dropped files (only support FileStat as target) - else if (target instanceof ExplorerItem) { - return this.addResources(target, droppedResources.map(res => res.resource), token); - } - } - - private async addResources(target: ExplorerItem, resources: URI[], token: CancellationToken): Promise { - if (resources && resources.length > 0) { - - // Resolve target to check for name collisions and ask user - const targetStat = await this.fileService.resolve(target.resource); - - if (token.isCancellationRequested) { - return; - } - - // Check for name collisions - const targetNames = new Set(); - const caseSensitive = this.fileService.hasCapability(target.resource, FileSystemProviderCapabilities.PathCaseSensitive); - if (targetStat.children) { - targetStat.children.forEach(child => { - targetNames.add(caseSensitive ? child.name : child.name.toLowerCase()); - }); - } - - const resourcesFiltered = (await Promise.all(resources.map(async resource => { - if (targetNames.has(caseSensitive ? basename(resource) : basename(resource).toLowerCase())) { - const confirmationResult = await this.dialogService.confirm(getFileOverwriteConfirm(basename(resource))); - if (!confirmationResult.confirmed) { - return undefined; - } - } - return resource; - }))).filter(r => r instanceof URI) as URI[]; - const resourceFileEdits = resourcesFiltered.map(resource => { - const sourceFileName = basename(resource); - const targetFile = joinPath(target.resource, sourceFileName); - return new ResourceFileEdit(resource, targetFile, { overwrite: true, copy: true }); - }); - - await this.explorerService.applyBulkEdit(resourceFileEdits, { - undoLabel: resourcesFiltered.length === 1 ? localize('copyFile', "Copy {0}", basename(resourcesFiltered[0])) : localize('copynFile', "Copy {0} resources", resourcesFiltered.length), - progressLabel: resourcesFiltered.length === 1 ? localize('copyingFile', "Copying {0}", basename(resourcesFiltered[0])) : localize('copyingnFile', "Copying {0} resources", resourcesFiltered.length) - }); - - // if we only add one file, just open it directly - if (resourceFileEdits.length === 1) { - const item = this.explorerService.findClosest(resourceFileEdits[0].newResource!); - if (item && !item.isDirectory) { - this.editorService.openEditor({ resource: item.resource, options: { pinned: true } }); - } - } + this.dialogService.show(Severity.Error, toErrorMessage(error), [localize('ok', 'OK')]); } } @@ -1395,15 +1030,15 @@ export class FileDragAndDrop implements ITreeDragAndDrop { const sources = items.filter(s => !s.isRoot); if (isCopy) { - await this.doHandleExplorerDropOnCopy(sources, target); - } else { - return this.doHandleExplorerDropOnMove(sources, target); + return this.doHandleExplorerDropOnCopy(sources, target); } + + return this.doHandleExplorerDropOnMove(sources, target); } - private doHandleRootDrop(roots: ExplorerItem[], target: ExplorerItem): Promise { + private async doHandleRootDrop(roots: ExplorerItem[], target: ExplorerItem): Promise { if (roots.length === 0) { - return Promise.resolve(undefined); + return; } const folders = this.contextService.getWorkspace().folders; @@ -1431,10 +1066,12 @@ export class FileDragAndDrop implements ITreeDragAndDrop { } workspaceCreationData.splice(targetIndex, 0, ...rootsToMove); + return this.workspaceEditingService.updateFolders(0, workspaceCreationData.length, workspaceCreationData); } private async doHandleExplorerDropOnCopy(sources: ExplorerItem[], target: ExplorerItem): Promise { + // Reuse duplicate action when user copies const incrementalNaming = this.configurationService.getValue().explorer.incrementalNaming; const resourceFileEdits = sources.map(({ resource, isDirectory }) => (new ResourceFileEdit(resource, findValidPasteFileTarget(this.explorerService, target, { resource, isDirectory, allowOverwrite: false }, incrementalNaming), { copy: true }))); @@ -1465,6 +1102,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop { try { await this.explorerService.applyBulkEdit(resourceFileEdits, options); } catch (error) { + // Conflict if ((error).fileOperationResult === FileOperationResult.FILE_MOVE_CONFLICT) { @@ -1475,20 +1113,17 @@ export class FileDragAndDrop implements ITreeDragAndDrop { } } - const confirm = getMultipleFilesOverwriteConfirm(overwrites); // Move with overwrite if the user confirms + const confirm = getMultipleFilesOverwriteConfirm(overwrites); const { confirmed } = await this.dialogService.confirm(confirm); if (confirmed) { - try { - await this.explorerService.applyBulkEdit(resourceFileEdits.map(re => new ResourceFileEdit(re.oldResource, re.newResource, { overwrite: true })), options); - } catch (error) { - this.notificationService.error(error); - } + await this.explorerService.applyBulkEdit(resourceFileEdits.map(re => new ResourceFileEdit(re.oldResource, re.newResource, { overwrite: true })), options); } } - // Any other error + + // Any other error: bubble up else { - this.notificationService.error(error); + throw error; } } } diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/views/media/openeditors.css b/src/vs/workbench/contrib/files/browser/views/media/openeditors.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/files/browser/views/media/openeditors.css rename to src/vs/workbench/contrib/files/browser/views/media/openeditors.css diff --git a/lib/vscode/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts rename to src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index 2aa047e2cb22..d8176ad5cffc 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -13,7 +13,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati import { IEditorGroupsService, IEditorGroup, GroupChangeKind, GroupsOrder, GroupOrientation } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { IEditorInput, Verbosity, EditorResourceAccessor, SideBySideEditor } from 'vs/workbench/common/editor'; +import { IEditorInput, Verbosity, EditorResourceAccessor, SideBySideEditor, EditorInputCapabilities, IEditorIdentifier } from 'vs/workbench/common/editor'; import { SaveAllInGroupAction, CloseGroupAction } from 'vs/workbench/contrib/files/browser/fileActions'; import { OpenEditorsFocusedContext, ExplorerFocusedContext, IFilesConfiguration, OpenEditor } from 'vs/workbench/contrib/files/common/files'; import { CloseAllEditorsAction, CloseEditorAction, UnpinEditorAction } from 'vs/workbench/browser/parts/editor/editorActions'; @@ -32,13 +32,12 @@ import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/m import { IMenuService, MenuId, IMenu, Action2, registerAction2, MenuRegistry } from 'vs/platform/actions/common/actions'; import { OpenEditorsDirtyEditorContext, OpenEditorsGroupContext, OpenEditorsReadonlyEditorContext, SAVE_ALL_LABEL, SAVE_ALL_COMMAND_ID, NEW_UNTITLED_FILE_COMMAND_ID } from 'vs/workbench/contrib/files/browser/fileCommands'; import { ResourceContextKey } from 'vs/workbench/common/resources'; -import { ResourcesDropHandler, fillResourceDataTransfers, CodeDataTransfers, containsDragType } from 'vs/workbench/browser/dnd'; +import { ResourcesDropHandler, fillEditorsDragData, CodeDataTransfers, containsDragType } from 'vs/workbench/browser/dnd'; import { ViewPane } from 'vs/workbench/browser/parts/views/viewPane'; import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IDragAndDropData, DataTransfers } from 'vs/base/browser/dnd'; import { memoize } from 'vs/base/common/decorators'; import { ElementsDragAndDropData, NativeDragAndDropData } from 'vs/base/browser/ui/list/listView'; -import { URI } from 'vs/base/common/uri'; import { withUndefinedAsNull } from 'vs/base/common/types'; import { isWeb } from 'vs/base/common/platform'; import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; @@ -164,6 +163,7 @@ export class OpenEditorsView extends ViewPane { } case GroupChangeKind.EDITOR_DIRTY: case GroupChangeKind.EDITOR_LABEL: + case GroupChangeKind.EDITOR_CAPABILITIES: case GroupChangeKind.EDITOR_STICKY: case GroupChangeKind.EDITOR_PIN: { this.list.splice(index, 1, [new OpenEditor(e.editor!, group)]); @@ -269,7 +269,7 @@ export class OpenEditorsView extends ViewPane { if (element instanceof OpenEditor) { const resource = element.getResource(); this.dirtyEditorFocusedContext.set(element.editor.isDirty() && !element.editor.isSaving()); - this.readonlyEditorFocusedContext.set(element.editor.isReadonly()); + this.readonlyEditorFocusedContext.set(element.editor.hasCapability(EditorInputCapabilities.Readonly)); this.resourceContext.set(withUndefinedAsNull(resource)); } else if (!!element) { this.groupFocusedContext.set(true); @@ -653,21 +653,18 @@ class OpenEditorsDragAndDrop implements IListDragAndDrop).elements; - const resources: URI[] = []; + const editors: IEditorIdentifier[] = []; if (items) { - items.forEach(i => { - if (i instanceof OpenEditor) { - const resource = i.getResource(); - if (resource) { - resources.push(resource); - } + for (const item of items) { + if (item instanceof OpenEditor) { + editors.push(item); } - }); + } } - if (resources.length) { + if (editors.length) { // Apply some datatransfer types to allow for dragging the element outside of the application - this.instantiationService.invokeFunction(fillResourceDataTransfers, resources, undefined, originalEvent); + this.instantiationService.invokeFunction(fillEditorsDragData, editors, originalEvent); } } diff --git a/lib/vscode/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts b/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts rename to src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts diff --git a/lib/vscode/src/vs/workbench/contrib/files/common/explorerModel.ts b/src/vs/workbench/contrib/files/common/explorerModel.ts similarity index 97% rename from lib/vscode/src/vs/workbench/contrib/files/common/explorerModel.ts rename to src/vs/workbench/contrib/files/common/explorerModel.ts index 4809b811ad6c..82955982e10b 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/common/explorerModel.ts +++ b/src/vs/workbench/contrib/files/common/explorerModel.ts @@ -30,7 +30,7 @@ export class ExplorerModel implements IDisposable { fileService: IFileService ) { const setRoots = () => this._roots = this.contextService.getWorkspace().folders - .map(folder => new ExplorerItem(folder.uri, fileService, undefined, true, false, folder.name)); + .map(folder => new ExplorerItem(folder.uri, fileService, undefined, true, false, false, folder.name)); setRoots(); this._listener = this.contextService.onDidChangeWorkspaceFolders(() => { @@ -89,6 +89,7 @@ export class ExplorerItem { private _parent: ExplorerItem | undefined, private _isDirectory?: boolean, private _isSymbolicLink?: boolean, + private _readonly?: boolean, private _name: string = basenameOrAuthority(resource), private _mtime?: number, private _unknown = false @@ -124,7 +125,7 @@ export class ExplorerItem { } get isReadonly(): boolean { - return this.fileService.hasCapability(this.resource, FileSystemProviderCapabilities.Readonly); + return this._readonly || this.fileService.hasCapability(this.resource, FileSystemProviderCapabilities.Readonly); } get mtime(): number | undefined { @@ -179,7 +180,7 @@ export class ExplorerItem { } static create(fileService: IFileService, raw: IFileStat, parent: ExplorerItem | undefined, resolveTo?: readonly URI[]): ExplorerItem { - const stat = new ExplorerItem(raw.resource, fileService, parent, raw.isDirectory, raw.isSymbolicLink, raw.name, raw.mtime, !raw.isFile && !raw.isDirectory); + const stat = new ExplorerItem(raw.resource, fileService, parent, raw.isDirectory, raw.isSymbolicLink, raw.readonly, raw.name, raw.mtime, !raw.isFile && !raw.isDirectory); // Recursively add children if present if (stat.isDirectory) { diff --git a/lib/vscode/src/vs/workbench/contrib/files/common/files.ts b/src/vs/workbench/contrib/files/common/files.ts similarity index 96% rename from lib/vscode/src/vs/workbench/contrib/files/common/files.ts rename to src/vs/workbench/contrib/files/common/files.ts index eb075dbdf2a0..70f2fcf8bb61 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/common/files.ts +++ b/src/vs/workbench/contrib/files/common/files.ts @@ -83,6 +83,7 @@ export interface IFilesConfiguration extends PlatformIFilesConfiguration, IWorkb enableDragAndDrop: boolean; confirmDelete: boolean; sortOrder: SortOrder; + sortOrderLexicographicOptions: LexicographicOptions; decorations: { colors: boolean; badges: boolean; @@ -105,6 +106,18 @@ export const enum SortOrder { Modified = 'modified' } +export const enum LexicographicOptions { + Default = 'default', + Upper = 'upper', + Lower = 'lower', + Unicode = 'unicode', +} + +export interface ISortOrderConfiguration { + sortOrder: SortOrder; + lexicographicOptions: LexicographicOptions; +} + export class TextFileContentProvider extends Disposable implements ITextModelContentProvider { private readonly fileWatcherDisposable = this._register(new MutableDisposable()); @@ -119,8 +132,8 @@ export class TextFileContentProvider extends Disposable implements ITextModelCon static async open(resource: URI, scheme: string, label: string, editorService: IEditorService, options?: ITextEditorOptions): Promise { await editorService.openEditor({ - leftResource: TextFileContentProvider.resourceToTextFile(scheme, resource), - rightResource: resource, + originalInput: { resource: TextFileContentProvider.resourceToTextFile(scheme, resource) }, + modifiedInput: { resource }, label, options }); diff --git a/lib/vscode/src/vs/workbench/contrib/files/common/workspaceWatcher.ts b/src/vs/workbench/contrib/files/common/workspaceWatcher.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/files/common/workspaceWatcher.ts rename to src/vs/workbench/contrib/files/common/workspaceWatcher.ts diff --git a/lib/vscode/src/vs/workbench/contrib/files/electron-sandbox/fileActions.contribution.ts b/src/vs/workbench/contrib/files/electron-sandbox/fileActions.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/files/electron-sandbox/fileActions.contribution.ts rename to src/vs/workbench/contrib/files/electron-sandbox/fileActions.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/files/electron-sandbox/fileCommands.ts b/src/vs/workbench/contrib/files/electron-sandbox/fileCommands.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/files/electron-sandbox/fileCommands.ts rename to src/vs/workbench/contrib/files/electron-sandbox/fileCommands.ts diff --git a/lib/vscode/src/vs/workbench/contrib/files/electron-sandbox/files.contribution.ts b/src/vs/workbench/contrib/files/electron-sandbox/files.contribution.ts similarity index 81% rename from lib/vscode/src/vs/workbench/contrib/files/electron-sandbox/files.contribution.ts rename to src/vs/workbench/contrib/files/electron-sandbox/files.contribution.ts index fd0604b572c6..71724d782505 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/electron-sandbox/files.contribution.ts +++ b/src/vs/workbench/contrib/files/electron-sandbox/files.contribution.ts @@ -5,8 +5,8 @@ import * as nls from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; -import { EditorExtensions, EditorInput } from 'vs/workbench/common/editor'; -import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; +import { EditorExtensions } from 'vs/workbench/common/editor'; +import { FileEditorInput } from 'vs/workbench/contrib/files/browser/editors/fileEditorInput'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IEditorRegistry, EditorDescriptor } from 'vs/workbench/browser/editor'; import { NativeTextFileEditor } from 'vs/workbench/contrib/files/electron-sandbox/textFileEditor'; @@ -19,6 +19,6 @@ Registry.as(EditorExtensions.Editors).registerEditor( nls.localize('textFileEditor', "Text File Editor") ), [ - new SyncDescriptor(FileEditorInput) + new SyncDescriptor(FileEditorInput) ] ); diff --git a/lib/vscode/src/vs/workbench/contrib/files/electron-sandbox/textFileEditor.ts b/src/vs/workbench/contrib/files/electron-sandbox/textFileEditor.ts similarity index 95% rename from lib/vscode/src/vs/workbench/contrib/files/electron-sandbox/textFileEditor.ts rename to src/vs/workbench/contrib/files/electron-sandbox/textFileEditor.ts index a47e3abe916b..bb34adbf9767 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/electron-sandbox/textFileEditor.ts +++ b/src/vs/workbench/contrib/files/electron-sandbox/textFileEditor.ts @@ -5,8 +5,7 @@ import { localize } from 'vs/nls'; import { TextFileEditor } from 'vs/workbench/contrib/files/browser/editors/textFileEditor'; -import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; -import { EditorOptions } from 'vs/workbench/common/editor'; +import { FileEditorInput } from 'vs/workbench/contrib/files/browser/editors/fileEditorInput'; import { FileOperationError, FileOperationResult, IFileService, MIN_MAX_MEMORY_SIZE_MB, FALLBACK_MAX_MEMORY_SIZE_MB } from 'vs/platform/files/common/files'; import { createErrorWithActions } from 'vs/base/common/errors'; import { toAction } from 'vs/base/common/actions'; @@ -25,6 +24,7 @@ import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; import { IExplorerService } from 'vs/workbench/contrib/files/browser/files'; import { IProductService } from 'vs/platform/product/common/productService'; +import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; /** * An implementation of editor for file system resources. @@ -52,7 +52,7 @@ export class NativeTextFileEditor extends TextFileEditor { super(telemetryService, fileService, viewletService, instantiationService, contextService, storageService, textResourceConfigurationService, editorService, themeService, editorGroupService, textFileService, explorerService, uriIdentityService); } - protected override handleSetInputError(error: Error, input: FileEditorInput, options: EditorOptions | undefined): void { + protected override handleSetInputError(error: Error, input: FileEditorInput, options: ITextEditorOptions | undefined): void { // Allow to restart with higher memory limit if the file is too large if ((error).fileOperationResult === FileOperationResult.FILE_EXCEEDS_MEMORY_LIMIT) { diff --git a/lib/vscode/src/vs/workbench/contrib/files/test/browser/editorAutoSave.test.ts b/src/vs/workbench/contrib/files/test/browser/editorAutoSave.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/files/test/browser/editorAutoSave.test.ts rename to src/vs/workbench/contrib/files/test/browser/editorAutoSave.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/files/test/browser/explorerModel.test.ts b/src/vs/workbench/contrib/files/test/browser/explorerModel.test.ts similarity index 96% rename from lib/vscode/src/vs/workbench/contrib/files/test/browser/explorerModel.test.ts rename to src/vs/workbench/contrib/files/test/browser/explorerModel.test.ts index d7b872b7628f..877158e416fb 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/test/browser/explorerModel.test.ts +++ b/src/vs/workbench/contrib/files/test/browser/explorerModel.test.ts @@ -14,7 +14,7 @@ import { TestFileService } from 'vs/workbench/test/browser/workbenchTestServices const fileService = new TestFileService(); function createStat(this: any, path: string, name: string, isFolder: boolean, hasChildren: boolean, size: number, mtime: number): ExplorerItem { - return new ExplorerItem(toResource.call(this, path), fileService, undefined, isFolder, false, name, mtime); + return new ExplorerItem(toResource.call(this, path), fileService, undefined, isFolder, false, false, name, mtime); } suite('Files - View Model', function () { @@ -245,19 +245,19 @@ suite('Files - View Model', function () { }); test('Merge Local with Disk', function () { - const merge1 = new ExplorerItem(URI.file(join('C:\\', '/path/to')), fileService, undefined, true, false, 'to', Date.now()); - const merge2 = new ExplorerItem(URI.file(join('C:\\', '/path/to')), fileService, undefined, true, false, 'to', Date.now()); + const merge1 = new ExplorerItem(URI.file(join('C:\\', '/path/to')), fileService, undefined, true, false, false, 'to', Date.now()); + const merge2 = new ExplorerItem(URI.file(join('C:\\', '/path/to')), fileService, undefined, true, false, false, 'to', Date.now()); // Merge Properties ExplorerItem.mergeLocalWithDisk(merge2, merge1); assert.strictEqual(merge1.mtime, merge2.mtime); // Merge Child when isDirectoryResolved=false is a no-op - merge2.addChild(new ExplorerItem(URI.file(join('C:\\', '/path/to/foo.html')), fileService, undefined, true, false, 'foo.html', Date.now())); + merge2.addChild(new ExplorerItem(URI.file(join('C:\\', '/path/to/foo.html')), fileService, undefined, true, false, false, 'foo.html', Date.now())); ExplorerItem.mergeLocalWithDisk(merge2, merge1); // Merge Child with isDirectoryResolved=true - const child = new ExplorerItem(URI.file(join('C:\\', '/path/to/foo.html')), fileService, undefined, true, false, 'foo.html', Date.now()); + const child = new ExplorerItem(URI.file(join('C:\\', '/path/to/foo.html')), fileService, undefined, true, false, false, 'foo.html', Date.now()); merge2.removeChild(child); merge2.addChild(child); (merge2)._isDirectoryResolved = true; diff --git a/lib/vscode/src/vs/workbench/contrib/files/test/browser/explorerView.test.ts b/src/vs/workbench/contrib/files/test/browser/explorerView.test.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/files/test/browser/explorerView.test.ts rename to src/vs/workbench/contrib/files/test/browser/explorerView.test.ts index 8af54cf4ea73..723981a62385 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/test/browser/explorerView.test.ts +++ b/src/vs/workbench/contrib/files/test/browser/explorerView.test.ts @@ -19,7 +19,7 @@ const $ = dom.$; const fileService = new TestFileService(); function createStat(this: any, path: string, name: string, isFolder: boolean, hasChildren: boolean, size: number, mtime: number, isSymLink = false, isUnknown = false): ExplorerItem { - return new ExplorerItem(toResource.call(this, path), fileService, undefined, isFolder, isSymLink, name, mtime, isUnknown); + return new ExplorerItem(toResource.call(this, path), fileService, undefined, isFolder, isSymLink, false, name, mtime, isUnknown); } suite('Files - ExplorerView', () => { diff --git a/lib/vscode/src/vs/workbench/contrib/files/test/browser/fileActions.test.ts b/src/vs/workbench/contrib/files/test/browser/fileActions.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/files/test/browser/fileActions.test.ts rename to src/vs/workbench/contrib/files/test/browser/fileActions.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts b/src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts similarity index 74% rename from lib/vscode/src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts rename to src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts index e447235e23f3..d4b44dc22da4 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts +++ b/src/vs/workbench/contrib/files/test/browser/fileEditorInput.test.ts @@ -6,12 +6,12 @@ import * as assert from 'assert'; import { URI } from 'vs/base/common/uri'; import { toResource } from 'vs/base/test/common/utils'; -import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; +import { FileEditorInput } from 'vs/workbench/contrib/files/browser/editors/fileEditorInput'; import { workbenchInstantiationService, TestServiceAccessor, TestEditorService, getLastResolvedFileStat } from 'vs/workbench/test/browser/workbenchTestServices'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IEditorInputFactoryRegistry, Verbosity, EditorExtensions } from 'vs/workbench/common/editor'; +import { IEditorInputFactoryRegistry, Verbosity, EditorExtensions, EditorInputCapabilities } from 'vs/workbench/common/editor'; import { EncodingMode, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles'; -import { FileOperationResult, FileOperationError } from 'vs/platform/files/common/files'; +import { FileOperationResult, FileOperationError, NotModifiedSinceFileOperationError, FileSystemProviderCapabilities } from 'vs/platform/files/common/files'; import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; import { timeout } from 'vs/base/common/async'; import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; @@ -19,15 +19,16 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; import { IResourceEditorInput } from 'vs/platform/editor/common/editor'; import { Registry } from 'vs/platform/registry/common/platform'; -import { FileEditorInputSerializer } from 'vs/workbench/contrib/files/browser/files'; +import { FileEditorInputSerializer } from 'vs/workbench/contrib/files/browser/editors/fileEditorHandler'; +import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider'; suite('Files - FileEditorInput', () => { let instantiationService: IInstantiationService; let accessor: TestServiceAccessor; - function createFileInput(resource: URI, preferredResource?: URI, preferredMode?: string, preferredName?: string, preferredDescription?: string): FileEditorInput { - return instantiationService.createInstance(FileEditorInput, resource, preferredResource, preferredName, preferredDescription, undefined, preferredMode); + function createFileInput(resource: URI, preferredResource?: URI, preferredMode?: string, preferredName?: string, preferredDescription?: string, preferredContents?: string): FileEditorInput { + return instantiationService.createInstance(FileEditorInput, resource, preferredResource, preferredName, preferredDescription, undefined, preferredMode, preferredContents); } setup(() => { @@ -57,6 +58,14 @@ suite('Files - FileEditorInput', () => { assert.ok(input.getDescription()); assert.ok(input.getTitle(Verbosity.SHORT)); + assert.ok(!input.hasCapability(EditorInputCapabilities.Untitled)); + assert.ok(!input.hasCapability(EditorInputCapabilities.Readonly)); + assert.ok(!input.hasCapability(EditorInputCapabilities.Singleton)); + assert.ok(!input.hasCapability(EditorInputCapabilities.RequiresTrust)); + + const untypedInput = input.asResourceEditorInput(0); + assert.strictEqual(untypedInput.resource.toString(), input.resource.toString()); + assert.strictEqual('file.js', input.getName()); assert.strictEqual(toResource.call(this, '/foo/bar/file.js').fsPath, input.resource.fsPath); @@ -99,6 +108,30 @@ suite('Files - FileEditorInput', () => { } }); + test('reports as untitled without supported file scheme', async function () { + let input = createFileInput(toResource.call(this, '/foo/bar/file.js').with({ scheme: 'someTestingScheme' })); + + assert.ok(input.hasCapability(EditorInputCapabilities.Untitled)); + assert.ok(!input.hasCapability(EditorInputCapabilities.Readonly)); + }); + + test('reports as readonly with readonly file scheme', async function () { + + class ReadonlyInMemoryFileSystemProvider extends InMemoryFileSystemProvider { + override readonly capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.Readonly; + } + + const disposable = accessor.fileService.registerProvider('someTestingReadonlyScheme', new ReadonlyInMemoryFileSystemProvider()); + try { + let input = createFileInput(toResource.call(this, '/foo/bar/file.js').with({ scheme: 'someTestingReadonlyScheme' })); + + assert.ok(!input.hasCapability(EditorInputCapabilities.Untitled)); + assert.ok(input.hasCapability(EditorInputCapabilities.Readonly)); + } finally { + disposable.dispose(); + } + }); + test('preferred resource', function () { const resource = toResource.call(this, '/foo/bar/updatefile.js'); const preferredResource = toResource.call(this, '/foo/bar/UPDATEFILE.js'); @@ -153,6 +186,32 @@ suite('Files - FileEditorInput', () => { assert.strictEqual(model2.textEditorModel!.getModeId(), mode); }); + test('preferred contents', async function () { + const input = createFileInput(toResource.call(this, '/foo/bar/file.js'), undefined, undefined, undefined, undefined, 'My contents'); + + const model = await input.resolve() as TextFileEditorModel; + assert.strictEqual(model.textEditorModel!.getValue(), 'My contents'); + assert.strictEqual(input.isDirty(), true); + + const untypedInput = input.asResourceEditorInput(0); + assert.strictEqual(untypedInput.contents, 'My contents'); + + input.setPreferredContents('Other contents'); + await input.resolve(); + assert.strictEqual(model.textEditorModel!.getValue(), 'Other contents'); + + model.textEditorModel?.setValue('Changed contents'); + await input.resolve(); + assert.strictEqual(model.textEditorModel!.getValue(), 'Changed contents'); // preferred contents only used once + + const input2 = createFileInput(toResource.call(this, '/foo/bar/file.js')); + input2.setPreferredContents('My contents'); + + const model2 = await input2.resolve() as TextFileEditorModel; + assert.strictEqual(model2.textEditorModel!.getValue(), 'My contents'); + assert.strictEqual(input2.isDirty(), true); + }); + test('matches', function () { const input1 = createFileInput(toResource.call(this, '/foo/bar/updatefile.js')); const input2 = createFileInput(toResource.call(this, '/foo/bar/updatefile.js')); @@ -342,4 +401,45 @@ suite('Files - FileEditorInput', () => { fileInput.dispose(); }); + + test('reports readonly changes', async function () { + const input = createFileInput(toResource.call(this, '/foo/bar/updatefile.js')); + + let listenerCount = 0; + const listener = input.onDidChangeCapabilities(() => { + listenerCount++; + }); + + const model = await accessor.textFileService.files.resolve(input.resource); + + assert.strictEqual(model.isReadonly(), false); + assert.strictEqual(input.hasCapability(EditorInputCapabilities.Readonly), false); + + const stat = await accessor.fileService.resolve(input.resource, { resolveMetadata: true }); + + try { + accessor.fileService.readShouldThrowError = new NotModifiedSinceFileOperationError('file not modified since', { ...stat, readonly: true }); + await input.resolve(); + } finally { + accessor.fileService.readShouldThrowError = undefined; + } + + assert.strictEqual(model.isReadonly(), true); + assert.strictEqual(input.hasCapability(EditorInputCapabilities.Readonly), true); + assert.strictEqual(listenerCount, 1); + + try { + accessor.fileService.readShouldThrowError = new NotModifiedSinceFileOperationError('file not modified since', { ...stat, readonly: false }); + await input.resolve(); + } finally { + accessor.fileService.readShouldThrowError = undefined; + } + + assert.strictEqual(model.isReadonly(), false); + assert.strictEqual(input.hasCapability(EditorInputCapabilities.Readonly), false); + assert.strictEqual(listenerCount, 2); + + input.dispose(); + listener.dispose(); + }); }); diff --git a/lib/vscode/src/vs/workbench/contrib/files/test/browser/fileOnDiskProvider.test.ts b/src/vs/workbench/contrib/files/test/browser/fileOnDiskProvider.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/files/test/browser/fileOnDiskProvider.test.ts rename to src/vs/workbench/contrib/files/test/browser/fileOnDiskProvider.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/files/test/browser/textFileEditorTracker.test.ts b/src/vs/workbench/contrib/files/test/browser/textFileEditorTracker.test.ts similarity index 92% rename from lib/vscode/src/vs/workbench/contrib/files/test/browser/textFileEditorTracker.test.ts rename to src/vs/workbench/contrib/files/test/browser/textFileEditorTracker.test.ts index 5df9a37e687e..bd45cd731f01 100644 --- a/lib/vscode/src/vs/workbench/contrib/files/test/browser/textFileEditorTracker.test.ts +++ b/src/vs/workbench/contrib/files/test/browser/textFileEditorTracker.test.ts @@ -25,6 +25,8 @@ import { IFilesConfigurationService } from 'vs/workbench/services/filesConfigura import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { FILE_EDITOR_INPUT_ID } from 'vs/workbench/contrib/files/common/files'; +import { IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust'; +import { TestWorkspaceTrustRequestService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService'; suite('Files - TextFileEditorTracker', () => { @@ -57,6 +59,7 @@ suite('Files - TextFileEditorTracker', () => { const part = await createEditorPart(instantiationService, disposables); instantiationService.stub(IEditorGroupsService, part); + instantiationService.stub(IWorkspaceTrustRequestService, new TestWorkspaceTrustRequestService(false)); const editorService: EditorService = instantiationService.createInstance(EditorService); instantiationService.stub(IEditorService, editorService); @@ -143,15 +146,15 @@ suite('Files - TextFileEditorTracker', () => { test('dirty untitled text file model opens as editor', async function () { const accessor = await createTracker(); - const untitledEditor = accessor.editorService.createEditorInput({ forceUntitled: true }) as UntitledTextEditorInput; - const model = disposables.add(await untitledEditor.resolve()); + const untitledTextEditor = accessor.editorService.createEditorInput({ forceUntitled: true }) as UntitledTextEditorInput; + const model = disposables.add(await untitledTextEditor.resolve()); - assert.ok(!accessor.editorService.isOpened(untitledEditor)); + assert.ok(!accessor.editorService.isOpened(untitledTextEditor)); model.textEditorModel?.setValue('Super Good'); await awaitEditorOpening(accessor.editorService); - assert.ok(accessor.editorService.isOpened(untitledEditor)); + assert.ok(accessor.editorService.isOpened(untitledTextEditor)); }); function awaitEditorOpening(editorService: IEditorService): Promise { diff --git a/lib/vscode/src/vs/workbench/contrib/format/browser/format.contribution.ts b/src/vs/workbench/contrib/format/browser/format.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/format/browser/format.contribution.ts rename to src/vs/workbench/contrib/format/browser/format.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts rename to src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts diff --git a/lib/vscode/src/vs/workbench/contrib/format/browser/formatActionsNone.ts b/src/vs/workbench/contrib/format/browser/formatActionsNone.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/format/browser/formatActionsNone.ts rename to src/vs/workbench/contrib/format/browser/formatActionsNone.ts diff --git a/lib/vscode/src/vs/workbench/contrib/format/browser/formatModified.ts b/src/vs/workbench/contrib/format/browser/formatModified.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/format/browser/formatModified.ts rename to src/vs/workbench/contrib/format/browser/formatModified.ts diff --git a/lib/vscode/src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts b/src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts similarity index 65% rename from lib/vscode/src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts rename to src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts index 190c892525fa..51965b5220c9 100644 --- a/lib/vscode/src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts +++ b/src/vs/workbench/contrib/issue/browser/issue.web.contribution.ts @@ -13,7 +13,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { CATEGORIES } from 'vs/workbench/common/actions'; import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { IWebIssueService, WebIssueService } from 'vs/workbench/contrib/issue/browser/issueService'; -import { OpenIssueReporterArgs, OpenIssueReporterActionId } from 'vs/workbench/contrib/issue/common/commands'; +import { OpenIssueReporterArgs, OpenIssueReporterActionId, OpenIssueReporterApiCommandId } from 'vs/workbench/contrib/issue/common/commands'; class RegisterIssueContribution implements IWorkbenchContribution { @@ -34,6 +34,53 @@ class RegisterIssueContribution implements IWorkbenchContribution { return accessor.get(IWebIssueService).openReporter({ extensionId }); }); + CommandsRegistry.registerCommand({ + id: OpenIssueReporterApiCommandId, + handler: function (accessor, args?: [string] | OpenIssueReporterArgs) { + let extensionId: string | undefined; + if (args) { + if (Array.isArray(args)) { + [extensionId] = args; + } else { + extensionId = args.extensionId; + } + } + + if (!!extensionId && typeof extensionId !== 'string') { + throw new Error(`Invalid argument when running '${OpenIssueReporterApiCommandId}: 'extensionId' must be of type string `); + } + + return accessor.get(IWebIssueService).openReporter({ extensionId }); + }, + description: { + description: 'Open the issue reporter and optionally prefill part of the form.', + args: [ + { + name: 'options', + description: 'Data to use to prefill the issue reporter with.', + isOptional: true, + schema: { + oneOf: [ + { + type: 'string', + description: 'The extension id to preselect.' + }, + { + type: 'object', + properties: { + extensionId: { + type: 'string' + }, + } + + } + ] + } + }, + ] + } + }); + const command: ICommandAction = { id: OpenIssueReporterActionId, title: { value: OpenIssueReporterActionLabel, original: 'Report Issue' }, diff --git a/lib/vscode/src/vs/workbench/contrib/issue/browser/issueService.ts b/src/vs/workbench/contrib/issue/browser/issueService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/issue/browser/issueService.ts rename to src/vs/workbench/contrib/issue/browser/issueService.ts diff --git a/lib/vscode/src/vs/workbench/contrib/issue/common/commands.ts b/src/vs/workbench/contrib/issue/common/commands.ts similarity index 88% rename from lib/vscode/src/vs/workbench/contrib/issue/common/commands.ts rename to src/vs/workbench/contrib/issue/common/commands.ts index bcd6e252c88c..a5a9ff998f2d 100644 --- a/lib/vscode/src/vs/workbench/contrib/issue/common/commands.ts +++ b/src/vs/workbench/contrib/issue/common/commands.ts @@ -5,6 +5,8 @@ export const OpenIssueReporterActionId = 'workbench.action.openIssueReporter'; +export const OpenIssueReporterApiCommandId = 'vscode.openIssueReporter'; + export interface OpenIssueReporterArgs { readonly extensionId?: string; readonly issueTitle?: string; diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts b/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts new file mode 100644 index 000000000000..c7f49c38f058 --- /dev/null +++ b/src/vs/workbench/contrib/issue/electron-sandbox/issue.contribution.ts @@ -0,0 +1,110 @@ +/*--------------------------------------------------------------------------------------------- + * 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 product from 'vs/platform/product/common/product'; +import { ICommandAction, MenuRegistry, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; +import { CATEGORIES } from 'vs/workbench/common/actions'; +import { ReportPerformanceIssueUsingReporterAction, OpenProcessExplorer } from 'vs/workbench/contrib/issue/electron-sandbox/issueActions'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue'; +import { WorkbenchIssueService } from 'vs/workbench/services/issue/electron-sandbox/issueService'; +import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { IssueReporterData } from 'vs/platform/issue/common/issue'; +import { IIssueService } from 'vs/platform/issue/electron-sandbox/issue'; +import { OpenIssueReporterArgs, OpenIssueReporterActionId, OpenIssueReporterApiCommandId } from 'vs/workbench/contrib/issue/common/commands'; + +if (!!product.reportIssueUrl) { + registerAction2(ReportPerformanceIssueUsingReporterAction); + + CommandsRegistry.registerCommand(OpenIssueReporterActionId, function (accessor, args?: [string] | OpenIssueReporterArgs) { + const data: Partial = Array.isArray(args) + ? { extensionId: args[0] } + : args || {}; + + return accessor.get(IWorkbenchIssueService).openReporter(data); + }); + + CommandsRegistry.registerCommand({ + id: OpenIssueReporterApiCommandId, + handler: function (accessor, args?: [string] | OpenIssueReporterArgs) { + const data: Partial = Array.isArray(args) + ? { extensionId: args[0] } + : args || {}; + + return accessor.get(IWorkbenchIssueService).openReporter(data); + }, + description: { + description: 'Open the issue reporter and optionally prefill part of the form.', + args: [ + { + name: 'options', + description: 'Data to use to prefill the issue reporter with.', + isOptional: true, + schema: { + oneOf: [ + { + type: 'string', + description: 'The extension id to preselect.' + }, + { + type: 'object', + properties: { + extensionId: { + type: 'string' + }, + issueTitle: { + type: 'string' + }, + issueBody: { + type: 'string' + } + } + + } + ] + } + }, + ] + } + }); + + const reportIssue: ICommandAction = { + id: OpenIssueReporterActionId, + title: { + value: localize({ key: 'reportIssueInEnglish', comment: ['Translate this to "Report Issue in English" in all languages please!'] }, "Report Issue..."), + original: 'Report Issue...' + }, + category: CATEGORIES.Help + }; + + MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: reportIssue }); + + MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '3_feedback', + command: { + id: OpenIssueReporterActionId, + title: localize({ key: 'miReportIssue', comment: ['&& denotes a mnemonic', 'Translate this to "Report Issue in English" in all languages please!'] }, "Report &&Issue") + }, + order: 3 + }); +} + +MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '5_tools', + command: { + id: 'workbench.action.openProcessExplorer', + title: localize({ key: 'miOpenProcessExplorerer', comment: ['&& denotes a mnemonic'] }, "Open &&Process Explorer") + }, + order: 2 +}); + +registerAction2(OpenProcessExplorer); + +registerSingleton(IWorkbenchIssueService, WorkbenchIssueService, true); + +CommandsRegistry.registerCommand('_issues.getSystemStatus', (accessor) => { + return accessor.get(IIssueService).getSystemStatus(); +}); diff --git a/src/vs/workbench/contrib/issue/electron-sandbox/issueActions.ts b/src/vs/workbench/contrib/issue/electron-sandbox/issueActions.ts new file mode 100644 index 000000000000..5687050db907 --- /dev/null +++ b/src/vs/workbench/contrib/issue/electron-sandbox/issueActions.ts @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { Action2 } from 'vs/platform/actions/common/actions'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IssueType } from 'vs/platform/issue/common/issue'; +import { CATEGORIES } from 'vs/workbench/common/actions'; +import { IWorkbenchIssueService } from 'vs/workbench/services/issue/common/issue'; + +export class OpenProcessExplorer extends Action2 { + + static readonly ID = 'workbench.action.openProcessExplorer'; + + constructor() { + super({ + id: OpenProcessExplorer.ID, + title: { value: localize('openProcessExplorer', "Open Process Explorer"), original: 'Open Process Explorer' }, + category: CATEGORIES.Developer, + f1: true + }); + } + + override async run(accessor: ServicesAccessor): Promise { + const issueService = accessor.get(IWorkbenchIssueService); + + return issueService.openProcessExplorer(); + } +} + +export class ReportPerformanceIssueUsingReporterAction extends Action2 { + + static readonly ID = 'workbench.action.reportPerformanceIssueUsingReporter'; + + constructor() { + super({ + id: ReportPerformanceIssueUsingReporterAction.ID, + title: { value: localize({ key: 'reportPerformanceIssue', comment: [`Here, 'issue' means problem or bug`] }, "Report Performance Issue"), original: 'Report Performance Issue' }, + category: CATEGORIES.Help, + f1: true + }); + } + + override async run(accessor: ServicesAccessor): Promise { + const issueService = accessor.get(IWorkbenchIssueService); + + return issueService.openReporter({ issueType: IssueType.PerformanceIssue }); + } +} diff --git a/lib/vscode/src/vs/workbench/contrib/keybindings/browser/keybindings.contribution.ts b/src/vs/workbench/contrib/keybindings/browser/keybindings.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/keybindings/browser/keybindings.contribution.ts rename to src/vs/workbench/contrib/keybindings/browser/keybindings.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts b/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts rename to src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/localizations/browser/localizationsActions.ts b/src/vs/workbench/contrib/localizations/browser/localizationsActions.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/localizations/browser/localizationsActions.ts rename to src/vs/workbench/contrib/localizations/browser/localizationsActions.ts index 240ce1053f0a..ad4dd8df5665 100644 --- a/lib/vscode/src/vs/workbench/contrib/localizations/browser/localizationsActions.ts +++ b/src/vs/workbench/contrib/localizations/browser/localizationsActions.ts @@ -41,7 +41,7 @@ export class ConfigureLocaleAction extends Action { return availableLanguages .map(language => { return { label: language }; }) - .concat({ label: localize('installAdditionalLanguages', "Install additional languages...") }); + .concat({ label: localize('installAdditionalLanguages', "Install Additional Languages...") }); } public override async run(): Promise { diff --git a/lib/vscode/src/vs/workbench/contrib/localizations/browser/minimalTranslations.ts b/src/vs/workbench/contrib/localizations/browser/minimalTranslations.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/localizations/browser/minimalTranslations.ts rename to src/vs/workbench/contrib/localizations/browser/minimalTranslations.ts diff --git a/lib/vscode/src/vs/workbench/contrib/logs/common/logConstants.ts b/src/vs/workbench/contrib/logs/common/logConstants.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/logs/common/logConstants.ts rename to src/vs/workbench/contrib/logs/common/logConstants.ts diff --git a/lib/vscode/src/vs/workbench/contrib/logs/common/logs.contribution.ts b/src/vs/workbench/contrib/logs/common/logs.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/logs/common/logs.contribution.ts rename to src/vs/workbench/contrib/logs/common/logs.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/logs/common/logsActions.ts b/src/vs/workbench/contrib/logs/common/logsActions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/logs/common/logsActions.ts rename to src/vs/workbench/contrib/logs/common/logsActions.ts diff --git a/lib/vscode/src/vs/workbench/contrib/logs/common/logsDataCleaner.ts b/src/vs/workbench/contrib/logs/common/logsDataCleaner.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/logs/common/logsDataCleaner.ts rename to src/vs/workbench/contrib/logs/common/logsDataCleaner.ts diff --git a/lib/vscode/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts b/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts rename to src/vs/workbench/contrib/logs/electron-sandbox/logs.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/logs/electron-sandbox/logsActions.ts b/src/vs/workbench/contrib/logs/electron-sandbox/logsActions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/logs/electron-sandbox/logsActions.ts rename to src/vs/workbench/contrib/logs/electron-sandbox/logsActions.ts diff --git a/lib/vscode/src/vs/workbench/contrib/markdown/common/markdownDocumentRenderer.ts b/src/vs/workbench/contrib/markdown/common/markdownDocumentRenderer.ts similarity index 93% rename from lib/vscode/src/vs/workbench/contrib/markdown/common/markdownDocumentRenderer.ts rename to src/vs/workbench/contrib/markdown/common/markdownDocumentRenderer.ts index 41baffa9e132..3eac5b211555 100644 --- a/lib/vscode/src/vs/workbench/contrib/markdown/common/markdownDocumentRenderer.ts +++ b/src/vs/workbench/contrib/markdown/common/markdownDocumentRenderer.ts @@ -18,6 +18,10 @@ body { margin: 0 auto; } +body *:last-child { + margin-bottom: 0; +} + img { max-width: 100%; max-height: 100%; @@ -153,16 +157,17 @@ function removeEmbeddedSVGs(documentContent: string): string { 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7', 'h8', 'br', 'b', 'i', 'strong', 'em', 'a', 'pre', 'code', 'img', 'tt', 'div', 'ins', 'del', 'sup', 'sub', 'p', 'ol', 'ul', 'table', 'thead', 'tbody', 'tfoot', 'blockquote', 'dl', 'dt', 'dd', 'kbd', 'q', 'samp', 'var', 'hr', 'ruby', 'rt', 'rp', 'li', 'tr', 'td', 'th', 's', 'strike', 'summary', 'details', - 'caption', 'figure', 'figcaption', 'abbr', 'bdo', 'cite', 'dfn', 'mark', 'small', 'span', 'time', 'wbr' + 'caption', 'figure', 'figcaption', 'abbr', 'bdo', 'cite', 'dfn', 'mark', 'small', 'span', 'time', 'wbr', 'checkbox', 'checklist', 'vertically-centered' ], allowedAttributes: { '*': [ 'align', ], - img: ['src', 'alt', 'title', 'aria-label', 'width', 'height'], + img: ['src', 'alt', 'title', 'aria-label', 'width', 'height', 'centered'], span: ['class'], + checkbox: ['on-checked', 'checked-on', 'label', 'class'] }, - allowedSchemes: ['http', 'https', 'command',], + allowedSchemes: ['http', 'https', 'command'], filter(token: { tag: string, attrs: { readonly [key: string]: string } }): boolean { return token.tag !== 'svg'; } diff --git a/lib/vscode/src/vs/workbench/contrib/markers/browser/constants.ts b/src/vs/workbench/contrib/markers/browser/constants.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/markers/browser/constants.ts rename to src/vs/workbench/contrib/markers/browser/constants.ts diff --git a/lib/vscode/src/vs/workbench/contrib/markers/browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/markers/browser/markers.contribution.ts rename to src/vs/workbench/contrib/markers/browser/markers.contribution.ts index e0d049f9a566..14b184c6cdb7 100644 --- a/lib/vscode/src/vs/workbench/contrib/markers/browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts @@ -374,7 +374,7 @@ class MarkersStatusBarContributions extends Disposable implements IWorkbenchCont @IStatusbarService private readonly statusbarService: IStatusbarService ) { super(); - this.markersStatusItem = this._register(this.statusbarService.addEntry(this.getMarkersItem(), 'status.problems', localize('status.problems', "Problems"), StatusbarAlignment.LEFT, 50 /* Medium Priority */)); + this.markersStatusItem = this._register(this.statusbarService.addEntry(this.getMarkersItem(), 'status.problems', StatusbarAlignment.LEFT, 50 /* Medium Priority */)); this.markerService.onMarkerChanged(() => this.markersStatusItem.update(this.getMarkersItem())); } @@ -382,6 +382,7 @@ class MarkersStatusBarContributions extends Disposable implements IWorkbenchCont const markersStatistics = this.markerService.getStatistics(); const tooltip = this.getMarkersTooltip(markersStatistics); return { + name: localize('status.problems', "Problems"), text: this.getMarkersText(markersStatistics), ariaLabel: tooltip, tooltip, diff --git a/lib/vscode/src/vs/workbench/contrib/markers/browser/markers.ts b/src/vs/workbench/contrib/markers/browser/markers.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/markers/browser/markers.ts rename to src/vs/workbench/contrib/markers/browser/markers.ts diff --git a/lib/vscode/src/vs/workbench/contrib/markers/browser/markersFileDecorations.ts b/src/vs/workbench/contrib/markers/browser/markersFileDecorations.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/markers/browser/markersFileDecorations.ts rename to src/vs/workbench/contrib/markers/browser/markersFileDecorations.ts diff --git a/lib/vscode/src/vs/workbench/contrib/markers/browser/markersFilterOptions.ts b/src/vs/workbench/contrib/markers/browser/markersFilterOptions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/markers/browser/markersFilterOptions.ts rename to src/vs/workbench/contrib/markers/browser/markersFilterOptions.ts diff --git a/lib/vscode/src/vs/workbench/contrib/markers/browser/markersModel.ts b/src/vs/workbench/contrib/markers/browser/markersModel.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/markers/browser/markersModel.ts rename to src/vs/workbench/contrib/markers/browser/markersModel.ts diff --git a/lib/vscode/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts rename to src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts index d8852663af1c..9b97b4d6bb1c 100644 --- a/lib/vscode/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts +++ b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts @@ -32,7 +32,7 @@ import { Action, IAction } from 'vs/base/common/actions'; import { localize } from 'vs/nls'; import { IDragAndDropData } from 'vs/base/browser/dnd'; import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView'; -import { fillResourceDataTransfers } from 'vs/workbench/browser/dnd'; +import { fillEditorsDragData } from 'vs/workbench/browser/dnd'; import { CancelablePromise, createCancelablePromise, Delayer } from 'vs/base/common/async'; import { IModelService } from 'vs/editor/common/services/modelService'; import { Range } from 'vs/editor/common/core/range'; @@ -892,13 +892,13 @@ export class ResourceDragAndDrop implements ITreeDragAndDrop { onDragStart(data: IDragAndDropData, originalEvent: DragEvent): void { const elements = (data as ElementsDragAndDropData).elements; - const resources: URI[] = elements + const resources = elements .filter(e => e instanceof ResourceMarkers) .map(resourceMarker => (resourceMarker as ResourceMarkers).resource); if (resources.length) { // Apply some datatransfer types to allow for dragging the element outside of the application - this.instantiationService.invokeFunction(fillResourceDataTransfers, resources, undefined, originalEvent); + this.instantiationService.invokeFunction(accessor => fillEditorsDragData(accessor, resources, originalEvent)); } } diff --git a/lib/vscode/src/vs/workbench/contrib/markers/browser/markersView.ts b/src/vs/workbench/contrib/markers/browser/markersView.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/markers/browser/markersView.ts rename to src/vs/workbench/contrib/markers/browser/markersView.ts diff --git a/lib/vscode/src/vs/workbench/contrib/markers/browser/markersViewActions.ts b/src/vs/workbench/contrib/markers/browser/markersViewActions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/markers/browser/markersViewActions.ts rename to src/vs/workbench/contrib/markers/browser/markersViewActions.ts diff --git a/lib/vscode/src/vs/workbench/contrib/markers/browser/media/markers.css b/src/vs/workbench/contrib/markers/browser/media/markers.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/markers/browser/media/markers.css rename to src/vs/workbench/contrib/markers/browser/media/markers.css diff --git a/lib/vscode/src/vs/workbench/contrib/markers/browser/messages.ts b/src/vs/workbench/contrib/markers/browser/messages.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/markers/browser/messages.ts rename to src/vs/workbench/contrib/markers/browser/messages.ts diff --git a/lib/vscode/src/vs/workbench/contrib/markers/test/browser/markersModel.test.ts b/src/vs/workbench/contrib/markers/test/browser/markersModel.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/markers/test/browser/markersModel.test.ts rename to src/vs/workbench/contrib/markers/test/browser/markersModel.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/cellOperations/cellOperations.ts b/src/vs/workbench/contrib/notebook/browser/contrib/cellOperations/cellOperations.ts similarity index 97% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/cellOperations/cellOperations.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/cellOperations/cellOperations.ts index d3ba97f52d78..ffdc4b2e985a 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/cellOperations/cellOperations.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/cellOperations/cellOperations.ts @@ -40,6 +40,12 @@ registerAction2(class extends NotebookCellAction { primary: KeyMod.Alt | KeyCode.UpArrow, when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, InputFocusedContext.toNegated()), weight: KeybindingWeight.WorkbenchContrib + }, + menu: { + id: MenuId.NotebookCellTitle, + when: ContextKeyExpr.equals('config.notebook.dragAndDropEnabled', false), + group: CellOverflowToolbarGroups.Edit, + order: 13 } }); } @@ -60,6 +66,12 @@ registerAction2(class extends NotebookCellAction { primary: KeyMod.Alt | KeyCode.DownArrow, when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, InputFocusedContext.toNegated()), weight: KeybindingWeight.WorkbenchContrib + }, + menu: { + id: MenuId.NotebookCellTitle, + when: ContextKeyExpr.equals('config.notebook.dragAndDropEnabled', false), + group: CellOverflowToolbarGroups.Edit, + order: 14 } }); } diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/cellOperations/test/cellOperations.test.ts b/src/vs/workbench/contrib/notebook/browser/contrib/cellOperations/test/cellOperations.test.ts similarity index 94% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/cellOperations/test/cellOperations.test.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/cellOperations/test/cellOperations.test.ts index 32671d6b33bc..095ab2e39ffb 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/cellOperations/test/cellOperations.test.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/cellOperations/test/cellOperations.test.ts @@ -17,9 +17,9 @@ suite('CellOperations', () => { test('Move cells - single cell', async function () { await withTestNotebook( [ - ['# header a', 'markdown', CellKind.Markdown, [], {}], + ['# header a', 'markdown', CellKind.Markup, [], {}], ['var b = 1;', 'javascript', CellKind.Code, [], {}], - ['# header b', 'markdown', CellKind.Markdown, [], {}], + ['# header b', 'markdown', CellKind.Markup, [], {}], ['var b = 2;', 'javascript', CellKind.Code, [], {}], ['var c = 3;', 'javascript', CellKind.Code, [], {}] ], @@ -34,9 +34,9 @@ suite('CellOperations', () => { test('Move cells - multiple cells in a selection', async function () { await withTestNotebook( [ - ['# header a', 'markdown', CellKind.Markdown, [], {}], + ['# header a', 'markdown', CellKind.Markup, [], {}], ['var b = 1;', 'javascript', CellKind.Code, [], {}], - ['# header b', 'markdown', CellKind.Markdown, [], {}], + ['# header b', 'markdown', CellKind.Markup, [], {}], ['var b = 2;', 'javascript', CellKind.Code, [], {}], ['var c = 3;', 'javascript', CellKind.Code, [], {}] ], @@ -53,9 +53,9 @@ suite('CellOperations', () => { test('Move cells - move with folding ranges', async function () { await withTestNotebook( [ - ['# header a', 'markdown', CellKind.Markdown, [], {}], + ['# header a', 'markdown', CellKind.Markup, [], {}], ['var b = 1;', 'javascript', CellKind.Code, [], {}], - ['# header b', 'markdown', CellKind.Markdown, [], {}], + ['# header b', 'markdown', CellKind.Markup, [], {}], ['var b = 2;', 'javascript', CellKind.Code, [], {}], ['var c = 3;', 'javascript', CellKind.Code, [], {}] ], @@ -80,9 +80,9 @@ suite('CellOperations', () => { test('Copy/duplicate cells - single cell', async function () { await withTestNotebook( [ - ['# header a', 'markdown', CellKind.Markdown, [], {}], + ['# header a', 'markdown', CellKind.Markup, [], {}], ['var b = 1;', 'javascript', CellKind.Code, [], {}], - ['# header b', 'markdown', CellKind.Markdown, [], {}], + ['# header b', 'markdown', CellKind.Markup, [], {}], ['var b = 2;', 'javascript', CellKind.Code, [], {}], ['var c = 3;', 'javascript', CellKind.Code, [], {}] ], @@ -99,9 +99,9 @@ suite('CellOperations', () => { test('Copy/duplicate cells - target and selection are different, #119769', async function () { await withTestNotebook( [ - ['# header a', 'markdown', CellKind.Markdown, [], {}], + ['# header a', 'markdown', CellKind.Markup, [], {}], ['var b = 1;', 'javascript', CellKind.Code, [], {}], - ['# header b', 'markdown', CellKind.Markdown, [], {}], + ['# header b', 'markdown', CellKind.Markup, [], {}], ['var b = 2;', 'javascript', CellKind.Code, [], {}], ['var c = 3;', 'javascript', CellKind.Code, [], {}] ], @@ -118,9 +118,9 @@ suite('CellOperations', () => { test('Copy/duplicate cells - multiple cells in a selection', async function () { await withTestNotebook( [ - ['# header a', 'markdown', CellKind.Markdown, [], {}], + ['# header a', 'markdown', CellKind.Markup, [], {}], ['var b = 1;', 'javascript', CellKind.Code, [], {}], - ['# header b', 'markdown', CellKind.Markdown, [], {}], + ['# header b', 'markdown', CellKind.Markup, [], {}], ['var b = 2;', 'javascript', CellKind.Code, [], {}], ['var c = 3;', 'javascript', CellKind.Code, [], {}] ], @@ -139,9 +139,9 @@ suite('CellOperations', () => { test('Copy/duplicate cells - move with folding ranges', async function () { await withTestNotebook( [ - ['# header a', 'markdown', CellKind.Markdown, [], {}], + ['# header a', 'markdown', CellKind.Markup, [], {}], ['var b = 1;', 'javascript', CellKind.Code, [], {}], - ['# header b', 'markdown', CellKind.Markdown, [], {}], + ['# header b', 'markdown', CellKind.Markup, [], {}], ['var b = 2;', 'javascript', CellKind.Code, [], {}], ['var c = 3;', 'javascript', CellKind.Code, [], {}] ], @@ -168,9 +168,9 @@ suite('CellOperations', () => { test('Join cell with below - single cell', async function () { await withTestNotebook( [ - ['# header a', 'markdown', CellKind.Markdown, [], {}], + ['# header a', 'markdown', CellKind.Markup, [], {}], ['var b = 1;', 'javascript', CellKind.Code, [], {}], - ['# header b', 'markdown', CellKind.Markdown, [], {}], + ['# header b', 'markdown', CellKind.Markup, [], {}], ['var b = 2;', 'javascript', CellKind.Code, [], {}], ['var c = 3;', 'javascript', CellKind.Code, [], {}] ], @@ -196,9 +196,9 @@ suite('CellOperations', () => { test('Join cell with above - single cell', async function () { await withTestNotebook( [ - ['# header a', 'markdown', CellKind.Markdown, [], {}], + ['# header a', 'markdown', CellKind.Markup, [], {}], ['var b = 1;', 'javascript', CellKind.Code, [], {}], - ['# header b', 'markdown', CellKind.Markdown, [], {}], + ['# header b', 'markdown', CellKind.Markup, [], {}], ['var b = 2;', 'javascript', CellKind.Code, [], {}], ['var c = 3;', 'javascript', CellKind.Code, [], {}] ], @@ -445,4 +445,3 @@ suite('CellOperations', () => { }); }); }); - diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts b/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard.ts diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/test/notebookClipboard.test.ts b/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/test/notebookClipboard.test.ts similarity index 86% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/test/notebookClipboard.test.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/clipboard/test/notebookClipboard.test.ts index c881379f4f70..48b600815506 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/test/notebookClipboard.test.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/clipboard/test/notebookClipboard.test.ts @@ -38,9 +38,9 @@ suite('Notebook Clipboard', () => { test('Cut multiple selected cells', async function () { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['paragraph 1', 'markdown', CellKind.Markdown, [], {}], - ['paragraph 2', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 2', 'markdown', CellKind.Markup, [], {}], ], async (editor, accessor) => { accessor.stub(INotebookService, new class extends mock() { override setToCopy() { } }); @@ -59,12 +59,12 @@ suite('Notebook Clipboard', () => { test('Cut should take folding info into account', async function () { await withTestNotebook( [ - ['# header a', 'markdown', CellKind.Markdown, [], {}], + ['# header a', 'markdown', CellKind.Markup, [], {}], ['var b = 1;', 'javascript', CellKind.Code, [], {}], - ['# header b', 'markdown', CellKind.Markdown, [], {}], + ['# header b', 'markdown', CellKind.Markup, [], {}], ['var b = 2;', 'javascript', CellKind.Code, [], {}], - ['var c = 3', 'javascript', CellKind.Markdown, [], {}], - ['# header d', 'markdown', CellKind.Markdown, [], {}], + ['var c = 3', 'javascript', CellKind.Markup, [], {}], + ['# header d', 'markdown', CellKind.Markup, [], {}], ['var e = 4;', 'javascript', CellKind.Code, [], {}], ], async (editor, accessor) => { @@ -91,12 +91,12 @@ suite('Notebook Clipboard', () => { test('Copy should take folding info into account', async function () { await withTestNotebook( [ - ['# header a', 'markdown', CellKind.Markdown, [], {}], + ['# header a', 'markdown', CellKind.Markup, [], {}], ['var b = 1;', 'javascript', CellKind.Code, [], {}], - ['# header b', 'markdown', CellKind.Markdown, [], {}], + ['# header b', 'markdown', CellKind.Markup, [], {}], ['var b = 2;', 'javascript', CellKind.Code, [], {}], - ['var c = 3', 'javascript', CellKind.Markdown, [], {}], - ['# header d', 'markdown', CellKind.Markdown, [], {}], + ['var c = 3', 'javascript', CellKind.Markup, [], {}], + ['# header d', 'markdown', CellKind.Markup, [], {}], ['var e = 4;', 'javascript', CellKind.Code, [], {}], ], async (editor, accessor) => { @@ -129,9 +129,9 @@ suite('Notebook Clipboard', () => { test('#119773, cut last item should not focus on the top first cell', async function () { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['paragraph 1', 'markdown', CellKind.Markdown, [], {}], - ['paragraph 2', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 2', 'markdown', CellKind.Markup, [], {}], ], async (editor, accessor) => { accessor.stub(INotebookService, new class extends mock() { override setToCopy() { } }); @@ -148,9 +148,9 @@ suite('Notebook Clipboard', () => { test('#119771, undo paste should restore selections', async function () { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['paragraph 1', 'markdown', CellKind.Markdown, [], {}], - ['paragraph 2', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 2', 'markdown', CellKind.Markup, [], {}], ], async (editor, accessor) => { accessor.stub(INotebookService, new class extends mock() { @@ -183,9 +183,9 @@ suite('Notebook Clipboard', () => { test('copy cell from ui still works if the target cell is not part of a selection', async () => { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['paragraph 1', 'markdown', CellKind.Markdown, [], {}], - ['paragraph 2', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 2', 'markdown', CellKind.Markup, [], {}], ], async (editor, accessor) => { let _toCopy: NotebookCellTextModel[] = []; @@ -213,10 +213,10 @@ suite('Notebook Clipboard', () => { test('cut cell from ui still works if the target cell is not part of a selection', async () => { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['paragraph 1', 'markdown', CellKind.Markdown, [], {}], - ['paragraph 2', 'markdown', CellKind.Markdown, [], {}], - ['paragraph 3', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 2', 'markdown', CellKind.Markup, [], {}], + ['paragraph 3', 'markdown', CellKind.Markup, [], {}], ], async (editor, accessor) => { accessor.stub(INotebookService, new class extends mock() { @@ -255,10 +255,10 @@ suite('Notebook Clipboard', () => { test('cut focus cell still works if the focus is not part of any selection', async () => { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['paragraph 1', 'markdown', CellKind.Markdown, [], {}], - ['paragraph 2', 'markdown', CellKind.Markdown, [], {}], - ['paragraph 3', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 2', 'markdown', CellKind.Markup, [], {}], + ['paragraph 3', 'markdown', CellKind.Markup, [], {}], ], async (editor, accessor) => { accessor.stub(INotebookService, new class extends mock() { @@ -280,10 +280,10 @@ suite('Notebook Clipboard', () => { test('cut focus cell still works if the focus is not part of any selection 2', async () => { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['paragraph 1', 'markdown', CellKind.Markdown, [], {}], - ['paragraph 2', 'markdown', CellKind.Markdown, [], {}], - ['paragraph 3', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 2', 'markdown', CellKind.Markup, [], {}], + ['paragraph 3', 'markdown', CellKind.Markup, [], {}], ], async (editor, accessor) => { accessor.stub(INotebookService, new class extends mock() { diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts similarity index 66% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts index 2d9af9784ce9..df23ae81bf6b 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts @@ -18,21 +18,27 @@ import { InputFocusedContext, InputFocusedContextKey } from 'vs/platform/context import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput'; -import { BaseCellRenderTemplate, CellEditState, CellFocusMode, EXECUTE_CELL_COMMAND_ID, EXPAND_CELL_INPUT_COMMAND_ID, getNotebookEditorFromEditorPane, IActiveNotebookEditor, ICellViewModel, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_EXECUTION_STATE, NOTEBOOK_CELL_TYPE, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_KERNEL_COUNT, NOTEBOOK_INTERRUPTIBLE_KERNEL, NOTEBOOK_HAS_RUNNING_CELL, CHANGE_CELL_LANGUAGE, QUIT_EDIT_CELL_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { BaseCellRenderTemplate, CellEditState, CellFocusMode, EXECUTE_CELL_COMMAND_ID, EXPAND_CELL_INPUT_COMMAND_ID, getNotebookEditorFromEditorPane, IActiveNotebookEditor, ICellViewModel, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_EXECUTION_STATE, NOTEBOOK_CELL_TYPE, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_KERNEL_COUNT, NOTEBOOK_INTERRUPTIBLE_KERNEL, NOTEBOOK_HAS_RUNNING_CELL, CHANGE_CELL_LANGUAGE, QUIT_EDIT_CELL_COMMAND_ID, NOTEBOOK_USE_CONSOLIDATED_OUTPUT_BUTTON, NOTEBOOK_HAS_OUTPUTS } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellEditType, CellKind, ICellEditOperation, isDocumentExcludePattern, NotebookCellMetadata, NotebookCellExecutionState, TransientCellMetadata, TransientDocumentMetadata, SelectionStateType, ICellReplaceEdit } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange'; +import { ICellRange, isICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import * as icons from 'vs/workbench/contrib/notebook/browser/notebookIcons'; import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput'; -import { EditorsOrder } from 'vs/workbench/common/editor'; +import { EditorsOrder, IEditorCommandsContext } from 'vs/workbench/common/editor'; import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions'; import { NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; import { Iterable } from 'vs/base/common/iterator'; +import { flatten, maxIndex, minIndex } from 'vs/base/common/arrays'; +import { Codicon } from 'vs/base/common/codicons'; + +// Kernel Command +export const SELECT_KERNEL_ID = 'notebook.selectKernel'; // Notebook Commands const EXECUTE_NOTEBOOK_COMMAND_ID = 'notebook.execute'; @@ -56,6 +62,8 @@ const DELETE_CELL_COMMAND_ID = 'notebook.cell.delete'; const CANCEL_CELL_COMMAND_ID = 'notebook.cell.cancelExecution'; const EXECUTE_CELL_SELECT_BELOW = 'notebook.cell.executeAndSelectBelow'; const EXECUTE_CELL_INSERT_BELOW = 'notebook.cell.executeAndInsertBelow'; +const EXECUTE_CELL_AND_BELOW = 'notebook.cell.executeCellAndBelow'; +const EXECUTE_CELLS_ABOVE = 'notebook.cell.executeCellsAbove'; const CLEAR_CELL_OUTPUTS_COMMAND_ID = 'notebook.cell.clearOutputs'; const CENTER_ACTIVE_CELL = 'notebook.centerActiveCell'; @@ -89,7 +97,7 @@ export interface INotebookActionContext { readonly cell?: ICellViewModel; readonly notebookEditor: IActiveNotebookEditor; readonly ui?: boolean; - readonly selectedCells?: ICellViewModel[]; + readonly selectedCells?: readonly ICellViewModel[]; } export interface INotebookCellActionContext extends INotebookActionContext { @@ -175,11 +183,11 @@ export abstract class NotebookAction extends Action2 { super(desc); } - async run(accessor: ServicesAccessor, context?: any): Promise { + async run(accessor: ServicesAccessor, context?: any, ...additionalArgs: any[]): Promise { const isFromUI = !!context; const from = isFromUI ? (this.isNotebookActionContext(context) ? 'notebookToolbar' : 'editorToolbar') : undefined; if (!this.isNotebookActionContext(context)) { - context = this.getEditorContextFromArgsOrActive(accessor, context); + context = this.getEditorContextFromArgsOrActive(accessor, context, ...additionalArgs); if (!context) { return; } @@ -190,7 +198,7 @@ export abstract class NotebookAction extends Action2 { telemetryService.publicLog2('workbenchActionExecuted', { id: this.desc.id, from: from }); } - this.runWithContext(accessor, context); + return this.runWithContext(accessor, context); } abstract runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise; @@ -199,11 +207,78 @@ export abstract class NotebookAction extends Action2 { return !!context && !!(context as INotebookActionContext).notebookEditor; } - protected getEditorContextFromArgsOrActive(accessor: ServicesAccessor, context?: any): INotebookActionContext | undefined { + protected getEditorContextFromArgsOrActive(accessor: ServicesAccessor, context?: any, ...additionalArgs: any[]): INotebookActionContext | undefined { return getContextFromActiveEditor(accessor.get(IEditorService)); } } +// todo@rebornix, replace NotebookAction with this +export abstract class NotebookMultiCellAction extends Action2 { + constructor(desc: IAction2Options) { + if (desc.f1 !== false) { + desc.f1 = false; + const f1Menu = { + id: MenuId.CommandPalette, + when: NOTEBOOK_IS_ACTIVE_EDITOR + }; + + if (!desc.menu) { + desc.menu = []; + } else if (!Array.isArray(desc.menu)) { + desc.menu = [desc.menu]; + } + + desc.menu = [ + ...desc.menu, + f1Menu + ]; + } + + desc.category = NOTEBOOK_ACTIONS_CATEGORY; + + super(desc); + } + + abstract parseArgs(accessor: ServicesAccessor, ...args: any[]): T | undefined; + abstract runWithContext(accessor: ServicesAccessor, context: T): Promise; + + protected isNotebookActionContext(context?: unknown): context is INotebookActionContext { + return !!context && !!(context as INotebookActionContext).notebookEditor; + } + private isEditorContext(context?: unknown): boolean { + return !!context && (context as IEditorCommandsContext).groupId !== undefined; + } + protected getEditorFromArgsOrActivePane(accessor: ServicesAccessor, context?: UriComponents): IActiveNotebookEditor | undefined { + const editorFromUri = getContextFromUri(accessor, context)?.notebookEditor; + + if (editorFromUri) { + return editorFromUri; + } + + const editor = getNotebookEditorFromEditorPane(accessor.get(IEditorService).activeEditorPane); + if (!editor || !editor.hasModel()) { + return; + } + + return editor; + } + + async run(accessor: ServicesAccessor, ...additionalArgs: any[]): Promise { + const context = additionalArgs[0]; + const isFromCellToolbar = this.isNotebookActionContext(context); + const isFromEditorToolbar = this.isEditorContext(context); + const from = isFromCellToolbar ? 'cellToolbar' : (isFromEditorToolbar ? 'editorToolbar' : 'other'); + const parsedArgs = this.parseArgs(accessor, ...additionalArgs); + if (!parsedArgs) { + return; + } + + const telemetryService = accessor.get(ITelemetryService); + telemetryService.publicLog2('workbenchActionExecuted', { id: this.desc.id, from: from }); + return this.runWithContext(accessor, parsedArgs); + } +} + export abstract class NotebookCellAction extends NotebookAction { protected isCellActionContext(context?: unknown): context is INotebookCellActionContext { return !!context && !!(context as INotebookCellActionContext).notebookEditor && !!(context as INotebookCellActionContext).cell; @@ -236,19 +311,195 @@ export abstract class NotebookCellAction extends abstract override runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise; } -const executeCellCondition = ContextKeyExpr.or( - ContextKeyExpr.and( - ContextKeyExpr.or( - ContextKeyExpr.equals(NOTEBOOK_CELL_EXECUTION_STATE.key, 'idle'), - ContextKeyExpr.equals(NOTEBOOK_CELL_EXECUTION_STATE.key, 'succeeded'), - ContextKeyExpr.equals(NOTEBOOK_CELL_EXECUTION_STATE.key, 'failed'), - ), - ContextKeyExpr.greater(NOTEBOOK_KERNEL_COUNT.key, 0)), - NOTEBOOK_CELL_TYPE.isEqualTo('markdown')); +const executeCellCondition = ContextKeyExpr.and( + NOTEBOOK_CELL_TYPE.isEqualTo('code'), + ContextKeyExpr.or( + ContextKeyExpr.equals(NOTEBOOK_CELL_EXECUTION_STATE.key, 'idle'), + ContextKeyExpr.equals(NOTEBOOK_CELL_EXECUTION_STATE.key, 'succeeded'), + ContextKeyExpr.equals(NOTEBOOK_CELL_EXECUTION_STATE.key, 'failed'), + ), + ContextKeyExpr.greater(NOTEBOOK_KERNEL_COUNT.key, 0)); const executeNotebookCondition = ContextKeyExpr.greater(NOTEBOOK_KERNEL_COUNT.key, 0); -registerAction2(class ExecuteCell extends NotebookCellAction { +interface IMultiCellArgs { + ranges: ICellRange[]; + document?: URI; +} + +function isMultiCellArgs(arg: unknown): arg is IMultiCellArgs { + if (arg === undefined) { + return false; + } + const ranges = (arg as IMultiCellArgs).ranges; + if (!ranges) { + return false; + } + + if (!Array.isArray(ranges) || ranges.some(range => !isICellRange(range))) { + return false; + } + + if ((arg as IMultiCellArgs).document) { + const uri = URI.revive((arg as IMultiCellArgs).document); + + if (!uri) { + return false; + } + } + + return true; +} + +function isNotebookActionContext(context?: unknown): context is INotebookActionContext { + return !!context && !!(context as INotebookActionContext).notebookEditor; +} + +function getEditorFromArgsOrActivePane(accessor: ServicesAccessor, context?: UriComponents): IActiveNotebookEditor | undefined { + const editorFromUri = getContextFromUri(accessor, context)?.notebookEditor; + + if (editorFromUri) { + return editorFromUri; + } + + const editor = getNotebookEditorFromEditorPane(accessor.get(IEditorService).activeEditorPane); + if (!editor || !editor.hasModel()) { + return; + } + + return editor; +} + +function parseMultiCellExecutionArgs(accessor: ServicesAccessor, ...args: any[]) { + const firstArg = args[0]; + if (isNotebookActionContext(firstArg)) { + // from UI + return firstArg; + } + + // then it's from keybindings or commands + // todo@rebornix assertType + if (isMultiCellArgs(firstArg)) { + const editor = getEditorFromArgsOrActivePane(accessor, firstArg.document); + if (!editor) { + return; + } + + const ranges = firstArg.ranges; + const selectedCells = flatten(ranges.map(range => editor.viewModel.getCells(range).slice(0))); + return { + notebookEditor: editor, + selectedCells + }; + } + + // handle legacy arguments + if (isICellRange(firstArg)) { + // cellRange, document + const secondArg = args[1]; + const editor = getEditorFromArgsOrActivePane(accessor, secondArg); + if (!editor) { + return; + } + + return { + notebookEditor: editor, + selectedCells: editor.viewModel.getCells(firstArg) + }; + } + + // let's just execute the active cell + const context = getContextFromActiveEditor(accessor.get(IEditorService)); + return context; +} + +registerAction2(class ExecuteAboveCells extends NotebookMultiCellAction { + constructor() { + super({ + id: EXECUTE_CELLS_ABOVE, + precondition: executeCellCondition, + title: localize('notebookActions.executeAbove', "Execute Above Cells"), + menu: [ + { + id: MenuId.NotebookCellExecute, + when: executeCellCondition + }, + { + id: MenuId.NotebookCellTitle, + group: 'inline', + when: ContextKeyExpr.and( + executeCellCondition, + ContextKeyExpr.equals('config.notebook.consolidatedRunButton', false)) + } + ], + icon: icons.executeAboveIcon + }); + } + + parseArgs(accessor: ServicesAccessor, ...args: any[]): INotebookActionContext | undefined { + return parseMultiCellExecutionArgs(accessor, ...args); + } + + async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise { + let endCellIdx: number | undefined = undefined; + if (context.ui && context.cell) { + endCellIdx = context.notebookEditor.viewModel.getCellIndex(context.cell); + } else if (context.selectedCells) { + endCellIdx = maxIndex(context.selectedCells, cell => context.notebookEditor.viewModel.getCellIndex(cell)); + } + + if (typeof endCellIdx === 'number') { + const range = { start: 0, end: endCellIdx }; + const cells = context.notebookEditor.viewModel.getCells(range); + context.notebookEditor.executeNotebookCells(cells); + } + } +}); + +registerAction2(class ExecuteCellAndBelow extends NotebookMultiCellAction { + constructor() { + super({ + id: EXECUTE_CELL_AND_BELOW, + precondition: executeCellCondition, + title: localize('notebookActions.executeBelow', "Execute Cell and Below"), + menu: [ + { + id: MenuId.NotebookCellExecute, + when: executeCellCondition, + }, + { + id: MenuId.NotebookCellTitle, + group: 'inline', + when: ContextKeyExpr.and( + executeCellCondition, + ContextKeyExpr.equals('config.notebook.consolidatedRunButton', false)) + } + ], + icon: icons.executeBelowIcon + }); + } + + parseArgs(accessor: ServicesAccessor, ...args: any[]): INotebookActionContext | undefined { + return parseMultiCellExecutionArgs(accessor, ...args); + } + + async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise { + let startCellIdx: number | undefined = undefined; + if (context.ui && context.cell) { + startCellIdx = context.notebookEditor.viewModel.getCellIndex(context.cell); + } else if (context.selectedCells) { + startCellIdx = minIndex(context.selectedCells, cell => context.notebookEditor.viewModel.getCellIndex(cell)); + } + + if (typeof startCellIdx === 'number') { + const range = { start: startCellIdx, end: context.notebookEditor.viewModel.viewCells.length }; + const cells = context.notebookEditor.viewModel.getCells(range); + context.notebookEditor.executeNotebookCells(cells); + } + } +}); + +registerAction2(class ExecuteCell extends NotebookMultiCellAction { constructor() { super({ id: EXECUTE_CELL_COMMAND_ID, @@ -271,25 +522,35 @@ registerAction2(class ExecuteCell extends NotebookCellAction { description: localize('notebookActions.execute', "Execute Cell"), args: [ { - name: 'range', - description: 'The cell range', + name: 'options', + description: 'The cell range options', schema: { 'type': 'object', - 'required': ['start', 'end'], + 'required': ['ranges'], 'properties': { - 'start': { - 'type': 'number' + 'ranges': { + 'type': 'array', + items: [ + { + 'type': 'object', + 'required': ['start', 'end'], + 'properties': { + 'start': { + 'type': 'number' + }, + 'end': { + 'type': 'number' + } + } + } + ] }, - 'end': { - 'type': 'number' + 'document': { + 'type': 'object', + 'description': 'The document uri', } } } - }, - { - name: 'uri', - description: 'The document uri', - constraint: URI } ] }, @@ -297,47 +558,11 @@ registerAction2(class ExecuteCell extends NotebookCellAction { }); } - override getCellContextFromArgs(accessor: ServicesAccessor, context?: ICellRange, ...additionalArgs: any[]): INotebookCellActionContext | undefined { - if (!context) { - return; - } - - if (typeof context.start !== 'number' || typeof context.end !== 'number' || context.start >= context.end) { - throw new Error(`The first argument '${context}' is not a valid CellRange`); - } - - if (additionalArgs.length && additionalArgs[0]) { - const uri = URI.revive(additionalArgs[0]); - - if (!uri) { - throw new Error(`The second argument '${uri}' is not a valid Uri`); - } - - const widget = getWidgetFromUri(accessor, uri); - if (widget) { - return { - notebookEditor: widget, - cell: widget.viewModel.cellAt(context.start)! - }; - } else { - throw new Error(`There is no editor opened for resource ${uri}`); - } - } - - const activeEditorContext = this.getEditorContextFromArgsOrActive(accessor); - - if (!activeEditorContext || !activeEditorContext.notebookEditor.viewModel || context.start >= activeEditorContext.notebookEditor.viewModel.length) { - return; - } - - // TODO@rebornix, support multiple cells - return { - notebookEditor: activeEditorContext.notebookEditor, - cell: activeEditorContext.notebookEditor.viewModel.cellAt(context.start)! - }; + parseArgs(accessor: ServicesAccessor, ...args: any[]): INotebookActionContext | undefined { + return parseMultiCellExecutionArgs(accessor, ...args); } - async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise { + async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise { return runCell(accessor, context); } }); @@ -347,7 +572,7 @@ const cellCancelCondition = ContextKeyExpr.or( ContextKeyExpr.equals(NOTEBOOK_CELL_EXECUTION_STATE.key, 'pending'), ); -registerAction2(class CancelExecuteCell extends NotebookCellAction { +registerAction2(class CancelExecuteCell extends NotebookMultiCellAction { constructor() { super({ id: CANCEL_CELL_COMMAND_ID, @@ -363,65 +588,51 @@ registerAction2(class CancelExecuteCell extends NotebookCellAction { description: localize('notebookActions.cancel', "Stop Cell Execution"), args: [ { - name: 'range', - description: 'The cell range', + name: 'options', + description: 'The cell range options', schema: { 'type': 'object', - 'required': ['start', 'end'], + 'required': ['ranges'], 'properties': { - 'start': { - 'type': 'number' + 'ranges': { + 'type': 'array', + items: [ + { + 'type': 'object', + 'required': ['start', 'end'], + 'properties': { + 'start': { + 'type': 'number' + }, + 'end': { + 'type': 'number' + } + } + } + ] }, - 'end': { - 'type': 'number' + 'document': { + 'type': 'object', + 'description': 'The document uri', } } } - }, - { - name: 'uri', - description: 'The document uri', - constraint: URI } ] }, }); } - override getCellContextFromArgs(accessor: ServicesAccessor, context?: ICellRange, ...additionalArgs: any[]): INotebookCellActionContext | undefined { - if (!context || typeof context.start !== 'number' || typeof context.end !== 'number' || context.start >= context.end) { - return; - } - - if (additionalArgs.length && additionalArgs[0]) { - const uri = URI.revive(additionalArgs[0]); - - if (uri) { - const widget = getWidgetFromUri(accessor, uri); - if (widget) { - return { - notebookEditor: widget, - cell: widget.viewModel.cellAt(context.start)! - }; - } - } - } - - const activeEditorContext = this.getEditorContextFromArgsOrActive(accessor); - - if (!activeEditorContext || !activeEditorContext.notebookEditor.viewModel || context.start >= activeEditorContext.notebookEditor.viewModel.length) { - return; - } - - // TODO@rebornix, support multiple cells - return { - notebookEditor: activeEditorContext.notebookEditor, - cell: activeEditorContext.notebookEditor.viewModel.cellAt(context.start)! - }; + parseArgs(accessor: ServicesAccessor, ...args: any[]): INotebookActionContext | undefined { + return parseMultiCellExecutionArgs(accessor, ...args); } - async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise { - return context.notebookEditor.cancelNotebookCells(Iterable.single(context.cell)); + async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise { + if (context.ui && context.cell) { + return context.notebookEditor.cancelNotebookCells(Iterable.single(context.cell)); + } else if (context.selectedCells) { + return context.notebookEditor.cancelNotebookCells(context.selectedCells); + } } }); @@ -448,7 +659,7 @@ registerAction2(class ExecuteCellSelectBelow extends NotebookCellAction { constructor() { super({ id: EXECUTE_CELL_SELECT_BELOW, - precondition: executeCellCondition, + precondition: ContextKeyExpr.or(executeCellCondition, NOTEBOOK_CELL_TYPE.isEqualTo('markup')), title: localize('notebookActions.executeAndSelectBelow', "Execute Notebook Cell and Select Below"), keybinding: { when: NOTEBOOK_CELL_LIST_FOCUSED, @@ -464,20 +675,33 @@ registerAction2(class ExecuteCellSelectBelow extends NotebookCellAction { return; } - const executionP = runCell(accessor, context); - - // Try to select below, fall back on inserting - const nextCell = context.notebookEditor.viewModel.cellAt(idx + 1); - if (nextCell) { - context.notebookEditor.focusNotebookCell(nextCell, 'container'); + if (context.cell.cellKind === CellKind.Markup) { + const nextCell = context.notebookEditor.viewModel.cellAt(idx + 1); + if (nextCell) { + context.notebookEditor.focusNotebookCell(nextCell, 'container'); + } else { + const newCell = context.notebookEditor.insertNotebookCell(context.cell, CellKind.Markup, 'below'); + if (newCell) { + context.notebookEditor.focusNotebookCell(newCell, 'editor'); + } + } + return; } else { - const newCell = context.notebookEditor.insertNotebookCell(context.cell, CellKind.Code, 'below'); - if (newCell) { - context.notebookEditor.focusNotebookCell(newCell, 'editor'); + const executionP = runCell(accessor, context); + + // Try to select below, fall back on inserting + const nextCell = context.notebookEditor.viewModel.cellAt(idx + 1); + if (nextCell) { + context.notebookEditor.focusNotebookCell(nextCell, 'container'); + } else { + const newCell = context.notebookEditor.insertNotebookCell(context.cell, CellKind.Code, 'below'); + if (newCell) { + context.notebookEditor.focusNotebookCell(newCell, 'editor'); + } } - } - return executionP; + return executionP; + } } }); @@ -508,7 +732,7 @@ registerAction2(class ExecuteCellInsertBelow extends NotebookCellAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class RenderAllMarkdownCellsAction extends NotebookAction { constructor() { super({ id: RENDER_ALL_MARKDOWN_CELLS, @@ -521,28 +745,44 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class ExecuteNotebookAction extends NotebookAction { constructor() { super({ id: EXECUTE_NOTEBOOK_COMMAND_ID, - title: localize('notebookActions.executeNotebook', "Execute Notebook (Run all cells)"), + title: localize('notebookActions.executeNotebook', "Run All"), icon: icons.executeAllIcon, description: { - description: localize('notebookActions.executeNotebook', "Execute Notebook (Run all cells)"), + description: localize('notebookActions.executeNotebook', "Run All"), args: [ { name: 'uri', - description: 'The document uri', - constraint: URI + description: 'The document uri' } ] }, - menu: { - id: MenuId.EditorTitle, - order: -1, - group: 'navigation', - when: ContextKeyExpr.and(NOTEBOOK_IS_ACTIVE_EDITOR, executeNotebookCondition, ContextKeyExpr.or(NOTEBOOK_INTERRUPTIBLE_KERNEL.toNegated(), NOTEBOOK_HAS_RUNNING_CELL.toNegated())), - } + menu: [ + { + id: MenuId.EditorTitle, + order: -1, + group: 'navigation', + when: ContextKeyExpr.and( + NOTEBOOK_IS_ACTIVE_EDITOR, + executeNotebookCondition, + ContextKeyExpr.or(NOTEBOOK_INTERRUPTIBLE_KERNEL.toNegated(), NOTEBOOK_HAS_RUNNING_CELL.toNegated()), + ContextKeyExpr.notEquals('config.notebook.globalToolbar', true) + ) + }, + { + id: MenuId.NotebookToolbar, + order: -1, + group: 'navigation/execute', + when: ContextKeyExpr.and( + executeNotebookCondition, + ContextKeyExpr.or(NOTEBOOK_INTERRUPTIBLE_KERNEL.toNegated(), NOTEBOOK_HAS_RUNNING_CELL.toNegated()), + ContextKeyExpr.equals('config.notebook.globalToolbar', true) + ) + } + ] }); } @@ -569,7 +809,7 @@ registerAction2(class extends NotebookAction { function renderAllMarkdownCells(context: INotebookActionContext): void { context.notebookEditor.viewModel.viewCells.forEach(cell => { - if (cell.cellKind === CellKind.Markdown) { + if (cell.cellKind === CellKind.Markup) { cell.updateEditState(CellEditState.Preview, 'renderAllMarkdownCells'); } }); @@ -579,10 +819,10 @@ registerAction2(class CancelNotebook extends NotebookAction { constructor() { super({ id: CANCEL_NOTEBOOK_COMMAND_ID, - title: localize('notebookActions.cancelNotebook', "Stop Notebook Execution"), + title: localize('notebookActions.cancelNotebook', "Stop Execution"), icon: icons.stopIcon, description: { - description: localize('notebookActions.cancelNotebook', "Stop Notebook Execution"), + description: localize('notebookActions.cancelNotebook', "Stop Execution"), args: [ { name: 'uri', @@ -591,12 +831,29 @@ registerAction2(class CancelNotebook extends NotebookAction { } ] }, - menu: { - id: MenuId.EditorTitle, - order: -1, - group: 'navigation', - when: ContextKeyExpr.and(NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_HAS_RUNNING_CELL, NOTEBOOK_INTERRUPTIBLE_KERNEL) - } + menu: [ + { + id: MenuId.EditorTitle, + order: -1, + group: 'navigation', + when: ContextKeyExpr.and( + NOTEBOOK_IS_ACTIVE_EDITOR, + NOTEBOOK_HAS_RUNNING_CELL, + NOTEBOOK_INTERRUPTIBLE_KERNEL, + ContextKeyExpr.notEquals('config.notebook.globalToolbar', true) + ) + }, + { + id: MenuId.NotebookToolbar, + order: -1, + group: 'navigation/execute', + when: ContextKeyExpr.and( + NOTEBOOK_HAS_RUNNING_CELL, + NOTEBOOK_INTERRUPTIBLE_KERNEL, + ContextKeyExpr.equals('config.notebook.globalToolbar', true) + ) + } + ] }); } @@ -623,7 +880,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorContext, { when: NOTEBOOK_EDITOR_FOCUSED }); -registerAction2(class extends NotebookCellAction { +registerAction2(class ChangeCellToCodeAction extends NotebookCellAction { constructor() { super({ id: CHANGE_CELL_TO_CODE_COMMAND_ID, @@ -633,10 +890,10 @@ registerAction2(class extends NotebookCellAction { primary: KeyCode.KEY_Y, weight: KeybindingWeight.WorkbenchContrib }, - precondition: ContextKeyExpr.and(NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_CELL_TYPE.isEqualTo('markdown')), + precondition: ContextKeyExpr.and(NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_CELL_TYPE.isEqualTo('markup')), menu: { id: MenuId.NotebookCellTitle, - when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_TYPE.isEqualTo('markdown')), + when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_TYPE.isEqualTo('markup')), group: CellOverflowToolbarGroups.Edit, } }); @@ -647,7 +904,7 @@ registerAction2(class extends NotebookCellAction { } }); -registerAction2(class extends NotebookCellAction { +registerAction2(class ChangeCellToMarkdownAction extends NotebookCellAction { constructor() { super({ id: CHANGE_CELL_TO_MARKDOWN_COMMAND_ID, @@ -667,14 +924,11 @@ registerAction2(class extends NotebookCellAction { } async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise { - await changeCellToKind(CellKind.Markdown, context); + await changeCellToKind(CellKind.Markup, context); } }); -async function runCell(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise { - if (context.cell.metadata?.runState === NotebookCellExecutionState.Executing) { - return; - } +async function runCell(accessor: ServicesAccessor, context: INotebookActionContext): Promise { const editorGroupService = accessor.get(IEditorGroupsService); const group = editorGroupService.activeGroup; @@ -685,11 +939,13 @@ async function runCell(accessor: ServicesAccessor, context: INotebookCellActionC } } - if (context.cell.cellKind === CellKind.Markdown) { - context.notebookEditor.focusNotebookCell(context.cell, 'container'); - return; - } else { + if (context.ui && context.cell) { + if (context.cell.internalMetadata.runState === NotebookCellExecutionState.Executing) { + return; + } return context.notebookEditor.executeNotebookCells(Iterable.single(context.cell)); + } else if (context.selectedCells) { + return context.notebookEditor.executeNotebookCells(context.selectedCells); } } @@ -751,11 +1007,17 @@ abstract class InsertCellCommand extends NotebookAction { } async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise { - context.notebookEditor.insertNotebookCell(context.cell, this.kind, this.direction, undefined, true); + if (context.cell) { + context.notebookEditor.insertNotebookCell(context.cell, this.kind, this.direction, undefined, true); + } else { + const focusRange = context.notebookEditor.getFocus(); + const next = focusRange.end - 1; + context.notebookEditor.insertNotebookCell(context.notebookEditor.viewModel.viewCells[next], this.kind, this.direction, undefined, true); + } } } -registerAction2(class extends InsertCellCommand { +registerAction2(class InsertCodeCellAboveAction extends InsertCellCommand { constructor() { super( { @@ -776,7 +1038,7 @@ registerAction2(class extends InsertCellCommand { } }); -registerAction2(class extends InsertCellCommand { +registerAction2(class InsertCodeCellBelowAction extends InsertCellCommand { constructor() { super( { @@ -797,7 +1059,7 @@ registerAction2(class extends InsertCellCommand { } }); -registerAction2(class extends NotebookAction { +registerAction2(class InsertCodeCellAtTopAction extends NotebookAction { constructor() { super( { @@ -822,7 +1084,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class InsertMarkdownCellAtTopAction extends NotebookAction { constructor() { super( { @@ -840,7 +1102,7 @@ registerAction2(class extends NotebookAction { } async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise { - const newCell = context.notebookEditor.insertNotebookCell(undefined, CellKind.Markdown, 'above', undefined, true); + const newCell = context.notebookEditor.insertNotebookCell(undefined, CellKind.Markup, 'above', undefined, true); if (newCell) { context.notebookEditor.focusNotebookCell(newCell, 'editor'); } @@ -855,7 +1117,41 @@ MenuRegistry.appendMenuItem(MenuId.NotebookCellBetween, { }, order: 0, group: 'inline', - when: NOTEBOOK_EDITOR_EDITABLE.isEqualTo(true) + when: ContextKeyExpr.and( + NOTEBOOK_EDITOR_EDITABLE.isEqualTo(true), + ContextKeyExpr.notEquals('config.notebook.experimental.insertToolbarAlignment', 'left') + ) +}); + +MenuRegistry.appendMenuItem(MenuId.NotebookCellBetween, { + command: { + id: INSERT_CODE_CELL_BELOW_COMMAND_ID, + title: localize('notebookActions.menu.insertCode.minimalToolbar', "Add Code"), + icon: Codicon.add, + tooltip: localize('notebookActions.menu.insertCode.tooltip', "Add Code Cell") + }, + order: 0, + group: 'inline', + when: ContextKeyExpr.and( + NOTEBOOK_EDITOR_EDITABLE.isEqualTo(true), + ContextKeyExpr.equals('config.notebook.experimental.insertToolbarAlignment', 'left') + ) +}); + +MenuRegistry.appendMenuItem(MenuId.NotebookToolbar, { + command: { + id: INSERT_CODE_CELL_BELOW_COMMAND_ID, + icon: Codicon.add, + title: localize('notebookActions.menu.insertCode.ontoolbar', "Code"), + tooltip: localize('notebookActions.menu.insertCode.tooltip', "Add Code Cell") + }, + order: -5, + group: 'navigation/add', + when: ContextKeyExpr.and( + NOTEBOOK_EDITOR_EDITABLE.isEqualTo(true), + ContextKeyExpr.notEquals('config.notebook.insertToolbarLocation', 'betweenCells'), + ContextKeyExpr.notEquals('config.notebook.insertToolbarLocation', 'hidden') + ) }); MenuRegistry.appendMenuItem(MenuId.NotebookCellListTop, { @@ -866,10 +1162,28 @@ MenuRegistry.appendMenuItem(MenuId.NotebookCellListTop, { }, order: 0, group: 'inline', - when: NOTEBOOK_EDITOR_EDITABLE.isEqualTo(true) + when: ContextKeyExpr.and( + NOTEBOOK_EDITOR_EDITABLE.isEqualTo(true), + ContextKeyExpr.notEquals('config.notebook.experimental.insertToolbarAlignment', 'left') + ) +}); + +MenuRegistry.appendMenuItem(MenuId.NotebookCellListTop, { + command: { + id: INSERT_CODE_CELL_AT_TOP_COMMAND_ID, + title: localize('notebookActions.menu.insertCode.minimaltoolbar', "Add Code"), + icon: Codicon.add, + tooltip: localize('notebookActions.menu.insertCode.tooltip', "Add Code Cell") + }, + order: 0, + group: 'inline', + when: ContextKeyExpr.and( + NOTEBOOK_EDITOR_EDITABLE.isEqualTo(true), + ContextKeyExpr.equals('config.notebook.experimental.insertToolbarAlignment', 'left') + ) }); -registerAction2(class extends InsertCellCommand { +registerAction2(class InsertMarkdownCellAboveAction extends InsertCellCommand { constructor() { super( { @@ -880,12 +1194,12 @@ registerAction2(class extends InsertCellCommand { order: 2 } }, - CellKind.Markdown, + CellKind.Markup, 'above'); } }); -registerAction2(class extends InsertCellCommand { +registerAction2(class InsertMarkdownCellBelowAction extends InsertCellCommand { constructor() { super( { @@ -896,7 +1210,7 @@ registerAction2(class extends InsertCellCommand { order: 3 } }, - CellKind.Markdown, + CellKind.Markup, 'below'); } }); @@ -909,7 +1223,26 @@ MenuRegistry.appendMenuItem(MenuId.NotebookCellBetween, { }, order: 1, group: 'inline', - when: NOTEBOOK_EDITOR_EDITABLE.isEqualTo(true) + when: ContextKeyExpr.and( + NOTEBOOK_EDITOR_EDITABLE.isEqualTo(true), + ContextKeyExpr.notEquals('config.notebook.experimental.insertToolbarAlignment', 'left') + ) +}); + +MenuRegistry.appendMenuItem(MenuId.NotebookToolbar, { + command: { + id: INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID, + icon: Codicon.add, + title: localize('notebookActions.menu.insertMarkdown.ontoolbar', "Markdown"), + tooltip: localize('notebookActions.menu.insertMarkdown.tooltip', "Add Markdown Cell") + }, + order: -5, + group: 'navigation/add', + when: ContextKeyExpr.and( + NOTEBOOK_EDITOR_EDITABLE.isEqualTo(true), + ContextKeyExpr.notEquals('config.notebook.insertToolbarLocation', 'betweenCells'), + ContextKeyExpr.notEquals('config.notebook.insertToolbarLocation', 'hidden') + ) }); MenuRegistry.appendMenuItem(MenuId.NotebookCellListTop, { @@ -920,10 +1253,13 @@ MenuRegistry.appendMenuItem(MenuId.NotebookCellListTop, { }, order: 1, group: 'inline', - when: NOTEBOOK_EDITOR_EDITABLE.isEqualTo(true) + when: ContextKeyExpr.and( + NOTEBOOK_EDITOR_EDITABLE.isEqualTo(true), + ContextKeyExpr.notEquals('config.notebook.experimental.insertToolbarAlignment', 'left') + ) }); -registerAction2(class extends NotebookCellAction { +registerAction2(class EditCellAction extends NotebookCellAction { constructor() { super( { @@ -937,7 +1273,7 @@ registerAction2(class extends NotebookCellAction { menu: { id: MenuId.NotebookCellTitle, when: ContextKeyExpr.and( - NOTEBOOK_CELL_TYPE.isEqualTo('markdown'), + NOTEBOOK_CELL_TYPE.isEqualTo('markup'), NOTEBOOK_CELL_MARKDOWN_EDIT_MODE.toNegated(), NOTEBOOK_CELL_EDITABLE), order: CellToolbarOrder.EditCell, @@ -952,7 +1288,14 @@ registerAction2(class extends NotebookCellAction { } }); -registerAction2(class extends NotebookCellAction { +const quitEditCondition = ContextKeyExpr.and( + NOTEBOOK_EDITOR_FOCUSED, + InputFocusedContext, + EditorContextKeys.hoverVisible.toNegated(), + EditorContextKeys.hasNonEmptySelection.toNegated(), + EditorContextKeys.hasMultipleSelections.toNegated() +); +registerAction2(class QuitEditCellAction extends NotebookCellAction { constructor() { super( { @@ -961,29 +1304,35 @@ registerAction2(class extends NotebookCellAction { menu: { id: MenuId.NotebookCellTitle, when: ContextKeyExpr.and( - NOTEBOOK_CELL_TYPE.isEqualTo('markdown'), + NOTEBOOK_CELL_TYPE.isEqualTo('markup'), NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_EDITABLE), order: CellToolbarOrder.SaveCell, group: CELL_TITLE_CELL_GROUP_ID }, icon: icons.stopEditIcon, - keybinding: { - when: ContextKeyExpr.and( - NOTEBOOK_EDITOR_FOCUSED, - InputFocusedContext, - EditorContextKeys.hoverVisible.toNegated(), - EditorContextKeys.hasNonEmptySelection.toNegated(), - EditorContextKeys.hasMultipleSelections.toNegated() - ), - primary: KeyCode.Escape, - weight: NOTEBOOK_EDITOR_WIDGET_ACTION_WEIGHT - 5 - }, + keybinding: [ + { + when: quitEditCondition, + primary: KeyCode.Escape, + weight: NOTEBOOK_EDITOR_WIDGET_ACTION_WEIGHT - 5 + }, + { + when: ContextKeyExpr.and( + quitEditCondition, + NOTEBOOK_CELL_TYPE.isEqualTo('markup')), + primary: KeyMod.WinCtrl | KeyCode.Enter, + win: { + primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Enter + }, + weight: NOTEBOOK_EDITOR_WIDGET_ACTION_WEIGHT + }, + ] }); } async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext) { - if (context.cell.cellKind === CellKind.Markdown) { + if (context.cell.cellKind === CellKind.Markup) { context.cell.updateEditState(CellEditState.Preview, QUIT_EDIT_CELL_COMMAND_ID); } @@ -1054,7 +1403,7 @@ export function runDeleteAction(viewModel: NotebookViewModel, cell: ICellViewMod } } -registerAction2(class extends NotebookCellAction { +registerAction2(class DeleteCellAction extends NotebookCellAction { constructor() { super( { @@ -1086,17 +1435,23 @@ registerAction2(class extends NotebookCellAction { } }); -registerAction2(class extends NotebookCellAction { +registerAction2(class ClearCellOutputsAction extends NotebookCellAction { constructor() { super({ id: CLEAR_CELL_OUTPUTS_COMMAND_ID, title: localize('clearCellOutputs', 'Clear Cell Outputs'), - menu: { - id: MenuId.NotebookCellTitle, - when: ContextKeyExpr.and(NOTEBOOK_CELL_TYPE.isEqualTo('code'), executeNotebookCondition, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_EDITABLE), - order: CellToolbarOrder.ClearCellOutput, - group: CELL_TITLE_OUTPUT_GROUP_ID - }, + menu: [ + { + id: MenuId.NotebookCellTitle, + when: ContextKeyExpr.and(NOTEBOOK_CELL_TYPE.isEqualTo('code'), executeNotebookCondition, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_USE_CONSOLIDATED_OUTPUT_BUTTON.toNegated()), + order: CellToolbarOrder.ClearCellOutput, + group: CELL_TITLE_OUTPUT_GROUP_ID + }, + { + id: MenuId.NotebookOutputToolbar, + when: ContextKeyExpr.and(NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_EDITABLE) + }, + ], keybinding: { when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, ContextKeyExpr.not(InputFocusedContextKey), NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_EDITABLE), primary: KeyMod.Alt | KeyCode.Delete, @@ -1121,16 +1476,15 @@ registerAction2(class extends NotebookCellAction { editor.viewModel.notebookDocument.applyEdits([{ editType: CellEditType.Output, index, outputs: [] }], true, undefined, () => undefined, undefined); - if (context.cell.metadata && context.cell.metadata?.runState !== NotebookCellExecutionState.Executing) { + if (context.cell.internalMetadata.runState !== NotebookCellExecutionState.Executing) { context.notebookEditor.viewModel.notebookDocument.applyEdits([{ - editType: CellEditType.Metadata, index, metadata: { - ...context.cell.metadata, - runState: NotebookCellExecutionState.Idle, - runStartTime: undefined, - runStartTimeAdjustment: undefined, - runEndTime: undefined, - executionOrder: undefined, - lastRunSuccess: undefined + editType: CellEditType.PartialInternalMetadata, index, internalMetadata: { + runState: null, + runStartTime: null, + runStartTimeAdjustment: null, + runEndTime: null, + executionOrder: null, + lastRunSuccess: null } }], true, undefined, () => undefined, undefined); } @@ -1229,7 +1583,7 @@ registerAction2(class ChangeCellLanguageAction extends NotebookCellAction { let description: string; - if (context.cell.cellKind === CellKind.Markdown ? (languageId === 'markdown') : (languageId === context.cell.language)) { + if (context.cell.cellKind === CellKind.Markup ? (languageId === 'markdown') : (languageId === context.cell.language)) { description = localize('languageDescription', "({0}) - Current Language", languageId); } else { description = localize('languageDescriptionConfigured', "({0})", languageId); @@ -1273,11 +1627,11 @@ registerAction2(class ChangeCellLanguageAction extends NotebookCellAction undefined, undefined); const clearExecutionMetadataEdits = editor.viewModel.notebookDocument.cells.map((cell, index) => { - if (cell.metadata && cell.metadata?.runState !== NotebookCellExecutionState.Executing) { + if (cell.internalMetadata.runState !== NotebookCellExecutionState.Executing) { return { - editType: CellEditType.Metadata, index, metadata: { - ...cell.metadata, - runState: NotebookCellExecutionState.Idle, - runStartTime: undefined, - runStartTimeAdjustment: undefined, - runEndTime: undefined, - executionOrder: undefined + editType: CellEditType.PartialInternalMetadata, index, internalMetadata: { + runState: null, + runStartTime: null, + runStartTimeAdjustment: null, + runEndTime: null, + executionOrder: null, + lastRunSuccess: null } }; } else { @@ -1356,7 +1725,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookCellAction { +registerAction2(class CenterActiveCellAction extends NotebookCellAction { constructor() { super({ id: CENTER_ACTIVE_CELL, @@ -1400,7 +1769,7 @@ abstract class ChangeNotebookCellMetadataAction extends NotebookCellAction { abstract getMetadataDelta(): NotebookCellMetadata; } -registerAction2(class extends ChangeNotebookCellMetadataAction { +registerAction2(class CollapseCellInputAction extends ChangeNotebookCellMetadataAction { constructor() { super({ id: COLLAPSE_CELL_INPUT_COMMAND_ID, @@ -1423,7 +1792,7 @@ registerAction2(class extends ChangeNotebookCellMetadataAction { } }); -registerAction2(class extends ChangeNotebookCellMetadataAction { +registerAction2(class ExpandCellInputAction extends ChangeNotebookCellMetadataAction { constructor() { super({ id: EXPAND_CELL_INPUT_COMMAND_ID, @@ -1446,7 +1815,7 @@ registerAction2(class extends ChangeNotebookCellMetadataAction { } }); -registerAction2(class extends ChangeNotebookCellMetadataAction { +registerAction2(class CollapseCellOutputAction extends ChangeNotebookCellMetadataAction { constructor() { super({ id: COLLAPSE_CELL_OUTPUT_COMMAND_ID, @@ -1469,7 +1838,7 @@ registerAction2(class extends ChangeNotebookCellMetadataAction { } }); -registerAction2(class extends ChangeNotebookCellMetadataAction { +registerAction2(class ExpandCellOuputAction extends ChangeNotebookCellMetadataAction { constructor() { super({ id: EXPAND_CELL_OUTPUT_COMMAND_ID, @@ -1492,16 +1861,65 @@ registerAction2(class extends ChangeNotebookCellMetadataAction { } }); -// Revisit once we have a story for trusted workspace -CommandsRegistry.registerCommand('notebook.trust', (accessor, args) => { - const uri = URI.revive(args as UriComponents); - const notebookService = accessor.get(INotebookService); - - - const document = notebookService.listNotebookDocuments().find(document => document.uri.toString() === uri.toString()); +registerAction2(class NotebookConfigureLayoutAction extends Action2 { + constructor() { + super({ + id: 'workbench.notebook.layout.select', + title: localize('workbench.notebook.layout.select.label', "Select between Notebook Layouts"), + f1: true, + category: NOTEBOOK_ACTIONS_CATEGORY, + menu: [ + { + id: MenuId.EditorTitle, + group: 'notebookLayout', + when: ContextKeyExpr.and( + NOTEBOOK_IS_ACTIVE_EDITOR, + ContextKeyExpr.notEquals('config.notebook.globalToolbar', true) + ), + order: 0 + }, + { + id: MenuId.NotebookToolbar, + group: 'notebookLayout', + when: ContextKeyExpr.equals('config.notebook.globalToolbar', true), + order: 0 + } + ] + }); + } + run(accessor: ServicesAccessor): void { + accessor.get(ICommandService).executeCommand('workbench.action.openWalkthrough', { category: 'notebooks', step: 'notebookProfile' }, true); + } +}); - if (document) { - document.applyEdits([{ editType: CellEditType.DocumentMetadata, metadata: { ...document.metadata, ...{ trusted: true } } }], true, undefined, () => undefined, undefined, false); +registerAction2(class NotebookConfigureLayoutAction extends Action2 { + constructor() { + super({ + id: 'workbench.notebook.layout.configure', + title: localize('workbench.notebook.layout.configure.label', "Customize Notebook Layout"), + f1: true, + category: NOTEBOOK_ACTIONS_CATEGORY, + menu: [ + { + id: MenuId.EditorTitle, + group: 'notebookLayout', + when: ContextKeyExpr.and( + NOTEBOOK_IS_ACTIVE_EDITOR, + ContextKeyExpr.notEquals('config.notebook.globalToolbar', true) + ), + order: 1 + }, + { + id: MenuId.NotebookToolbar, + group: 'notebookLayout', + when: ContextKeyExpr.equals('config.notebook.globalToolbar', true), + order: 1 + } + ] + }); + } + run(accessor: ServicesAccessor): void { + accessor.get(IPreferencesService).openSettings(false, '@tag:notebookLayout'); } }); @@ -1512,7 +1930,7 @@ CommandsRegistry.registerCommand('_resolveNotebookContentProvider', (accessor, a filenamePattern: (string | glob.IRelativePattern | { include: string | glob.IRelativePattern, exclude: string | glob.IRelativePattern; })[]; }[] => { const notebookService = accessor.get(INotebookService); - const contentProviders = notebookService.getContributedNotebookProviders(); + const contentProviders = notebookService.getContributedNotebookTypes(); return contentProviders.map(provider => { const filenamePatterns = provider.selectors.map(selector => { if (typeof selector === 'string') { diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/find/findController.ts b/src/vs/workbench/contrib/notebook/browser/contrib/find/findController.ts similarity index 60% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/find/findController.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/find/findController.ts index bf46cd65ad36..29364b4abc7a 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/find/findController.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/find/findController.ts @@ -8,14 +8,9 @@ import { alert as alertFn } from 'vs/base/browser/ui/aria/aria'; import * as strings from 'vs/base/common/strings'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IContextKeyService, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, INotebookEditor, CellFindMatch, CellEditState, INotebookEditorContribution, NOTEBOOK_EDITOR_FOCUSED, getNotebookEditorFromEditorPane, NOTEBOOK_IS_ACTIVE_EDITOR } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, INotebookEditor, CellEditState, INotebookEditorContribution, NOTEBOOK_EDITOR_FOCUSED, getNotebookEditorFromEditorPane, NOTEBOOK_IS_ACTIVE_EDITOR } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { Range } from 'vs/editor/common/core/range'; import { MATCHES_LIMIT } from 'vs/editor/contrib/find/findModel'; -import { FindDecorations } from 'vs/editor/contrib/find/findDecorations'; -import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; -import { IModelDeltaDecoration } from 'vs/editor/common/model'; -import { ICellModelDeltaDecorations, ICellModelDecorations } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; -import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { SimpleFindReplaceWidget } from 'vs/workbench/contrib/codeEditor/browser/find/simpleFindReplaceWidget'; @@ -28,11 +23,12 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; -import { INotebookSearchOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { StartFindAction, StartFindReplaceAction } from 'vs/editor/contrib/find/findController'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { NLS_MATCHES_LOCATION, NLS_NO_RESULTS } from 'vs/editor/contrib/find/findWidget'; +import { FindModel } from 'vs/workbench/contrib/notebook/browser/contrib/find/findModel'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; const FIND_HIDE_TRANSITION = 'find-hide-transition'; const FIND_SHOW_TRANSITION = 'find-show-transition'; @@ -42,14 +38,10 @@ let MAX_MATCHES_COUNT_WIDTH = 69; export class NotebookFindWidget extends SimpleFindReplaceWidget implements INotebookEditorContribution { static id: string = 'workbench.notebook.find'; protected _findWidgetFocused: IContextKey; - private _findMatches: CellFindMatch[] = []; - protected _findMatchesStarts: PrefixSumComputer | null = null; - private _currentMatch: number = -1; - private _allMatchesDecorations: ICellModelDecorations[] = []; - private _currentMatchDecorations: ICellModelDecorations[] = []; private _showTimeout: number | null = null; private _hideTimeout: number | null = null; private _previousFocusElement?: HTMLElement; + private _findModel: FindModel; constructor( private readonly _notebookEditor: INotebookEditor, @@ -60,6 +52,8 @@ export class NotebookFindWidget extends SimpleFindReplaceWidget implements INote ) { super(contextViewService, contextKeyService, themeService, new FindReplaceState(), true); + this._findModel = new FindModel(this._notebookEditor, this._state, this._configurationService); + DOM.append(this._notebookEditor.getDomNode(), this.getDomNode()); this._findWidgetFocused = KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED.bindTo(contextKeyService); @@ -80,90 +74,43 @@ export class NotebookFindWidget extends SimpleFindReplaceWidget implements INote private _onFindInputKeyDown(e: IKeyboardEvent): void { if (e.equals(KeyCode.Enter)) { - if (this._findMatches.length) { - this.find(false); - } else { - this.set(null, true); - } + this._findModel.find(false); e.preventDefault(); return; } else if (e.equals(KeyMod.Shift | KeyCode.Enter)) { - if (this._findMatches.length) { - this.find(true); - } else { - this.set(null, true); - } + this.find(true); e.preventDefault(); return; } } protected onInputChanged(): boolean { - const val = this.inputValue; - const wordSeparators = this._configurationService.inspect('editor.wordSeparators').value; - const options: INotebookSearchOptions = { regex: this._getRegexValue(), wholeWord: this._getWholeWordValue(), caseSensitive: this._getCaseSensitiveValue(), wordSeparators: wordSeparators }; - if (val) { - this._findMatches = this._notebookEditor.viewModel!.find(val, options).filter(match => match.matches.length > 0); - this.set(this._findMatches, false); - if (this._findMatches.length) { - return true; - } else { - return false; - } - } else { - this.set([], false); + this._state.change({ searchString: this.inputValue }, false); + // this._findModel.research(); + const findMatches = this._findModel.findMatches; + if (findMatches && findMatches.length) { + return true; } return false; } protected find(previous: boolean): void { - if (!this._findMatches.length) { - return; - } - - // let currCell; - if (!this._findMatchesStarts) { - this.set(this._findMatches, true); - } else { - // const currIndex = this._findMatchesStarts!.getIndexOf(this._currentMatch); - // currCell = this._findMatches[currIndex.index].cell; - - const totalVal = this._findMatchesStarts.getTotalValue(); - const nextVal = (this._currentMatch + (previous ? -1 : 1) + totalVal) % totalVal; - this._currentMatch = nextVal; - } - - const nextIndex = this._findMatchesStarts!.getIndexOf(this._currentMatch); - // const newFocusedCell = this._findMatches[nextIndex.index].cell; - this.setCurrentFindMatchDecoration(nextIndex.index, nextIndex.remainder); - this.revealCellRange(nextIndex.index, nextIndex.remainder); - - this._state.changeMatchInfo( - this._currentMatch, - this._findMatches.reduce((p, c) => p + c.matches.length, 0), - undefined - ); - - // if (currCell && currCell !== newFocusedCell && currCell.getEditState() === CellEditState.Editing && currCell.editStateSource === 'find') { - // currCell.updateEditState(CellEditState.Preview, 'find'); - // } - // this._updateMatchesCount(); + this._findModel.find(previous); } protected replaceOne() { - if (!this._findMatches.length) { + if (!this._findModel.findMatches.length) { return; } - if (!this._findMatchesStarts) { - this.set(this._findMatches, true); - } + this._findModel.ensureFindMatches(); - const nextIndex = this._findMatchesStarts!.getIndexOf(this._currentMatch); - const cell = this._findMatches[nextIndex.index].cell; - const match = this._findMatches[nextIndex.index].matches[nextIndex.remainder]; + if (this._findModel.currentMatch < 0) { + this._findModel.find(false); + } + const { cell, match } = this._findModel.getCurrentMatch(); this._progressBar.infinite().show(); this._notebookEditor.viewModel!.replaceOne(cell, match.range, this.replaceValue).then(() => { @@ -174,18 +121,11 @@ export class NotebookFindWidget extends SimpleFindReplaceWidget implements INote protected replaceAll() { this._progressBar.infinite().show(); - this._notebookEditor.viewModel!.replaceAll(this._findMatches, this.replaceValue).then(() => { + this._notebookEditor.viewModel!.replaceAll(this._findModel.findMatches, this.replaceValue).then(() => { this._progressBar.stop(); }); } - private revealCellRange(cellIndex: number, matchIndex: number) { - this._findMatches[cellIndex].cell.updateEditState(CellEditState.Editing, 'find'); - this._notebookEditor.focusElement(this._findMatches[cellIndex].cell); - this._notebookEditor.setCellEditorSelection(this._findMatches[cellIndex].cell, this._findMatches[cellIndex].matches[matchIndex].range); - this._notebookEditor.revealRangeInCenterIfOutsideViewportAsync(this._findMatches[cellIndex].cell, this._findMatches[cellIndex].matches[matchIndex].range); - } - protected findFirst(): void { } protected onFocusTrackerFocus() { @@ -207,99 +147,9 @@ export class NotebookFindWidget extends SimpleFindReplaceWidget implements INote protected onFindInputFocusTrackerFocus(): void { } protected onFindInputFocusTrackerBlur(): void { } - private constructFindMatchesStarts() { - if (this._findMatches && this._findMatches.length) { - const values = new Uint32Array(this._findMatches.length); - for (let i = 0; i < this._findMatches.length; i++) { - values[i] = this._findMatches[i].matches.length; - } - - this._findMatchesStarts = new PrefixSumComputer(values); - } else { - this._findMatchesStarts = null; - } - } - - private set(cellFindMatches: CellFindMatch[] | null, autoStart: boolean): void { - if (!cellFindMatches || !cellFindMatches.length) { - this._findMatches = []; - this.setAllFindMatchesDecorations([]); - - this.constructFindMatchesStarts(); - this._currentMatch = -1; - this.clearCurrentFindMatchDecoration(); - return; - } - - // all matches - this._findMatches = cellFindMatches; - this.setAllFindMatchesDecorations(cellFindMatches || []); - - // current match - this.constructFindMatchesStarts(); - - if (autoStart) { - this._currentMatch = 0; - this.setCurrentFindMatchDecoration(0, 0); - } - - this._state.changeMatchInfo( - this._currentMatch, - this._findMatches.reduce((p, c) => p + c.matches.length, 0), - undefined - ); - } - - private setCurrentFindMatchDecoration(cellIndex: number, matchIndex: number) { - this._notebookEditor.changeModelDecorations(accessor => { - const findMatchesOptions: ModelDecorationOptions = FindDecorations._CURRENT_FIND_MATCH_DECORATION; - - const cell = this._findMatches[cellIndex].cell; - const match = this._findMatches[cellIndex].matches[matchIndex]; - const decorations: IModelDeltaDecoration[] = [ - { range: match.range, options: findMatchesOptions } - ]; - const deltaDecoration: ICellModelDeltaDecorations = { - ownerId: cell.handle, - decorations: decorations - }; - - this._currentMatchDecorations = accessor.deltaDecorations(this._currentMatchDecorations, [deltaDecoration]); - }); - } - - private clearCurrentFindMatchDecoration() { - this._notebookEditor.changeModelDecorations(accessor => { - this._currentMatchDecorations = accessor.deltaDecorations(this._currentMatchDecorations, []); - }); - } - - private setAllFindMatchesDecorations(cellFindMatches: CellFindMatch[]) { - this._notebookEditor.changeModelDecorations((accessor) => { - - const findMatchesOptions: ModelDecorationOptions = FindDecorations._FIND_MATCH_DECORATION; - - const deltaDecorations: ICellModelDeltaDecorations[] = cellFindMatches.map(cellFindMatch => { - const findMatches = cellFindMatch.matches; - - // Find matches - const newFindMatchesDecorations: IModelDeltaDecoration[] = new Array(findMatches.length); - for (let i = 0, len = findMatches.length; i < len; i++) { - newFindMatchesDecorations[i] = { - range: findMatches[i].range, - options: findMatchesOptions - }; - } - - return { ownerId: cellFindMatch.cell.handle, decorations: newFindMatchesDecorations }; - }); - - this._allMatchesDecorations = accessor.deltaDecorations(this._allMatchesDecorations, deltaDecorations); - }); - } - override show(initialInput?: string): void { super.show(initialInput); + this._state.change({ searchString: initialInput ?? '', isRevealed: true }, false); this._findInput.select(); if (this._showTimeout === null) { @@ -342,7 +192,8 @@ export class NotebookFindWidget extends SimpleFindReplaceWidget implements INote override hide() { super.hide(); - this.set([], false); + this._state.change({ isRevealed: false }, false); + this._findModel.clear(); if (this._hideTimeout === null) { if (this._showTimeout !== null) { @@ -371,7 +222,7 @@ export class NotebookFindWidget extends SimpleFindReplaceWidget implements INote } override _updateMatchesCount(): void { - if (!this._findMatches) { + if (!this._findModel || !this._findModel.findMatches) { return; } @@ -390,7 +241,7 @@ export class NotebookFindWidget extends SimpleFindReplaceWidget implements INote if (this._state.matchesCount >= MATCHES_LIMIT) { matchesCount += '+'; } - let matchesPosition: string = this._currentMatch < 0 ? '?' : String((this._currentMatch + 1)); + let matchesPosition: string = this._findModel.currentMatch < 0 ? '?' : String((this._findModel.currentMatch + 1)); label = strings.format(NLS_MATCHES_LOCATION, matchesPosition, matchesCount); } else { label = NLS_NO_RESULTS; @@ -412,18 +263,12 @@ export class NotebookFindWidget extends SimpleFindReplaceWidget implements INote // TODO@rebornix, aria for `cell ${index}, line {line}` return localize('ariaSearchNoResultWithLineNumNoCurrentMatch', "{0} found for '{1}'", label, searchString); } - - clear() { - this._currentMatch = -1; - this._findMatches = []; - } - override dispose() { this._notebookEditor?.removeClassName(FIND_SHOW_TRANSITION); this._notebookEditor?.removeClassName(FIND_HIDE_TRANSITION); + this._findModel.dispose(); super.dispose(); } - } registerNotebookContribution(NotebookFindWidget.id, NotebookFindWidget); @@ -481,7 +326,7 @@ registerAction2(class extends Action2 { } }); -StartFindAction.addImplementation(100, (accessor: ServicesAccessor, args: any) => { +StartFindAction.addImplementation(100, (accessor: ServicesAccessor, codeEditor: ICodeEditor, args: any) => { const editorService = accessor.get(IEditorService); const editor = getNotebookEditorFromEditorPane(editorService.activeEditorPane); @@ -494,7 +339,7 @@ StartFindAction.addImplementation(100, (accessor: ServicesAccessor, args: any) = return true; }); -StartFindReplaceAction.addImplementation(100, (accessor: ServicesAccessor, args: any) => { +StartFindReplaceAction.addImplementation(100, (accessor: ServicesAccessor, codeEditor: ICodeEditor, args: any) => { const editorService = accessor.get(IEditorService); const editor = getNotebookEditorFromEditorPane(editorService.activeEditorPane); diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/find/findModel.ts b/src/vs/workbench/contrib/notebook/browser/contrib/find/findModel.ts new file mode 100644 index 000000000000..3e6d07b78223 --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/contrib/find/findModel.ts @@ -0,0 +1,340 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { INotebookEditor, CellFindMatch, CellEditState, CellFindMatchWithIndex } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { Range } from 'vs/editor/common/core/range'; +import { FindDecorations } from 'vs/editor/contrib/find/findDecorations'; +import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; +import { IModelDeltaDecoration } from 'vs/editor/common/model'; +import { ICellModelDeltaDecorations, ICellModelDecorations } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; +import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; +import { FindReplaceState } from 'vs/editor/contrib/find/findState'; +import { CellKind, INotebookSearchOptions, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { findFirstInSorted } from 'vs/base/common/arrays'; +import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; + + +export class FindModel extends Disposable { + private _findMatches: CellFindMatch[] = []; + protected _findMatchesStarts: PrefixSumComputer | null = null; + private _currentMatch: number = -1; + private _allMatchesDecorations: ICellModelDecorations[] = []; + private _currentMatchDecorations: ICellModelDecorations[] = []; + private _modelDisposable = new DisposableStore(); + + get findMatches() { + return this._findMatches; + } + + get currentMatch() { + return this._currentMatch; + } + + constructor( + private readonly _notebookEditor: INotebookEditor, + private readonly _state: FindReplaceState, + @IConfigurationService private readonly _configurationService: IConfigurationService + ) { + super(); + + this._register(_state.onFindReplaceStateChange(e => { + if (e.searchString || (e.isRevealed && this._state.isRevealed)) { + this.research(); + } + + if (e.isRevealed && !this._state.isRevealed) { + this.clear(); + } + })); + + this._register(this._notebookEditor.onDidChangeModel(e => { + this._registerModelListener(e); + })); + + if (this._notebookEditor.hasModel()) { + this._registerModelListener(this._notebookEditor.textModel); + } + } + + ensureFindMatches() { + if (!this._findMatchesStarts) { + this.set(this._findMatches, true); + } + } + + getCurrentMatch() { + const nextIndex = this._findMatchesStarts!.getIndexOf(this._currentMatch); + const cell = this._findMatches[nextIndex.index].cell; + const match = this._findMatches[nextIndex.index].matches[nextIndex.remainder]; + + return { + cell, + match + }; + } + + find(previous: boolean) { + if (!this.findMatches.length) { + return; + } + + // let currCell; + if (!this._findMatchesStarts) { + this.set(this._findMatches, true); + } else { + // const currIndex = this._findMatchesStarts!.getIndexOf(this._currentMatch); + // currCell = this._findMatches[currIndex.index].cell; + const totalVal = this._findMatchesStarts.getTotalValue(); + if (this._currentMatch === -1) { + this._currentMatch = previous ? totalVal - 1 : 0; + } else { + const nextVal = (this._currentMatch + (previous ? -1 : 1) + totalVal) % totalVal; + this._currentMatch = nextVal; + } + } + + const nextIndex = this._findMatchesStarts!.getIndexOf(this._currentMatch); + // const newFocusedCell = this._findMatches[nextIndex.index].cell; + this.setCurrentFindMatchDecoration(nextIndex.index, nextIndex.remainder); + this.revealCellRange(nextIndex.index, nextIndex.remainder); + + this._state.changeMatchInfo( + this._currentMatch, + this._findMatches.reduce((p, c) => p + c.matches.length, 0), + undefined + ); + } + + private revealCellRange(cellIndex: number, matchIndex: number) { + this._findMatches[cellIndex].cell.updateEditState(CellEditState.Editing, 'find'); + this._notebookEditor.focusElement(this._findMatches[cellIndex].cell); + this._notebookEditor.setCellEditorSelection(this._findMatches[cellIndex].cell, this._findMatches[cellIndex].matches[matchIndex].range); + this._notebookEditor.revealRangeInCenterIfOutsideViewportAsync(this._findMatches[cellIndex].cell, this._findMatches[cellIndex].matches[matchIndex].range); + } + + private _registerModelListener(notebookTextModel?: NotebookTextModel) { + this._modelDisposable.clear(); + + if (notebookTextModel) { + this._modelDisposable.add(notebookTextModel.onDidChangeContent((e) => { + if (!e.rawEvents.some(event => event.kind === NotebookCellsChangeType.ChangeCellContent || event.kind === NotebookCellsChangeType.ModelChange)) { + return; + } + + this.research(); + })); + } + + this.research(); + } + + research() { + if (!this._state.isRevealed) { + this.set([], false); + return; + } + + const findMatches = this._getFindMatches(); + if (!findMatches) { + return; + } + + if (this._currentMatch === -1) { + // no active current match + this.set(findMatches, false); + return; + } + + const oldCurrIndex = this._findMatchesStarts!.getIndexOf(this._currentMatch); + const oldCurrCell = this._findMatches[oldCurrIndex.index].cell; + const oldCurrMatchCellIndex = this._notebookEditor.viewModel!.getCellIndex(oldCurrCell); + + if (oldCurrMatchCellIndex < 0) { + // the cell containing the active match is deleted + const focusedCell = this._notebookEditor.viewModel!.viewCells[this._notebookEditor.viewModel!.getFocus().start]; + + if (!focusedCell) { + this.set(findMatches, false); + return; + } + + const matchAfterSelection = findFirstInSorted(findMatches.map(match => match.index), index => index >= oldCurrMatchCellIndex); + this._updateCurrentMatch(findMatches, this._matchesCountBeforeIndex(findMatches, matchAfterSelection)); + return; + } + + // the cell still exist + const cell = this._notebookEditor.viewModel!.viewCells[oldCurrMatchCellIndex]; + if (cell.cellKind === CellKind.Markup && cell.getEditState() === CellEditState.Preview) { + // find the nearest match above this cell + const matchAfterSelection = findFirstInSorted(findMatches.map(match => match.index), index => index >= oldCurrMatchCellIndex); + this._updateCurrentMatch(findMatches, this._matchesCountBeforeIndex(findMatches, matchAfterSelection)); + return; + } + + if ((cell.cellKind === CellKind.Markup && cell.getEditState() === CellEditState.Editing) || cell.cellKind === CellKind.Code) { + // check if there is monaco editor selection and find the first match, otherwise find the first match above current cell + // this._findMatches[cellIndex].matches[matchIndex].range + const currentMatchDecorationId = this._currentMatchDecorations.find(decoration => decoration.ownerId === cell.handle); + + if (currentMatchDecorationId) { + const currMatchRangeInEditor = (cell.editorAttached && currentMatchDecorationId.decorations[0] ? cell.getCellDecorationRange(currentMatchDecorationId.decorations[0]) : null) + ?? this._findMatches[oldCurrIndex.index].matches[oldCurrIndex.remainder].range; + + // not attached, just use the range + const matchAfterSelection = findFirstInSorted(findMatches, match => match.index >= oldCurrMatchCellIndex); + if (findMatches[matchAfterSelection].index > oldCurrMatchCellIndex) { + // there is no search result in curr cell anymore + this._updateCurrentMatch(findMatches, this._matchesCountBeforeIndex(findMatches, matchAfterSelection)); + } else { + // findMatches[matchAfterSelection].index === currMatchCellIndex + const cellMatch = findMatches[matchAfterSelection]; + const matchAfterOldSelection = findFirstInSorted(cellMatch.matches, match => Range.compareRangesUsingStarts(match.range, currMatchRangeInEditor) >= 0); + this._updateCurrentMatch(findMatches, this._matchesCountBeforeIndex(findMatches, matchAfterSelection) + matchAfterOldSelection); + } + } else { + const matchAfterSelection = findFirstInSorted(findMatches.map(match => match.index), index => index >= oldCurrMatchCellIndex); + this._updateCurrentMatch(findMatches, this._matchesCountBeforeIndex(findMatches, matchAfterSelection)); + } + + return; + } + + this.set(findMatches, false); + } + + private set(cellFindMatches: CellFindMatch[] | null, autoStart: boolean): void { + if (!cellFindMatches || !cellFindMatches.length) { + this._findMatches = []; + this.setAllFindMatchesDecorations([]); + + this.constructFindMatchesStarts(); + this._currentMatch = -1; + this.clearCurrentFindMatchDecoration(); + return; + } + + // all matches + this._findMatches = cellFindMatches; + this.setAllFindMatchesDecorations(cellFindMatches || []); + + // current match + this.constructFindMatchesStarts(); + + if (autoStart) { + this._currentMatch = 0; + this.setCurrentFindMatchDecoration(0, 0); + } + + this._state.changeMatchInfo( + this._currentMatch, + this._findMatches.reduce((p, c) => p + c.matches.length, 0), + undefined + ); + } + + private _getFindMatches(): CellFindMatchWithIndex[] | null { + const val = this._state.searchString; + const wordSeparators = this._configurationService.inspect('editor.wordSeparators').value; + + const options: INotebookSearchOptions = { regex: this._state.isRegex, wholeWord: this._state.wholeWord, caseSensitive: this._state.matchCase, wordSeparators: wordSeparators }; + if (!val) { + return null; + } + + const findMatches = this._notebookEditor.viewModel!.find(val, options).filter(match => match.matches.length > 0); + return findMatches; + } + + private _updateCurrentMatch(findMatches: CellFindMatchWithIndex[], currentMatchesPosition: number) { + this.set(findMatches, false); + this._currentMatch = currentMatchesPosition; + const nextIndex = this._findMatchesStarts!.getIndexOf(this._currentMatch); + this.setCurrentFindMatchDecoration(nextIndex.index, nextIndex.remainder); + + this._state.changeMatchInfo( + this._currentMatch, + this._findMatches.reduce((p, c) => p + c.matches.length, 0), + undefined + ); + } + + private _matchesCountBeforeIndex(findMatches: CellFindMatchWithIndex[], index: number) { + let prevMatchesCount = 0; + for (let i = 0; i < index; i++) { + prevMatchesCount += findMatches[i].matches.length; + } + + return prevMatchesCount; + } + + private constructFindMatchesStarts() { + if (this._findMatches && this._findMatches.length) { + const values = new Uint32Array(this._findMatches.length); + for (let i = 0; i < this._findMatches.length; i++) { + values[i] = this._findMatches[i].matches.length; + } + + this._findMatchesStarts = new PrefixSumComputer(values); + } else { + this._findMatchesStarts = null; + } + } + + private setCurrentFindMatchDecoration(cellIndex: number, matchIndex: number) { + this._notebookEditor.changeModelDecorations(accessor => { + const findMatchesOptions: ModelDecorationOptions = FindDecorations._CURRENT_FIND_MATCH_DECORATION; + + const cell = this._findMatches[cellIndex].cell; + const match = this._findMatches[cellIndex].matches[matchIndex]; + const decorations: IModelDeltaDecoration[] = [ + { range: match.range, options: findMatchesOptions } + ]; + const deltaDecoration: ICellModelDeltaDecorations = { + ownerId: cell.handle, + decorations: decorations + }; + + this._currentMatchDecorations = accessor.deltaDecorations(this._currentMatchDecorations, [deltaDecoration]); + }); + } + + private clearCurrentFindMatchDecoration() { + this._notebookEditor.changeModelDecorations(accessor => { + this._currentMatchDecorations = accessor.deltaDecorations(this._currentMatchDecorations, []); + }); + } + + private setAllFindMatchesDecorations(cellFindMatches: CellFindMatch[]) { + this._notebookEditor.changeModelDecorations((accessor) => { + + const findMatchesOptions: ModelDecorationOptions = FindDecorations._FIND_MATCH_DECORATION; + + const deltaDecorations: ICellModelDeltaDecorations[] = cellFindMatches.map(cellFindMatch => { + const findMatches = cellFindMatch.matches; + + // Find matches + const newFindMatchesDecorations: IModelDeltaDecoration[] = new Array(findMatches.length); + for (let i = 0, len = findMatches.length; i < len; i++) { + newFindMatchesDecorations[i] = { + range: findMatches[i].range, + options: findMatchesOptions + }; + } + + return { ownerId: cellFindMatch.cell.handle, decorations: newFindMatchesDecorations }; + }); + + this._allMatchesDecorations = accessor.deltaDecorations(this._allMatchesDecorations, deltaDecorations); + }); + } + + + clear() { + this.set([], false); + } +} diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/find/media/notebookFind.css b/src/vs/workbench/contrib/notebook/browser/contrib/find/media/notebookFind.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/find/media/notebookFind.css rename to src/vs/workbench/contrib/notebook/browser/contrib/find/media/notebookFind.css diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/find/test/find.test.ts b/src/vs/workbench/contrib/notebook/browser/contrib/find/test/find.test.ts new file mode 100644 index 000000000000..b70d58c31dbb --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/contrib/find/test/find.test.ts @@ -0,0 +1,195 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { Range } from 'vs/editor/common/core/range'; +import { ITextBuffer, ValidAnnotatedEditOperation } from 'vs/editor/common/model'; +import { USUAL_WORD_SEPARATORS } from 'vs/editor/common/model/wordHelper'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { FindReplaceState } from 'vs/editor/contrib/find/findState'; +import { IConfigurationService, IConfigurationValue } from 'vs/platform/configuration/common/configuration'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { FindModel } from 'vs/workbench/contrib/notebook/browser/contrib/find/findModel'; +import { IActiveNotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICellModelDecorations, ICellModelDeltaDecorations } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; +import { CellEditType, CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { TestCell, withTestNotebook } from 'vs/workbench/contrib/notebook/test/testNotebookEditor'; + +suite('Notebook Find', () => { + const configurationValue: IConfigurationValue = { + value: USUAL_WORD_SEPARATORS + }; + const configurationService = new class extends TestConfigurationService { + override inspect() { + return configurationValue; + } + }(); + + const setupEditorForTest = (editor: IActiveNotebookEditor) => { + editor.changeModelDecorations = (callback) => { + return callback({ + deltaDecorations: (oldDecorations: ICellModelDecorations[], newDecorations: ICellModelDeltaDecorations[]) => { + const ret: ICellModelDecorations[] = []; + newDecorations.forEach(dec => { + const cell = editor.viewModel.viewCells.find(cell => cell.handle === dec.ownerId); + const decorations = cell?.deltaModelDecorations([], dec.decorations) ?? []; + + if (decorations.length > 0) { + ret.push({ ownerId: dec.ownerId, decorations: decorations }); + } + }); + + return ret; + } + }); + }; + }; + + test('Update find matches basics', async function () { + await withTestNotebook( + [ + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 2', 'markdown', CellKind.Markup, [], {}], + ], + async (editor, accessor) => { + accessor.stub(IConfigurationService, configurationService); + const state = new FindReplaceState(); + const model = new FindModel(editor, state, accessor.get(IConfigurationService)); + state.change({ isRevealed: true }, true); + state.change({ searchString: '1' }, true); + assert.strictEqual(model.findMatches.length, 2); + assert.strictEqual(model.currentMatch, -1); + model.find(false); + assert.strictEqual(model.currentMatch, 0); + model.find(false); + assert.strictEqual(model.currentMatch, 1); + model.find(false); + assert.strictEqual(model.currentMatch, 0); + + assert.strictEqual(editor.textModel.length, 3); + + editor.textModel.applyEdits([{ + editType: CellEditType.Replace, index: 3, count: 0, cells: [ + new TestCell(editor.viewModel.viewType, 3, '# next paragraph 1', 'markdown', CellKind.Code, [], accessor.get(IModeService)), + ] + }], true, undefined, () => undefined, undefined, true); + assert.strictEqual(editor.textModel.length, 4); + assert.strictEqual(model.findMatches.length, 3); + assert.strictEqual(model.currentMatch, 0); + }); + }); + + test('Update find matches basics 2', async function () { + await withTestNotebook( + [ + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 1.1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 1.2', 'markdown', CellKind.Markup, [], {}], + ['paragraph 1.3', 'markdown', CellKind.Markup, [], {}], + ['paragraph 2', 'markdown', CellKind.Markup, [], {}], + ], + async (editor, accessor) => { + setupEditorForTest(editor); + accessor.stub(IConfigurationService, configurationService); + const state = new FindReplaceState(); + const model = new FindModel(editor, state, accessor.get(IConfigurationService)); + state.change({ isRevealed: true }, true); + state.change({ searchString: '1' }, true); + // find matches is not necessarily find results + assert.strictEqual(model.findMatches.length, 4); + assert.strictEqual(model.currentMatch, -1); + model.find(false); + assert.strictEqual(model.currentMatch, 0); + model.find(false); + assert.strictEqual(model.currentMatch, 1); + model.find(false); + assert.strictEqual(model.currentMatch, 2); + + editor.textModel.applyEdits([{ + editType: CellEditType.Replace, index: 2, count: 1, cells: [] + }], true, undefined, () => undefined, undefined, true); + assert.strictEqual(model.findMatches.length, 3); + + assert.strictEqual(model.currentMatch, 2); + model.find(true); + assert.strictEqual(model.currentMatch, 1); + model.find(false); + assert.strictEqual(model.currentMatch, 2); + model.find(false); + assert.strictEqual(model.currentMatch, 3); + model.find(false); + assert.strictEqual(model.currentMatch, 0); + }); + }); + + test('Update find matches basics 3', async function () { + await withTestNotebook( + [ + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 1.1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 1.2', 'markdown', CellKind.Markup, [], {}], + ['paragraph 1.3', 'markdown', CellKind.Markup, [], {}], + ['paragraph 2', 'markdown', CellKind.Markup, [], {}], + ], + async (editor, accessor) => { + setupEditorForTest(editor); + accessor.stub(IConfigurationService, configurationService); + const state = new FindReplaceState(); + const model = new FindModel(editor, state, accessor.get(IConfigurationService)); + state.change({ isRevealed: true }, true); + state.change({ searchString: '1' }, true); + // find matches is not necessarily find results + assert.strictEqual(model.findMatches.length, 4); + assert.strictEqual(model.currentMatch, -1); + model.find(true); + assert.strictEqual(model.currentMatch, 4); + + editor.textModel.applyEdits([{ + editType: CellEditType.Replace, index: 2, count: 1, cells: [] + }], true, undefined, () => undefined, undefined, true); + assert.strictEqual(model.findMatches.length, 3); + assert.strictEqual(model.currentMatch, 3); + model.find(false); + assert.strictEqual(model.currentMatch, 0); + model.find(true); + assert.strictEqual(model.currentMatch, 3); + model.find(true); + assert.strictEqual(model.currentMatch, 2); + }); + }); + + test('Update find matches, #112748', async function () { + await withTestNotebook( + [ + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 1.1', 'markdown', CellKind.Markup, [], {}], + ['paragraph 1.2', 'markdown', CellKind.Markup, [], {}], + ['paragraph 1.3', 'markdown', CellKind.Markup, [], {}], + ['paragraph 2', 'markdown', CellKind.Markup, [], {}], + ], + async (editor, accessor) => { + setupEditorForTest(editor); + accessor.stub(IConfigurationService, configurationService); + const state = new FindReplaceState(); + const model = new FindModel(editor, state, accessor.get(IConfigurationService)); + state.change({ isRevealed: true }, true); + state.change({ searchString: '1' }, true); + // find matches is not necessarily find results + assert.strictEqual(model.findMatches.length, 4); + assert.strictEqual(model.currentMatch, -1); + model.find(false); + model.find(false); + model.find(false); + assert.strictEqual(model.currentMatch, 2); + (editor.viewModel.viewCells[1].textBuffer as ITextBuffer).applyEdits([ + new ValidAnnotatedEditOperation(null, new Range(1, 1, 1, 14), '', false, false, false) + ], false, true); + // cell content updates, recompute + model.research(); + assert.strictEqual(model.currentMatch, 1); + }); + }); +}); diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/fold/folding.ts b/src/vs/workbench/contrib/notebook/browser/contrib/fold/folding.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/fold/folding.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/fold/folding.ts index 04f01b0575d0..73e57fe89215 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/fold/folding.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/fold/folding.ts @@ -38,8 +38,8 @@ export class FoldingController extends Disposable implements INotebookEditorCont return; } - this._localStore.add(this._notebookEditor.viewModel.eventDispatcher.onDidChangeCellState(e => { - if (e.source.editStateChanged && e.cell.cellKind === CellKind.Markdown) { + this._localStore.add(this._notebookEditor.viewModel.viewContext.eventDispatcher.onDidChangeCellState(e => { + if (e.source.editStateChanged && e.cell.cellKind === CellKind.Markup) { this._foldingModel?.recompute(); // this._updateEditorFoldingRanges(); } diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/fold/foldingModel.ts b/src/vs/workbench/contrib/notebook/browser/contrib/fold/foldingModel.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/fold/foldingModel.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/fold/foldingModel.ts diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/fold/test/notebookFolding.test.ts b/src/vs/workbench/contrib/notebook/browser/contrib/fold/test/notebookFolding.test.ts similarity index 59% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/fold/test/notebookFolding.test.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/fold/test/notebookFolding.test.ts index 7457d5f02479..db6ed0d83c15 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/fold/test/notebookFolding.test.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/fold/test/notebookFolding.test.ts @@ -16,13 +16,13 @@ suite('Notebook Folding', () => { test('Folding based on markdown cells', async function () { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['body', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.1', 'markdown', CellKind.Markdown, [], {}], - ['body 2', 'markdown', CellKind.Markdown, [], {}], - ['body 3', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.2', 'markdown', CellKind.Markdown, [], {}], - ['var e = 7;', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['body', 'markdown', CellKind.Markup, [], {}], + ['## header 2.1', 'markdown', CellKind.Markup, [], {}], + ['body 2', 'markdown', CellKind.Markup, [], {}], + ['body 3', 'markdown', CellKind.Markup, [], {}], + ['## header 2.2', 'markdown', CellKind.Markup, [], {}], + ['var e = 7;', 'markdown', CellKind.Markup, [], {}], ], (editor) => { const viewModel = editor.viewModel; @@ -43,13 +43,13 @@ suite('Notebook Folding', () => { test('Top level header in a cell wins', async function () { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['body', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.1\n# header3', 'markdown', CellKind.Markdown, [], {}], - ['body 2', 'markdown', CellKind.Markdown, [], {}], - ['body 3', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.2', 'markdown', CellKind.Markdown, [], {}], - ['var e = 7;', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['body', 'markdown', CellKind.Markup, [], {}], + ['## header 2.1\n# header3', 'markdown', CellKind.Markup, [], {}], + ['body 2', 'markdown', CellKind.Markup, [], {}], + ['body 3', 'markdown', CellKind.Markup, [], {}], + ['## header 2.2', 'markdown', CellKind.Markup, [], {}], + ['var e = 7;', 'markdown', CellKind.Markup, [], {}], ], (editor) => { const viewModel = editor.viewModel; @@ -75,13 +75,13 @@ suite('Notebook Folding', () => { test('Folding', async function () { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['body', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.1', 'markdown', CellKind.Markdown, [], {}], - ['body 2', 'markdown', CellKind.Markdown, [], {}], - ['body 3', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.2', 'markdown', CellKind.Markdown, [], {}], - ['var e = 7;', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['body', 'markdown', CellKind.Markup, [], {}], + ['## header 2.1', 'markdown', CellKind.Markup, [], {}], + ['body 2', 'markdown', CellKind.Markup, [], {}], + ['body 3', 'markdown', CellKind.Markup, [], {}], + ['## header 2.2', 'markdown', CellKind.Markup, [], {}], + ['var e = 7;', 'markdown', CellKind.Markup, [], {}], ], (editor) => { const viewModel = editor.viewModel; @@ -97,13 +97,13 @@ suite('Notebook Folding', () => { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['body', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.1\n', 'markdown', CellKind.Markdown, [], {}], - ['body 2', 'markdown', CellKind.Markdown, [], {}], - ['body 3', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.2', 'markdown', CellKind.Markdown, [], {}], - ['var e = 7;', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['body', 'markdown', CellKind.Markup, [], {}], + ['## header 2.1\n', 'markdown', CellKind.Markup, [], {}], + ['body 2', 'markdown', CellKind.Markup, [], {}], + ['body 3', 'markdown', CellKind.Markup, [], {}], + ['## header 2.2', 'markdown', CellKind.Markup, [], {}], + ['var e = 7;', 'markdown', CellKind.Markup, [], {}], ], (editor) => { const viewModel = editor.viewModel; @@ -120,13 +120,13 @@ suite('Notebook Folding', () => { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['body', 'markdown', CellKind.Markdown, [], {}], - ['# header 2.1\n', 'markdown', CellKind.Markdown, [], {}], - ['body 2', 'markdown', CellKind.Markdown, [], {}], - ['body 3', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.2', 'markdown', CellKind.Markdown, [], {}], - ['var e = 7;', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['body', 'markdown', CellKind.Markup, [], {}], + ['# header 2.1\n', 'markdown', CellKind.Markup, [], {}], + ['body 2', 'markdown', CellKind.Markup, [], {}], + ['body 3', 'markdown', CellKind.Markup, [], {}], + ['## header 2.2', 'markdown', CellKind.Markup, [], {}], + ['var e = 7;', 'markdown', CellKind.Markup, [], {}], ], (editor) => { const viewModel = editor.viewModel; @@ -145,13 +145,13 @@ suite('Notebook Folding', () => { test('Nested Folding', async function () { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['body', 'markdown', CellKind.Markdown, [], {}], - ['# header 2.1\n', 'markdown', CellKind.Markdown, [], {}], - ['body 2', 'markdown', CellKind.Markdown, [], {}], - ['body 3', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.2', 'markdown', CellKind.Markdown, [], {}], - ['var e = 7;', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['body', 'markdown', CellKind.Markup, [], {}], + ['# header 2.1\n', 'markdown', CellKind.Markup, [], {}], + ['body 2', 'markdown', CellKind.Markup, [], {}], + ['body 3', 'markdown', CellKind.Markup, [], {}], + ['## header 2.2', 'markdown', CellKind.Markup, [], {}], + ['var e = 7;', 'markdown', CellKind.Markup, [], {}], ], (editor) => { const viewModel = editor.viewModel; @@ -200,18 +200,18 @@ suite('Notebook Folding', () => { test('Folding Memento', async function () { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['body', 'markdown', CellKind.Markdown, [], {}], - ['# header 2.1\n', 'markdown', CellKind.Markdown, [], {}], - ['body 2', 'markdown', CellKind.Markdown, [], {}], - ['body 3', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.2', 'markdown', CellKind.Markdown, [], {}], - ['var e = 7;', 'markdown', CellKind.Markdown, [], {}], - ['# header 2.1\n', 'markdown', CellKind.Markdown, [], {}], - ['body 2', 'markdown', CellKind.Markdown, [], {}], - ['body 3', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.2', 'markdown', CellKind.Markdown, [], {}], - ['var e = 7;', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['body', 'markdown', CellKind.Markup, [], {}], + ['# header 2.1\n', 'markdown', CellKind.Markup, [], {}], + ['body 2', 'markdown', CellKind.Markup, [], {}], + ['body 3', 'markdown', CellKind.Markup, [], {}], + ['## header 2.2', 'markdown', CellKind.Markup, [], {}], + ['var e = 7;', 'markdown', CellKind.Markup, [], {}], + ['# header 2.1\n', 'markdown', CellKind.Markup, [], {}], + ['body 2', 'markdown', CellKind.Markup, [], {}], + ['body 3', 'markdown', CellKind.Markup, [], {}], + ['## header 2.2', 'markdown', CellKind.Markup, [], {}], + ['var e = 7;', 'markdown', CellKind.Markup, [], {}], ], (editor) => { const viewModel = editor.viewModel; @@ -229,18 +229,18 @@ suite('Notebook Folding', () => { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['body', 'markdown', CellKind.Markdown, [], {}], - ['# header 2.1\n', 'markdown', CellKind.Markdown, [], {}], - ['body 2', 'markdown', CellKind.Markdown, [], {}], - ['body 3', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.2', 'markdown', CellKind.Markdown, [], {}], - ['var e = 7;', 'markdown', CellKind.Markdown, [], {}], - ['# header 2.1\n', 'markdown', CellKind.Markdown, [], {}], - ['body 2', 'markdown', CellKind.Markdown, [], {}], - ['body 3', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.2', 'markdown', CellKind.Markdown, [], {}], - ['var e = 7;', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['body', 'markdown', CellKind.Markup, [], {}], + ['# header 2.1\n', 'markdown', CellKind.Markup, [], {}], + ['body 2', 'markdown', CellKind.Markup, [], {}], + ['body 3', 'markdown', CellKind.Markup, [], {}], + ['## header 2.2', 'markdown', CellKind.Markup, [], {}], + ['var e = 7;', 'markdown', CellKind.Markup, [], {}], + ['# header 2.1\n', 'markdown', CellKind.Markup, [], {}], + ['body 2', 'markdown', CellKind.Markup, [], {}], + ['body 3', 'markdown', CellKind.Markup, [], {}], + ['## header 2.2', 'markdown', CellKind.Markup, [], {}], + ['var e = 7;', 'markdown', CellKind.Markup, [], {}], ], (editor) => { const viewModel = editor.viewModel; @@ -262,18 +262,18 @@ suite('Notebook Folding', () => { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['body', 'markdown', CellKind.Markdown, [], {}], - ['# header 2.1\n', 'markdown', CellKind.Markdown, [], {}], - ['body 2', 'markdown', CellKind.Markdown, [], {}], - ['body 3', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.2', 'markdown', CellKind.Markdown, [], {}], - ['var e = 7;', 'markdown', CellKind.Markdown, [], {}], - ['# header 2.1\n', 'markdown', CellKind.Markdown, [], {}], - ['body 2', 'markdown', CellKind.Markdown, [], {}], - ['body 3', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.2', 'markdown', CellKind.Markdown, [], {}], - ['var e = 7;', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['body', 'markdown', CellKind.Markup, [], {}], + ['# header 2.1\n', 'markdown', CellKind.Markup, [], {}], + ['body 2', 'markdown', CellKind.Markup, [], {}], + ['body 3', 'markdown', CellKind.Markup, [], {}], + ['## header 2.2', 'markdown', CellKind.Markup, [], {}], + ['var e = 7;', 'markdown', CellKind.Markup, [], {}], + ['# header 2.1\n', 'markdown', CellKind.Markup, [], {}], + ['body 2', 'markdown', CellKind.Markup, [], {}], + ['body 3', 'markdown', CellKind.Markup, [], {}], + ['## header 2.2', 'markdown', CellKind.Markup, [], {}], + ['var e = 7;', 'markdown', CellKind.Markup, [], {}], ], (editor) => { const viewModel = editor.viewModel; @@ -297,18 +297,18 @@ suite('Notebook Folding', () => { test('View Index', async function () { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['body', 'markdown', CellKind.Markdown, [], {}], - ['# header 2.1\n', 'markdown', CellKind.Markdown, [], {}], - ['body 2', 'markdown', CellKind.Markdown, [], {}], - ['body 3', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.2', 'markdown', CellKind.Markdown, [], {}], - ['var e = 7;', 'markdown', CellKind.Markdown, [], {}], - ['# header 2.1\n', 'markdown', CellKind.Markdown, [], {}], - ['body 2', 'markdown', CellKind.Markdown, [], {}], - ['body 3', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.2', 'markdown', CellKind.Markdown, [], {}], - ['var e = 7;', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['body', 'markdown', CellKind.Markup, [], {}], + ['# header 2.1\n', 'markdown', CellKind.Markup, [], {}], + ['body 2', 'markdown', CellKind.Markup, [], {}], + ['body 3', 'markdown', CellKind.Markup, [], {}], + ['## header 2.2', 'markdown', CellKind.Markup, [], {}], + ['var e = 7;', 'markdown', CellKind.Markup, [], {}], + ['# header 2.1\n', 'markdown', CellKind.Markup, [], {}], + ['body 2', 'markdown', CellKind.Markup, [], {}], + ['body 3', 'markdown', CellKind.Markup, [], {}], + ['## header 2.2', 'markdown', CellKind.Markup, [], {}], + ['var e = 7;', 'markdown', CellKind.Markup, [], {}], ], (editor) => { const viewModel = editor.viewModel; @@ -334,18 +334,18 @@ suite('Notebook Folding', () => { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['body', 'markdown', CellKind.Markdown, [], {}], - ['# header 2.1\n', 'markdown', CellKind.Markdown, [], {}], - ['body 2', 'markdown', CellKind.Markdown, [], {}], - ['body 3', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.2', 'markdown', CellKind.Markdown, [], {}], - ['var e = 7;', 'markdown', CellKind.Markdown, [], {}], - ['# header 2.1\n', 'markdown', CellKind.Markdown, [], {}], - ['body 2', 'markdown', CellKind.Markdown, [], {}], - ['body 3', 'markdown', CellKind.Markdown, [], {}], - ['## header 2.2', 'markdown', CellKind.Markdown, [], {}], - ['var e = 7;', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['body', 'markdown', CellKind.Markup, [], {}], + ['# header 2.1\n', 'markdown', CellKind.Markup, [], {}], + ['body 2', 'markdown', CellKind.Markup, [], {}], + ['body 3', 'markdown', CellKind.Markup, [], {}], + ['## header 2.2', 'markdown', CellKind.Markup, [], {}], + ['var e = 7;', 'markdown', CellKind.Markup, [], {}], + ['# header 2.1\n', 'markdown', CellKind.Markup, [], {}], + ['body 2', 'markdown', CellKind.Markup, [], {}], + ['body 3', 'markdown', CellKind.Markup, [], {}], + ['## header 2.2', 'markdown', CellKind.Markup, [], {}], + ['var e = 7;', 'markdown', CellKind.Markup, [], {}], ], (editor) => { const viewModel = editor.viewModel; diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/format/formatting.ts b/src/vs/workbench/contrib/notebook/browser/contrib/format/formatting.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/format/formatting.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/format/formatting.ts diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts b/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts new file mode 100644 index 000000000000..da940be17a7e --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts @@ -0,0 +1,98 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { localize } from 'vs/nls'; +import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; +import { CATEGORIES } from 'vs/workbench/common/actions'; +import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; +import { Memento } from 'vs/workbench/common/memento'; +import { HAS_OPENED_NOTEBOOK } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; + +const hasOpenedNotebookKey = 'hasOpenedNotebook'; +const hasShownGettingStartedKey = 'hasShownNotebookGettingStarted'; + +const showGettingStartedSetting = 'notebook.experimental.openGettingStarted'; + +/** + * Sets a context key when a notebook has ever been opened by the user + */ +export class NotebookGettingStarted extends Disposable implements IWorkbenchContribution { + + constructor( + @IEditorService _editorService: IEditorService, + @IStorageService _storageService: IStorageService, + @IContextKeyService _contextKeyService: IContextKeyService, + @ICommandService _commandService: ICommandService, + @IConfigurationService _configurationService: IConfigurationService, + ) { + super(); + + const hasOpenedNotebook = HAS_OPENED_NOTEBOOK.bindTo(_contextKeyService); + const memento = new Memento('notebookGettingStarted2', _storageService); + const storedValue = memento.getMemento(StorageScope.GLOBAL, StorageTarget.USER); + if (storedValue[hasOpenedNotebookKey]) { + hasOpenedNotebook.set(true); + } + + const needToShowGettingStarted = _configurationService.getValue(showGettingStartedSetting) && !storedValue[hasShownGettingStartedKey]; + if (!storedValue[hasOpenedNotebookKey] || needToShowGettingStarted) { + const onDidOpenNotebook = () => { + hasOpenedNotebook.set(true); + storedValue[hasOpenedNotebookKey] = true; + + if (needToShowGettingStarted) { + _commandService.executeCommand('workbench.action.openWalkthrough', { category: 'notebooks', step: 'notebookProfile' }, true); + storedValue[hasShownGettingStartedKey] = true; + } + + memento.saveMemento(); + }; + + if (_editorService.activeEditor?.typeId === NotebookEditorInput.ID) { + // active editor is notebook + onDidOpenNotebook(); + return; + } + + const listener = this._register(_editorService.onDidActiveEditorChange(() => { + if (_editorService.activeEditor?.typeId === NotebookEditorInput.ID) { + listener.dispose(); + onDidOpenNotebook(); + } + })); + } + } +} + +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NotebookGettingStarted, LifecyclePhase.Restored); + +registerAction2(class NotebookClearNotebookLayoutAction extends Action2 { + constructor() { + super({ + id: 'workbench.notebook.layout.gettingStarted', + title: localize('workbench.notebook.layout.gettingStarted.label', "Reset notebook getting started"), + f1: true, + category: CATEGORIES.Developer, + }); + } + run(accessor: ServicesAccessor): void { + const storageService = accessor.get(IStorageService); + const memento = new Memento('notebookGettingStarted', storageService); + + const storedValue = memento.getMemento(StorageScope.GLOBAL, StorageTarget.USER); + storedValue[hasOpenedNotebookKey] = undefined; + memento.saveMemento(); + } +}); diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/layout/layoutActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/layout/layoutActions.ts similarity index 92% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/layout/layoutActions.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/layout/layoutActions.ts index b9cadaff9682..1448a578b402 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/layout/layoutActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/layout/layoutActions.ts @@ -8,7 +8,7 @@ import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/act import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { INotebookActionContext, NOTEBOOK_ACTIONS_CATEGORY } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions'; -import { CellToolbarLocKey } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellToolbarLocation } from 'vs/workbench/contrib/notebook/common/notebookCommon'; const TOGGLE_CELL_TOOLBAR_POSITION = 'notebook.toggleCellToolbarPosition'; @@ -33,9 +33,9 @@ export class ToggleCellToolbarPositionAction extends Action2 { // from toolbar const viewType = editor.viewModel.viewType; const configurationService = accessor.get(IConfigurationService); - const toolbarPosition = configurationService.getValue(CellToolbarLocKey); + const toolbarPosition = configurationService.getValue(CellToolbarLocation); const newConfig = this.togglePosition(viewType, toolbarPosition); - await configurationService.updateValue(CellToolbarLocKey, newConfig); + await configurationService.updateValue(CellToolbarLocation, newConfig); } } diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/layout/test/layoutActions.test.ts b/src/vs/workbench/contrib/notebook/browser/contrib/layout/test/layoutActions.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/layout/test/layoutActions.test.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/layout/test/layoutActions.test.ts diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/marker/markerProvider.ts b/src/vs/workbench/contrib/notebook/browser/contrib/marker/markerProvider.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/marker/markerProvider.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/marker/markerProvider.ts diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/navigation/arrow.ts b/src/vs/workbench/contrib/notebook/browser/contrib/navigation/arrow.ts similarity index 96% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/navigation/arrow.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/navigation/arrow.ts index 703fa826ea7d..e42a72f336fd 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/navigation/arrow.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/navigation/arrow.ts @@ -68,7 +68,7 @@ registerAction2(class extends NotebookCellAction { return; } - const newFocusMode = newCell.cellKind === CellKind.Markdown && newCell.getEditState() === CellEditState.Preview ? 'container' : 'editor'; + const newFocusMode = newCell.cellKind === CellKind.Markup && newCell.getEditState() === CellEditState.Preview ? 'container' : 'editor'; editor.focusNotebookCell(newCell, newFocusMode); editor.cursorNavigationMode = true; } @@ -115,7 +115,7 @@ registerAction2(class extends NotebookCellAction { return; } - const newFocusMode = newCell.cellKind === CellKind.Markdown && newCell.getEditState() === CellEditState.Preview ? 'container' : 'editor'; + const newFocusMode = newCell.cellKind === CellKind.Markup && newCell.getEditState() === CellEditState.Preview ? 'container' : 'editor'; editor.focusNotebookCell(newCell, newFocusMode); editor.cursorNavigationMode = true; } diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.css b/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.css rename to src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.css diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts b/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts index f4299895a2f2..0b74fe883264 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts @@ -396,7 +396,7 @@ export class NotebookCellOutline implements IOutline { for (let i = 0; i < viewModel.length; i++) { const cell = viewModel.viewCells[i]; - const isMarkdown = cell.cellKind === CellKind.Markdown; + const isMarkdown = cell.cellKind === CellKind.Markup; if (!isMarkdown && !includeCodeCells) { continue; } diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/outline/test/notebookOutline.test.ts b/src/vs/workbench/contrib/notebook/browser/contrib/outline/test/notebookOutline.test.ts similarity index 94% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/outline/test/notebookOutline.test.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/outline/test/notebookOutline.test.ts index f1e7fe845ba5..0a5f80bc2782 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/outline/test/notebookOutline.test.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/outline/test/notebookOutline.test.ts @@ -49,7 +49,7 @@ suite('Notebook Outline', function () { test('special characters in heading', async function () { await withNotebookOutline([ - ['# Hellö & Hällo', 'md', CellKind.Markdown] + ['# Hellö & Hällo', 'md', CellKind.Markup] ], outline => { assert.ok(outline instanceof NotebookCellOutline); assert.deepStrictEqual(outline.config.quickPickDataSource.getQuickPickElements().length, 1); @@ -57,7 +57,7 @@ suite('Notebook Outline', function () { }); await withNotebookOutline([ - ['# bold', 'md', CellKind.Markdown] + ['# bold', 'md', CellKind.Markup] ], outline => { assert.ok(outline instanceof NotebookCellOutline); assert.deepStrictEqual(outline.config.quickPickDataSource.getQuickPickElements().length, 1); @@ -67,7 +67,7 @@ suite('Notebook Outline', function () { test('Heading text defines entry label', async function () { return await withNotebookOutline([ - ['foo\n # h1', 'md', CellKind.Markdown] + ['foo\n # h1', 'md', CellKind.Markup] ], outline => { assert.ok(outline instanceof NotebookCellOutline); assert.deepStrictEqual(outline.config.quickPickDataSource.getQuickPickElements().length, 1); @@ -77,7 +77,7 @@ suite('Notebook Outline', function () { test('Notebook outline ignores markdown headings #115200', async function () { await withNotebookOutline([ - ['## h2 \n# h1', 'md', CellKind.Markdown] + ['## h2 \n# h1', 'md', CellKind.Markup] ], outline => { assert.ok(outline instanceof NotebookCellOutline); assert.deepStrictEqual(outline.config.quickPickDataSource.getQuickPickElements().length, 2); @@ -86,8 +86,8 @@ suite('Notebook Outline', function () { }); await withNotebookOutline([ - ['## h2', 'md', CellKind.Markdown], - ['# h1', 'md', CellKind.Markdown] + ['## h2', 'md', CellKind.Markup], + ['# h1', 'md', CellKind.Markup] ], outline => { assert.ok(outline instanceof NotebookCellOutline); assert.deepStrictEqual(outline.config.quickPickDataSource.getQuickPickElements().length, 2); diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/profile/notebookProfile.ts b/src/vs/workbench/contrib/notebook/browser/contrib/profile/notebookProfile.ts new file mode 100644 index 000000000000..339665e267eb --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/contrib/profile/notebookProfile.ts @@ -0,0 +1,130 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { Registry } from 'vs/platform/registry/common/platform'; +import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; +import { localize } from 'vs/nls'; +import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { optional } from 'vs/platform/instantiation/common/instantiation'; +import { CellToolbarLocation, CompactView, ConsolidatedRunButton, FocusIndicator, GlobalToolbar, InsertToolbarLocation, ShowCellStatusBar, UndoRedoPerCell } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { ITASExperimentService } from 'vs/workbench/services/experiment/common/experimentService'; +import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; +import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; + +export enum NotebookProfileType { + default = 'default', + jupyter = 'jupyter', + colab = 'colab' +} + +const profiles = { + [NotebookProfileType.default]: { + [FocusIndicator]: 'gutter', + [InsertToolbarLocation]: 'both', + [GlobalToolbar]: true, + [CellToolbarLocation]: { default: 'right' }, + [CompactView]: true, + [ShowCellStatusBar]: 'visible', + [ConsolidatedRunButton]: true, + [UndoRedoPerCell]: false + }, + [NotebookProfileType.jupyter]: { + [FocusIndicator]: 'gutter', + [InsertToolbarLocation]: 'notebookToolbar', + [GlobalToolbar]: true, + [CellToolbarLocation]: { default: 'left' }, + [CompactView]: true, + [ShowCellStatusBar]: 'visible', + [ConsolidatedRunButton]: false, + [UndoRedoPerCell]: true + }, + [NotebookProfileType.colab]: { + [FocusIndicator]: 'border', + [InsertToolbarLocation]: 'betweenCells', + [GlobalToolbar]: false, + [CellToolbarLocation]: { default: 'right' }, + [CompactView]: false, + [ShowCellStatusBar]: 'hidden', + [ConsolidatedRunButton]: true, + [UndoRedoPerCell]: false + } +}; + +async function applyProfile(configService: IConfigurationService, profile: Record): Promise { + const promises = []; + for (let settingKey in profile) { + promises.push(configService.updateValue(settingKey, profile[settingKey])); + } + + await Promise.all(promises); +} + +export interface ISetProfileArgs { + profile: NotebookProfileType; +} + +registerAction2(class extends Action2 { + constructor() { + super({ + id: 'notebook.setProfile', + title: localize('setProfileTitle', "Set Profile") + }); + } + + async run(accessor: ServicesAccessor, args: unknown): Promise { + if (!isSetProfileArgs(args)) { + return; + } + + const configService = accessor.get(IConfigurationService); + return applyProfile(configService, profiles[args.profile]); + } +}); + +function isSetProfileArgs(args: unknown): args is ISetProfileArgs { + const setProfileArgs = args as ISetProfileArgs; + return setProfileArgs.profile === NotebookProfileType.colab || + setProfileArgs.profile === NotebookProfileType.default || + setProfileArgs.profile === NotebookProfileType.jupyter; +} + +export class NotebookProfileContribution extends Disposable { + constructor(@IConfigurationService configService: IConfigurationService, @optional(ITASExperimentService) private readonly experimentService: ITASExperimentService) { + super(); + + if (this.experimentService) { + this.experimentService.getTreatment('notebookprofile').then(treatment => { + if (treatment === undefined) { + return; + } else { + // check if settings are already modified + const focusIndicator = configService.getValue(FocusIndicator); + const insertToolbarPosition = configService.getValue(InsertToolbarLocation); + const globalToolbar = configService.getValue(GlobalToolbar); + // const cellToolbarLocation = configService.getValue(CellToolbarLocation); + const compactView = configService.getValue(CompactView); + const showCellStatusBar = configService.getValue(ShowCellStatusBar); + const consolidatedRunButton = configService.getValue(ConsolidatedRunButton); + if (focusIndicator === 'border' + && insertToolbarPosition === 'both' + && globalToolbar === false + // && cellToolbarLocation === undefined + && compactView === true + && showCellStatusBar === 'visible' + && consolidatedRunButton === true + ) { + applyProfile(configService, profiles[treatment] ?? profiles[NotebookProfileType.default]); + } + } + }); + } + } +} + +const workbenchContributionsRegistry = Registry.as(WorkbenchExtensions.Workbench); +workbenchContributionsRegistry.registerWorkbenchContribution(NotebookProfileContribution, LifecyclePhase.Ready); + diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/status/editorStatus.ts b/src/vs/workbench/contrib/notebook/browser/contrib/status/editorStatus.ts similarity index 66% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/status/editorStatus.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/status/editorStatus.ts index cc3f20a71017..512f64673481 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/status/editorStatus.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/status/editorStatus.ts @@ -5,34 +5,56 @@ import * as nls from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; -import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; +import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IQuickInputButton, IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; -import { NOTEBOOK_ACTIONS_CATEGORY } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions'; -import { getNotebookEditorFromEditorPane, INotebookEditor, NOTEBOOK_IS_ACTIVE_EDITOR } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { NOTEBOOK_ACTIONS_CATEGORY, SELECT_KERNEL_ID } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions'; +import { getNotebookEditorFromEditorPane, INotebookEditor, NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_KERNEL_COUNT } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { combinedDisposable, Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/workbench/services/statusbar/common/statusbar'; import { configureKernelIcon, selectKernelIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; -import { INotebookKernel, INotebookTextModel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookKernel, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ILabelService } from 'vs/platform/label/common/label'; import { ILogService } from 'vs/platform/log/common/log'; +import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; +import { HoverProviderRegistry } from 'vs/editor/common/modes'; +import { Schemas } from 'vs/base/common/network'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; registerAction2(class extends Action2 { constructor() { super({ - id: 'notebook.selectKernel', + id: SELECT_KERNEL_ID, category: NOTEBOOK_ACTIONS_CATEGORY, title: { value: nls.localize('notebookActions.selectKernel', "Select Notebook Kernel"), original: 'Select Notebook Kernel' }, precondition: NOTEBOOK_IS_ACTIVE_EDITOR, icon: selectKernelIcon, f1: true, + menu: [{ + id: MenuId.EditorTitle, + when: ContextKeyExpr.and( + NOTEBOOK_IS_ACTIVE_EDITOR, + NOTEBOOK_KERNEL_COUNT.notEqualsTo(0), + ContextKeyExpr.notEquals('config.notebook.globalToolbar', true) + ), + group: 'navigation', + order: -10 + }, { + id: MenuId.NotebookToolbar, + when: ContextKeyExpr.and( + NOTEBOOK_KERNEL_COUNT.notEqualsTo(0), + ContextKeyExpr.equals('config.notebook.globalToolbar', true) + ), + group: 'status', + order: -10 + }], description: { description: nls.localize('notebookActions.selectKernel.args', "Notebook Kernel Args"), args: [ @@ -54,7 +76,6 @@ registerAction2(class extends Action2 { } ] }, - }); } @@ -144,15 +165,65 @@ registerAction2(class extends Action2 { } }); + +class ImplictKernelSelector implements IDisposable { + + readonly dispose: () => void; + + constructor( + notebook: NotebookTextModel, + suggested: INotebookKernel, + @INotebookKernelService notebookKernelService: INotebookKernelService, + @ILogService logService: ILogService + ) { + const disposables = new DisposableStore(); + this.dispose = disposables.dispose.bind(disposables); + + const selectKernel = () => { + disposables.clear(); + notebookKernelService.selectKernelForNotebook(suggested, notebook); + }; + + // IMPLICITLY select a suggested kernel when the notebook has been changed + // e.g change cell source, move cells, etc + disposables.add(notebook.onDidChangeContent(e => { + for (let event of e.rawEvents) { + switch (event.kind) { + case NotebookCellsChangeType.ChangeCellContent: + case NotebookCellsChangeType.ModelChange: + case NotebookCellsChangeType.Move: + case NotebookCellsChangeType.ChangeLanguage: + logService.trace('IMPLICIT kernel selection because of change event', event.kind); + selectKernel(); + break; + } + } + })); + + + // IMPLICITLY select a suggested kernel when users start to hover. This should + // be a strong enough hint that the user wants to interact with the notebook. Maybe + // add more triggers like goto-providers or completion-providers + disposables.add(HoverProviderRegistry.register({ scheme: Schemas.vscodeNotebookCell, pattern: notebook.uri.path }, { + provideHover() { + logService.trace('IMPLICIT kernel selection because of hover'); + selectKernel(); + return undefined; + } + })); + } +} + export class KernelStatus extends Disposable implements IWorkbenchContribution { private readonly _editorDisposables = this._register(new DisposableStore()); - private readonly _kernelInfoElement = this._register(new MutableDisposable()); + private readonly _kernelInfoElement = this._register(new DisposableStore()); constructor( @IEditorService private readonly _editorService: IEditorService, @IStatusbarService private readonly _statusbarService: IStatusbarService, @INotebookKernelService private readonly _notebookKernelService: INotebookKernelService, + @ILogService private readonly _logService: ILogService, ) { super(); this._register(this._editorService.onDidActiveEditorChange(() => this._updateStatusbar())); @@ -169,6 +240,12 @@ export class KernelStatus extends Disposable implements IWorkbenchContribution { } const updateStatus = () => { + if (activeEditor.notebookOptions.getLayoutConfiguration().globalToolbar) { + // kernel info rendered in the notebook toolbar already + this._kernelInfoElement.clear(); + return; + } + const notebook = activeEditor.viewModel?.notebookDocument; if (notebook) { this._showKernelStatus(notebook); @@ -181,62 +258,68 @@ export class KernelStatus extends Disposable implements IWorkbenchContribution { this._editorDisposables.add(this._notebookKernelService.onDidChangeNotebookKernelBinding(updateStatus)); this._editorDisposables.add(this._notebookKernelService.onDidChangeNotebookAffinity(updateStatus)); this._editorDisposables.add(activeEditor.onDidChangeModel(updateStatus)); + this._editorDisposables.add(activeEditor.notebookOptions.onDidChangeOptions(updateStatus)); updateStatus(); } - private _showKernelStatus(notebook: INotebookTextModel) { + private _showKernelStatus(notebook: NotebookTextModel) { + + this._kernelInfoElement.clear(); - let { selected, all } = this._notebookKernelService.getMatchingKernel(notebook); + let { selected, suggested, all } = this._notebookKernelService.getMatchingKernel(notebook); let isSuggested = false; if (all.length === 0) { // no kernel -> no status - this._kernelInfoElement.clear(); return; - } else if (selected || all.length === 1) { + } else if (selected || suggested) { // selected or single kernel - if (!selected) { - selected = all[0]; + let kernel = selected; + + if (!kernel) { + // proceed with suggested kernel - show UI and install handler that selects the kernel + // when non trivial interactions with the notebook happen. + kernel = suggested!; isSuggested = true; + this._kernelInfoElement.add(new ImplictKernelSelector(notebook, kernel, this._notebookKernelService, this._logService)); } - const text = `$(notebook-kernel-select) ${selected.label}`; - const tooltip = selected.description ?? selected.detail ?? selected.label; - const registration = this._statusbarService.addEntry( + const tooltip = kernel.description ?? kernel.detail ?? kernel.label; + this._kernelInfoElement.add(this._statusbarService.addEntry( { - text, - ariaLabel: selected.label, + name: nls.localize('notebook.info', "Notebook Kernel Info"), + text: `$(notebook-kernel-select) ${kernel.label}`, + ariaLabel: kernel.label, tooltip: isSuggested ? nls.localize('tooltop', "{0} (suggestion)", tooltip) : tooltip, - command: 'notebook.selectKernel', + command: SELECT_KERNEL_ID, }, 'notebook.selectKernel', - nls.localize('notebook.info', "Notebook Kernel Info"), StatusbarAlignment.RIGHT, - 1000 - ); - const listener = selected.onDidChange(() => this._showKernelStatus(notebook)); - this._kernelInfoElement.value = combinedDisposable(listener, registration); + 10 + )); + + this._kernelInfoElement.add(kernel.onDidChange(() => this._showKernelStatus(notebook))); + } else { // multiple kernels -> show selection hint - const registration = this._statusbarService.addEntry( + this._kernelInfoElement.add(this._statusbarService.addEntry( { + name: nls.localize('notebook.select', "Notebook Kernel Selection"), text: nls.localize('kernel.select.label', "Select Kernel"), ariaLabel: nls.localize('kernel.select.label', "Select Kernel"), - command: 'notebook.selectKernel', + command: SELECT_KERNEL_ID, backgroundColor: { id: 'statusBarItem.prominentBackground' } }, 'notebook.selectKernel', - nls.localize('notebook.select', "Notebook Kernel Selection"), StatusbarAlignment.RIGHT, - 1000 - ); - this._kernelInfoElement.value = registration; + 10 + )); } } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(KernelStatus, LifecyclePhase.Ready); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(KernelStatus, LifecyclePhase.Restored); export class ActiveCellStatus extends Disposable implements IWorkbenchContribution { @@ -276,14 +359,14 @@ export class ActiveCellStatus extends Disposable implements IWorkbenchContributi return; } - const entry = { text: newText, ariaLabel: newText }; + const entry = { name: nls.localize('notebook.activeCellStatusName', "Notebook Editor Selections"), text: newText, ariaLabel: newText }; if (!this._accessor.value) { this._accessor.value = this._statusbarService.addEntry( entry, 'notebook.activeCellStatus', - nls.localize('notebook.activeCellStatusName', "Notebook Editor Selections"), StatusbarAlignment.RIGHT, - 100); + 100 + ); } else { this._accessor.value.update(entry); } @@ -297,10 +380,11 @@ export class ActiveCellStatus extends Disposable implements IWorkbenchContributi const idxFocused = vm.getCellIndex(activeCell) + 1; const numSelected = vm.getSelections().reduce((prev, range) => prev + (range.end - range.start), 0); + const totalCells = vm.getCells().length; return numSelected > 1 ? nls.localize('notebook.multiActiveCellIndicator', "Cell {0} ({1} selected)", idxFocused, numSelected) : - nls.localize('notebook.singleActiveCellIndicator', "Cell {0}", idxFocused); + nls.localize('notebook.singleActiveCellIndicator', "Cell {0} of {1}", idxFocused, totalCells); } } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ActiveCellStatus, LifecyclePhase.Ready); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ActiveCellStatus, LifecyclePhase.Restored); diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/contributedStatusBarItemController.ts b/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/contributedStatusBarItemController.ts similarity index 88% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/contributedStatusBarItemController.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/statusBar/contributedStatusBarItemController.ts index 4358ff31a02d..a625c2e73304 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/contributedStatusBarItemController.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/contributedStatusBarItemController.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { flatten } from 'vs/base/common/arrays'; -import { Throttler } from 'vs/base/common/async'; +import { disposableTimeout, Throttler } from 'vs/base/common/async'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { ICellVisibilityChangeEvent, NotebookVisibleCellObserver } from 'vs/workbench/contrib/notebook/browser/contrib/statusBar/notebookVisibleCellObserver'; @@ -15,7 +15,7 @@ import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/com import { INotebookCellStatusBarItemList } from 'vs/workbench/contrib/notebook/common/notebookCommon'; export class ContributedStatusBarItemController extends Disposable implements INotebookEditorContribution { - static id: string = 'workbench.notebook.statusBar'; + static id: string = 'workbench.notebook.statusBar.contributed'; private readonly _visibleCells = new Map(); @@ -69,7 +69,7 @@ class CellStatusBarHelper extends Disposable { private _currentItemIds: string[] = []; private _currentItemLists: INotebookCellStatusBarItemList[] = []; - private readonly _cancelTokenSource: CancellationTokenSource; + private _activeToken: CancellationTokenSource | undefined; private readonly _updateThrottler = new Throttler(); @@ -80,29 +80,31 @@ class CellStatusBarHelper extends Disposable { ) { super(); - this._cancelTokenSource = new CancellationTokenSource(); - this._register(toDisposable(() => this._cancelTokenSource.dispose(true))); - + this._register(toDisposable(() => this._activeToken?.dispose(true))); this._updateSoon(); this._register(this._cell.model.onDidChangeContent(() => this._updateSoon())); this._register(this._cell.model.onDidChangeLanguage(() => this._updateSoon())); this._register(this._cell.model.onDidChangeMetadata(() => this._updateSoon())); + this._register(this._cell.model.onDidChangeInternalMetadata(() => this._updateSoon())); this._register(this._cell.model.onDidChangeOutputs(() => this._updateSoon())); } private _updateSoon(): void { // Wait a tick to make sure that the event is fired to the EH before triggering status bar providers - setTimeout(() => { + this._register(disposableTimeout(() => { this._updateThrottler.queue(() => this._update()); - }, 0); + }, 0)); } private async _update() { const cellIndex = this._notebookViewModel.getCellIndex(this._cell); const docUri = this._notebookViewModel.notebookDocument.uri; const viewType = this._notebookViewModel.notebookDocument.viewType; - const itemLists = await this._notebookCellStatusBarService.getStatusBarItemsForCell(docUri, cellIndex, viewType, this._cancelTokenSource.token); - if (this._cancelTokenSource.token.isCancellationRequested) { + + this._activeToken?.dispose(true); + const tokenSource = this._activeToken = new CancellationTokenSource(); + const itemLists = await this._notebookCellStatusBarService.getStatusBarItemsForCell(docUri, cellIndex, viewType, tokenSource.token); + if (tokenSource.token.isCancellationRequested) { itemLists.forEach(itemList => itemList.dispose && itemList.dispose()); return; } diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/executionStatusBarItemController.ts b/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/executionStatusBarItemController.ts similarity index 59% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/executionStatusBarItemController.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/statusBar/executionStatusBarItemController.ts index 438389b3780d..e32ba0518d53 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/executionStatusBarItemController.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/executionStatusBarItemController.ts @@ -4,19 +4,23 @@ *--------------------------------------------------------------------------------------------*/ import { RunOnceScheduler } from 'vs/base/common/async'; -import { Event } from 'vs/base/common/event'; import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { localize } from 'vs/nls'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { InputFocusedContext } from 'vs/platform/contextkey/common/contextkeys'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { themeColorFromId } from 'vs/platform/theme/common/themeService'; import { ICellVisibilityChangeEvent, NotebookVisibleCellObserver } from 'vs/workbench/contrib/notebook/browser/contrib/statusBar/notebookVisibleCellObserver'; -import { ICellViewModel, INotebookEditor, INotebookEditorContribution } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { EXECUTE_CELL_COMMAND_ID, ICellViewModel, INotebookEditor, INotebookEditorContribution, NOTEBOOK_CELL_EXECUTION_STATE, QUIT_EDIT_CELL_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { registerNotebookContribution } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions'; import { cellStatusIconError, cellStatusIconSuccess } from 'vs/workbench/contrib/notebook/browser/notebookEditorWidget'; import { NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; -import { CellStatusbarAlignment, INotebookCellStatusBarItem, NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, CellStatusbarAlignment, INotebookCellStatusBarItem, NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon'; export class NotebookStatusBarController extends Disposable implements INotebookEditorContribution { - static id: string = 'workbench.notebook.statusBar'; + static id: string = 'workbench.notebook.statusBar.exec'; private readonly _visibleCells = new Map(); @@ -24,6 +28,7 @@ export class NotebookStatusBarController extends Disposable implements INotebook constructor( private readonly _notebookEditor: INotebookEditor, + @IInstantiationService private readonly _instantiationService: IInstantiationService ) { super(); this._observer = this._register(new NotebookVisibleCellObserver(this._notebookEditor)); @@ -46,8 +51,9 @@ export class NotebookStatusBarController extends Disposable implements INotebook for (let newCell of e.added) { const helpers = [ - new ExecutionStateCellStatusBarHelper(vm, newCell), - new TimerCellStatusBarHelper(vm, newCell) + this._instantiationService.createInstance(ExecutionStateCellStatusBarHelper, vm, newCell), + this._instantiationService.createInstance(TimerCellStatusBarHelper, vm, newCell), + this._instantiationService.createInstance(KeybindingPlaceholderStatusBarHelper, vm, newCell), ]; this._visibleCells.set(newCell.handle, helpers); } @@ -83,7 +89,7 @@ class ExecutionStateCellStatusBarHelper extends Disposable { super(); this._update(); - this._register(this._cell.model.onDidChangeMetadata(() => this._update())); + this._register(this._cell.model.onDidChangeInternalMetadata(() => this._update())); } private async _update() { @@ -101,13 +107,13 @@ class ExecutionStateCellStatusBarHelper extends Disposable { return; } - const item = this._getItemForState(cell.metadata?.runState, cell.metadata?.lastRunSuccess); + const item = this._getItemForState(cell.internalMetadata.runState, cell.internalMetadata.lastRunSuccess); // Show the execution spinner for a minimum time - if (cell.metadata?.runState === NotebookCellExecutionState.Executing) { + if (cell.internalMetadata.runState === NotebookCellExecutionState.Executing) { this._currentExecutingStateTimer = setTimeout(() => { this._currentExecutingStateTimer = undefined; - if (cell.metadata?.runState !== NotebookCellExecutionState.Executing) { + if (cell.internalMetadata.runState !== NotebookCellExecutionState.Executing) { this._update(); } }, ExecutionStateCellStatusBarHelper.MIN_SPINNER_TIME); @@ -117,7 +123,7 @@ class ExecutionStateCellStatusBarHelper extends Disposable { } private _getItemForState(runState: NotebookCellExecutionState | undefined, lastRunSuccess: boolean | undefined): INotebookCellStatusBarItem | undefined { - if (runState === NotebookCellExecutionState.Idle && lastRunSuccess) { + if (!runState && lastRunSuccess) { return { text: '$(notebook-state-success)', color: themeColorFromId(cellStatusIconSuccess), @@ -125,7 +131,7 @@ class ExecutionStateCellStatusBarHelper extends Disposable { alignment: CellStatusbarAlignment.Left, priority: Number.MAX_SAFE_INTEGER }; - } else if (runState === NotebookCellExecutionState.Idle && lastRunSuccess === false) { + } else if (!runState && lastRunSuccess === false) { return { text: '$(notebook-state-error)', color: themeColorFromId(cellStatusIconError), @@ -173,23 +179,22 @@ class TimerCellStatusBarHelper extends Disposable { this._scheduler = this._register(new RunOnceScheduler(() => this._update(), TimerCellStatusBarHelper.UPDATE_INTERVAL)); this._update(); - this._register( - Event.filter(this._cell.model.onDidChangeMetadata, e => !!e.runStateChanged) - (() => this._update())); + this._register(this._cell.model.onDidChangeInternalMetadata(() => this._update())); } private async _update() { let item: INotebookCellStatusBarItem | undefined; - if (this._cell.metadata?.runState === NotebookCellExecutionState.Executing) { - const startTime = this._cell.metadata.runStartTime; - const adjustment = this._cell.metadata.runStartTimeAdjustment; + const state = this._cell.internalMetadata.runState; + if (state === NotebookCellExecutionState.Executing) { + const startTime = this._cell.internalMetadata.runStartTime; + const adjustment = this._cell.internalMetadata.runStartTimeAdjustment; if (typeof startTime === 'number') { item = this._getTimeItem(startTime, Date.now(), adjustment); this._scheduler.schedule(); } - } else if (this._cell.metadata?.runState === NotebookCellExecutionState.Idle) { - const startTime = this._cell.metadata.runStartTime; - const endTime = this._cell.metadata.runEndTime; + } else if (!state) { + const startTime = this._cell.internalMetadata.runStartTime; + const endTime = this._cell.internalMetadata.runEndTime; if (typeof startTime === 'number' && typeof endTime === 'number') { item = this._getTimeItem(startTime, endTime); } @@ -222,4 +227,80 @@ class TimerCellStatusBarHelper extends Disposable { } } +/** + * Shows a keybinding hint for the execute command + */ +class KeybindingPlaceholderStatusBarHelper extends Disposable { + private _currentItemIds: string[] = []; + private readonly _contextKeyService: IContextKeyService; + + constructor( + private readonly _notebookViewModel: NotebookViewModel, + private readonly _cell: ICellViewModel, + @IKeybindingService private readonly _keybindingService: IKeybindingService, + @IContextKeyService _contextKeyService: IContextKeyService, + ) { + super(); + + // Create a fake ContextKeyService, and look up the keybindings within this context. + this._contextKeyService = this._register(_contextKeyService.createScoped(document.createElement('div'))); + InputFocusedContext.bindTo(this._contextKeyService).set(true); + EditorContextKeys.editorTextFocus.bindTo(this._contextKeyService).set(true); + EditorContextKeys.focus.bindTo(this._contextKeyService).set(true); + EditorContextKeys.textInputFocus.bindTo(this._contextKeyService).set(true); + NOTEBOOK_CELL_EXECUTION_STATE.bindTo(this._contextKeyService).set('idle'); + + this._update(); + this._register(this._cell.model.onDidChangeInternalMetadata(() => this._update())); + } + + private async _update() { + const items = this._getItemsForCell(this._cell); + if (Array.isArray(items)) { + this._currentItemIds = this._notebookViewModel.deltaCellStatusBarItems(this._currentItemIds, [{ handle: this._cell.handle, items }]); + } + } + + private _getItemsForCell(cell: ICellViewModel): INotebookCellStatusBarItem[] { + if (typeof cell.internalMetadata.runState !== 'undefined' || typeof cell.internalMetadata.lastRunSuccess !== 'undefined') { + return []; + } + + let text: string; + if (cell.cellKind === CellKind.Code) { + const keybinding = this._keybindingService.lookupKeybinding(EXECUTE_CELL_COMMAND_ID, this._contextKeyService)?.getLabel(); + if (!keybinding) { + return []; + } + + text = localize('notebook.cell.status.codeExecuteTip', "Press {0} to execute cell", keybinding); + } else { + const keybinding = this._keybindingService.lookupKeybinding(QUIT_EDIT_CELL_COMMAND_ID, this._contextKeyService)?.getLabel(); + if (!keybinding) { + return []; + } + + text = localize('notebook.cell.status.markdownExecuteTip', "Press {0} to stop editing", keybinding); + } + + const item = { + text, + tooltip: text, + alignment: CellStatusbarAlignment.Left, + opacity: '0.7', + onlyShowWhenActive: true, + priority: 100 + }; + + return [item]; + } + + + override dispose() { + super.dispose(); + + this._notebookViewModel.deltaCellStatusBarItems(this._currentItemIds, [{ handle: this._cell.handle, items: [] }]); + } +} + registerNotebookContribution(NotebookStatusBarController.id, NotebookStatusBarController); diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/notebookVisibleCellObserver.ts b/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/notebookVisibleCellObserver.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/notebookVisibleCellObserver.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/statusBar/notebookVisibleCellObserver.ts diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/statusBarProviders.ts b/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/statusBarProviders.ts similarity index 67% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/statusBarProviders.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/statusBar/statusBarProviders.ts index 31b6e4282d2d..c18498f3c6de 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/statusBarProviders.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/statusBarProviders.ts @@ -5,7 +5,6 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { Disposable } from 'vs/base/common/lifecycle'; -import { isWindows } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { IModeService } from 'vs/editor/common/services/modeService'; import { localize } from 'vs/nls'; @@ -15,52 +14,12 @@ import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } fr import { CHANGE_CELL_LANGUAGE } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService'; import { CellKind, CellStatusbarAlignment, INotebookCellStatusBarItem, INotebookCellStatusBarItemList, INotebookCellStatusBarItemProvider } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { NotebookSelector } from 'vs/workbench/contrib/notebook/common/notebookSelector'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -class CellStatusBarPlaceholderProvider implements INotebookCellStatusBarItemProvider { - readonly selector: NotebookSelector = { - pattern: '**/*' - }; - - constructor( - @INotebookService private readonly _notebookService: INotebookService, - ) { } - - async provideCellStatusBarItems(uri: URI, index: number, token: CancellationToken): Promise { - const doc = this._notebookService.getNotebookTextModel(uri); - const cell = doc?.cells[index]; - if (!cell || typeof cell.metadata.runState !== 'undefined' || typeof cell.metadata.lastRunSuccess !== 'undefined') { - return; - } - - let text: string; - if (cell.cellKind === CellKind.Code) { - text = isWindows ? - localize('notebook.cell.status.codeExecuteTipWin', "Press Ctrl+Alt+Enter to execute cell") : - localize('notebook.cell.status.codeExecuteTipNotWin', "Press Ctrl+Enter to execute cell"); - } else { - text = localize('notebook.cell.status.markdownExecuteTip', "Press Escape to stop editing"); - } - - const item = { - text, - tooltip: text, - alignment: CellStatusbarAlignment.Left, - opacity: '0.7', - onlyShowWhenActive: true - }; - return { - items: [item] - }; - } -} - class CellStatusBarLanguagePickerProvider implements INotebookCellStatusBarItemProvider { - readonly selector: NotebookSelector = { - pattern: '**/*' - }; + + readonly viewType = '*'; constructor( @INotebookService private readonly _notebookService: INotebookService, @@ -74,7 +33,7 @@ class CellStatusBarLanguagePickerProvider implements INotebookCellStatusBarItemP return; } - const modeId = cell.cellKind === CellKind.Markdown ? + const modeId = cell.cellKind === CellKind.Markup ? 'markdown' : (this._modeService.getModeIdForLanguageName(cell.language) || cell.language); const text = this._modeService.getLanguageName(modeId) || this._modeService.getLanguageName('plaintext'); @@ -98,7 +57,6 @@ class BuiltinCellStatusBarProviders extends Disposable { super(); const builtinProviders = [ - CellStatusBarPlaceholderProvider, CellStatusBarLanguagePickerProvider, ]; builtinProviders.forEach(p => { diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/troubleshoot/layout.ts b/src/vs/workbench/contrib/notebook/browser/contrib/troubleshoot/layout.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/troubleshoot/layout.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/troubleshoot/layout.ts diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/notebookUndoRedo.ts b/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/notebookUndoRedo.ts similarity index 77% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/notebookUndoRedo.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/notebookUndoRedo.ts index b198ae8de101..c2e5a97057e6 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/notebookUndoRedo.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/notebookUndoRedo.ts @@ -9,7 +9,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { CellEditState, getNotebookEditorFromEditorPane, NotebookEditorOptions } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellEditState, getNotebookEditorFromEditorPane } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { RedoCommand, UndoCommand } from 'vs/editor/browser/editorExtensions'; class NotebookUndoRedoContribution extends Disposable { @@ -24,12 +24,12 @@ class NotebookUndoRedoContribution extends Disposable { return editor.viewModel.undo().then(cellResources => { if (cellResources?.length) { editor?.viewModel?.viewCells.forEach(cell => { - if (cell.cellKind === CellKind.Markdown && cellResources.find(resource => resource.fragment === cell.model.uri.fragment)) { + if (cell.cellKind === CellKind.Markup && cellResources.find(resource => resource.fragment === cell.model.uri.fragment)) { cell.updateEditState(CellEditState.Editing, 'undo'); } }); - editor?.setOptions(new NotebookEditorOptions({ cellOptions: { resource: cellResources[0] }, preserveFocus: true })); + editor?.setOptions({ cellOptions: { resource: cellResources[0] }, preserveFocus: true }); } }); } @@ -43,12 +43,12 @@ class NotebookUndoRedoContribution extends Disposable { return editor.viewModel.redo().then(cellResources => { if (cellResources?.length) { editor?.viewModel?.viewCells.forEach(cell => { - if (cell.cellKind === CellKind.Markdown && cellResources.find(resource => resource.fragment === cell.model.uri.fragment)) { + if (cell.cellKind === CellKind.Markup && cellResources.find(resource => resource.fragment === cell.model.uri.fragment)) { cell.updateEditState(CellEditState.Editing, 'redo'); } }); - editor?.setOptions(new NotebookEditorOptions({ cellOptions: { resource: cellResources[0] }, preserveFocus: true })); + editor?.setOptions({ cellOptions: { resource: cellResources[0] }, preserveFocus: true }); } }); } diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/test/notebookUndoRedo.test.ts b/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/test/notebookUndoRedo.test.ts similarity index 91% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/test/notebookUndoRedo.test.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/test/notebookUndoRedo.test.ts index 5c4358699baf..f9c76ebf4b99 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/test/notebookUndoRedo.test.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/undoRedo/test/notebookUndoRedo.test.ts @@ -12,8 +12,8 @@ suite('Notebook Undo/Redo', () => { test('Basics', async function () { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['body', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['body', 'markdown', CellKind.Markup, [], {}], ], async (editor, accessor) => { const modeService = accessor.get(IModeService); @@ -57,8 +57,8 @@ suite('Notebook Undo/Redo', () => { test('Invalid replace count should not throw', async function () { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['body', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['body', 'markdown', CellKind.Markup, [], {}], ], async (editor, accessor) => { const modeService = accessor.get(IModeService); @@ -81,8 +81,8 @@ suite('Notebook Undo/Redo', () => { test('Replace beyond length', async function () { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['body', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['body', 'markdown', CellKind.Markup, [], {}], ], async (editor) => { const viewModel = editor.viewModel; @@ -100,8 +100,8 @@ suite('Notebook Undo/Redo', () => { test('Invalid replace count should not affect undo/redo', async function () { await withTestNotebook( [ - ['# header 1', 'markdown', CellKind.Markdown, [], {}], - ['body', 'markdown', CellKind.Markdown, [], {}], + ['# header 1', 'markdown', CellKind.Markup, [], {}], + ['body', 'markdown', CellKind.Markup, [], {}], ], async (editor, accessor) => { const modeService = accessor.get(IModeService); diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/viewportCustomMarkdown/viewportCustomMarkdown.ts b/src/vs/workbench/contrib/notebook/browser/contrib/viewportCustomMarkdown/viewportCustomMarkdown.ts similarity index 80% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/viewportCustomMarkdown/viewportCustomMarkdown.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/viewportCustomMarkdown/viewportCustomMarkdown.ts index ac8c52e30f90..d9838fa18699 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/contrib/viewportCustomMarkdown/viewportCustomMarkdown.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/viewportCustomMarkdown/viewportCustomMarkdown.ts @@ -13,7 +13,7 @@ import { BUILTIN_RENDERER_ID, CellKind } from 'vs/workbench/contrib/notebook/com import { cellRangesToIndexes } from 'vs/workbench/contrib/notebook/common/notebookRange'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; -class NotebookClipboardContribution extends Disposable implements INotebookEditorContribution { +class NotebookViewportContribution extends Disposable implements INotebookEditorContribution { static id: string = 'workbench.notebook.viewportCustomMarkdown'; private readonly _warmupViewport: RunOnceScheduler; @@ -22,18 +22,26 @@ class NotebookClipboardContribution extends Disposable implements INotebookEdito super(); this._warmupViewport = new RunOnceScheduler(() => this._warmupViewportNow(), 200); - + this._register(this._warmupViewport); this._register(this._notebookEditor.onDidScroll(() => { this._warmupViewport.schedule(); })); } private _warmupViewportNow() { + if (this._notebookEditor.isDisposed) { + return; + } + + if (!this._notebookEditor.hasModel()) { + return; + } + const visibleRanges = this._notebookEditor.getVisibleRangesPlusViewportAboveBelow(); cellRangesToIndexes(visibleRanges).forEach(index => { const cell = this._notebookEditor.viewModel?.viewCells[index]; - if (cell?.cellKind === CellKind.Markdown && cell?.getEditState() === CellEditState.Preview && !cell.metadata?.inputCollapsed) { + if (cell?.cellKind === CellKind.Markup && cell?.getEditState() === CellEditState.Preview && !cell.metadata.inputCollapsed) { this._notebookEditor.createMarkdownPreview(cell); } else if (cell?.cellKind === CellKind.Code) { const viewCell = (cell as CodeCellViewModel); @@ -50,10 +58,14 @@ class NotebookClipboardContribution extends Disposable implements INotebookEdito return; } + if (!this._notebookEditor.hasModel()) { + return; + } + if (pickedMimeTypeRenderer.rendererId === BUILTIN_RENDERER_ID) { const renderer = this._notebookEditor.getOutputRenderer().getContribution(pickedMimeTypeRenderer.mimeType); if (renderer?.getType() === RenderOutputType.Html) { - const renderResult = renderer!.render(output, output.model.outputs.filter(op => op.mime === pickedMimeTypeRenderer.mimeType), DOM.$(''), undefined) as IInsetRenderOutput; + const renderResult = renderer.render(output, output.model.outputs.filter(op => op.mime === pickedMimeTypeRenderer.mimeType), DOM.$(''), this._notebookEditor.viewModel.uri) as IInsetRenderOutput; this._notebookEditor.createOutput(viewCell, renderResult, 0); } return; @@ -72,4 +84,4 @@ class NotebookClipboardContribution extends Disposable implements INotebookEdito } } -registerNotebookContribution(NotebookClipboardContribution.id, NotebookClipboardContribution); +registerNotebookContribution(NotebookViewportContribution.id, NotebookViewportContribution); diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts similarity index 97% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts rename to src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index da02d0400db0..ba85ba7c48dd 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -5,11 +5,11 @@ import * as DOM from 'vs/base/browser/dom'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { Schemas } from 'vs/base/common/network'; import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { DiffElementViewModelBase, getFormatedMetadataJSON, OUTPUT_EDITOR_HEIGHT_MAGIC, PropertyFoldingState, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DiffSide, DIFF_CELL_MARGIN, INotebookTextDiffEditor, NOTEBOOK_DIFF_CELL_PROPERTY, NOTEBOOK_DIFF_CELL_PROPERTY_EXPANDED } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; -import { EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; import { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -25,7 +25,6 @@ import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/men import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { Delayer } from 'vs/base/common/async'; import { CodiconActionViewItem } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellActionView'; -import { getEditorTopPadding } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { collapsedIcon, expandedIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; import { OutputContainer } from 'vs/workbench/contrib/notebook/browser/diff/diffElementOutputs'; import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; @@ -41,11 +40,12 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +const fixedEditorPadding = { + top: 12, + bottom: 12 +}; export const fixedEditorOptions: IEditorOptions = { - padding: { - top: 12, - bottom: 12 - }, + padding: fixedEditorPadding, scrollBeyondLastLine: false, scrollbar: { verticalScrollbarSize: 14, @@ -491,22 +491,6 @@ abstract class AbstractElementRenderer extends Disposable { } break; - case 'executionOrder': - // number - if (typeof newMetadataObj[key] === 'number') { - result[key] = newMetadataObj[key]; - } else { - result[key] = currentMetadata[key as keyof NotebookCellMetadata]; - } - break; - case 'runState': - // enum - if (typeof newMetadataObj[key] === 'number' && [1, 2, 3, 4].indexOf(newMetadataObj[key]) >= 0) { - result[key] = newMetadataObj[key]; - } else { - result[key] = currentMetadata[key as keyof NotebookCellMetadata]; - } - break; default: result[key] = newMetadataObj[key]; break; @@ -550,8 +534,8 @@ abstract class AbstractElementRenderer extends Disposable { this._metadataEditorContainer?.classList.add('diff'); - const originalMetadataModel = await this.textModelService.createModelReference(CellUri.generateCellMetadataUri(this.cell.originalDocument.uri, this.cell.original!.handle)); - const modifiedMetadataModel = await this.textModelService.createModelReference(CellUri.generateCellMetadataUri(this.cell.modifiedDocument.uri, this.cell.modified!.handle)); + const originalMetadataModel = await this.textModelService.createModelReference(CellUri.generateCellUri(this.cell.originalDocument.uri, this.cell.original!.handle, Schemas.vscodeNotebookCellMetadata)); + const modifiedMetadataModel = await this.textModelService.createModelReference(CellUri.generateCellUri(this.cell.modifiedDocument.uri, this.cell.modified!.handle, Schemas.vscodeNotebookCellMetadata)); this._metadataEditor.setModel({ original: originalMetadataModel.object.textEditorModel, modified: modifiedMetadataModel.object.textEditorModel @@ -613,7 +597,7 @@ abstract class AbstractElementRenderer extends Disposable { ? this.cell.modified!.handle : this.cell.original!.handle; - const modelUri = CellUri.generateCellMetadataUri(uri, handle); + const modelUri = CellUri.generateCellUri(uri, handle, Schemas.vscodeNotebookCellMetadata); const metadataModel = this.modelService.createModel(originalMetadataSource, mode, modelUri, false); this._metadataEditor.setModel(metadataModel); this._metadataEditorDisposeStore.add(metadataModel); @@ -979,7 +963,7 @@ export class DeletedElement extends SingleSideDiffElement { const originalCell = this.cell.original!; const lineCount = originalCell.textModel.textBuffer.getLineCount(); const lineHeight = this.notebookEditor.getLayoutInfo().fontInfo.lineHeight || 17; - const editorHeight = lineCount * lineHeight + getEditorTopPadding() + EDITOR_BOTTOM_PADDING; + const editorHeight = lineCount * lineHeight + fixedEditorPadding.top + fixedEditorPadding.bottom; this._editor = this.templateData.sourceEditor; this._editor.layout({ @@ -1130,7 +1114,7 @@ export class InsertElement extends SingleSideDiffElement { const modifiedCell = this.cell.modified!; const lineCount = modifiedCell.textModel.textBuffer.getLineCount(); const lineHeight = this.notebookEditor.getLayoutInfo().fontInfo.lineHeight || 17; - const editorHeight = lineCount * lineHeight + getEditorTopPadding() + EDITOR_BOTTOM_PADDING; + const editorHeight = lineCount * lineHeight + fixedEditorPadding.top + fixedEditorPadding.bottom; this._editor = this.templateData.sourceEditor; this._editor.layout( @@ -1468,7 +1452,8 @@ export class ModifiedElement extends AbstractElementRenderer { const modifiedCell = this.cell.modified!; const lineCount = modifiedCell.textModel.textBuffer.getLineCount(); const lineHeight = this.notebookEditor.getLayoutInfo().fontInfo.lineHeight || 17; - const editorHeight = this.cell.layoutInfo.editorHeight !== 0 ? this.cell.layoutInfo.editorHeight : lineCount * lineHeight + getEditorTopPadding() + EDITOR_BOTTOM_PADDING; + + const editorHeight = this.cell.layoutInfo.editorHeight !== 0 ? this.cell.layoutInfo.editorHeight : lineCount * lineHeight + fixedEditorPadding.top + fixedEditorPadding.bottom; this._editorContainer = this.templateData.editorContainer; this._editor = this.templateData.sourceEditor; diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts similarity index 97% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts rename to src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts index 160389b88141..013bdbd92c68 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts @@ -14,7 +14,6 @@ import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/r import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { BUILTIN_RENDERER_ID, NotebookCellOutputsSplice } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; -import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { mimetypeIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; @@ -90,7 +89,7 @@ export class OutputElement extends Disposable { result = this._notebookEditor.getOutputRenderer().render(this.output, innerContainer, pickedMimeTypeRenderer.mimeType, this._notebookTextModel.uri); } - this.output.pickedMimeType = pick; + this.output.pickedMimeType = pickedMimeTypeRenderer; } this.domNode = outputItemDiv; @@ -202,7 +201,7 @@ export class OutputElement extends Disposable { ); } - viewModel.pickedMimeType = pick; + viewModel.pickedMimeType = mimeTypes[pick]; this.render(index, nextElement as HTMLElement); } } @@ -250,9 +249,7 @@ export class OutputContainer extends Disposable { private _outputContainer: HTMLElement, @INotebookService private _notebookService: INotebookService, @IQuickInputService private readonly _quickInputService: IQuickInputService, - @IOpenerService readonly _openerService: IOpenerService, - @ITextFileService readonly _textFileService: ITextFileService, - + @IOpenerService readonly _openerService: IOpenerService ) { super(); this._register(this._diffElementViewModel.onDidLayoutChange(() => { diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts rename to src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts rename to src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/eventDispatcher.ts b/src/vs/workbench/contrib/notebook/browser/diff/eventDispatcher.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/eventDispatcher.ts rename to src/vs/workbench/contrib/notebook/browser/diff/eventDispatcher.ts diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css rename to src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts similarity index 95% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts rename to src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts index ededf65643a0..edd615095787 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts @@ -45,15 +45,17 @@ registerAction2(class extends Action2 { const activeEditor = editorService.activeEditorPane; if (activeEditor && activeEditor instanceof NotebookTextDiffEditor) { const diffEditorInput = activeEditor.input as NotebookDiffEditorInput; - const leftResource = diffEditorInput.originalResource; - const rightResource = diffEditorInput.resource; - const options = { - preserveFocus: false - }; - - const label = diffEditorInput.textDiffName; - const input = editorService.createEditorInput({ leftResource, rightResource, label, options }); - await editorService.openEditor(input, { override: EditorOverride.DISABLED }, viewColumnToEditorGroup(editorGroupService, undefined)); + + await editorService.openEditor( + { + originalInput: { resource: diffEditorInput.originalResource }, + modifiedInput: { resource: diffEditorInput.resource }, + label: diffEditorInput.textDiffName, + options: { + preserveFocus: false, + override: EditorOverride.DISABLED + } + }, viewColumnToEditorGroup(editorGroupService, undefined)); } } }); diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts similarity index 97% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts rename to src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts index 0ca043aacff0..9685efbaec3c 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts @@ -15,6 +15,7 @@ import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { NotebookOptions } from 'vs/workbench/contrib/notebook/common/notebookOptions'; export enum DiffSide { Original = 0, @@ -26,6 +27,7 @@ export interface IDiffCellInfo extends ICommonCellInfo { } export interface INotebookTextDiffEditor extends ICommonNotebookEditor { + notebookOptions: NotebookOptions; readonly textModel?: NotebookTextModel; onMouseUp: Event<{ readonly event: MouseEvent; readonly target: DiffElementViewModelBase; }>; onDidDynamicOutputRendered: Event<{ cell: IGenericCellViewModel, output: ICellOutputViewModel }>; diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts similarity index 94% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts rename to src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 03d33ccf4969..6b6904662873 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -8,7 +8,7 @@ import * as DOM from 'vs/base/browser/dom'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -import { EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor'; +import { IEditorOpenContext } from 'vs/workbench/common/editor'; import { notebookCellBorder, NotebookEditorWidget } from 'vs/workbench/contrib/notebook/browser/notebookEditorWidget'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { NotebookDiffEditorInput } from '../notebookDiffEditorInput'; @@ -20,10 +20,10 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { diffDiagonalFill, diffInserted, diffRemoved, editorBackground, focusBorder, foreground } from 'vs/platform/theme/common/colorRegistry'; import { INotebookEditorWorkerService } from 'vs/workbench/contrib/notebook/common/services/notebookWorkerService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IEditorOptions as ICodeEditorOptions } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo'; import { getPixelRatio, getZoomLevel } from 'vs/base/browser/browser'; -import { CellEditState, ICellOutputViewModel, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel, IInsetRenderOutput, NotebookLayoutInfo, NOTEBOOK_DIFF_EDITOR_ID } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellEditState, ICellOutputViewModel, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel, IInsetRenderOutput, INotebookEditorOptions, NotebookLayoutInfo, NOTEBOOK_DIFF_EDITOR_ID } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { DiffSide, DIFF_CELL_MARGIN, IDiffCellInfo, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { Emitter, Event } from 'vs/base/common/event'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; @@ -38,9 +38,9 @@ import { generateUuid } from 'vs/base/common/uuid'; import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView'; -import { CELL_OUTPUT_PADDING, MARKDOWN_PREVIEW_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; import { NotebookDiffEditorEventDispatcher, NotebookDiffLayoutChangedEvent } from 'vs/workbench/contrib/notebook/browser/diff/eventDispatcher'; import { readFontInfo } from 'vs/editor/browser/config/configuration'; +import { NotebookOptions } from 'vs/workbench/contrib/notebook/common/notebookOptions'; const $ = DOM.$; @@ -72,9 +72,15 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD private _revealFirst: boolean; private readonly _insetModifyQueueByOutputId = new SequencerByKey(); - protected _onDidDynamicOutputRendered = new Emitter<{ cell: IGenericCellViewModel, output: ICellOutputViewModel }>(); + protected _onDidDynamicOutputRendered = new Emitter<{ cell: IGenericCellViewModel, output: ICellOutputViewModel; }>(); onDidDynamicOutputRendered = this._onDidDynamicOutputRendered.event; + private _notebookOptions: NotebookOptions; + + get notebookOptions() { + return this._notebookOptions; + } + private readonly _localStore = this._register(new DisposableStore()); private _isDisposed: boolean = false; @@ -93,10 +99,11 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD @IStorageService storageService: IStorageService, ) { super(NotebookTextDiffEditor.ID, telemetryService, themeService, storageService); - const editorOptions = this.configurationService.getValue('editor'); + this._notebookOptions = new NotebookOptions(this.configurationService); + this._register(this._notebookOptions); + const editorOptions = this.configurationService.getValue('editor'); this._fontInfo = readFontInfo(BareFontInfo.createFromRawSettings(editorOptions, getZoomLevel(), getPixelRatio())); this._revealFirst = true; - this._outputRenderer = new OutputRenderer(this, this.instantiationService); } @@ -136,10 +143,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD setMarkdownCellEditState(cellId: string, editState: CellEditState): void { // throw new Error('Method not implemented.'); } - markdownCellDragStart(cellId: string, position: { clientY: number }): void { + markdownCellDragStart(cellId: string, event: { dragOffsetY: number; }): void { // throw new Error('Method not implemented.'); } - markdownCellDrag(cellId: string, position: { clientY: number }): void { + markdownCellDrag(cellId: string, event: { dragOffsetY: number; }): void { // throw new Error('Method not implemented.'); } markdownCellDragEnd(cellId: string): void { @@ -285,7 +292,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } } - override async setInput(input: NotebookDiffEditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + override async setInput(input: NotebookDiffEditorInput, options: INotebookEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { await super.setInput(input, options, context, token); const model = await input.resolve(); @@ -366,21 +373,12 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD })); } - private readonly webviewOptions = { - outputNodePadding: CELL_OUTPUT_PADDING, - outputNodeLeftPadding: 32, - previewNodePadding: MARKDOWN_PREVIEW_PADDING, - leftMargin: 0, - rightMargin: 0, - runGutter: 0 - }; - private async _createModifiedWebview(id: string, resource: URI): Promise { if (this._modifiedWebview) { this._modifiedWebview.dispose(); } - this._modifiedWebview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource, this.webviewOptions) as BackLayerWebView; + this._modifiedWebview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource, this._notebookOptions.computeDiffWebviewOptions(), undefined) as BackLayerWebView; // attach the webview container to the DOM tree first this._list.rowsContainer.insertAdjacentElement('afterbegin', this._modifiedWebview.element); await this._modifiedWebview.createWebview(); @@ -393,7 +391,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._originalWebview.dispose(); } - this._originalWebview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource, this.webviewOptions) as BackLayerWebView; + this._originalWebview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource, this._notebookOptions.computeDiffWebviewOptions(), undefined) as BackLayerWebView; // attach the webview container to the DOM tree first this._list.rowsContainer.insertAdjacentElement('afterbegin', this._originalWebview.element); await this._originalWebview.createWebview(); @@ -413,16 +411,43 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._originalWebview?.removeInsets([...this._originalWebview?.insetMapping.keys()]); this._modifiedWebview?.removeInsets([...this._modifiedWebview?.insetMapping.keys()]); - this._diffElementViewModels = viewModels; - this._list.splice(0, this._list.length, this._diffElementViewModels); + this._setViewModel(viewModels); + // this._diffElementViewModels = viewModels; + // this._list.splice(0, this._list.length, this._diffElementViewModels); - if (this._revealFirst && firstChangeIndex !== -1) { + if (this._revealFirst && firstChangeIndex !== -1 && firstChangeIndex < this._list.length) { this._revealFirst = false; this._list.setFocus([firstChangeIndex]); this._list.reveal(firstChangeIndex, 0.3); } } + private _setViewModel(viewModels: DiffElementViewModelBase[]) { + let isSame = true; + if (this._diffElementViewModels.length === viewModels.length) { + for (let i = 0; i < viewModels.length; i++) { + const a = this._diffElementViewModels[i]; + const b = viewModels[i]; + + if (a.original?.textModel.getHashValue() !== b.original?.textModel.getHashValue() + || a.modified?.textModel.getHashValue() !== b.modified?.textModel.getHashValue()) { + isSame = false; + break; + } + } + } else { + isSame = false; + } + + if (isSame) { + return; + } + + this._diffElementViewModels = viewModels; + this._list.splice(0, this._list.length, this._diffElementViewModels); + + } + /** * making sure that swapping cells are always translated to `insert+delete`. */ @@ -741,6 +766,8 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._modifiedResourceDisposableStore.clear(); this._list?.splice(0, this._list?.length || 0); + this._model = null; + this._diffElementViewModels = []; } getOutputRenderer(): OutputRenderer { diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts rename to src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/extensionPoint.ts b/src/vs/workbench/contrib/notebook/browser/extensionPoint.ts similarity index 63% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/extensionPoint.ts rename to src/vs/workbench/contrib/notebook/browser/extensionPoint.ts index 1c7fe9d20093..3e827183b54b 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/extensionPoint.ts +++ b/src/vs/workbench/contrib/notebook/browser/extensionPoint.ts @@ -6,73 +6,58 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema'; import * as nls from 'vs/nls'; import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { NotebookEditorPriority } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { NotebookEditorPriority, NotebookRendererEntrypoint, RendererMessagingSpec } from 'vs/workbench/contrib/notebook/common/notebookCommon'; namespace NotebookEditorContribution { - export const viewType = 'viewType'; + export const type = 'type'; export const displayName = 'displayName'; export const selector = 'selector'; export const priority = 'priority'; } export interface INotebookEditorContribution { - readonly [NotebookEditorContribution.viewType]: string; + readonly [NotebookEditorContribution.type]: string; readonly [NotebookEditorContribution.displayName]: string; readonly [NotebookEditorContribution.selector]?: readonly { filenamePattern?: string; excludeFileNamePattern?: string; }[]; readonly [NotebookEditorContribution.priority]?: string; } namespace NotebookRendererContribution { - export const viewType = 'viewType'; + export const id = 'id'; export const displayName = 'displayName'; export const mimeTypes = 'mimeTypes'; export const entrypoint = 'entrypoint'; export const hardDependencies = 'dependencies'; export const optionalDependencies = 'optionalDependencies'; + export const requiresMessaging = 'requiresMessaging'; } export interface INotebookRendererContribution { readonly [NotebookRendererContribution.id]?: string; - readonly [NotebookRendererContribution.viewType]?: string; readonly [NotebookRendererContribution.displayName]: string; readonly [NotebookRendererContribution.mimeTypes]?: readonly string[]; - readonly [NotebookRendererContribution.entrypoint]: string; + readonly [NotebookRendererContribution.entrypoint]: NotebookRendererEntrypoint; readonly [NotebookRendererContribution.hardDependencies]: readonly string[]; readonly [NotebookRendererContribution.optionalDependencies]: readonly string[]; -} - -enum NotebookMarkupRendererContribution { - id = 'id', - displayName = 'displayName', - entrypoint = 'entrypoint', - dependsOn = 'dependsOn', - mimeTypes = 'mimeTypes', -} - -export interface INotebookMarkupRendererContribution { - readonly [NotebookMarkupRendererContribution.id]?: string; - readonly [NotebookMarkupRendererContribution.displayName]: string; - readonly [NotebookMarkupRendererContribution.entrypoint]: string; - readonly [NotebookMarkupRendererContribution.dependsOn]: string | undefined; - readonly [NotebookMarkupRendererContribution.mimeTypes]: string[] | undefined; + readonly [NotebookRendererContribution.requiresMessaging]: RendererMessagingSpec; } const notebookProviderContribution: IJSONSchema = { description: nls.localize('contributes.notebook.provider', 'Contributes notebook document provider.'), type: 'array', - defaultSnippets: [{ body: [{ viewType: '', displayName: '' }] }], + defaultSnippets: [{ body: [{ type: '', displayName: '', 'selector': [{ 'filenamePattern': '' }] }] }], items: { type: 'object', required: [ - NotebookEditorContribution.viewType, + NotebookEditorContribution.type, NotebookEditorContribution.displayName, NotebookEditorContribution.selector, ], properties: { - [NotebookEditorContribution.viewType]: { + [NotebookEditorContribution.type]: { type: 'string', - description: nls.localize('contributes.notebook.provider.viewType', 'Unique identifier of the notebook.'), + description: nls.localize('contributes.notebook.provider.viewType', 'Type of the notebook.'), }, [NotebookEditorContribution.displayName]: { type: 'string', @@ -129,11 +114,6 @@ const notebookRendererContribution: IJSONSchema = { type: 'string', description: nls.localize('contributes.notebook.renderer.viewType', 'Unique identifier of the notebook output renderer.'), }, - [NotebookRendererContribution.viewType]: { - type: 'string', - deprecationMessage: nls.localize('contributes.notebook.provider.viewType.deprecated', 'Rename `viewType` to `id`.'), - description: nls.localize('contributes.notebook.renderer.viewType', 'Unique identifier of the notebook output renderer.'), - }, [NotebookRendererContribution.displayName]: { type: 'string', description: nls.localize('contributes.notebook.renderer.displayName', 'Human readable name of the notebook output renderer.'), @@ -146,8 +126,27 @@ const notebookRendererContribution: IJSONSchema = { } }, [NotebookRendererContribution.entrypoint]: { - type: 'string', description: nls.localize('contributes.notebook.renderer.entrypoint', 'File to load in the webview to render the extension.'), + oneOf: [ + { + type: 'string', + }, + // todo@connor4312 + @mjbvz: uncomment this once it's ready for external adoption + // { + // type: 'object', + // required: ['extends', 'path'], + // properties: { + // extends: { + // type: 'string', + // description: nls.localize('contributes.notebook.renderer.entrypoint.extends', 'Existing renderer that this one extends.'), + // }, + // path: { + // type: 'string', + // description: nls.localize('contributes.notebook.renderer.entrypoint', 'File to load in the webview to render the extension.'), + // }, + // } + // } + ] }, [NotebookRendererContribution.hardDependencies]: { type: 'array', @@ -161,60 +160,33 @@ const notebookRendererContribution: IJSONSchema = { items: { type: 'string' }, markdownDescription: nls.localize('contributes.notebook.renderer.optionalDependencies', 'List of soft kernel dependencies the renderer can make use of. If any of the dependencies are present in the `NotebookKernel.preloads`, the renderer will be preferred over renderers that don\'t interact with the kernel.'), }, - } - } -}; -const notebookMarkupRendererContribution: IJSONSchema = { - description: nls.localize('contributes.notebook.markdownRenderer', 'Contributes a renderer for markdown cells in notebooks.'), - type: 'array', - defaultSnippets: [{ body: [{ id: '', displayName: '', entrypoint: '' }] }], - items: { - type: 'object', - required: [ - NotebookMarkupRendererContribution.id, - NotebookMarkupRendererContribution.displayName, - NotebookMarkupRendererContribution.entrypoint, - ], - properties: { - [NotebookMarkupRendererContribution.id]: { - type: 'string', - description: nls.localize('contributes.notebook.markdownRenderer.id', 'Unique identifier of the notebook markdown renderer.'), - }, - [NotebookMarkupRendererContribution.displayName]: { - type: 'string', - description: nls.localize('contributes.notebook.markdownRenderer.displayName', 'Human readable name of the notebook markdown renderer.'), - }, - [NotebookMarkupRendererContribution.entrypoint]: { - type: 'string', - description: nls.localize('contributes.notebook.markdownRenderer.entrypoint', 'File to load in the webview to render the extension.'), - }, - [NotebookMarkupRendererContribution.mimeTypes]: { - type: 'array', - items: { type: 'string' }, - description: nls.localize('contributes.notebook.markdownRenderer.mimeTypes', 'The mime type that the renderer handles.'), - }, - [NotebookMarkupRendererContribution.dependsOn]: { - type: 'string', - description: nls.localize('contributes.notebook.markdownRenderer.dependsOn', 'If specified, this renderer augments another renderer instead of providing full rendering.'), + [NotebookRendererContribution.requiresMessaging]: { + default: 'never', + enum: [ + 'always', + 'optional', + 'never', + ], + + enumDescriptions: [ + nls.localize('contributes.notebook.renderer.requiresMessaging.always', 'Messaging is required. The renderer will only be used when it\'s part of an extension that can be run in an extension host.'), + nls.localize('contributes.notebook.renderer.requiresMessaging.optional', 'The renderer is better with messaging available, but it\'s not requried.'), + nls.localize('contributes.notebook.renderer.requiresMessaging.never', 'The renderer does not require messaging.'), + ], + description: nls.localize('contributes.notebook.renderer.requiresMessaging', 'Defines how and if the renderer needs to communicate with an extension host, via `createRendererMessaging`. Renderers with stronger messaging requirements may not work in all environments.'), }, } } }; -export const notebookProviderExtensionPoint = ExtensionsRegistry.registerExtensionPoint( +export const notebooksExtensionPoint = ExtensionsRegistry.registerExtensionPoint( { - extensionPoint: 'notebookProvider', + extensionPoint: 'notebooks', jsonSchema: notebookProviderContribution }); export const notebookRendererExtensionPoint = ExtensionsRegistry.registerExtensionPoint( { - extensionPoint: 'notebookOutputRenderer', + extensionPoint: 'notebookRenderer', jsonSchema: notebookRendererContribution }); - -export const notebookMarkupRendererExtensionPoint = ExtensionsRegistry.registerExtensionPoint( - { - extensionPoint: 'notebookMarkupRenderers', - jsonSchema: notebookMarkupRendererContribution - }); diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/media/notebook.css b/src/vs/workbench/contrib/notebook/browser/media/notebook.css similarity index 81% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/media/notebook.css rename to src/vs/workbench/contrib/notebook/browser/media/notebook.css index 128c3f17ad88..788360ba69d3 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/media/notebook.css +++ b/src/vs/workbench/contrib/notebook/browser/media/notebook.css @@ -11,23 +11,81 @@ position: relative; } -.monaco-workbench .notebookOverlay .notebook-top-toolbar { +.monaco-workbench .notebookOverlay .notebook-toolbar-container { width: 100%; - display: inline-flex; - padding-left: 8px; - margin-top: 4px; + display: none; + margin-top: 2px; + margin-bottom: 2px; } -.monaco-workbench .notebookOverlay .notebook-top-toolbar .monaco-action-bar .action-item { - width: 24px; +.monaco-workbench .notebookOverlay .notebook-toolbar-container .monaco-action-bar .action-item { height: 22px; display: flex; align-items: center; + border-radius: 5px; + margin-right: 8px; } -.monaco-workbench .notebookOverlay .notebook-top-toolbar .monaco-action-bar .action-item .action-label { +.monaco-workbench .notebookOverlay .notebook-toolbar-container > .monaco-scrollable-element { + flex: 1; +} + +.monaco-workbench .notebookOverlay .notebook-toolbar-container > .monaco-scrollable-element .notebook-toolbar-left { + padding: 0px 8px; +} + +.monaco-workbench .notebookOverlay .notebook-toolbar-container .notebook-toolbar-right { + display: flex; + padding: 0px 0px 0px 8px; +} + +.monaco-workbench .notebookOverlay .notebook-toolbar-container .monaco-action-bar .action-item .kernel-label { background-size: 16px; - margin: 4px 4px 0 4px; + padding: 0px 5px 0px 3px; + border-radius: 5px; + font-size: 13px; + height: 22px; +} + +.monaco-workbench .notebookOverlay .notebook-toolbar-container .notebook-toolbar-left .monaco-action-bar .action-item .action-label.separator { + margin: 5px 0px !important; + padding: 0px !important; +} + +.monaco-workbench .notebookOverlay .notebook-toolbar-container .monaco-action-bar .action-item:hover { + background-color: var(--code-toolbarHoverBackground); +} + +.monaco-workbench .notebookOverlay .notebook-toolbar-container .monaco-action-bar .action-item .action-label { + background-size: 16px; + padding-left: 2px; +} + +.monaco-workbench .notebook-action-view-item .action-label { + display: inline-flex; +} + +.monaco-workbench .notebookOverlay .notebook-toolbar-container .monaco-action-bar .action-item .notebook-label { + background-size: 16px; + padding: 0px 5px 0px 2px; + border-radius: 5px; + background-color: unset; +} + +.monaco-workbench .notebookOverlay .notebook-toolbar-container .monaco-action-bar .action-item.disabled .notebook-label { + opacity: 0.4; +} + +.monaco-workbench .notebookOverlay .notebook-toolbar-container .monaco-action-bar:not(.vertical) .action-item.active .action-label:not(.disabled) { + background-color: unset; +} + +.monaco-workbench .notebookOverlay .notebook-toolbar-container .monaco-action-bar:not(.vertical) .action-label:not(.disabled):hover { + background-color: unset; +} + +.monaco-workbench .notebookOverlay .notebook-toolbar-container .monaco-action-bar:not(.vertical) .action-item.active { + background-color: unset; } .monaco-workbench .cell.markdown { @@ -162,6 +220,7 @@ .monaco-workbench .notebookOverlay .output { position: absolute; height: 0px; + font-size: var(--notebook-cell-output-font-size); user-select: text; -webkit-user-select: text; -ms-user-select: text; @@ -200,18 +259,21 @@ color: red; /*TODO@rebornix theme color*/ } -.monaco-workbench .notebookOverlay .cell-drag-image .output .multi-mimetype-output { +.monaco-workbench .notebookOverlay .cell-drag-image .output .cell-output-toolbar { display: none; } -.monaco-workbench .notebookOverlay .output .multi-mimetype-output { +.monaco-workbench .notebookOverlay .output .cell-output-toolbar { position: absolute; top: 4px; - left: -30px; - width: 16px; + left: -32px; height: 16px; cursor: pointer; - padding: 6px; + padding: 6px 0px; +} + +.monaco-workbench .notebookOverlay .output .cell-output-toolbar .actions-container { + justify-content: center; } .monaco-workbench .notebookOverlay .output pre { @@ -293,44 +355,17 @@ display: none; } -/* top and bottom borders on cells */ -.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-top:before, -.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-bottom:before, -.monaco-workbench .notebookOverlay .monaco-list .markdown-cell-row .cell-inner-container:before, -.monaco-workbench .notebookOverlay .monaco-list .markdown-cell-row .cell-inner-container:after { - content: ""; - position: absolute; - width: 100%; - height: 1px; -} - -.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-left:before, -.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-right:before { - content: ""; - position: absolute; - width: 1px; - height: 100%; - z-index: 10; -} - -/* top border */ -.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-top:before { - border-top: 1px solid transparent; -} - -/* left border */ -.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-left:before { - border-left: 1px solid transparent; +.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .notebook-folding-indicator.mouseover .codicon { + opacity: 0; + transition: opacity 0.s; } -/* bottom border */ -.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-bottom:before { - border-bottom: 1px solid transparent; +.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .markdown-cell-hover .notebook-folding-indicator.mouseover .codicon { + opacity: 1; } -/* right border */ -.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-right:before { - border-right: 1px solid transparent; +.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover .notebook-folding-indicator.mouseover .codicon { + opacity: 1; } .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-top:before { @@ -368,19 +403,7 @@ z-index: 50; } -.monaco-workbench .notebookOverlay.cell-title-toolbar-right > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-title-toolbar { - right: 44px; -} - -.monaco-workbench .notebookOverlay.cell-title-toolbar-left > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-title-toolbar { - left: 76px; -} - -.monaco-workbench .notebookOverlay.cell-title-toolbar-hidden > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-title-toolbar { - display: none; -} - -.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-title-toolbar .action-item { +.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-title-toolbar .action-item.menu-entry { width: 24px; height: 24px; display: flex; @@ -410,7 +433,7 @@ overflow: hidden; } -.monaco-workbench .notebookOverlay.cell-statusbar-hidden .cell-statusbar-container { +.monaco-workbench .notebookOverlay .cell-statusbar-hidden .cell-statusbar-container { display: none; } @@ -471,7 +494,7 @@ .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .run-button-container { position: absolute; flex-shrink: 0; - z-index: 27; /* Above the drag handle */ + z-index: 29; /* Above the drag handle, output, and toolbars */ } .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .run-button-container .monaco-toolbar { @@ -479,8 +502,7 @@ height: initial; } -.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .run-button-container .monaco-toolbar .codicon { - margin: 0 4px 0 0; +.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .run-button-container .monaco-toolbar .action-item:not(.monaco-dropdown-with-primary) .codicon { padding: 6px; } @@ -490,6 +512,7 @@ .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover .run-button-container .monaco-toolbar, .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused .run-button-container .monaco-toolbar, +.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-run-toolbar-dropdown-active .run-button-container .monaco-toolbar, .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.cell-output-hover .run-button-container .monaco-toolbar { visibility: visible; } @@ -503,12 +526,14 @@ opacity: .6; /* Sizing hacks */ - left: 26px; - width: 35px; bottom: 0px; text-align: center; } +.monaco-workbench .notebookOverlay>.cell-list-container>.monaco-list>.monaco-scrollable-element>.monaco-list-rows>.monaco-list-row .cell-statusbar-hidden .execution-count-label { + line-height: 15px; +} + .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .output-collapsed .execution-count-label { bottom: 24px; } @@ -530,14 +555,24 @@ height: 2px; } -.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list:focus-within > .monaco-scrollable-element > .monaco-list-rows:not(:hover) > .monaco-list-row.focused .cell-has-toolbar-actions .cell-title-toolbar, -.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover .cell-has-toolbar-actions .cell-title-toolbar, -.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .markdown-cell-hover.cell-has-toolbar-actions .cell-title-toolbar, -.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-has-toolbar-actions.cell-output-hover .cell-title-toolbar, -.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-has-toolbar-actions:hover .cell-title-toolbar, -.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-title-toolbar:hover, -.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-toolbar-dropdown-active .cell-title-toolbar { +/* toolbar visible on hover */ +.monaco-workbench .notebookOverlay.cell-toolbar-hover > .cell-list-container > .monaco-list:focus-within > .monaco-scrollable-element > .monaco-list-rows:not(:hover) > .monaco-list-row.focused .cell-has-toolbar-actions .cell-title-toolbar, +.monaco-workbench .notebookOverlay.cell-toolbar-hover > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover .cell-has-toolbar-actions .cell-title-toolbar, +.monaco-workbench .notebookOverlay.cell-toolbar-hover > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .markdown-cell-hover.cell-has-toolbar-actions .cell-title-toolbar, +.monaco-workbench .notebookOverlay.cell-toolbar-hover > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-has-toolbar-actions.cell-output-hover .cell-title-toolbar, +.monaco-workbench .notebookOverlay.cell-toolbar-hover > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-has-toolbar-actions:hover .cell-title-toolbar, +.monaco-workbench .notebookOverlay.cell-toolbar-hover > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-title-toolbar:hover, +.monaco-workbench .notebookOverlay.cell-toolbar-hover > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-toolbar-dropdown-active .cell-title-toolbar { + opacity: 1; +} + +/* toolbar visible on click */ +.monaco-workbench .notebookOverlay.cell-toolbar-click > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-title-toolbar { + visibility: hidden; +} +.monaco-workbench .notebookOverlay.cell-toolbar-click > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused .cell-title-toolbar { opacity: 1; + visibility: visible; } .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list:not(.element-focused):focus:before { @@ -574,6 +609,26 @@ right: 0px; } +/** cell border colors */ + +.monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-editor-focus .cell-focus-indicator-top:before, +.monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-editor-focus .cell-focus-indicator-bottom:before, +.monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-inner-container.cell-editor-focus:before { + border-color: var(notebook-selected-cell-border-color) !important; +} + +.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-top:before, +.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-bottom:before { + border-color: var(--notebook-inactive-focused-cell-border-color) !important; +} + +.monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-inner-container:not(.cell-editor-focus) .cell-focus-indicator-top:before, +.monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-inner-container:not(.cell-editor-focus) .cell-focus-indicator-bottom:before, +.monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-inner-container:not(.cell-editor-focus) .cell-focus-indicator-left:before, +.monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-inner-container:not(.cell-editor-focus) .cell-focus-indicator-right:before { + border-color: var(--notebook-focused-cell-border-color) !important; +} + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-drag-handle { position: absolute; top: 0px; @@ -851,7 +906,7 @@ position: absolute; top: 10px; - left: 8px; + left: 6px; display: flex; justify-content: center; align-items: center; @@ -865,7 +920,7 @@ .monaco-workbench .notebookOverlay > .cell-list-container .notebook-folding-indicator .codicon { visibility: visible; height: 16px; - padding: 4px 4px 4px 6px; + padding: 4px 4px 4px 4px; } /** Theming */ @@ -954,3 +1009,4 @@ .hc-black .notebookOverlay .monaco-list.selection-multiple:focus-within .monaco-list-row.selected:not(.focused) .cell-focus-indicator-bottom:before { border-bottom-style: dotted; } .hc-black .notebookOverlay .monaco-list.selection-multiple:focus-within .monaco-list-row.selected:not(.focused) .cell-inner-container:not(.cell-editor-focus) .cell-focus-indicator-left:before { border-left-style: dotted; } .hc-black .notebookOverlay .monaco-list.selection-multiple:focus-within .monaco-list-row.selected:not(.focused) .cell-inner-container:not(.cell-editor-focus) .cell-focus-indicator-right:before { border-right-style: dotted; } + diff --git a/src/vs/workbench/contrib/notebook/browser/media/notebookKernelActionViewItem.css b/src/vs/workbench/contrib/notebook/browser/media/notebookKernelActionViewItem.css new file mode 100644 index 000000000000..5f394da2d1f1 --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/media/notebookKernelActionViewItem.css @@ -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. + *--------------------------------------------------------------------------------------------*/ + +.monaco-workbench .kernel-action-view-item { + border-radius: 5px; +} +.monaco-workbench .kernel-action-view-item:hover { + background-color: var(--code-toolbarHoverBackground); +} + +.monaco-workbench .kernel-action-view-item .action-label { + display: inline-flex; +} + +.monaco-workbench .kernel-action-view-item .kernel-label { + font-size: 11px; + padding: 3px 5px 3px 3px; + border-radius: 5px; + height: 16px; + display: inline-flex; + vertical-align: text-bottom; +} diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts similarity index 58% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts rename to src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts index 2d2887db0149..5c000e4c0800 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -4,17 +4,19 @@ *--------------------------------------------------------------------------------------------*/ import { Schemas } from 'vs/base/common/network'; -import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { parse } from 'vs/base/common/marshalling'; import { isEqual } from 'vs/base/common/resources'; import { assertType } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; +import { format } from 'vs/base/common/jsonFormatter'; +import { applyEdits } from 'vs/base/common/jsonEdit'; import { ITextModel, ITextBufferFactory, DefaultEndOfLine, ITextBuffer } from 'vs/editor/common/model'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IModeService } from 'vs/editor/common/services/modeService'; import { ITextModelContentProvider, ITextModelService } from 'vs/editor/common/services/resolverService'; import * as nls from 'vs/nls'; -import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; +import { Extensions, IConfigurationPropertySchema, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -22,13 +24,13 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle import { Registry } from 'vs/platform/registry/common/platform'; import { EditorDescriptor, IEditorRegistry } from 'vs/workbench/browser/editor'; import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; -import { EditorInput, ICustomEditorInputFactory, IEditorInput, IEditorInputSerializer, IEditorInputFactoryRegistry, IEditorInputWithOptions, EditorExtensions } from 'vs/workbench/common/editor'; -import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/common/workingCopyBackup'; +import { IEditorInput, IEditorInputSerializer, IEditorInputFactoryRegistry, IEditorInputWithOptions, EditorExtensions } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { NotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookEditor'; import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { NotebookService } from 'vs/workbench/contrib/notebook/browser/notebookServiceImpl'; -import { CellKind, CellToolbarLocKey, CellUri, DisplayOrderKey, ExperimentalUseMarkdownRenderer, getCellUndoRedoComparisonKey, IResolvedNotebookEditorModel, NotebookDocumentBackupData, NotebookTextDiffEditorPreview, NOTEBOOK_WORKING_COPY_TYPE_PREFIX, ShowCellStatusBarKey } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, CellToolbarLocation, CellToolbarVisibility, CellUri, DisplayOrderKey, UndoRedoPerCell, ExperimentalUseMarkdownRenderer, getCellUndoRedoComparisonKey, IResolvedNotebookEditorModel, NotebookDocumentBackupData, NotebookTextDiffEditorPreview, NotebookWorkingCopyTypeIdentifier, ShowCellStatusBar, CompactView, FocusIndicator, InsertToolbarLocation, GlobalToolbar, ConsolidatedOutputButton, ShowFoldingControls, DragAndDropEnabled, NotebookCellEditorOptionsCustomizations, ConsolidatedRunButton } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService'; @@ -41,16 +43,22 @@ import { NotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/brow import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService'; import { NotebookEditorWidgetService } from 'vs/workbench/contrib/notebook/browser/notebookEditorServiceImpl'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; -import { IJSONSchema } from 'vs/base/common/jsonSchema'; +import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema'; import { Event } from 'vs/base/common/event'; import { getFormatedMetadataJSON } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { NotebookModelResolverServiceImpl } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl'; import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; import { NotebookKernelService } from 'vs/workbench/contrib/notebook/browser/notebookKernelServiceImpl'; -import { IWorkingCopyIdentifier, NO_TYPE_ID } from 'vs/workbench/services/workingCopy/common/workingCopy'; +import { IWorkingCopyIdentifier } from 'vs/workbench/services/workingCopy/common/workingCopy'; import { EditorOverride } from 'vs/platform/editor/common/editor'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IWorkingCopyEditorService } from 'vs/workbench/services/workingCopy/common/workingCopyEditorService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ILabelService } from 'vs/platform/label/common/label'; +import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/common/workingCopyBackup'; +import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { NotebookRendererMessagingService } from 'vs/workbench/contrib/notebook/browser/notebookRendererMessagingServiceImpl'; +import { INotebookRendererMessagingService } from 'vs/workbench/contrib/notebook/common/notebookRendererMessagingService'; // Editor Contribution import 'vs/workbench/contrib/notebook/browser/contrib/clipboard/notebookClipboard'; @@ -58,10 +66,12 @@ import 'vs/workbench/contrib/notebook/browser/contrib/coreActions'; import 'vs/workbench/contrib/notebook/browser/contrib/find/findController'; import 'vs/workbench/contrib/notebook/browser/contrib/fold/folding'; import 'vs/workbench/contrib/notebook/browser/contrib/format/formatting'; +import 'vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted'; import 'vs/workbench/contrib/notebook/browser/contrib/layout/layoutActions'; import 'vs/workbench/contrib/notebook/browser/contrib/marker/markerProvider'; import 'vs/workbench/contrib/notebook/browser/contrib/navigation/arrow'; import 'vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline'; +import 'vs/workbench/contrib/notebook/browser/contrib/profile/notebookProfile'; import 'vs/workbench/contrib/notebook/browser/contrib/statusBar/statusBarProviders'; import 'vs/workbench/contrib/notebook/browser/contrib/statusBar/contributedStatusBarItemController'; import 'vs/workbench/contrib/notebook/browser/contrib/statusBar/executionStatusBarItemController'; @@ -71,12 +81,12 @@ import 'vs/workbench/contrib/notebook/browser/contrib/cellOperations/cellOperati import 'vs/workbench/contrib/notebook/browser/contrib/viewportCustomMarkdown/viewportCustomMarkdown'; import 'vs/workbench/contrib/notebook/browser/contrib/troubleshoot/layout'; - // Diff Editor Contribution import 'vs/workbench/contrib/notebook/browser/diff/notebookDiffActions'; // Output renderers registration import 'vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform'; +import { editorOptionsRegistry } from 'vs/editor/common/config/editorOptions'; /*--------------------------------------------------------------------------------------------- */ @@ -120,7 +130,7 @@ class NotebookDiffEditorSerializer implements IEditorInputSerializer { } deserialize(instantiationService: IInstantiationService, raw: string) { - type Data = { resource: URI, originalResource: URI, name: string, originalName: string, viewType: string, textDiffName: string | undefined, group: number }; + type Data = { resource: URI, originalResource: URI, name: string, originalName: string, viewType: string, textDiffName: string | undefined, group: number; }; const data = parse(raw); if (!data) { return undefined; @@ -154,7 +164,7 @@ class NotebookEditorSerializer implements IEditorInputSerializer { }); } deserialize(instantiationService: IInstantiationService, raw: string) { - type Data = { resource: URI, viewType: string, group: number }; + type Data = { resource: URI, viewType: string, group: number; }; const data = parse(raw); if (!data) { return undefined; @@ -174,35 +184,6 @@ Registry.as(EditorExtensions.EditorInputFactories). NotebookEditorSerializer ); -Registry.as(EditorExtensions.EditorInputFactories).registerCustomEditorInputFactory( - Schemas.vscodeNotebook, - new class implements ICustomEditorInputFactory { - async createCustomEditorInput(resource: URI, instantiationService: IInstantiationService): Promise { - return instantiationService.invokeFunction(async accessor => { - const workingCopyBackupService = accessor.get(IWorkingCopyBackupService); - - const backup = await workingCopyBackupService.resolve({ resource, typeId: NO_TYPE_ID }); - if (!backup?.meta) { - throw new Error(`No backup found for Notebook editor: ${resource}`); - } - - const input = NotebookEditorInput.create(instantiationService, resource, backup.meta.viewType, { startDirty: true }); - return input; - }); - } - - canResolveBackup(editorInput: IEditorInput, backupResource: URI): boolean { - if (editorInput instanceof NotebookEditorInput) { - if (isEqual(URI.from({ scheme: Schemas.vscodeNotebook, path: editorInput.resource.toString() }), backupResource)) { - return true; - } - } - - return false; - } - } -); - Registry.as(EditorExtensions.EditorInputFactories).registerEditorInputSerializer( NotebookDiffEditorInput.ID, NotebookDiffEditorSerializer @@ -211,12 +192,15 @@ Registry.as(EditorExtensions.EditorInputFactories). export class NotebookContribution extends Disposable implements IWorkbenchContribution { constructor( @IUndoRedoService undoRedoService: IUndoRedoService, + @IConfigurationService configurationService: IConfigurationService, ) { super(); + const undoRedoPerCell = configurationService.getValue(UndoRedoPerCell); + this._register(undoRedoService.registerUriComparisonKeyComputer(CellUri.scheme, { getComparisonKey: (uri: URI): string => { - return getCellUndoRedoComparisonKey(uri); + return getCellUndoRedoComparisonKey(uri, undoRedoPerCell); } })); } @@ -265,7 +249,7 @@ class CellContentProvider implements ITextModelContentProvider { return cell.textBuffer.getLineContent(1).substr(0, limit); } }; - const language = cell.cellKind === CellKind.Markdown ? this._modeService.create('markdown') : (cell.language ? this._modeService.create(cell.language) : this._modeService.createByFilepathOrFirstLine(resource, cell.textBuffer.getLineContent(1))); + const language = cell.cellKind === CellKind.Markup ? this._modeService.create('markdown') : (cell.language ? this._modeService.create(cell.language) : this._modeService.createByFilepathOrFirstLine(resource, cell.textBuffer.getLineContent(1))); result = this._modelService.createModel( bufferFactory, language, @@ -276,7 +260,7 @@ class CellContentProvider implements ITextModelContentProvider { } if (result) { - const once = result.onWillDispose(() => { + const once = Event.any(result.onWillDispose, ref.object.notebook.onWillDispose)(() => { once.dispose(); ref.dispose(); }); @@ -286,29 +270,52 @@ class CellContentProvider implements ITextModelContentProvider { } } -class CellMetadataContentProvider implements ITextModelContentProvider { - private readonly _registration: IDisposable; +class CellInfoContentProvider { + private readonly _disposables: IDisposable[] = []; constructor( @ITextModelService textModelService: ITextModelService, @IModelService private readonly _modelService: IModelService, @IModeService private readonly _modeService: IModeService, + @ILabelService private readonly _labelService: ILabelService, @INotebookEditorModelResolverService private readonly _notebookModelResolverService: INotebookEditorModelResolverService, ) { - this._registration = textModelService.registerTextModelContentProvider(Schemas.vscodeNotebookCellMetadata, this); + this._disposables.push(textModelService.registerTextModelContentProvider(Schemas.vscodeNotebookCellMetadata, { + provideTextContent: this.provideMetadataTextContent.bind(this) + })); + + this._disposables.push(textModelService.registerTextModelContentProvider(Schemas.vscodeNotebookCellOutput, { + provideTextContent: this.provideOutputTextContent.bind(this) + })); + + this._disposables.push(this._labelService.registerFormatter({ + scheme: Schemas.vscodeNotebookCellMetadata, + formatting: { + label: '${path} (metadata)', + separator: '/' + } + })); + + this._disposables.push(this._labelService.registerFormatter({ + scheme: Schemas.vscodeNotebookCellOutput, + formatting: { + label: '${path} (output)', + separator: '/' + } + })); } dispose(): void { - this._registration.dispose(); + this._disposables.forEach(d => d.dispose()); } - async provideTextContent(resource: URI): Promise { + async provideMetadataTextContent(resource: URI): Promise { const existing = this._modelService.getModel(resource); if (existing) { return existing; } - const data = CellUri.parseCellMetadataUri(resource); - // const data = parseCellUri(resource); + + const data = CellUri.parseCellUri(resource, Schemas.vscodeNotebookCellMetadata); if (!data) { return null; } @@ -320,7 +327,7 @@ class CellMetadataContentProvider implements ITextModelContentProvider { for (const cell of ref.object.notebook.cells) { if (cell.handle === data.handle) { - const metadataSource = getFormatedMetadataJSON(ref.object.notebook, cell.metadata || {}, cell.language); + const metadataSource = getFormatedMetadataJSON(ref.object.notebook, cell.metadata, cell.language); result = this._modelService.createModel( metadataSource, mode, @@ -339,6 +346,46 @@ class CellMetadataContentProvider implements ITextModelContentProvider { return result; } + + async provideOutputTextContent(resource: URI): Promise { + const existing = this._modelService.getModel(resource); + if (existing) { + return existing; + } + + const data = CellUri.parseCellUri(resource, Schemas.vscodeNotebookCellOutput); + if (!data) { + return null; + } + + const ref = await this._notebookModelResolverService.resolve(data.notebook); + let result: ITextModel | null = null; + + const mode = this._modeService.create('json'); + + for (const cell of ref.object.notebook.cells) { + if (cell.handle === data.handle) { + const content = JSON.stringify(cell.outputs); + const edits = format(content, undefined, {}); + const outputSource = applyEdits(content, edits); + result = this._modelService.createModel( + outputSource, + mode, + resource + ); + break; + } + } + + if (result) { + const once = result.onWillDispose(() => { + once.dispose(); + ref.dispose(); + }); + } + + return result; + } } class RegisterSchemasContribution extends Disposable implements IWorkbenchContribution { @@ -374,27 +421,37 @@ class RegisterSchemasContribution extends Disposable implements IWorkbenchContri } } -// makes sure that every dirty notebook gets an editor -class NotebookFileTracker implements IWorkbenchContribution { +class NotebookEditorManager implements IWorkbenchContribution { - private readonly _dirtyListener: IDisposable; + private readonly _disposables = new DisposableStore(); constructor( @IInstantiationService private readonly _instantiationService: IInstantiationService, @IEditorService private readonly _editorService: IEditorService, @INotebookEditorModelResolverService private readonly _notebookEditorModelService: INotebookEditorModelResolverService, + @INotebookService notebookService: INotebookService, + @IEditorGroupsService editorGroups: IEditorGroupsService, ) { + // OPEN notebook editor for models that have turned dirty without being visible in an editor type E = IResolvedNotebookEditorModel; - this._dirtyListener = Event.debounce( + this._disposables.add(Event.debounce( this._notebookEditorModelService.onDidChangeDirty, (last, current) => !last ? [current] : [...last, current], 100 - )(this._openMissingDirtyNotebookEditors, this); + )(this._openMissingDirtyNotebookEditors, this)); + + // CLOSE notebook editor for models that have no more serializer + this._disposables.add(notebookService.onWillRemoveViewType(e => { + for (const group of editorGroups.groups) { + const staleInputs = group.editors.filter(input => input instanceof NotebookEditorInput && input.viewType === e); + group.closeEditors(staleInputs); + } + })); } dispose(): void { - this._dirtyListener.dispose(); + this._disposables.dispose(); } private _openMissingDirtyNotebookEditors(models: IResolvedNotebookEditorModel[]): void { @@ -413,7 +470,7 @@ class NotebookFileTracker implements IWorkbenchContribution { } } -class NotebookWorkingCopyEditorHandler extends Disposable implements IWorkbenchContribution { +class SimpleNotebookWorkingCopyEditorHandler extends Disposable implements IWorkbenchContribution { constructor( @IInstantiationService private readonly _instantiationService: IInstantiationService, @@ -429,28 +486,62 @@ class NotebookWorkingCopyEditorHandler extends Disposable implements IWorkbenchC await this._extensionService.whenInstalledExtensionsRegistered(); this._register(this._workingCopyEditorService.registerHandler({ - handles: workingCopy => typeof this.getViewType(workingCopy) === 'string', - isOpen: (workingCopy, editor) => editor instanceof NotebookEditorInput && editor.viewType === this.getViewType(workingCopy), - createEditor: workingCopy => NotebookEditorInput.create(this._instantiationService, workingCopy.resource, this.getViewType(workingCopy)!) + handles: workingCopy => typeof this._getViewType(workingCopy) === 'string', + isOpen: (workingCopy, editor) => editor instanceof NotebookEditorInput && editor.viewType === this._getViewType(workingCopy), + createEditor: workingCopy => NotebookEditorInput.create(this._instantiationService, workingCopy.resource, this._getViewType(workingCopy)!) })); } - private getViewType(workingCopy: IWorkingCopyIdentifier): string | undefined { - if (workingCopy.typeId.startsWith(NOTEBOOK_WORKING_COPY_TYPE_PREFIX)) { - return workingCopy.typeId.substr(NOTEBOOK_WORKING_COPY_TYPE_PREFIX.length); - } + private _getViewType(workingCopy: IWorkingCopyIdentifier): string | undefined { + return NotebookWorkingCopyTypeIdentifier.parse(workingCopy.typeId); + } +} - return undefined; +class ComplexNotebookWorkingCopyEditorHandler extends Disposable implements IWorkbenchContribution { + + constructor( + @IInstantiationService private readonly _instantiationService: IInstantiationService, + @IWorkingCopyEditorService private readonly _workingCopyEditorService: IWorkingCopyEditorService, + @IExtensionService private readonly _extensionService: IExtensionService, + @IWorkingCopyBackupService private readonly _workingCopyBackupService: IWorkingCopyBackupService + ) { + super(); + + this._installHandler(); + } + + private async _installHandler(): Promise { + await this._extensionService.whenInstalledExtensionsRegistered(); + + this._register(this._workingCopyEditorService.registerHandler({ + handles: workingCopy => workingCopy.resource.scheme === Schemas.vscodeNotebook, + isOpen: (workingCopy, editor) => editor instanceof NotebookEditorInput && isEqual(URI.from({ scheme: Schemas.vscodeNotebook, path: editor.resource.toString() }), workingCopy.resource), + createEditor: async workingCopy => { + // TODO this is really bad and should adopt the `typeId` + // for backups instead of storing that information in the + // backup. + // But since complex notebooks are deprecated, not worth + // pushing for it and should eventually delete this code + // entirely. + const backup = await this._workingCopyBackupService.resolve(workingCopy); + if (!backup?.meta) { + throw new Error(`No backup found for Notebook editor: ${workingCopy.resource}`); + } + + return NotebookEditorInput.create(this._instantiationService, workingCopy.resource, backup.meta.viewType, { startDirty: true }); + } + })); } } const workbenchContributionsRegistry = Registry.as(WorkbenchExtensions.Workbench); workbenchContributionsRegistry.registerWorkbenchContribution(NotebookContribution, LifecyclePhase.Starting); workbenchContributionsRegistry.registerWorkbenchContribution(CellContentProvider, LifecyclePhase.Starting); -workbenchContributionsRegistry.registerWorkbenchContribution(CellMetadataContentProvider, LifecyclePhase.Starting); +workbenchContributionsRegistry.registerWorkbenchContribution(CellInfoContentProvider, LifecyclePhase.Starting); workbenchContributionsRegistry.registerWorkbenchContribution(RegisterSchemasContribution, LifecyclePhase.Starting); -workbenchContributionsRegistry.registerWorkbenchContribution(NotebookFileTracker, LifecyclePhase.Ready); -workbenchContributionsRegistry.registerWorkbenchContribution(NotebookWorkingCopyEditorHandler, LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(NotebookEditorManager, LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(SimpleNotebookWorkingCopyEditorHandler, LifecyclePhase.Ready); +workbenchContributionsRegistry.registerWorkbenchContribution(ComplexNotebookWorkingCopyEditorHandler, LifecyclePhase.Ready); registerSingleton(INotebookService, NotebookService); registerSingleton(INotebookEditorWorkerService, NotebookEditorWorkerServiceImpl); @@ -458,6 +549,45 @@ registerSingleton(INotebookEditorModelResolverService, NotebookModelResolverServ registerSingleton(INotebookCellStatusBarService, NotebookCellStatusBarService, true); registerSingleton(INotebookEditorService, NotebookEditorWidgetService, true); registerSingleton(INotebookKernelService, NotebookKernelService, true); +registerSingleton(INotebookRendererMessagingService, NotebookRendererMessagingService, true); + +const schemas: IJSONSchemaMap = {}; +function isConfigurationPropertySchema(x: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema; }): x is IConfigurationPropertySchema { + return (typeof x.type !== 'undefined' || typeof x.anyOf !== 'undefined'); +} +for (const editorOption of editorOptionsRegistry) { + const schema = editorOption.schema; + if (schema) { + if (isConfigurationPropertySchema(schema)) { + schemas[`editor.${editorOption.name}`] = schema; + } else { + for (let key in schema) { + if (Object.hasOwnProperty.call(schema, key)) { + schemas[key] = schema[key]; + } + } + } + } +} + +const editorOptionsCustomizationSchema: IConfigurationPropertySchema = { + description: nls.localize('notebook.editorOptions.experimentalCustomization', 'Settings for code editors used in notebooks. This can be used to customize most editor.* settings.'), + default: {}, + allOf: [ + { + properties: schemas, + } + // , { + // patternProperties: { + // '^\\[.*\\]$': { + // type: 'object', + // default: {}, + // properties: schemas + // } + // } + // } + ] +}; const configurationRegistry = Registry.as(Extensions.Configuration); configurationRegistry.registerConfiguration({ @@ -474,7 +604,7 @@ configurationRegistry.registerConfiguration({ }, default: [] }, - [CellToolbarLocKey]: { + [CellToolbarLocation]: { description: nls.localize('notebook.cellToolbarLocation.description', "Where the cell toolbar should be shown, or whether it should be hidden."), type: 'object', additionalProperties: { @@ -484,12 +614,19 @@ configurationRegistry.registerConfiguration({ }, default: { 'default': 'right' - } + }, + tags: ['notebookLayout'] }, - [ShowCellStatusBarKey]: { + [ShowCellStatusBar]: { description: nls.localize('notebook.showCellStatusbar.description', "Whether the cell status bar should be shown."), - type: 'boolean', - default: true + type: 'string', + enum: ['hidden', 'visible', 'visibleAfterExecute'], + enumDescriptions: [ + nls.localize('notebook.showCellStatusbar.hidden.description', "The cell status bar is always hidden."), + nls.localize('notebook.showCellStatusbar.visible.description', "The cell status bar is always visible."), + nls.localize('notebook.showCellStatusbar.visibleAfterExecute.description', "The cell status bar is hidden until the cell has executed. Then it becomes visible to show the execution status.")], + default: 'visible', + tags: ['notebookLayout'] }, [NotebookTextDiffEditorPreview]: { description: nls.localize('notebook.diff.enablePreview.description', "Whether to use the enhanced text diff editor for notebook."), @@ -501,5 +638,69 @@ configurationRegistry.registerConfiguration({ type: 'boolean', default: true }, + [CellToolbarVisibility]: { + markdownDescription: nls.localize('notebook.cellToolbarVisibility.description', "Whether the cell toolbar should appear on hover or click."), + type: 'string', + enum: ['hover', 'click'], + default: 'click', + tags: ['notebookLayout'] + }, + [UndoRedoPerCell]: { + description: nls.localize('notebook.undoRedoPerCell.description', "Whether to use separate undo/redo stack for each cell."), + type: 'boolean', + default: false + }, + [CompactView]: { + description: nls.localize('notebook.compactView.description', "Control whether the notebook editor should be rendered in a compact form. "), + type: 'boolean', + default: true, + tags: ['notebookLayout'] + }, + [FocusIndicator]: { + description: nls.localize('notebook.focusIndicator.description', "Control whether to render the focus indicator as cell borders or a highlight bar on the left gutter"), + type: 'string', + enum: ['border', 'gutter'], + default: 'gutter', + tags: ['notebookLayout'] + }, + [InsertToolbarLocation]: { + description: nls.localize('notebook.insertToolbarPosition.description', "Control where the insert cell actions should be rendered."), + type: 'string', + enum: ['betweenCells', 'notebookToolbar', 'both', 'hidden'], + default: 'both', + tags: ['notebookLayout'] + }, + [GlobalToolbar]: { + description: nls.localize('notebook.globalToolbar.description', "Control whether to render a global toolbar inside the notebook editor."), + type: 'boolean', + default: true, + tags: ['notebookLayout'] + }, + [ConsolidatedOutputButton]: { + description: nls.localize('notebook.consolidatedOutputButton.description', "Control whether outputs action should be rendered in the output toolbar."), + type: 'boolean', + default: true, + tags: ['notebookLayout'] + }, + [ShowFoldingControls]: { + description: nls.localize('notebook.showFoldingControls.description', "Controls when the folding controls are shown."), + type: 'string', + enum: ['always', 'mouseover'], + default: 'mouseover', + tags: ['notebookLayout'] + }, + [DragAndDropEnabled]: { + description: nls.localize('notebook.dragAndDrop.description', "Control whether the notebook editor should allow moving cells through drag and drop."), + type: 'boolean', + default: true, + tags: ['notebookLayout'] + }, + [ConsolidatedRunButton]: { + description: nls.localize('notebook.consolidatedRunButton.description', "Control whether extra actions are shown in a dropdown next to the run button."), + type: 'boolean', + default: true, + tags: ['notebookLayout'] + }, + [NotebookCellEditorOptionsCustomizations]: editorOptionsCustomizationSchema } }); diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts similarity index 92% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts rename to src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 01ea269fc931..ce0d5b5f2665 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -8,7 +8,7 @@ import { IListContextMenuEvent, IListEvent, IListMouseEvent } from 'vs/base/brow import { IListOptions, IListStyles } from 'vs/base/browser/ui/list/listWidget'; import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; -import { Emitter, Event } from 'vs/base/common/event'; +import { Event } from 'vs/base/common/event'; import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { ScrollEvent } from 'vs/base/common/scrollable'; import { URI } from 'vs/base/common/uri'; @@ -16,26 +16,28 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { FontInfo } from 'vs/editor/common/config/fontInfo'; import { IPosition } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; -import { FindMatch, IReadonlyTextBuffer, ITextModel } from 'vs/editor/common/model'; +import { FindMatch, IModelDeltaDecoration, IReadonlyTextBuffer, ITextModel } from 'vs/editor/common/model'; import { ContextKeyExpr, RawContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; -import { CellKind, NotebookCellMetadata, INotebookKernel, IOrderedMimeType, INotebookRendererInfo, ICellOutput, IOutputItemDto, INotebookCellStatusBarItem } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, NotebookCellMetadata, INotebookKernel, IOrderedMimeType, INotebookRendererInfo, ICellOutput, IOutputItemDto, INotebookCellStatusBarItem, NotebookCellInternalMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ICellRange, cellRangesToIndexes, reduceRanges } from 'vs/workbench/contrib/notebook/common/notebookRange'; import { Webview } from 'vs/workbench/contrib/webview/browser/webview'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { IMenu } from 'vs/platform/actions/common/actions'; -import { EditorOptions, IEditorPane } from 'vs/workbench/common/editor'; -import { IResourceEditorInput } from 'vs/platform/editor/common/editor'; +import { IEditorPane } from 'vs/workbench/common/editor'; +import { ITextEditorOptions, ITextResourceEditorInput } from 'vs/platform/editor/common/editor'; import { IConstructorSignature1 } from 'vs/platform/instantiation/common/instantiation'; import { CellEditorStatusBar } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets'; import { INotebookWebviewMessage } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView'; +import { NotebookOptions } from 'vs/workbench/contrib/notebook/common/notebookOptions'; export const NOTEBOOK_EDITOR_ID = 'workbench.editor.notebook'; export const NOTEBOOK_DIFF_EDITOR_ID = 'workbench.editor.notebookTextDiffEditor'; //#region Context Keys +export const HAS_OPENED_NOTEBOOK = new RawContextKey('userHasOpenedNotebook', false); export const KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED = new RawContextKey('notebookFindWidgetFocused', false); // Is Notebook @@ -48,10 +50,11 @@ export const NOTEBOOK_CELL_LIST_FOCUSED = new RawContextKey('notebookCe export const NOTEBOOK_OUTPUT_FOCUSED = new RawContextKey('notebookOutputFocused', false); export const NOTEBOOK_EDITOR_EDITABLE = new RawContextKey('notebookEditable', true); export const NOTEBOOK_HAS_RUNNING_CELL = new RawContextKey('notebookHasRunningCell', false); +export const NOTEBOOK_USE_CONSOLIDATED_OUTPUT_BUTTON = new RawContextKey('notebookUseConsolidatedOutputButton', false); // Cell keys -export const NOTEBOOK_VIEW_TYPE = new RawContextKey('notebookViewType', undefined); -export const NOTEBOOK_CELL_TYPE = new RawContextKey('notebookCellType', undefined); // code, markdown +export const NOTEBOOK_VIEW_TYPE = new RawContextKey('notebookType', undefined); +export const NOTEBOOK_CELL_TYPE = new RawContextKey<'code' | 'markup'>('notebookCellType', undefined); export const NOTEBOOK_CELL_EDITABLE = new RawContextKey('notebookCellEditable', false); // bool export const NOTEBOOK_CELL_FOCUSED = new RawContextKey('notebookCellFocused', false); // bool export const NOTEBOOK_CELL_EDITOR_FOCUSED = new RawContextKey('notebookCellEditorFocused', false); // bool @@ -64,8 +67,11 @@ export const NOTEBOOK_CELL_INPUT_COLLAPSED = new RawContextKey('noteboo export const NOTEBOOK_CELL_OUTPUT_COLLAPSED = new RawContextKey('notebookCellOutputIsCollapsed', false); // bool // Kernels export const NOTEBOOK_KERNEL_COUNT = new RawContextKey('notebookKernelCount', 0); +export const NOTEBOOK_KERNEL_SELECTED = new RawContextKey('notebookKernelSelected', false); export const NOTEBOOK_INTERRUPTIBLE_KERNEL = new RawContextKey('notebookInterruptibleKernel', false); +export const NOTEBOOK_HAS_OUTPUTS = new RawContextKey('notebookHasOutputs', false); + //#endregion //#region Shared commands @@ -87,6 +93,7 @@ export interface IRenderMainframeOutput { type: RenderOutputType.Mainframe; supportAppend?: boolean; initHeight?: number; + disposable?: IDisposable; } export interface IRenderPlainHtmlOutput { @@ -112,14 +119,14 @@ export interface ICellOutputViewModel { */ model: ICellOutput; resolveMimeTypes(textModel: NotebookTextModel, kernelProvides: readonly string[] | undefined): [readonly IOrderedMimeType[], number]; - pickedMimeType: number; + pickedMimeType: IOrderedMimeType | undefined; supportAppend(): boolean; + hasMultiMimeType(): boolean; toRawJSON(): any; } export interface IDisplayOutputViewModel extends ICellOutputViewModel { resolveMimeTypes(textModel: NotebookTextModel, kernelProvides: readonly string[] | undefined): [readonly IOrderedMimeType[], number]; - pickedMimeType: number; } @@ -131,7 +138,7 @@ export interface IGenericCellViewModel { id: string; handle: number; uri: URI; - metadata: NotebookCellMetadata | undefined; + metadata: NotebookCellMetadata; outputIsHovered: boolean; outputIsFocused: boolean; outputsViewModels: ICellOutputViewModel[]; @@ -168,16 +175,16 @@ export interface ICommonNotebookEditor { triggerScroll(event: IMouseWheelEvent): void; getCellByInfo(cellInfo: ICommonCellInfo): IGenericCellViewModel; getCellById(cellId: string): IGenericCellViewModel | undefined; - toggleNotebookCellSelection(cell: IGenericCellViewModel): void; + toggleNotebookCellSelection(cell: IGenericCellViewModel, selectFromPrevious: boolean): void; focusNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output', options?: IFocusNotebookCellOptions): void; focusNextNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number, isInit: boolean, source?: string): void; scheduleOutputHeightAck(cellInfo: ICommonCellInfo, outputId: string, height: number): void; updateMarkdownCellHeight(cellId: string, height: number, isInit: boolean): void; setMarkdownCellEditState(cellId: string, editState: CellEditState): void; - markdownCellDragStart(cellId: string, position: { clientY: number }): void; - markdownCellDrag(cellId: string, position: { clientY: number }): void; - markdownCellDrop(cellId: string, position: { clientY: number, ctrlKey: boolean, altKey: boolean }): void; + markdownCellDragStart(cellId: string, event: { dragOffsetY: number }): void; + markdownCellDrag(cellId: string, event: { dragOffsetY: number }): void; + markdownCellDrop(cellId: string, event: { dragOffsetY: number, ctrlKey: boolean, altKey: boolean }): void; markdownCellDragEnd(cellId: string): void; } @@ -230,6 +237,7 @@ export interface MarkdownCellLayoutInfo { readonly fontInfo: FontInfo | null; readonly editorWidth: number; readonly editorHeight: number; + readonly previewHeight: number; readonly bottomToolbarOffset: number; readonly totalHeight: number; } @@ -237,6 +245,8 @@ export interface MarkdownCellLayoutInfo { export interface MarkdownCellLayoutChangeEvent { font?: FontInfo; outerWidth?: number; + editorHeight?: number; + previewHeight?: number; totalHeight?: number; } @@ -248,6 +258,7 @@ export interface ICellViewModel extends IGenericCellViewModel { readonly onDidChangeLayout: Event<{ totalHeight?: boolean | number; outerWidth?: number; }>; readonly onDidChangeCellStatusBarItems: Event; readonly editStateSource: string; + readonly editorAttached: boolean; dragging: boolean; handle: number; uri: URI; @@ -259,7 +270,8 @@ export interface ICellViewModel extends IGenericCellViewModel { getText(): string; getTextLength(): number; getHeight(lineHeight: number): number; - metadata: NotebookCellMetadata | undefined; + metadata: NotebookCellMetadata; + internalMetadata: NotebookCellInternalMetadata; textModel: ITextModel | undefined; hasModel(): this is IEditableCellViewModel; resolveTextModel(): Promise; @@ -268,6 +280,8 @@ export interface ICellViewModel extends IGenericCellViewModel { getCellStatusBarItems(): INotebookCellStatusBarItem[]; getEditState(): CellEditState; updateEditState(state: CellEditState, source: string): void; + deltaModelDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[]; + getCellDecorationRange(id: string): Range | null; } export interface IEditableCellViewModel extends ICellViewModel { @@ -311,23 +325,10 @@ export interface INotebookDeltaCellStatusBarItems { items: INotebookCellStatusBarItem[]; } -export class NotebookEditorOptions extends EditorOptions { - - readonly cellOptions?: IResourceEditorInput; +export interface INotebookEditorOptions extends ITextEditorOptions { + readonly cellOptions?: ITextResourceEditorInput; readonly cellSelections?: ICellRange[]; readonly isReadOnly?: boolean; - - constructor(options: Partial) { - super(); - this.overwrite(options); - this.cellOptions = options.cellOptions; - this.cellSelections = options.cellSelections; - this.isReadOnly = options.isReadOnly; - } - - with(options: Partial): NotebookEditorOptions { - return new NotebookEditorOptions({ ...this, ...options }); - } } export type INotebookEditorContributionCtor = IConstructorSignature1; @@ -344,6 +345,7 @@ export interface INotebookEditorCreationOptions { export interface IActiveNotebookEditor extends INotebookEditor { viewModel: NotebookViewModel; + textModel: NotebookTextModel; getFocus(): ICellRange; } @@ -377,6 +379,7 @@ export interface INotebookEditor extends ICommonNotebookEditor { readonly onDidScroll: Event; readonly onDidChangeActiveCell: Event; + readonly notebookOptions: NotebookOptions; isDisposed: boolean; dispose(): void; @@ -395,7 +398,7 @@ export interface INotebookEditor extends ICommonNotebookEditor { hasWebviewFocus(): boolean; hasOutputTextSelection(): boolean; - setOptions(options: NotebookEditorOptions | undefined): Promise; + setOptions(options: INotebookEditorOptions | undefined): Promise; /** * Select & focus cell @@ -498,7 +501,7 @@ export interface INotebookEditor extends ICommonNotebookEditor { /** * Send message to the webview for outputs. */ - postMessage(forRendererId: string | undefined, message: any): void; + postMessage(message: any): void; /** * Remove class name on the notebook editor root DOM node. @@ -761,7 +764,7 @@ export interface IOutputTransformContribution { * This call is allowed to have side effects, such as placing output * directly into the container element. */ - render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI | undefined): IRenderOutput; + render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI): IRenderOutput; } export interface CellFindMatch { @@ -769,6 +772,12 @@ export interface CellFindMatch { matches: FindMatch[]; } +export interface CellFindMatchWithIndex { + cell: CellViewModel; + index: number; + matches: FindMatch[]; +} + export enum CellRevealType { Line, Range @@ -809,6 +818,7 @@ export enum CursorAtBoundary { export interface CellViewModelStateChangeEvent { readonly metadataChanged?: boolean; + readonly internalMetadataChanged?: boolean; readonly runStateChanged?: boolean; readonly selectionChanged?: boolean; readonly focusModeChanged?: boolean; @@ -897,20 +907,6 @@ export function getNotebookEditorFromEditorPane(editorPane?: IEditorPane): INote return editorPane?.getId() === NOTEBOOK_EDITOR_ID ? editorPane.getControl() as INotebookEditor | undefined : undefined; } -let EDITOR_TOP_PADDING = 12; -const editorTopPaddingChangeEmitter = new Emitter(); - -export const EditorTopPaddingChangeEvent = editorTopPaddingChangeEmitter.event; - -export function updateEditorTopPadding(top: number) { - EDITOR_TOP_PADDING = top; - editorTopPaddingChangeEmitter.fire(); -} - -export function getEditorTopPadding() { - return EDITOR_TOP_PADDING; -} - /** * ranges: model selections * this will convert model selections to view indexes first, and then include the hidden ranges in the list view diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookCellStatusBarServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookCellStatusBarServiceImpl.ts similarity index 93% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookCellStatusBarServiceImpl.ts rename to src/vs/workbench/contrib/notebook/browser/notebookCellStatusBarServiceImpl.ts index 05d2a1fc52a4..cb27b64cd422 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookCellStatusBarServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookCellStatusBarServiceImpl.ts @@ -10,7 +10,6 @@ import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle' import { URI } from 'vs/base/common/uri'; import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService'; import { INotebookCellStatusBarItemList, INotebookCellStatusBarItemProvider } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { score } from 'vs/workbench/contrib/notebook/common/notebookSelector'; export class NotebookCellStatusBarService extends Disposable implements INotebookCellStatusBarService { @@ -43,7 +42,7 @@ export class NotebookCellStatusBarService extends Disposable implements INoteboo } async getStatusBarItemsForCell(docUri: URI, cellIndex: number, viewType: string, token: CancellationToken): Promise { - const providers = this._providers.filter(p => score(p.selector, docUri, viewType) > 0); + const providers = this._providers.filter(p => p.viewType === viewType || p.viewType === '*'); return await Promise.all(providers.map(async p => { try { return await p.provideCellStatusBarItems(docUri, cellIndex, token) ?? { items: [] }; diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookDiffEditorInput.ts b/src/vs/workbench/contrib/notebook/browser/notebookDiffEditorInput.ts similarity index 81% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookDiffEditorInput.ts rename to src/vs/workbench/contrib/notebook/browser/notebookDiffEditorInput.ts index 7151038410aa..b8a16e1cf8bd 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookDiffEditorInput.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookDiffEditorInput.ts @@ -4,7 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import * as glob from 'vs/base/common/glob'; -import { EditorInput, IEditorInput, GroupIdentifier, ISaveOptions, IMoveResult, IRevertOptions, EditorModel } from 'vs/workbench/common/editor'; +import { IEditorInput, GroupIdentifier, ISaveOptions, IMoveResult, IRevertOptions, EditorInputCapabilities, IResourceDiffEditorInput } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; +import { EditorModel } from 'vs/workbench/common/editor/editorModel'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { URI } from 'vs/base/common/uri'; import { isEqual } from 'vs/base/common/resources'; @@ -14,6 +16,7 @@ import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebo import { IReference } from 'vs/base/common/lifecycle'; import { INotebookDiffEditorModel, IResolvedNotebookEditorModel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { Schemas } from 'vs/base/common/network'; +import { FileSystemProviderCapabilities, IFileService } from 'vs/platform/files/common/files'; interface NotebookEditorInputOptions { startDirty?: boolean; @@ -68,7 +71,8 @@ export class NotebookDiffEditorInput extends EditorInput { public readonly options: NotebookEditorInputOptions, @INotebookService private readonly _notebookService: INotebookService, @INotebookEditorModelResolverService private readonly _notebookModelResolverService: INotebookEditorModelResolverService, - @IFileDialogService private readonly _fileDialogService: IFileDialogService + @IFileDialogService private readonly _fileDialogService: IFileDialogService, + @IFileService private readonly _fileService: IFileService ) { super(); this._defaultDirtyState = !!options.startDirty; @@ -78,6 +82,26 @@ export class NotebookDiffEditorInput extends EditorInput { return NotebookDiffEditorInput.ID; } + override get capabilities(): EditorInputCapabilities { + let capabilities = EditorInputCapabilities.None; + + if (this._modifiedTextModel?.object.resource.scheme === Schemas.untitled) { + capabilities |= EditorInputCapabilities.Untitled; + } + + if (this._modifiedTextModel) { + if (this._modifiedTextModel.object.isReadonly()) { + capabilities |= EditorInputCapabilities.Readonly; + } + } else { + if (this._fileService.hasCapability(this.resource, FileSystemProviderCapabilities.Readonly)) { + capabilities |= EditorInputCapabilities.Readonly; + } + } + + return capabilities; + } + override getName(): string { return this.textDiffName; } @@ -89,18 +113,10 @@ export class NotebookDiffEditorInput extends EditorInput { return this._modifiedTextModel.object.isDirty(); } - override isUntitled(): boolean { - return this._modifiedTextModel?.object.resource.scheme === Schemas.untitled; - } - - override isReadonly() { - return false; - } - override async save(group: GroupIdentifier, options?: ISaveOptions): Promise { if (this._modifiedTextModel) { - if (this.isUntitled()) { + if (this.hasCapability(EditorInputCapabilities.Untitled)) { return this.saveAs(group, options); } else { await this._modifiedTextModel.object.save(); @@ -117,7 +133,7 @@ export class NotebookDiffEditorInput extends EditorInput { return undefined; } - const provider = this._notebookService.getContributedNotebookProvider(this.viewType!); + const provider = this._notebookService.getContributedNotebookType(this.viewType!); if (!provider) { return undefined; @@ -158,7 +174,7 @@ ${patterns} // called when users rename a notebook document override rename(group: GroupIdentifier, target: URI): IMoveResult | undefined { if (this._modifiedTextModel) { - const contributedNotebookProviders = this._notebookService.getContributedNotebookProviders(target); + const contributedNotebookProviders = this._notebookService.getContributedNotebookTypes(target); if (contributedNotebookProviders.find(provider => provider.id === this._modifiedTextModel!.object.viewType)) { return this._move(group, target); @@ -199,8 +215,18 @@ ${patterns} return new NotebookDiffEditorModel(this._originalTextModel.object, this._modifiedTextModel.object); } + override asResourceEditorInput(group: GroupIdentifier): IResourceDiffEditorInput { + return { + originalInput: { resource: this.originalResource }, + modifiedInput: { resource: this.resource }, + options: { + override: this.viewType + } + }; + } + override matches(otherInput: unknown): boolean { - if (this === otherInput) { + if (super.matches(otherInput)) { return true; } if (otherInput instanceof NotebookDiffEditorInput) { diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts similarity index 84% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts rename to src/vs/workbench/contrib/notebook/browser/notebookEditor.ts index 989cec381bc4..f88c3f92d2de 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts @@ -6,7 +6,7 @@ import * as DOM from 'vs/base/browser/dom'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter, Event } from 'vs/base/common/event'; -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import 'vs/css!./media/notebook'; import { localize } from 'vs/nls'; import { extname } from 'vs/base/common/resources'; @@ -18,17 +18,21 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; -import { EditorOptions, IEditorInput, IEditorMemento, IEditorOpenContext } from 'vs/workbench/common/editor'; +import { EditorInputCapabilities, IEditorInput, IEditorMemento, IEditorOpenContext } from 'vs/workbench/common/editor'; import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput'; import { NotebookEditorWidget } from 'vs/workbench/contrib/notebook/browser/notebookEditorWidget'; import { INotebookEditorViewState, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { IEditorDropService } from 'vs/workbench/services/editor/browser/editorDropService'; import { IEditorGroup, IEditorGroupsService, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { NotebookEditorOptions, NOTEBOOK_EDITOR_ID } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { INotebookEditorOptions, NOTEBOOK_EDITOR_ID } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { IBorrowValue, INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService'; import { clearMarks, getAndClearMarks, mark } from 'vs/workbench/contrib/notebook/common/notebookPerformance'; import { IFileService } from 'vs/platform/files/common/files'; +import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IAction } from 'vs/base/common/actions'; +import { SELECT_KERNEL_ID } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions'; +import { NotebooKernelActionViewItem } from 'vs/workbench/contrib/notebook/browser/notebookKernelActionViewItem'; const NOTEBOOK_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'NotebookEditorViewState'; @@ -37,11 +41,13 @@ export class NotebookEditor extends EditorPane { private readonly _editorMemento: IEditorMemento; private readonly _groupListener = this._register(new DisposableStore()); - private readonly _widgetDisposableStore: DisposableStore = new DisposableStore(); + private readonly _widgetDisposableStore: DisposableStore = this._register(new DisposableStore()); private _widget: IBorrowValue = { value: undefined }; private _rootElement!: HTMLElement; private _dimension?: DOM.Dimension; + private readonly inputListener = this._register(new MutableDisposable()); + // todo@rebornix is there a reason that `super.fireOnDidFocus` isn't used? private readonly _onDidFocusWidget = this._register(new Emitter()); override get onDidFocus(): Event { return this._onDidFocusWidget.event; } @@ -65,13 +71,25 @@ export class NotebookEditor extends EditorPane { super(NotebookEditor.ID, telemetryService, themeService, storageService); this._editorMemento = this.getEditorMemento(_editorGroupService, NOTEBOOK_EDITOR_VIEW_STATE_PREFERENCE_KEY); - this._register(this.fileService.onDidChangeFileSystemProviderCapabilities(e => this.onDidFileSystemProviderChange(e.scheme))); - this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(e => this.onDidFileSystemProviderChange(e.scheme))); + this._register(this.fileService.onDidChangeFileSystemProviderCapabilities(e => this.onDidChangeFileSystemProvider(e.scheme))); + this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(e => this.onDidChangeFileSystemProvider(e.scheme))); + } + + private onDidChangeFileSystemProvider(scheme: string): void { + if (this.input instanceof NotebookEditorInput && this.input.resource?.scheme === scheme) { + this.updateReadonly(this.input); + } + } + + private onDidChangeInputCapabilities(input: NotebookEditorInput): void { + if (this.input === input) { + this.updateReadonly(input); + } } - private onDidFileSystemProviderChange(scheme: string): void { - if (this.input?.resource?.scheme === scheme && this._widget.value) { - this._widget.value.setOptions(new NotebookEditorOptions({ isReadOnly: this.input.isReadonly() })); + private updateReadonly(input: NotebookEditorInput): void { + if (this._widget.value) { + this._widget.value.setOptions({ isReadOnly: input.hasCapability(EditorInputCapabilities.Readonly) }); } } @@ -103,6 +121,14 @@ export class NotebookEditor extends EditorPane { return this._rootElement; } + override getActionViewItem(action: IAction): IActionViewItem | undefined { + if (action.id === SELECT_KERNEL_ID) { + // this is being disposed by the consumer + return this.instantiationService.createInstance(NotebooKernelActionViewItem, action, this); + } + return undefined; + } + override getControl(): NotebookEditorWidget | undefined { return this._widget.value; } @@ -140,11 +166,13 @@ export class NotebookEditor extends EditorPane { return !!value && (DOM.isAncestor(activeElement, value.getDomNode() || DOM.isAncestor(activeElement, value.getOverflowContainerDomNode()))); } - override async setInput(input: NotebookEditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + override async setInput(input: NotebookEditorInput, options: INotebookEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { clearMarks(input.resource); mark(input.resource, 'startTime'); const group = this.group!; + this.inputListener.value = input.onDidChangeCapabilities(() => this.onDidChangeInputCapabilities(input)); + this._saveEditorViewState(this.input); this._widgetDisposableStore.clear(); @@ -193,8 +221,8 @@ export class NotebookEditor extends EditorPane { this._widget.value?.setParentContextKeyService(this._contextKeyService); await this._widget.value!.setModel(model.notebook, viewState); - const isReadonly = input.isReadonly(); - await this._widget.value!.setOptions(options instanceof NotebookEditorOptions ? options.with({ isReadOnly: isReadonly }) : new NotebookEditorOptions({ isReadOnly: isReadonly })); + const isReadOnly = input.hasCapability(EditorInputCapabilities.Readonly); + await this._widget.value!.setOptions({ ...options, isReadOnly }); this._widgetDisposableStore.add(this._widget.value!.onDidFocus(() => this._onDidFocusWidget.fire())); this._widgetDisposableStore.add(this._editorDropService.createEditorDropTarget(this._widget.value!.getDomNode(), { @@ -258,6 +286,8 @@ export class NotebookEditor extends EditorPane { } override clearInput(): void { + this.inputListener.clear(); + if (this._widget.value) { this._saveEditorViewState(this.input); this._widget.value.onWillHide(); @@ -265,10 +295,8 @@ export class NotebookEditor extends EditorPane { super.clearInput(); } - override setOptions(options: EditorOptions | undefined): void { - if (options instanceof NotebookEditorOptions) { - this._widget.value?.setOptions(options); - } + override setOptions(options: INotebookEditorOptions | undefined): void { + this._widget.value?.setOptions(options); super.setOptions(options); } diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorDecorations.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorDecorations.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorDecorations.ts rename to src/vs/workbench/contrib/notebook/browser/notebookEditorDecorations.ts diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorExtensions.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorExtensions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorExtensions.ts rename to src/vs/workbench/contrib/notebook/browser/notebookEditorExtensions.ts diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorKernelManager.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorKernelManager.ts similarity index 81% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorKernelManager.ts rename to src/vs/workbench/contrib/notebook/browser/notebookEditorKernelManager.ts index 597865448d1a..2f97e8579929 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorKernelManager.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorKernelManager.ts @@ -6,10 +6,11 @@ import * as nls from 'vs/nls'; import { Disposable } from 'vs/base/common/lifecycle'; import { ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CellKind, INotebookKernel, INotebookTextModel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, INotebookKernel, INotebookTextModel, NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; import { IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust'; +import { SELECT_KERNEL_ID } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions'; export class NotebookEditorKernelManager extends Disposable { @@ -24,32 +25,19 @@ export class NotebookEditorKernelManager extends Disposable { getSelectedOrSuggestedKernel(notebook: INotebookTextModel): INotebookKernel | undefined { // returns SELECTED or the ONLY available kernel const info = this._notebookKernelService.getMatchingKernel(notebook); - if (info.selected) { - return info.selected; - } - if (info.all.length === 1) { - return info.all[0]; - } - return undefined; + return info.selected ?? info.suggested; } async executeNotebookCells(notebook: INotebookTextModel, cells: Iterable): Promise { const message = nls.localize('notebookRunTrust', "Executing a notebook cell will run code from this workspace."); - const trust = await this._workspaceTrustRequestService.requestWorkspaceTrust({ - modal: true, - message - }); + const trust = await this._workspaceTrustRequestService.requestWorkspaceTrust({ message }); if (!trust) { return; } - if (!notebook.metadata.trusted) { - return; - } - let kernel = this.getSelectedOrSuggestedKernel(notebook); if (!kernel) { - await this._commandService.executeCommand('notebook.selectKernel'); + await this._commandService.executeCommand(SELECT_KERNEL_ID); kernel = this.getSelectedOrSuggestedKernel(notebook); } @@ -59,7 +47,7 @@ export class NotebookEditorKernelManager extends Disposable { const cellHandles: number[] = []; for (const cell of cells) { - if (cell.cellKind !== CellKind.Code) { + if (cell.cellKind !== CellKind.Code || cell.internalMetadata.runState === NotebookCellExecutionState.Pending || cell.internalMetadata.runState === NotebookCellExecutionState.Executing) { continue; } if (!kernel.supportedLanguages.includes(cell.language)) { diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorService.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorService.ts rename to src/vs/workbench/contrib/notebook/browser/notebookEditorService.ts diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorServiceImpl.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorServiceImpl.ts rename to src/vs/workbench/contrib/notebook/browser/notebookEditorServiceImpl.ts index 17bcdd78ecd6..c48fcbcf6f8e 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorServiceImpl.ts @@ -52,6 +52,7 @@ export class NotebookEditorWidgetService implements INotebookEditorService { value.token = undefined; this._disposeWidget(value.widget); widgets.delete(e.editor.resource); + value.widget = (undefined); // unset the widget so that others that still hold a reference don't harm us })); listeners.push(group.onWillMoveEditor(e => { if (e.editor instanceof NotebookEditorInput) { diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorToolbar.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorToolbar.ts new file mode 100644 index 000000000000..424eecf4304c --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorToolbar.ts @@ -0,0 +1,230 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as DOM from 'vs/base/browser/dom'; +import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; +import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; +import { IAction, Separator } from 'vs/base/common/actions'; +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { ScrollbarVisibility } from 'vs/base/common/scrollable'; +import { IMenu, MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IInstantiationService, optional } from 'vs/platform/instantiation/common/instantiation'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { toolbarActiveBackground } from 'vs/platform/theme/common/colorRegistry'; +import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { SELECT_KERNEL_ID } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions'; +import { INotebookEditor, NOTEBOOK_EDITOR_ID } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { NotebooKernelActionViewItem } from 'vs/workbench/contrib/notebook/browser/notebookKernelActionViewItem'; +import { ActionViewWithLabel } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellActionView'; +import { CellMenus } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellMenus'; +import { GlobalToolbar } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { ITASExperimentService } from 'vs/workbench/services/experiment/common/experimentService'; + +export class NotebookEditorToolbar extends Disposable { + // private _editorToolbarContainer!: HTMLElement; + private _leftToolbarScrollable!: DomScrollableElement; + private _notebookTopLeftToolbarContainer!: HTMLElement; + private _notebookTopRightToolbarContainer!: HTMLElement; + private _notebookGlobalActionsMenu!: IMenu; + private _notebookLeftToolbar!: ToolBar; + private _notebookRightToolbar!: ToolBar; + private _useGlobalToolbar: boolean = false; + + private readonly _onDidChangeState = this._register(new Emitter()); + onDidChangeState: Event = this._onDidChangeState.event; + + get useGlobalToolbar(): boolean { + return this._useGlobalToolbar; + } + + private _pendingLayout: IDisposable | undefined; + + constructor( + readonly notebookEditor: INotebookEditor, + readonly contextKeyService: IContextKeyService, + readonly domNode: HTMLElement, + @IInstantiationService readonly instantiationService: IInstantiationService, + @IConfigurationService readonly configurationService: IConfigurationService, + @IContextMenuService readonly contextMenuService: IContextMenuService, + @IEditorService private readonly editorService: IEditorService, + @IKeybindingService private readonly keybindingService: IKeybindingService, + @optional(ITASExperimentService) private readonly experimentService: ITASExperimentService + ) { + super(); + + this._buildBody(); + + this._register(this.editorService.onDidActiveEditorChange(() => { + if (this.editorService.activeEditorPane?.getId() === NOTEBOOK_EDITOR_ID) { + const notebookEditor = this.editorService.activeEditorPane.getControl() as INotebookEditor; + if (notebookEditor === this.notebookEditor) { + // this is the active editor + this._showNotebookActionsinEditorToolbar(); + return; + } + } + })); + + this._reigsterNotebookActionsToolbar(); + } + + private _buildBody() { + this._notebookTopLeftToolbarContainer = document.createElement('div'); + this._notebookTopLeftToolbarContainer.classList.add('notebook-toolbar-left'); + this._leftToolbarScrollable = new DomScrollableElement(this._notebookTopLeftToolbarContainer, { + vertical: ScrollbarVisibility.Hidden, + horizontal: ScrollbarVisibility.Auto, + horizontalScrollbarSize: 3, + useShadows: false, + scrollYToX: true + }); + this._register(this._leftToolbarScrollable); + + DOM.append(this.domNode, this._leftToolbarScrollable.getDomNode()); + this._notebookTopRightToolbarContainer = document.createElement('div'); + this._notebookTopRightToolbarContainer.classList.add('notebook-toolbar-right'); + DOM.append(this.domNode, this._notebookTopRightToolbarContainer); + } + + private _reigsterNotebookActionsToolbar() { + const cellMenu = this.instantiationService.createInstance(CellMenus); + this._notebookGlobalActionsMenu = this._register(cellMenu.getNotebookToolbar(this.contextKeyService)); + this._register(this._notebookGlobalActionsMenu); + + this._useGlobalToolbar = this.configurationService.getValue(GlobalToolbar) ?? false; + this._register(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(GlobalToolbar)) { + this._useGlobalToolbar = this.configurationService.getValue(GlobalToolbar); + this._showNotebookActionsinEditorToolbar(); + } + })); + + const context = { + ui: true, + notebookEditor: this.notebookEditor + }; + + const actionProvider = (action: IAction) => { + if (action.id === SELECT_KERNEL_ID) { + // // this is being disposed by the consumer + return this.instantiationService.createInstance(NotebooKernelActionViewItem, action, this.notebookEditor); + } + + return action instanceof MenuItemAction ? this.instantiationService.createInstance(ActionViewWithLabel, action) : undefined; + }; + + this._notebookLeftToolbar = new ToolBar(this._notebookTopLeftToolbarContainer, this.contextMenuService, { + getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id), + actionViewItemProvider: actionProvider, + renderDropdownAsChildElement: true + }); + this._register(this._notebookLeftToolbar); + this._notebookLeftToolbar.context = context; + + this._notebookRightToolbar = new ToolBar(this._notebookTopRightToolbarContainer, this.contextMenuService, { + getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id), + actionViewItemProvider: actionProvider, + renderDropdownAsChildElement: true + }); + this._register(this._notebookRightToolbar); + this._notebookRightToolbar.context = context; + + this._showNotebookActionsinEditorToolbar(); + this._register(this._notebookGlobalActionsMenu.onDidChange(() => { + this._showNotebookActionsinEditorToolbar(); + })); + + if (this.experimentService) { + this.experimentService.getTreatment('nbtoolbarineditor').then(treatment => { + if (treatment === undefined) { + return; + } + if (this._useGlobalToolbar !== treatment) { + this._useGlobalToolbar = treatment; + this._showNotebookActionsinEditorToolbar(); + } + }); + } + } + + private _showNotebookActionsinEditorToolbar() { + // when there is no view model, just ignore. + if (!this.notebookEditor.hasModel()) { + return; + } + + if (!this._useGlobalToolbar) { + this.domNode.style.display = 'none'; + } else { + this._notebookLeftToolbar.setActions([], []); + const groups = this._notebookGlobalActionsMenu.getActions({ shouldForwardArgs: true, renderShortTitle: true }); + this.domNode.style.display = 'flex'; + const primaryLeftGroups = groups.filter(group => /^navigation/.test(group[0])); + let primaryActions: IAction[] = []; + primaryLeftGroups.sort((a, b) => { + if (a[0] === 'navigation') { + return 1; + } + + if (b[0] === 'navigation') { + return -1; + } + + return 0; + }).forEach((group, index) => { + primaryActions.push(...group[1]); + if (index < primaryLeftGroups.length - 1) { + primaryActions.push(new Separator()); + } + }); + const primaryRightGroup = groups.find(group => /^status/.test(group[0])); + const primaryRightActions = primaryRightGroup ? primaryRightGroup[1] : []; + const secondaryActions = groups.filter(group => !/^navigation/.test(group[0]) && !/^status/.test(group[0])).reduce((prev: (MenuItemAction | SubmenuItemAction)[], curr) => { prev.push(...curr[1]); return prev; }, []); + + this._notebookLeftToolbar.setActions(primaryActions, secondaryActions); + this._notebookRightToolbar.setActions(primaryRightActions, []); + this._updateScrollbar(); + } + + this._onDidChangeState.fire(); + } + + layout() { + this._updateScrollbar(); + } + + private _updateScrollbar() { + this._pendingLayout?.dispose(); + + this._pendingLayout = DOM.measure(() => { + DOM.measure(() => { // double RAF + this._leftToolbarScrollable.setRevealOnScroll(false); + this._leftToolbarScrollable.scanDomNode(); + this._leftToolbarScrollable.setRevealOnScroll(true); + }); + }); + } + + override dispose() { + this._pendingLayout?.dispose(); + super.dispose(); + } +} + +registerThemingParticipant((theme, collector) => { + const toolbarActiveBackgroundColor = theme.getColor(toolbarActiveBackground); + if (toolbarActiveBackgroundColor) { + collector.addRule(` + .monaco-workbench .notebookOverlay .notebook-toolbar-container .monaco-action-bar:not(.vertical) .action-item.active { + background-color: ${toolbarActiveBackgroundColor}; + } + `); + } +}); diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts similarity index 77% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts rename to src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 65e8ed9b1be2..5f94dbb1c9fe 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -25,12 +25,12 @@ import { Range } from 'vs/editor/common/core/range'; import { IEditor } from 'vs/editor/common/editorCommon'; import { IModeService } from 'vs/editor/common/services/modeService'; import * as nls from 'vs/nls'; -import { createActionViewItem, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { IMenu, IMenuService, MenuId, MenuItemAction, MenuRegistry, SubmenuItemAction } from 'vs/platform/actions/common/actions'; +import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; +import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IInstantiationService, optional } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; @@ -42,8 +42,7 @@ import { IEditorMemento } from 'vs/workbench/common/editor'; import { Memento, MementoObject } from 'vs/workbench/common/memento'; import { PANEL_BORDER } from 'vs/workbench/common/theme'; import { debugIconStartForeground } from 'vs/workbench/contrib/debug/browser/debugColors'; -import { BOTTOM_CELL_TOOLBAR_GAP, BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_BOTTOM_MARGIN, CELL_OUTPUT_PADDING, CELL_RIGHT_MARGIN, CELL_RUN_GUTTER, CELL_TOP_MARGIN, CODE_CELL_LEFT_MARGIN, COLLAPSED_INDICATOR_HEIGHT, MARKDOWN_CELL_BOTTOM_MARGIN, MARKDOWN_CELL_TOP_MARGIN, MARKDOWN_PREVIEW_PADDING, SCROLLABLE_ELEMENT_PADDING_TOP } from 'vs/workbench/contrib/notebook/browser/constants'; -import { CellEditState, CellFocusMode, IActiveNotebookEditor, ICellOutputViewModel, ICellViewModel, ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IFocusNotebookCellOptions, IGenericCellViewModel, IInsetRenderOutput, INotebookCellList, INotebookCellOutputLayoutInfo, INotebookDeltaDecoration, INotebookEditor, INotebookEditorContribution, INotebookEditorContributionDescription, INotebookEditorCreationOptions, INotebookEditorMouseEvent, NotebookEditorOptions, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_ID, NOTEBOOK_OUTPUT_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellEditState, CellFocusMode, IActiveNotebookEditor, ICellOutputViewModel, ICellViewModel, ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IFocusNotebookCellOptions, IGenericCellViewModel, IInsetRenderOutput, INotebookCellList, INotebookCellOutputLayoutInfo, INotebookDeltaDecoration, INotebookEditor, INotebookEditorContribution, INotebookEditorContributionDescription, INotebookEditorCreationOptions, INotebookEditorMouseEvent, INotebookEditorOptions, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_ID, NOTEBOOK_OUTPUT_FOCUSED, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookDecorationCSSRules, NotebookRefCountedStyleSheet } from 'vs/workbench/contrib/notebook/browser/notebookEditorDecorations'; import { NotebookEditorExtensionsRegistry } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions'; import { NotebookEditorKernelManager } from 'vs/workbench/contrib/notebook/browser/notebookEditorKernelManager'; @@ -59,22 +58,20 @@ import { NotebookEventDispatcher, NotebookLayoutChangedEvent } from 'vs/workbenc import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel'; import { CellViewModel, IModelDecorationsChangeAccessor, INotebookEditorViewState, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; -import { CellKind, CellToolbarLocKey, ExperimentalUseMarkdownRenderer, SelectionStateType, ShowCellStatusBarKey } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, ExperimentalUseMarkdownRenderer, SelectionStateType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange'; import { editorGutterModifiedBackground } from 'vs/workbench/contrib/scm/browser/dirtydiffDecorator'; import { Webview } from 'vs/workbench/contrib/webview/browser/webview'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; -import { CellMenus } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellMenus'; -import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { ITASExperimentService } from 'vs/workbench/services/experiment/common/experimentService'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { isWeb } from 'vs/base/common/platform'; import { mark } from 'vs/workbench/contrib/notebook/common/notebookPerformance'; import { readFontInfo } from 'vs/editor/browser/config/configuration'; import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; import { NotebookEditorContextKeys } from 'vs/workbench/contrib/notebook/browser/notebookEditorWidgetContextKeys'; +import { NotebookOptions } from 'vs/workbench/contrib/notebook/common/notebookOptions'; +import { ViewContext } from 'vs/workbench/contrib/notebook/browser/viewModel/viewContext'; +import { NotebookEditorToolbar } from 'vs/workbench/contrib/notebook/browser/notebookEditorToolbar'; +import { INotebookRendererMessagingService } from 'vs/workbench/contrib/notebook/common/notebookRendererMessagingService'; const $ = DOM.$; @@ -202,17 +199,20 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor private static readonly EDITOR_MEMENTOS = new Map>(); private _overlayContainer!: HTMLElement; private _notebookTopToolbarContainer!: HTMLElement; + private _notebookTopToolbar!: NotebookEditorToolbar; private _body!: HTMLElement; + private _styleElement!: HTMLStyleElement; private _overflowContainer!: HTMLElement; private _webview: BackLayerWebView | null = null; private _webviewResolvePromise: Promise | null> | null = null; private _webviewTransparentCover: HTMLElement | null = null; + private _listDelegate: NotebookCellListDelegate | null = null; private _list!: INotebookCellList; private _listViewInfoAccessor!: ListViewInfoAccessor; private _dndController: CellDragAndDropController | null = null; private _listTopCellToolbar: ListTopCellToolbar | null = null; private _renderedEditors: Map = new Map(); - private _eventDispatcher: NotebookEventDispatcher | undefined; + private _viewContext: ViewContext; private _notebookViewModel: NotebookViewModel | undefined; private _localStore: DisposableStore = this._register(new DisposableStore()); private _localCellStateListeners: DisposableStore[] = []; @@ -305,15 +305,20 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor public readonly scopedContextKeyService: IContextKeyService; private readonly instantiationService: IInstantiationService; + private readonly _notebookOptions: NotebookOptions; + + get notebookOptions() { + return this._notebookOptions; + } constructor( readonly creationOptions: INotebookEditorCreationOptions, @IInstantiationService instantiationService: IInstantiationService, @IStorageService storageService: IStorageService, @IAccessibilityService accessibilityService: IAccessibilityService, + @INotebookRendererMessagingService private readonly notebookRendererMessaging: INotebookRendererMessagingService, @INotebookEditorService private readonly notebookEditorService: INotebookEditorService, - @INotebookKernelService notebookKernelService: INotebookKernelService, - @IEditorService private readonly editorService: IEditorService, + @INotebookKernelService private readonly notebookKernelService: INotebookKernelService, @IConfigurationService private readonly configurationService: IConfigurationService, @IContextKeyService contextKeyService: IContextKeyService, @ILayoutService private readonly layoutService: ILayoutService, @@ -321,14 +326,15 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor @IMenuService private readonly menuService: IMenuService, @IThemeService private readonly themeService: IThemeService, @ITelemetryService private readonly telemetryService: ITelemetryService, - @IModeService private readonly modeService: IModeService, - @IKeybindingService private readonly keybindingService: IKeybindingService, - @optional(ITASExperimentService) private readonly experimentService: ITASExperimentService + @IModeService private readonly modeService: IModeService ) { super(); this.isEmbedded = creationOptions.isEmbedded || false; - this.useRenderer = !isWeb && !!this.configurationService.getValue(ExperimentalUseMarkdownRenderer) && !accessibilityService.isScreenReaderOptimized(); + this.useRenderer = !!this.configurationService.getValue(ExperimentalUseMarkdownRenderer) && !accessibilityService.isScreenReaderOptimized(); + this._notebookOptions = new NotebookOptions(this.configurationService); + this._register(this._notebookOptions); + this._viewContext = new ViewContext(this._notebookOptions, new NotebookEventDispatcher()); this._overlayContainer = document.createElement('div'); this.scopedContextKeyService = contextKeyService.createScoped(this._overlayContainer); @@ -345,21 +351,33 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor this._memento = new Memento(NOTEBOOK_EDITOR_ID, storageService); - this._outputRenderer = new OutputRenderer(this, this.instantiationService); + this._outputRenderer = this._register(new OutputRenderer(this, this.instantiationService)); this._scrollBeyondLastLine = this.configurationService.getValue('editor.scrollBeyondLastLine'); - this.configurationService.onDidChangeConfiguration(e => { + this._register(this.configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration('editor.scrollBeyondLastLine')) { this._scrollBeyondLastLine = this.configurationService.getValue('editor.scrollBeyondLastLine'); if (this._dimension && this._isVisible) { this.layout(this._dimension); } } + })); - if (e.affectsConfiguration(CellToolbarLocKey) || e.affectsConfiguration(ShowCellStatusBarKey)) { + this._register(this._notebookOptions.onDidChangeOptions(e => { + if (e.cellStatusBarVisibility || e.cellToolbarLocation || e.cellToolbarInteraction) { this._updateForNotebookConfiguration(); } - }); + + if (e.compactView || e.focusIndicator || e.insertToolbarPosition || e.cellToolbarLocation || e.dragAndDropEnabled || e.fontSize || e.insertToolbarAlignment) { + this._styleElement?.remove(); + this._createLayoutStyles(); + this._webview?.updateOptions(this.notebookOptions.computeWebviewOptions()); + } + + if (this._dimension && this._isVisible) { + this.layout(this._dimension); + } + })); this.notebookEditorService.addNotebookEditor(this); @@ -384,12 +402,20 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor contributions = NotebookEditorExtensionsRegistry.getEditorContributions(); } for (const desc of contributions) { + let contribution: INotebookEditorContribution | undefined; try { - const contribution = this.instantiationService.createInstance(desc.ctor, this); - this._contributions.set(desc.id, contribution); + contribution = this.instantiationService.createInstance(desc.ctor, this); } catch (err) { onUnexpectedError(err); } + if (contribution) { + if (!this._contributions.has(desc.id)) { + this._contributions.set(desc.id, contribution); + } else { + contribution.dispose(); + throw new Error(`DUPLICATE notebook editor contribution: '${desc.id}'`); + } + } } this._updateForNotebookConfiguration(); @@ -479,41 +505,22 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor return; } - const cellToolbarLocation = this.configurationService.getValue(CellToolbarLocKey); this._overlayContainer.classList.remove('cell-title-toolbar-left'); this._overlayContainer.classList.remove('cell-title-toolbar-right'); this._overlayContainer.classList.remove('cell-title-toolbar-hidden'); + const cellToolbarLocation = this._notebookOptions.computeCellToolbarLocation(this.viewModel?.viewType); + this._overlayContainer.classList.add(`cell-title-toolbar-${cellToolbarLocation}`); - if (typeof cellToolbarLocation === 'string') { - if (cellToolbarLocation === 'left' || cellToolbarLocation === 'right' || cellToolbarLocation === 'hidden') { - this._overlayContainer.classList.add(`cell-title-toolbar-${cellToolbarLocation}`); - } - } else { - if (this.viewModel) { - const notebookSpecificSetting = cellToolbarLocation[this.viewModel.viewType] ?? cellToolbarLocation['default']; - let cellToolbarLocationForCurrentView = 'right'; - - switch (notebookSpecificSetting) { - case 'left': - cellToolbarLocationForCurrentView = 'left'; - break; - case 'right': - cellToolbarLocationForCurrentView = 'right'; - case 'hidden': - cellToolbarLocationForCurrentView = 'hidden'; - default: - cellToolbarLocationForCurrentView = 'right'; - break; - } + const cellToolbarInteraction = this._notebookOptions.getLayoutConfiguration().cellToolbarInteraction; + let cellToolbarInteractionState = 'hover'; + this._overlayContainer.classList.remove('cell-toolbar-hover'); + this._overlayContainer.classList.remove('cell-toolbar-click'); - this._overlayContainer.classList.add(`cell-title-toolbar-${cellToolbarLocationForCurrentView}`); - } else { - this._overlayContainer.classList.add(`cell-title-toolbar-right`); - } + if (cellToolbarInteraction === 'hover' || cellToolbarInteraction === 'click') { + cellToolbarInteractionState = cellToolbarInteraction; } + this._overlayContainer.classList.add(`cell-toolbar-${cellToolbarInteractionState}`); - const showCellStatusBar = this.configurationService.getValue(ShowCellStatusBarKey); - this._overlayContainer.classList.toggle('cell-statusbar-hidden', !showCellStatusBar); } private _generateFontInfo(): void { @@ -523,19 +530,248 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor private _createBody(parent: HTMLElement): void { this._notebookTopToolbarContainer = document.createElement('div'); - this._notebookTopToolbarContainer.classList.add('notebook-top-toolbar'); + this._notebookTopToolbarContainer.classList.add('notebook-toolbar-container'); this._notebookTopToolbarContainer.style.display = 'none'; DOM.append(parent, this._notebookTopToolbarContainer); this._body = document.createElement('div'); + DOM.append(parent, this._body); this._body.classList.add('cell-list-container'); + this._createLayoutStyles(); this._createCellList(); - DOM.append(parent, this._body); this._overflowContainer = document.createElement('div'); this._overflowContainer.classList.add('notebook-overflow-widget-container', 'monaco-editor'); DOM.append(parent, this._overflowContainer); } + private _createLayoutStyles(): void { + this._styleElement = DOM.createStyleSheet(this._body); + const { + cellRightMargin, + cellTopMargin, + cellRunGutter, + cellBottomMargin, + codeCellLeftMargin, + markdownCellGutter, + markdownCellLeftMargin, + markdownCellBottomMargin, + markdownCellTopMargin, + // bottomToolbarGap: bottomCellToolbarGap, + // bottomToolbarHeight: bottomCellToolbarHeight, + collapsedIndicatorHeight, + compactView, + focusIndicator, + insertToolbarPosition, + insertToolbarAlignment, + fontSize, + focusIndicatorLeftMargin + } = this._notebookOptions.getLayoutConfiguration(); + + const { bottomToolbarGap, bottomToolbarHeight } = this._notebookOptions.computeBottomToolbarDimensions(this.viewModel?.viewType); + + const styleSheets: string[] = []; + + styleSheets.push(` + :root { + --notebook-cell-output-font-size: ${fontSize}px; + } + `); + + if (compactView) { + styleSheets.push(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .markdown-cell-row div.cell.code { margin-left: ${codeCellLeftMargin + cellRunGutter}px; }`); + } else { + styleSheets.push(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .markdown-cell-row div.cell.code { margin-left: ${codeCellLeftMargin}px; }`); + } + + // focus indicator + if (focusIndicator === 'border') { + styleSheets.push(` + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-top:before, + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-bottom:before, + .monaco-workbench .notebookOverlay .monaco-list .markdown-cell-row .cell-inner-container:before, + .monaco-workbench .notebookOverlay .monaco-list .markdown-cell-row .cell-inner-container:after { + content: ""; + position: absolute; + width: 100%; + height: 1px; + } + + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-left:before, + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-right:before { + content: ""; + position: absolute; + width: 1px; + height: 100%; + z-index: 10; + } + + /* top border */ + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-top:before { + border-top: 1px solid transparent; + } + + /* left border */ + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-left:before { + border-left: 1px solid transparent; + } + + /* bottom border */ + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-bottom:before { + border-bottom: 1px solid transparent; + } + + /* right border */ + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-right:before { + border-right: 1px solid transparent; + } + `); + + // left and right border margins + styleSheets.push(` + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row.focused .cell-focus-indicator-left:before, + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row.focused .cell-focus-indicator-right:before, + .monaco-workbench .notebookOverlay .monaco-list.selection-multiple .monaco-list-row.code-cell-row.selected .cell-focus-indicator-left:before, + .monaco-workbench .notebookOverlay .monaco-list.selection-multiple .monaco-list-row.code-cell-row.selected .cell-focus-indicator-right:before { + top: -${cellTopMargin}px; height: calc(100% + ${cellTopMargin + cellBottomMargin}px) + }`); + } else { + // gutter + styleSheets.push(` + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-left:before, + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-right:before { + content: ""; + position: absolute; + width: 0px; + height: 100%; + z-index: 10; + } + `); + + // left and right border margins + styleSheets.push(` + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row.focused .cell-focus-indicator-left:before, + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row.focused .cell-focus-indicator-right:before, + .monaco-workbench .notebookOverlay .monaco-list.selection-multiple .monaco-list-row.code-cell-row.selected .cell-focus-indicator-left:before, + .monaco-workbench .notebookOverlay .monaco-list.selection-multiple .monaco-list-row.code-cell-row.selected .cell-focus-indicator-right:before { + top: 0px; height: 100%; + }`); + + styleSheets.push(` + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-left:before, + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.selected .cell-focus-indicator-left:before { + border-left: 3px solid transparent; + border-radius: 2px; + margin-left: ${focusIndicatorLeftMargin}px; + }`); + + // boder should always show + styleSheets.push(` + .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-inner-container .cell-focus-indicator-left:before { + border-color: var(--notebook-focused-cell-border-color) !important; + } + + .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-inner-container .cell-focus-indicator-left:before { + border-color: var(--notebook-inactive-focused-cell-border-color) !important; + } + `); + } + + // between cell insert toolbar + if (insertToolbarPosition === 'betweenCells' || insertToolbarPosition === 'both') { + styleSheets.push(`.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container { display: flex; }`); + styleSheets.push(`.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .cell-list-top-cell-toolbar-container { display: flex; }`); + } else { + styleSheets.push(`.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container { display: none; }`); + styleSheets.push(`.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .cell-list-top-cell-toolbar-container { display: none; }`); + } + + if (insertToolbarAlignment === 'left') { + styleSheets.push(` + .monaco-workbench .notebookOverlay .cell-list-top-cell-toolbar-container .action-item:first-child, + .monaco-workbench .notebookOverlay .cell-list-top-cell-toolbar-container .action-item:first-child, .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container .action-item:first-child { + margin-right: 0px !important; + }`); + + styleSheets.push(` + .monaco-workbench .notebookOverlay .cell-list-top-cell-toolbar-container .monaco-toolbar .action-label, + .monaco-workbench .notebookOverlay .cell-list-top-cell-toolbar-container .monaco-toolbar .action-label, .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container .monaco-toolbar .action-label { + padding: 0px !important; + justify-content: center; + border-radius: 4px; + }`); + + styleSheets.push(` + .monaco-workbench .notebookOverlay .cell-list-top-cell-toolbar-container, + .monaco-workbench .notebookOverlay .cell-list-top-cell-toolbar-container, .monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container { + align-items: flex-start; + justify-content: left; + margin: 0 16px 0 ${8 + codeCellLeftMargin}px; + }`); + + styleSheets.push(` + .monaco-workbench .notebookOverlay .cell-list-top-cell-toolbar-container, + .notebookOverlay .cell-bottom-toolbar-container .action-item { + border: 0px; + }`); + } + + // top insert toolbar + const topInsertToolbarHeight = this._notebookOptions.computeTopInserToolbarHeight(this.viewModel?.viewType); + styleSheets.push(`.notebookOverlay .cell-list-top-cell-toolbar-container { top: -${topInsertToolbarHeight}px }`); + styleSheets.push(`.notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element, + .notebookOverlay > .cell-list-container > .notebook-gutter > .monaco-list > .monaco-scrollable-element { + padding-top: ${topInsertToolbarHeight}px; + box-sizing: border-box; + }`); + + styleSheets.push(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .code-cell-row div.cell.code { margin-left: ${codeCellLeftMargin + cellRunGutter}px; }`); + styleSheets.push(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row div.cell { margin-right: ${cellRightMargin}px; }`); + styleSheets.push(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row > .cell-inner-container { padding-top: ${cellTopMargin}px; }`); + styleSheets.push(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .markdown-cell-row > .cell-inner-container { padding-bottom: ${markdownCellBottomMargin}px; padding-top: ${markdownCellTopMargin}px; }`); + styleSheets.push(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .markdown-cell-row > .cell-inner-container.webview-backed-markdown-cell { padding: 0; }`); + styleSheets.push(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .markdown-cell-row > .webview-backed-markdown-cell.markdown-cell-edit-mode .cell.code { padding-bottom: ${markdownCellBottomMargin}px; padding-top: ${markdownCellTopMargin}px; }`); + styleSheets.push(`.notebookOverlay .output { margin: 0px ${cellRightMargin}px 0px ${codeCellLeftMargin + cellRunGutter}px; }`); + styleSheets.push(`.notebookOverlay .output { width: calc(100% - ${codeCellLeftMargin + cellRunGutter + cellRightMargin}px); }`); + + // output toolbar + styleSheets.push(`.monaco-workbench .notebookOverlay .output .cell-output-toolbar { left: -${cellRunGutter}px; }`); + styleSheets.push(`.monaco-workbench .notebookOverlay .output .cell-output-toolbar { width: ${cellRunGutter}px; }`); + + styleSheets.push(`.notebookOverlay .output-show-more-container { margin: 0px ${cellRightMargin}px 0px ${codeCellLeftMargin + cellRunGutter}px; }`); + styleSheets.push(`.notebookOverlay .output-show-more-container { width: calc(100% - ${codeCellLeftMargin + cellRunGutter + cellRightMargin}px); }`); + styleSheets.push(`.notebookOverlay .cell .run-button-container { width: ${cellRunGutter}px; left: ${codeCellLeftMargin}px }`); + styleSheets.push(`.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .execution-count-label { left: ${codeCellLeftMargin}px; width: ${cellRunGutter}px; }`); + + styleSheets.push(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row div.cell.markdown { padding-left: ${cellRunGutter}px; }`); + styleSheets.push(`.monaco-workbench .notebookOverlay > .cell-list-container .notebook-folding-indicator { left: ${(markdownCellGutter - 20) / 2 + markdownCellLeftMargin}px; }`); + styleSheets.push(`.notebookOverlay .monaco-list .monaco-list-row :not(.webview-backed-markdown-cell) .cell-focus-indicator-top { height: ${cellTopMargin}px; }`); + styleSheets.push(`.notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-side { bottom: ${bottomToolbarGap}px; }`); + styleSheets.push(`.notebookOverlay .monaco-list .monaco-list-row.code-cell-row .cell-focus-indicator-left, + .notebookOverlay .monaco-list .monaco-list-row.code-cell-row .cell-drag-handle { width: ${codeCellLeftMargin + cellRunGutter}px; }`); + styleSheets.push(`.notebookOverlay .monaco-list .monaco-list-row.markdown-cell-row .cell-focus-indicator-left { width: ${codeCellLeftMargin}px; }`); + styleSheets.push(`.notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator.cell-focus-indicator-right { width: ${cellRightMargin}px; }`); + styleSheets.push(`.notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-bottom { height: ${cellBottomMargin}px; }`); + styleSheets.push(`.notebookOverlay .monaco-list .monaco-list-row .cell-shadow-container-bottom { top: ${cellBottomMargin}px; }`); + + styleSheets.push(`.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-collapsed-part { margin-left: ${codeCellLeftMargin + cellRunGutter}px; height: ${collapsedIndicatorHeight}px; }`); + + styleSheets.push(`.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container { height: ${bottomToolbarHeight}px }`); + styleSheets.push(`.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .cell-list-top-cell-toolbar-container { height: ${bottomToolbarHeight}px }`); + + // cell toolbar + styleSheets.push(`.monaco-workbench .notebookOverlay.cell-title-toolbar-right > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-title-toolbar { + right: ${cellRightMargin + 26}px; + } + .monaco-workbench .notebookOverlay.cell-title-toolbar-left > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-title-toolbar { + left: ${codeCellLeftMargin + cellRunGutter + 16}px; + } + .monaco-workbench .notebookOverlay.cell-title-toolbar-hidden > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-title-toolbar { + display: none; + }`); + + this._styleElement.textContent = styleSheets.join('\n'); + } + private _createCellList(): void { this._body.classList.add('cell-list-container'); @@ -546,12 +782,20 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor this.instantiationService.createInstance(MarkdownCellRenderer, this, this._dndController, this._renderedEditors, getScopedContextKeyService, { useRenderer: this.useRenderer }), ]; + renderers.forEach(renderer => { + this._register(renderer); + }); + + this._listDelegate = this.instantiationService.createInstance(NotebookCellListDelegate); + this._register(this._listDelegate); + this._list = this.instantiationService.createInstance( NotebookCellList, 'NotebookCellList', this._overlayContainer, this._body, - this.instantiationService.createInstance(NotebookCellListDelegate), + this._viewContext, + this._listDelegate, renderers, this.scopedContextKeyService, { @@ -592,7 +836,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor const index = this.viewModel.getCellIndex(element); if (index >= 0) { - return `Cell ${index}, ${element.cellKind === CellKind.Markdown ? 'markdown' : 'code'} cell`; + return `Cell ${index}, ${element.cellKind === CellKind.Markup ? 'markdown' : 'code'} cell`; } return ''; @@ -673,19 +917,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor this._register(widgetFocusTracker.onDidBlur(() => this._onDidBlurEmitter.fire())); this._reigsterNotebookActionsToolbar(); - this._register(this.editorService.onDidActiveEditorChange(() => { - if (this.editorService.activeEditorPane?.getId() === NOTEBOOK_EDITOR_ID) { - const notebookEditor = this.editorService.activeEditorPane.getControl() as INotebookEditor; - if (notebookEditor === this) { - // this is the active editor - this._showNotebookActionsinEditorToolbar(); - return; - } - } - this._editorToolbarDisposable.clear(); - this._toolbarActionDisposable.clear(); - })); } private showListContextMenu(e: IListContextMenuEvent) { @@ -701,126 +933,13 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor }); } - private _notebookGlobalActionsMenu!: IMenu; - private _toolbarActionDisposable = this._register(new DisposableStore()); - private _topToolbar!: ToolBar; - private _useGlobalToolbar: boolean = false; - private _editorToolbarDisposable = this._register(new DisposableStore()); private _reigsterNotebookActionsToolbar() { - const cellMenu = this.instantiationService.createInstance(CellMenus); - this._notebookGlobalActionsMenu = this._register(cellMenu.getNotebookToolbar(this.scopedContextKeyService)); - this._register(this._notebookGlobalActionsMenu); - - this._useGlobalToolbar = this.configurationService.getValue('notebook.experimental.globalToolbar') ?? false; - this._register(this.configurationService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration('notebook.experimental.globalToolbar')) { - this._useGlobalToolbar = this.configurationService.getValue('notebook.experimental.globalToolbar'); - this._showNotebookActionsinEditorToolbar(); + this._notebookTopToolbar = this._register(this.instantiationService.createInstance(NotebookEditorToolbar, this, this.scopedContextKeyService, this._notebookTopToolbarContainer)); + this._register(this._notebookTopToolbar.onDidChangeState(() => { + if (this._dimension && this._isVisible) { + this.layout(this._dimension); } })); - - this._topToolbar = new ToolBar(this._notebookTopToolbarContainer, this.contextMenuService, { - getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id), - actionViewItemProvider: action => { - return createActionViewItem(this.instantiationService, action); - }, - renderDropdownAsChildElement: true - }); - this._register(this._topToolbar); - this._topToolbar.context = { - ui: true, - notebookEditor: this - }; - - this._showNotebookActionsinEditorToolbar(); - this._register(this._notebookGlobalActionsMenu.onDidChange(() => { - this._showNotebookActionsinEditorToolbar(); - })); - - if (this.experimentService) { - this.experimentService.getTreatment('nbtoolbarineditor').then(treatment => { - if (treatment === undefined) { - return; - } - if (this._useGlobalToolbar !== treatment) { - this._useGlobalToolbar = treatment; - this._showNotebookActionsinEditorToolbar(); - } - }); - } - } - - private _showNotebookActionsinEditorToolbar() { - // when there is no view model, just ignore. - if (!this.viewModel) { - return; - } - - if (!this._useGlobalToolbar) { - // schedule actions registration in next frame, otherwise we are seeing duplicated notbebook actions temporarily - this._editorToolbarDisposable.clear(); - this._editorToolbarDisposable.add(DOM.scheduleAtNextAnimationFrame(() => { - const groups = this._notebookGlobalActionsMenu.getActions({ shouldForwardArgs: true }); - this._toolbarActionDisposable.clear(); - this._topToolbar.setActions([], []); - if (!this.viewModel) { - return; - } - - if (!this._isVisible) { - return; - } - - if (this.editorService.activeEditorPane?.getId() === NOTEBOOK_EDITOR_ID) { - const notebookEditor = this.editorService.activeEditorPane.getControl() as INotebookEditor; - if (notebookEditor !== this) { - // clear actions but not recreate because it is not active editor - return; - } - } - - groups.forEach(group => { - const groupName = group[0]; - const actions = group[1]; - - let order = groupName === 'navigation' ? -10 : 0; - for (let i = 0; i < actions.length; i++) { - const menuItemAction = actions[i] as MenuItemAction; - this._toolbarActionDisposable.add(MenuRegistry.appendMenuItem(MenuId.EditorTitle, { - command: { - id: menuItemAction.item.id, - title: menuItemAction.item.title, - category: menuItemAction.item.category, - tooltip: menuItemAction.item.tooltip, - icon: menuItemAction.item.icon, - precondition: menuItemAction.item.precondition, - toggled: menuItemAction.item.toggled, - }, - title: menuItemAction.item.title + ' ' + this.viewModel?.uri.scheme, - group: groupName, - order: order - })); - order++; - } - }); - })); - - this._notebookTopToolbarContainer.style.display = 'none'; - } else { - this._toolbarActionDisposable.clear(); - this._topToolbar.setActions([], []); - const groups = this._notebookGlobalActionsMenu.getActions({ shouldForwardArgs: true }); - this._notebookTopToolbarContainer.style.display = 'flex'; - const primaryGroup = groups.find(group => group[0] === 'navigation'); - const primaryActions = primaryGroup ? primaryGroup[1] : []; - const secondaryActions = groups.filter(group => group[0] !== 'navigation').reduce((prev: (MenuItemAction | SubmenuItemAction)[], curr) => { prev.push(...curr[1]); return prev; }, []); - - this._topToolbar.setActions(primaryActions, secondaryActions); - } - - if (this._dimension && this._isVisible) { - this.layout(this._dimension); - } } private _updateForCursorNavigationMode(applyFocusChange: () => void): void { @@ -858,9 +977,20 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor async setModel(textModel: NotebookTextModel, viewState: INotebookEditorViewState | undefined): Promise { if (this.viewModel === undefined || !this.viewModel.equal(textModel)) { + const oldTopInsertToolbarHeight = this._notebookOptions.computeTopInserToolbarHeight(this.viewModel?.viewType); + const oldBottomToolbarDimensions = this._notebookOptions.computeBottomToolbarDimensions(this.viewModel?.viewType); this._detachModel(); await this._attachModel(textModel, viewState); - + const newTopInsertToolbarHeight = this._notebookOptions.computeTopInserToolbarHeight(this.viewModel?.viewType); + const newBottomToolbarDimensions = this._notebookOptions.computeBottomToolbarDimensions(this.viewModel?.viewType); + + if (oldTopInsertToolbarHeight !== newTopInsertToolbarHeight + || oldBottomToolbarDimensions.bottomToolbarGap !== newBottomToolbarDimensions.bottomToolbarGap + || oldBottomToolbarDimensions.bottomToolbarHeight !== newBottomToolbarDimensions.bottomToolbarHeight) { + this._styleElement?.remove(); + this._createLayoutStyles(); + this._webview?.updateOptions(this.notebookOptions.computeWebviewOptions()); + } type WorkbenchNotebookOpenClassification = { scheme: { classification: 'SystemMetaData', purpose: 'FeatureInsight'; }; ext: { classification: 'SystemMetaData', purpose: 'FeatureInsight'; }; @@ -910,7 +1040,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } } - async setOptions(options: NotebookEditorOptions | undefined) { + async setOptions(options: INotebookEditorOptions | undefined) { if (!this.hasModel()) { return; } @@ -925,7 +1055,13 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor const cell = this.viewModel.viewCells.find(cell => cell.uri.toString() === cellOptions.resource.toString()); if (cell) { this.focusElement(cell); - await this.revealInCenterIfOutsideViewportAsync(cell); + const selection = cellOptions.options?.selection; + if (selection) { + await this.revealLineInCenterIfOutsideViewportAsync(cell, selection.startLineNumber); + } else { + await this.revealInCenterIfOutsideViewportAsync(cell); + } + const editor = this._renderedEditors.get(cell)!; if (editor) { if (cellOptions.options?.selection) { @@ -1043,14 +1179,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } private async _createWebview(id: string, resource: URI): Promise { - this._webview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource, { - outputNodePadding: CELL_OUTPUT_PADDING, - outputNodeLeftPadding: CELL_OUTPUT_PADDING, - previewNodePadding: MARKDOWN_PREVIEW_PADDING, - leftMargin: CODE_CELL_LEFT_MARGIN, - rightMargin: CELL_RIGHT_MARGIN, - runGutter: CELL_RUN_GUTTER, - }); + this._webview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource, this._notebookOptions.computeWebviewOptions(), this.notebookRendererMessaging.getScoped(this._uuid)); this._webview.element.style.width = '100%'; // attach the webview container to the DOM tree first @@ -1059,10 +1188,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor private async _attachModel(textModel: NotebookTextModel, viewState: INotebookEditorViewState | undefined) { await this._createWebview(this.getId(), textModel.uri); - - this._eventDispatcher = new NotebookEventDispatcher(); - this.viewModel = this.instantiationService.createInstance(NotebookViewModel, textModel.viewType, textModel, this._eventDispatcher, this.getLayoutInfo()); - this._eventDispatcher.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]); + this.viewModel = this.instantiationService.createInstance(NotebookViewModel, textModel.viewType, textModel, this._viewContext, this.getLayoutInfo()); + this._viewContext.eventDispatcher.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]); this._updateForOptions(); this._updateForNotebookConfiguration(); @@ -1118,7 +1245,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor const deletedCells: MarkdownCellViewModel[] = []; for (const cell of cells) { - if (cell.cellKind === CellKind.Markdown) { + if (cell.cellKind === CellKind.Markup) { const mdCell = cell as MarkdownCellViewModel; if (this.viewModel?.viewCells.find(cell => cell.handle === mdCell.handle)) { // Cell has been folded but is still in model @@ -1161,7 +1288,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor })); if (this._dimension) { - this._list.layout(this._dimension.height - SCROLLABLE_ELEMENT_PADDING_TOP, this._dimension.width); + const topInserToolbarHeight = this._notebookOptions.computeTopInserToolbarHeight(this.viewModel?.viewType); + this._list.layout(this._dimension.height - topInserToolbarHeight, this._dimension.width); } else { this._list.layout(); } @@ -1191,7 +1319,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor })); } - if (cell.cellKind === CellKind.Markdown) { + if (cell.cellKind === CellKind.Markup) { store.add((cell as MarkdownCellViewModel).onDidHideInput(() => { this.hideMarkdownPreviews([(cell as MarkdownCellViewModel)]); })); @@ -1245,7 +1373,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor offset += (totalHeightCache ? totalHeightCache[i] : 0); continue; } else { - if (cell.cellKind === CellKind.Markdown) { + if (cell.cellKind === CellKind.Markup) { requests.push([cell, offset]); } } @@ -1257,19 +1385,24 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } } - await this._webview!.initializeMarkdown(requests - .map(request => ({ cellId: request[0].id, cellHandle: request[0].handle, content: request[0].getText(), offset: request[1] }))); + await this._webview!.initializeMarkdown(requests.map(request => ({ + cellId: request[0].id, + cellHandle: request[0].handle, + content: request[0].getText(), + offset: request[1], + visible: false, + }))); } else { - const initRequests = viewModel.viewCells.filter(cell => cell.cellKind === CellKind.Markdown).slice(0, 5).map(cell => ({ cellId: cell.id, cellHandle: cell.handle, content: cell.getText(), offset: -10000 })); + const initRequests = viewModel.viewCells.filter(cell => cell.cellKind === CellKind.Markup).slice(0, 5).map(cell => ({ cellId: cell.id, cellHandle: cell.handle, content: cell.getText(), offset: -10000, visible: false })); await this._webview!.initializeMarkdown(initRequests); // no cached view state so we are rendering the first viewport // after above async call, we already get init height for markdown cells, we can update their offset let offset = 0; - const offsetUpdateRequests: { id: string, top: number }[] = []; + const offsetUpdateRequests: { id: string, top: number; }[] = []; const scrollBottom = Math.max(this._dimension?.height ?? 0, 1080); for (const cell of viewModel.viewCells) { - if (cell.cellKind === CellKind.Markdown) { + if (cell.cellKind === CellKind.Markup) { offsetUpdateRequests.push({ id: cell.id, top: offset }); } @@ -1330,7 +1463,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor if (this._list) { state.scrollPosition = { left: this._list.scrollLeft, top: this._list.scrollTop }; - const cellHeights: { [key: number]: number } = {}; + const cellHeights: { [key: number]: number; } = {}; for (let i = 0; i < this.viewModel!.length; i++) { const elm = this.viewModel!.cellAt(i) as CellViewModel; if (elm.cellKind === CellKind.Code) { @@ -1356,7 +1489,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } // Save contribution view states - const contributionsState: { [key: string]: unknown } = {}; + const contributionsState: { [key: string]: unknown; } = {}; for (const [id, contribution] of this._contributions) { if (typeof contribution.saveViewState === 'function') { contributionsState[id] = contribution.saveViewState(); @@ -1384,16 +1517,18 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor }; } + const topInserToolbarHeight = this._notebookOptions.computeTopInserToolbarHeight(this.viewModel?.viewType); + this._dimension = new DOM.Dimension(dimension.width, dimension.height); - DOM.size(this._body, dimension.width, dimension.height - (this._useGlobalToolbar ? /** Toolbar height */ 26 : 0)); - if (this._list.getRenderHeight() < dimension.height - SCROLLABLE_ELEMENT_PADDING_TOP) { + DOM.size(this._body, dimension.width, dimension.height - (this._notebookTopToolbar?.useGlobalToolbar ? /** Toolbar height */ 26 : 0)); + if (this._list.getRenderHeight() < dimension.height - topInserToolbarHeight) { // the new dimension is larger than the list viewport, update its additional height first, otherwise the list view will move down a bit (as the `scrollBottom` will move down) - this._list.updateOptions({ additionalScrollHeight: this._scrollBeyondLastLine ? Math.max(0, (dimension.height - SCROLLABLE_ELEMENT_PADDING_TOP - 50)) : SCROLLABLE_ELEMENT_PADDING_TOP }); - this._list.layout(dimension.height - SCROLLABLE_ELEMENT_PADDING_TOP, dimension.width); + this._list.updateOptions({ additionalScrollHeight: this._scrollBeyondLastLine ? Math.max(0, (dimension.height - topInserToolbarHeight - 50)) : topInserToolbarHeight }); + this._list.layout(dimension.height - topInserToolbarHeight, dimension.width); } else { // the new dimension is smaller than the list viewport, if we update the additional height, the `scrollBottom` will move up, which moves the whole list view upwards a bit. So we run a layout first. - this._list.layout(dimension.height - SCROLLABLE_ELEMENT_PADDING_TOP, dimension.width); - this._list.updateOptions({ additionalScrollHeight: this._scrollBeyondLastLine ? Math.max(0, (dimension.height - SCROLLABLE_ELEMENT_PADDING_TOP - 50)) : SCROLLABLE_ELEMENT_PADDING_TOP }); + this._list.layout(dimension.height - topInserToolbarHeight, dimension.width); + this._list.updateOptions({ additionalScrollHeight: this._scrollBeyondLastLine ? Math.max(0, (dimension.height - topInserToolbarHeight - 50)) : topInserToolbarHeight }); } this._overlayContainer.style.visibility = 'visible'; @@ -1411,7 +1546,9 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor this._webviewTransparentCover.style.width = `${dimension.width}px`; } - this._eventDispatcher?.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]); + this._notebookTopToolbar.layout(); + + this._viewContext?.eventDispatcher.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]); } //#endregion @@ -1454,11 +1591,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor const focused = DOM.isAncestor(document.activeElement, this._overlayContainer); this._editorFocus.set(focused); this.viewModel?.setFocus(focused); - - if (!focused) { - this._editorToolbarDisposable.clear(); - this._toolbarActionDisposable.clear(); - } } hasFocus() { @@ -1686,21 +1818,15 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor //#region Kernel/Execution - private async _loadKernelPreloads() { - const kernel = this.activeKernel; - if (!kernel) { - return; - } - const preloadUris = kernel.preloadUris; - if (!preloadUris.length) { + private async _loadKernelPreloads(): Promise { + if (!this.hasModel()) { return; } - + const { selected } = this.notebookKernelService.getMatchingKernel(this.viewModel.notebookDocument); if (!this._webview?.isResolved()) { await this._resolveWebview(); } - - this._webview?.updateKernelPreloads([kernel.localResourceRoot], kernel.preloadUris); + this._webview?.updateKernelPreloads(selected); } get activeKernel() { @@ -1730,7 +1856,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor //#endregion //#region Cell operations/layout API - private _pendingLayouts = new WeakMap(); + private _pendingLayouts: WeakMap | null = new WeakMap(); async layoutNotebookCell(cell: ICellViewModel, height: number): Promise { this._debug('layout cell', cell.handle, height); const viewIndex = this._list.getViewIndex(cell); @@ -1747,8 +1873,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor this._list.updateElementHeight2(cell, height); }; - if (this._pendingLayouts.has(cell)) { - this._pendingLayouts.get(cell)!.dispose(); + if (this._pendingLayouts?.has(cell)) { + this._pendingLayouts?.get(cell)!.dispose(); } let r: () => void; @@ -1761,13 +1887,13 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor return; } - this._pendingLayouts.delete(cell); + this._pendingLayouts?.delete(cell); relayout(cell, height); r(); }); - this._pendingLayouts.set(cell, toDisposable(() => { + this._pendingLayouts?.set(cell, toDisposable(() => { layoutDisposable.dispose(); r(); })); @@ -1800,7 +1926,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor const defaultLanguage = supportedLanguages[0] || 'plaintext'; if (cell?.cellKind === CellKind.Code) { language = cell.language; - } else if (cell?.cellKind === CellKind.Markdown) { + } else if (cell?.cellKind === CellKind.Markup) { const nearestCodeCellIndex = this._nearestCodeCellIndex(index); if (nearestCodeCellIndex > -1) { language = this.viewModel.cellAt(nearestCodeCellIndex)!.language; @@ -1855,7 +1981,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor return false; } - if (this._pendingLayouts.has(cell)) { + if (this._pendingLayouts?.has(cell)) { this._pendingLayouts.get(cell)!.dispose(); } @@ -1978,13 +2104,13 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor let position = ''; switch (focusItem) { case 'editor': - position = `the inner ${cell.cellKind === CellKind.Markdown ? 'markdown' : 'code'} editor is focused, press escape to focus the cell container`; + position = `the inner ${cell.cellKind === CellKind.Markup ? 'markdown' : 'code'} editor is focused, press escape to focus the cell container`; break; case 'output': position = `the cell output is focused, press escape to focus the cell container`; break; case 'container': - position = `the ${cell.cellKind === CellKind.Markdown ? 'markdown preview' : 'cell container'} is focused, press enter to focus the inner ${cell.cellKind === CellKind.Markdown ? 'markdown' : 'code'} editor`; + position = `the ${cell.cellKind === CellKind.Markup ? 'markdown preview' : 'cell container'} is focused, press enter to focus the inner ${cell.cellKind === CellKind.Markup ? 'markdown' : 'code'} editor`; break; default: break; @@ -1993,17 +2119,36 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } } - toggleNotebookCellSelection(cell: ICellViewModel): void { + toggleNotebookCellSelection(selectedCell: ICellViewModel, selectFromPrevious: boolean): void { const currentSelections = this._list.getSelectedElements(); + const isSelected = currentSelections.includes(selectedCell); + + const previousSelection = selectFromPrevious ? currentSelections[currentSelections.length - 1] ?? selectedCell : selectedCell; + const selectedIndex = this._list.getViewIndex(selectedCell)!; + const previousIndex = this._list.getViewIndex(previousSelection)!; - const isSelected = currentSelections.includes(cell); + const cellsInSelectionRange = this.getCellsInRange(selectedIndex, previousIndex); if (isSelected) { // Deselect - this._list.selectElements(currentSelections.filter(current => current !== cell)); + this._list.selectElements(currentSelections.filter(current => !cellsInSelectionRange.includes(current))); } else { // Add to selection - this._list.selectElements([...currentSelections, cell]); + this.focusElement(selectedCell); + this._list.selectElements([...currentSelections.filter(current => !cellsInSelectionRange.includes(current)), ...cellsInSelectionRange]); + } + } + + private getCellsInRange(fromInclusive: number, toInclusive: number): ICellViewModel[] { + const selectedCellsInRange: ICellViewModel[] = []; + for (let index = 0; index < this._list.length; ++index) { + const cell = this._list.element(index); + if (cell) { + if ((index >= fromInclusive && index <= toInclusive) || (index >= toInclusive && index <= fromInclusive)) { + selectedCellsInRange.push(cell); + } + } } + return selectedCellsInRange; } focusNotebookCell(cell: ICellViewModel, focusItem: 'editor' | 'container' | 'output', options?: IFocusNotebookCellOptions) { @@ -2115,7 +2260,13 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } const cellTop = this._list.getAbsoluteTopOfElement(cell); - await this._webview.showMarkdownPreview(cell.id, cell.handle, cell.getText(), cellTop, cell.contentHash); + await this._webview.showMarkdownPreview({ + cellHandle: cell.handle, + cellId: cell.id, + content: cell.getText(), + offset: cellTop, + visible: true, + }); } async unhideMarkdownPreviews(cells: readonly MarkdownCellViewModel[]) { @@ -2198,6 +2349,10 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor return; } + if (output.type === RenderOutputType.Extension) { + this.notebookRendererMessaging.prepare(output.renderer.id); + } + const cellTop = this._list.getAbsoluteTopOfElement(cell); if (!this._webview.insetMapping.has(output.source)) { await this._webview.createOutput({ cellId: cell.id, cellHandle: cell.handle, cellUri: cell.uri }, output, cellTop, offset); @@ -2241,13 +2396,9 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor readonly onDidReceiveMessage: Event = this._onDidReceiveMessage.event; - postMessage(forRendererId: string | undefined, message: any) { + postMessage(message: any) { if (this._webview?.isResolved()) { - if (forRendererId === undefined) { - this._webview.webview.postMessage(message); - } else { - this._webview.postRendererMessage(forRendererId, message); - } + this._webview.postKernelMessage(message); } } @@ -2325,7 +2476,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor this._webview.removeInsets(removedItems); - const markdownUpdateItems: { id: string, top: number }[] = []; + const markdownUpdateItems: { id: string, top: number; }[] = []; for (const cellId of this._webview.markdownPreviewMapping.keys()) { const cell = this.viewModel?.viewCells.find(cell => cell.id === cellId); if (cell) { @@ -2352,10 +2503,9 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor updateMarkdownCellHeight(cellId: string, height: number, isInit: boolean) { const cell = this.getCellById(cellId); if (cell && cell instanceof MarkdownCellViewModel) { - if (height + BOTTOM_CELL_TOOLBAR_GAP !== cell.layoutInfo.totalHeight) { - this._debug('updateMarkdownCellHeight', cell.handle, height + BOTTOM_CELL_TOOLBAR_GAP, isInit); - cell.renderedMarkdownHeight = height; - } + const { bottomToolbarGap } = this._notebookOptions.computeBottomToolbarDimensions(this.viewModel?.viewType); + this._debug('updateMarkdownCellHeight', cell.handle, height + bottomToolbarGap, isInit); + cell.renderedMarkdownHeight = height; } } @@ -2366,24 +2516,24 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } } - markdownCellDragStart(cellId: string, ctx: { clientY: number }): void { + markdownCellDragStart(cellId: string, event: { dragOffsetY: number; }): void { const cell = this.getCellById(cellId); if (cell instanceof MarkdownCellViewModel) { - this._dndController?.startExplicitDrag(cell, ctx); + this._dndController?.startExplicitDrag(cell, event.dragOffsetY); } } - markdownCellDrag(cellId: string, ctx: { clientY: number }): void { + markdownCellDrag(cellId: string, event: { dragOffsetY: number; }): void { const cell = this.getCellById(cellId); if (cell instanceof MarkdownCellViewModel) { - this._dndController?.explicitDrag(cell, ctx); + this._dndController?.explicitDrag(cell, event.dragOffsetY); } } - markdownCellDrop(cellId: string, ctx: { clientY: number, ctrlKey: boolean, altKey: boolean }): void { + markdownCellDrop(cellId: string, event: { dragOffsetY: number, ctrlKey: boolean, altKey: boolean; }): void { const cell = this.getCellById(cellId); if (cell instanceof MarkdownCellViewModel) { - this._dndController?.explicitDrop(cell, ctx); + this._dndController?.explicitDrop(cell, event); } } @@ -2420,10 +2570,23 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor this._overlayContainer.remove(); this.viewModel?.dispose(); + + // unref + this._webview = null; + this._webviewResolvePromise = null; + this._webviewTransparentCover = null; + this._dndController = null; + this._listTopCellToolbar = null; + this._notebookViewModel = undefined; + this._cellContextKeyManager = null; + this._renderedEditors.clear(); + this._pendingLayouts = null; + this._listDelegate = null; + super.dispose(); } - toJSON(): { notebookUri: URI | undefined } { + toJSON(): { notebookUri: URI | undefined; } { return { notebookUri: this.viewModel?.uri, }; @@ -2552,26 +2715,37 @@ export const cellSymbolHighlight = registerColor('notebook.symbolHighlightBackgr hc: null }, nls.localize('notebook.symbolHighlightBackground', "Background color of highlighted cell")); +export const cellEditorBackground = registerColor('notebook.cellEditorBackground', { + light: null, + dark: null, + hc: null +}, nls.localize('notebook.cellEditorBackground', "Cell editor background color.")); + registerThemingParticipant((theme, collector) => { - collector.addRule(`.notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element, - .notebookOverlay > .cell-list-container > .notebook-gutter > .monaco-list > .monaco-scrollable-element { - padding-top: ${SCROLLABLE_ELEMENT_PADDING_TOP}px; - box-sizing: border-box; - }`); + // add css variable rules + + const focusedCellBorderColor = theme.getColor(focusedCellBorder); + const inactiveFocusedBorderColor = theme.getColor(inactiveFocusedCellBorder); + const selectedCellBorderColor = theme.getColor(selectedCellBorder); + collector.addRule(` + :root { + --notebook-focused-cell-border-color: ${focusedCellBorderColor}; + --notebook-inactive-focused-cell-border-color: ${inactiveFocusedBorderColor}; + --notebook-selected-cell-border-color: ${selectedCellBorderColor}; + } + `); + const link = theme.getColor(textLinkForeground); if (link) { - collector.addRule(`.notebookOverlay .output a, - .notebookOverlay .cell.markdown a, + collector.addRule(`.notebookOverlay .cell.markdown a, .notebookOverlay .output-show-more-container a { color: ${link};} `); } const activeLink = theme.getColor(textLinkActiveForeground); if (activeLink) { - collector.addRule(`.notebookOverlay .output a:hover, - .notebookOverlay .cell .output a:active, - .notebookOverlay .output-show-more-container a:active + collector.addRule(`.notebookOverlay .output-show-more-container a:active { color: ${activeLink}; }`); } const shortcut = theme.getColor(textPreformatForeground); @@ -2599,17 +2773,20 @@ registerThemingParticipant((theme, collector) => { collector.addRule(`.notebookOverlay .output-show-more-container { background-color: ${containerBackground}; }`); } - const editorBackgroundColor = theme.getColor(editorBackground); + const notebookBackground = theme.getColor(editorBackground); + if (notebookBackground) { + collector.addRule(`.notebookOverlay .cell-drag-image .cell-editor-container > div { background: ${notebookBackground} !important; }`); + collector.addRule(`.notebookOverlay .monaco-list-row .cell-title-toolbar { background-color: ${notebookBackground}; }`); + collector.addRule(`.notebookOverlay .monaco-list-row.cell-drag-image { background-color: ${notebookBackground}; }`); + collector.addRule(`.notebookOverlay .cell-bottom-toolbar-container .action-item { background-color: ${notebookBackground} }`); + collector.addRule(`.notebookOverlay .cell-list-top-cell-toolbar-container .action-item { background-color: ${notebookBackground} }`); + } + + const editorBackgroundColor = theme.getColor(cellEditorBackground) ?? theme.getColor(editorBackground); if (editorBackgroundColor) { collector.addRule(`.notebookOverlay .cell .monaco-editor-background, - .notebookOverlay .cell .margin-view-overlays, - .notebookOverlay .cell .cell-statusbar-container { background: ${editorBackgroundColor}; }`); - collector.addRule(`.notebookOverlay .cell-drag-image .cell-editor-container > div { background: ${editorBackgroundColor} !important; }`); - - collector.addRule(`.notebookOverlay .monaco-list-row .cell-title-toolbar { background-color: ${editorBackgroundColor}; }`); - collector.addRule(`.notebookOverlay .monaco-list-row.cell-drag-image { background-color: ${editorBackgroundColor}; }`); - collector.addRule(`.notebookOverlay .cell-bottom-toolbar-container .action-item { background-color: ${editorBackgroundColor} }`); - collector.addRule(`.notebookOverlay .cell-list-top-cell-toolbar-container .action-item { background-color: ${editorBackgroundColor} }`); + .notebookOverlay .cell .margin-view-overlays, + .notebookOverlay .cell .cell-statusbar-container { background: ${editorBackgroundColor}; }`); } const cellToolbarSeperator = theme.getColor(CELL_TOOLBAR_SEPERATOR); @@ -2623,8 +2800,8 @@ registerThemingParticipant((theme, collector) => { const focusedCellBackgroundColor = theme.getColor(focusedCellBackground); if (focusedCellBackgroundColor) { - collector.addRule(`.notebookOverlay .code-cell-row.focused .cell-focus-indicator, - .notebookOverlay .markdown-cell-row.focused { background-color: ${focusedCellBackgroundColor} !important; }`); + collector.addRule(`.notebookOverlay .code-cell-row.focused .cell-focus-indicator { background-color: ${focusedCellBackgroundColor} !important; }`); + collector.addRule(`.notebookOverlay .markdown-cell-row.focused { background-color: ${focusedCellBackgroundColor} !important; }`); collector.addRule(`.notebookOverlay .code-cell-row.focused .cell-collapsed-part { background-color: ${focusedCellBackgroundColor} !important; }`); } @@ -2656,30 +2833,6 @@ registerThemingParticipant((theme, collector) => { .notebookOverlay .code-cell-row:not(.focused).cell-output-hover .cell-collapsed-part { background-color: ${cellHoverBackgroundColor}; }`); } - const focusedCellBorderColor = theme.getColor(focusedCellBorder); - collector.addRule(` - .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-focus-indicator-top:before, - .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-focus-indicator-bottom:before, - .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-inner-container:not(.cell-editor-focus) .cell-focus-indicator-left:before, - .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-inner-container:not(.cell-editor-focus) .cell-focus-indicator-right:before { - border-color: ${focusedCellBorderColor} !important; - }`); - - const inactiveFocusedBorderColor = theme.getColor(inactiveFocusedCellBorder); - collector.addRule(` - .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-top:before, - .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.focused .cell-focus-indicator-bottom:before { - border-color: ${inactiveFocusedBorderColor} !important; - }`); - - const selectedCellBorderColor = theme.getColor(selectedCellBorder); - collector.addRule(` - .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-editor-focus .cell-focus-indicator-top:before, - .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-editor-focus .cell-focus-indicator-bottom:before, - .monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused .cell-inner-container.cell-editor-focus:before { - border-color: ${selectedCellBorderColor} !important; - }`); - const cellSymbolHighlightColor = theme.getColor(cellSymbolHighlight); if (cellSymbolHighlightColor) { collector.addRule(`.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row.nb-symbolHighlight .cell-focus-indicator, @@ -2768,43 +2921,5 @@ registerThemingParticipant((theme, collector) => { }`); } - // Cell Margin - collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .markdown-cell-row div.cell.code { margin-left: ${CODE_CELL_LEFT_MARGIN}px; }`); - collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .code-cell-row div.cell.code { margin-left: ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px; }`); - collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row div.cell { margin-right: ${CELL_RIGHT_MARGIN}px; }`); - collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row > .cell-inner-container { padding-top: ${CELL_TOP_MARGIN}px; }`); - collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .markdown-cell-row > .cell-inner-container { padding-bottom: ${MARKDOWN_CELL_BOTTOM_MARGIN}px; padding-top: ${MARKDOWN_CELL_TOP_MARGIN}px; }`); - collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .markdown-cell-row > .cell-inner-container.webview-backed-markdown-cell { padding: 0; }`); - collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .markdown-cell-row > .webview-backed-markdown-cell.markdown-cell-edit-mode .cell.code { padding-bottom: ${MARKDOWN_CELL_BOTTOM_MARGIN}px; padding-top: ${MARKDOWN_CELL_TOP_MARGIN}px; }`); - collector.addRule(`.notebookOverlay .output { margin: 0px ${CELL_RIGHT_MARGIN}px 0px ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px; }`); - collector.addRule(`.notebookOverlay .output { width: calc(100% - ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER + CELL_RIGHT_MARGIN}px); }`); - - collector.addRule(`.notebookOverlay .output-show-more-container { margin: 0px ${CELL_RIGHT_MARGIN}px 0px ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px; }`); - collector.addRule(`.notebookOverlay .output-show-more-container { width: calc(100% - ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER + CELL_RIGHT_MARGIN}px); }`); - - collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row div.cell.markdown { padding-left: ${CELL_RUN_GUTTER}px; }`); - collector.addRule(`.notebookOverlay .cell .run-button-container { width: 20px; left: ${CODE_CELL_LEFT_MARGIN + Math.floor(CELL_RUN_GUTTER - 20) / 2}px }`); - collector.addRule(`.notebookOverlay .monaco-list .monaco-list-row :not(.webview-backed-markdown-cell) .cell-focus-indicator-top { height: ${CELL_TOP_MARGIN}px; }`); - collector.addRule(`.notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-side { bottom: ${BOTTOM_CELL_TOOLBAR_GAP}px; }`); - collector.addRule(`.notebookOverlay .monaco-list .monaco-list-row.code-cell-row .cell-focus-indicator-left, - .notebookOverlay .monaco-list .monaco-list-row.code-cell-row .cell-drag-handle { width: ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px; }`); - collector.addRule(`.notebookOverlay .monaco-list .monaco-list-row.markdown-cell-row .cell-focus-indicator-left { width: ${CODE_CELL_LEFT_MARGIN}px; }`); - collector.addRule(`.notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator.cell-focus-indicator-right { width: ${CELL_RIGHT_MARGIN}px; }`); - collector.addRule(`.notebookOverlay .monaco-list .monaco-list-row .cell-focus-indicator-bottom { height: ${CELL_BOTTOM_MARGIN}px; }`); - collector.addRule(`.notebookOverlay .monaco-list .monaco-list-row .cell-shadow-container-bottom { top: ${CELL_BOTTOM_MARGIN}px; }`); - - collector.addRule(`.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-collapsed-part { margin-left: ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px; height: ${COLLAPSED_INDICATOR_HEIGHT}px; }`); - collector.addRule(`.notebookOverlay .cell-list-top-cell-toolbar-container { top: -${SCROLLABLE_ELEMENT_PADDING_TOP}px }`); - - collector.addRule(`.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container { height: ${BOTTOM_CELL_TOOLBAR_HEIGHT}px }`); - collector.addRule(`.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .cell-list-top-cell-toolbar-container { height: ${BOTTOM_CELL_TOOLBAR_HEIGHT}px }`); - - // left and right border margins - collector.addRule(` - .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row.focused .cell-focus-indicator-left:before, - .monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row.focused .cell-focus-indicator-right:before, - .monaco-workbench .notebookOverlay .monaco-list.selection-multiple .monaco-list-row.code-cell-row.selected .cell-focus-indicator-left:before, - .monaco-workbench .notebookOverlay .monaco-list.selection-multiple .monaco-list-row.code-cell-row.selected .cell-focus-indicator-right:before { - top: -${CELL_TOP_MARGIN}px; height: calc(100% + ${CELL_TOP_MARGIN + CELL_BOTTOM_MARGIN}px) - }`); + }); diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorWidgetContextKeys.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidgetContextKeys.ts similarity index 56% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorWidgetContextKeys.ts rename to src/vs/workbench/contrib/notebook/browser/notebookEditorWidgetContextKeys.ts index ba83b21978be..91a12f7ee467 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookEditorWidgetContextKeys.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidgetContextKeys.ts @@ -5,7 +5,7 @@ import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { ICellViewModel, NOTEBOOK_HAS_RUNNING_CELL, NOTEBOOK_INTERRUPTIBLE_KERNEL, NOTEBOOK_KERNEL_COUNT, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICellViewModel, INotebookEditor, NOTEBOOK_HAS_OUTPUTS, NOTEBOOK_HAS_RUNNING_CELL, NOTEBOOK_INTERRUPTIBLE_KERNEL, NOTEBOOK_KERNEL_COUNT, NOTEBOOK_KERNEL_SELECTED, NOTEBOOK_USE_CONSOLIDATED_OUTPUT_BUTTON, NOTEBOOK_VIEW_TYPE } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; @@ -13,12 +13,17 @@ import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/not export class NotebookEditorContextKeys { private readonly _notebookKernelCount: IContextKey; + private readonly _notebookKernelSelected: IContextKey; private readonly _interruptibleKernel: IContextKey; private readonly _someCellRunning: IContextKey; + private readonly _hasOutputs: IContextKey; + private readonly _useConsolidatedOutputButton: IContextKey; + private _viewType!: IContextKey; private readonly _disposables = new DisposableStore(); private readonly _viewModelDisposables = new DisposableStore(); private readonly _cellStateListeners: IDisposable[] = []; + private readonly _cellOutputsListeners: IDisposable[] = []; constructor( private readonly _editor: INotebookEditor, @@ -26,13 +31,22 @@ export class NotebookEditorContextKeys { @IContextKeyService contextKeyService: IContextKeyService, ) { this._notebookKernelCount = NOTEBOOK_KERNEL_COUNT.bindTo(contextKeyService); + this._notebookKernelSelected = NOTEBOOK_KERNEL_SELECTED.bindTo(contextKeyService); this._interruptibleKernel = NOTEBOOK_INTERRUPTIBLE_KERNEL.bindTo(contextKeyService); this._someCellRunning = NOTEBOOK_HAS_RUNNING_CELL.bindTo(contextKeyService); + this._useConsolidatedOutputButton = NOTEBOOK_USE_CONSOLIDATED_OUTPUT_BUTTON.bindTo(contextKeyService); + this._hasOutputs = NOTEBOOK_HAS_OUTPUTS.bindTo(contextKeyService); + this._viewType = NOTEBOOK_VIEW_TYPE.bindTo(contextKeyService); + + this._handleDidChangeModel(); + this._updateForNotebookOptions(); this._disposables.add(_editor.onDidChangeModel(this._handleDidChangeModel, this)); this._disposables.add(_notebookKernelService.onDidAddKernel(this._updateKernelContext, this)); this._disposables.add(_notebookKernelService.onDidChangeNotebookKernelBinding(this._updateKernelContext, this)); - this._handleDidChangeModel(); + this._disposables.add(_editor.notebookOptions.onDidChangeOptions(() => { + this._updateForNotebookOptions(); + })); } dispose(): void { @@ -41,6 +55,11 @@ export class NotebookEditorContextKeys { this._notebookKernelCount.reset(); this._interruptibleKernel.reset(); this._someCellRunning.reset(); + this._viewType.reset(); + dispose(this._cellStateListeners); + this._cellStateListeners.length = 0; + dispose(this._cellOutputsListeners); + this._cellOutputsListeners.length = 0; } private _handleDidChangeModel(): void { @@ -50,6 +69,8 @@ export class NotebookEditorContextKeys { this._viewModelDisposables.clear(); dispose(this._cellStateListeners); this._cellStateListeners.length = 0; + dispose(this._cellOutputsListeners); + this._cellOutputsListeners.length = 0; if (!this._editor.hasModel()) { return; @@ -62,26 +83,52 @@ export class NotebookEditorContextKeys { if (!e.runStateChanged) { return; } - if (c.metadata?.runState === NotebookCellExecutionState.Pending) { + if (c.internalMetadata.runState === NotebookCellExecutionState.Pending) { executionCount++; - } else if (c.metadata?.runState === NotebookCellExecutionState.Idle) { + } else if (!c.internalMetadata.runState) { executionCount--; } this._someCellRunning.set(executionCount > 0); }); }; + const recomputeOutputsExistence = () => { + let hasOutputs = false; + if (this._editor.hasModel()) { + for (let i = 0; i < this._editor.viewModel.viewCells.length; i++) { + if (this._editor.viewModel.viewCells[i].outputsViewModels.length > 0) { + hasOutputs = true; + break; + } + } + } + + this._hasOutputs.set(hasOutputs); + }; + + const addCellOutputsListener = (c: ICellViewModel) => { + return c.model.onDidChangeOutputs(() => { + recomputeOutputsExistence(); + }); + }; + for (const cell of this._editor.viewModel.viewCells) { this._cellStateListeners.push(addCellStateListener(cell)); + this._cellOutputsListeners.push(addCellOutputsListener(cell)); } + recomputeOutputsExistence(); + this._viewModelDisposables.add(this._editor.viewModel.onDidChangeViewCells(e => { e.splices.reverse().forEach(splice => { const [start, deleted, newCells] = splice; - const deletedCells = this._cellStateListeners.splice(start, deleted, ...newCells.map(addCellStateListener)); - dispose(deletedCells); + const deletedCellStates = this._cellStateListeners.splice(start, deleted, ...newCells.map(addCellStateListener)); + const deletedCellOutputStates = this._cellOutputsListeners.splice(start, deleted, ...newCells.map(addCellOutputsListener)); + dispose(deletedCellStates); + dispose(deletedCellOutputStates); }); })); + this._viewType.set(this._editor.viewModel.viewType); } private _updateKernelContext(): void { @@ -94,5 +141,10 @@ export class NotebookEditorContextKeys { const { selected, all } = this._notebookKernelService.getMatchingKernel(this._editor.viewModel.notebookDocument); this._notebookKernelCount.set(all.length); this._interruptibleKernel.set(selected?.implementsInterrupt ?? false); + this._notebookKernelSelected.set(Boolean(selected)); + } + + private _updateForNotebookOptions(): void { + this._useConsolidatedOutputButton.set(this._editor.notebookOptions.getLayoutConfiguration().consolidatedOutputButton); } } diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookIcons.ts b/src/vs/workbench/contrib/notebook/browser/notebookIcons.ts similarity index 92% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookIcons.ts rename to src/vs/workbench/contrib/notebook/browser/notebookIcons.ts index edeff4ff744f..3fe6bdbd6c5d 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookIcons.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookIcons.ts @@ -11,6 +11,8 @@ export const configureKernelIcon = registerIcon('notebook-kernel-configure', Cod export const selectKernelIcon = registerIcon('notebook-kernel-select', Codicon.serverEnvironment, localize('selectKernelIcon', 'Configure icon to select a kernel in notebook editors.')); export const executeIcon = registerIcon('notebook-execute', Codicon.play, localize('executeIcon', 'Icon to execute in notebook editors.')); +export const executeAboveIcon = registerIcon('notebook-execute-above', Codicon.runAbove, localize('executeAboveIcon', 'Icon to execute above cells in notebook editors.')); +export const executeBelowIcon = registerIcon('notebook-execute-below', Codicon.runBelow, localize('executeBelowIcon', 'Icon to execute below cells in notebook editors.')); export const stopIcon = registerIcon('notebook-stop', Codicon.primitiveSquare, localize('stopIcon', 'Icon to stop an execution in notebook editors.')); export const deleteCellIcon = registerIcon('notebook-delete-cell', Codicon.trash, localize('deleteCellIcon', 'Icon to delete a cell in notebook editors.')); export const executeAllIcon = registerIcon('notebook-execute-all', Codicon.runAll, localize('executeAllIcon', 'Icon to execute all cells in notebook editors.')); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookKernelActionViewItem.ts b/src/vs/workbench/contrib/notebook/browser/notebookKernelActionViewItem.ts new file mode 100644 index 000000000000..9a70372f3504 --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/notebookKernelActionViewItem.ts @@ -0,0 +1,102 @@ +/*--------------------------------------------------------------------------------------------- + * 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!./media/notebookKernelActionViewItem'; +import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; +import { Action, IAction } from 'vs/base/common/actions'; +import { localize } from 'vs/nls'; +import { registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { NotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookEditor'; +import { selectKernelIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; +import { INotebookKernelMatchResult, INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; +import { toolbarHoverBackground } from 'vs/platform/theme/common/colorRegistry'; +import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; + +registerThemingParticipant((theme, collector) => { + const value = theme.getColor(toolbarHoverBackground); + collector.addRule(`:root { + --code-toolbarHoverBackground: ${value}; + }`); +}); + +export class NotebooKernelActionViewItem extends ActionViewItem { + + private _kernelLabel?: HTMLAnchorElement; + + constructor( + actualAction: IAction, + private readonly _editor: NotebookEditor | INotebookEditor, + @INotebookKernelService private readonly _notebookKernelService: INotebookKernelService, + ) { + super( + undefined, + new Action('fakeAction', undefined, ThemeIcon.asClassName(selectKernelIcon), true, (event) => actualAction.run(event)), + { label: false, icon: true } + ); + this._register(_editor.onDidChangeModel(this._update, this)); + this._register(_notebookKernelService.onDidChangeNotebookAffinity(this._update, this)); + this._register(_notebookKernelService.onDidChangeNotebookKernelBinding(this._update, this)); + } + + override render(container: HTMLElement): void { + this._update(); + super.render(container); + container.classList.add('kernel-action-view-item'); + this._kernelLabel = document.createElement('a'); + container.appendChild(this._kernelLabel); + this.updateLabel(); + } + + override updateLabel() { + if (this._kernelLabel) { + this._kernelLabel.classList.add('kernel-label'); + this._kernelLabel.innerText = this._action.label; + this._kernelLabel.title = this._action.tooltip; + } + } + + protected _update(): void { + const notebook = this._editor.viewModel?.notebookDocument; + + if (!notebook) { + this._resetAction(); + return; + } + + const info = this._notebookKernelService.getMatchingKernel(notebook); + this._updateActionFromKernelInfo(info); + } + + private _updateActionFromKernelInfo(info: INotebookKernelMatchResult): void { + + if (info.all.length === 0) { + // should not happen - means "bad" context keys + this._resetAction(); + return; + } + + this._action.enabled = true; + const selectedOrSuggested = info.selected ?? info.suggested; + if (selectedOrSuggested) { + // selected or suggested kernel + this._action.label = selectedOrSuggested.label; + this._action.tooltip = selectedOrSuggested.description ?? selectedOrSuggested.detail ?? ''; + if (!info.selected) { + // special UI for selected kernel? + } + + } else { + // many kernels + this._action.label = localize('select', "Select Kernel"); + this._action.tooltip = ''; + } + } + + private _resetAction(): void { + this._action.enabled = false; + this._action.label = ''; + this._action.class = ''; + } +} diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookKernelServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookKernelServiceImpl.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookKernelServiceImpl.ts rename to src/vs/workbench/contrib/notebook/browser/notebookKernelServiceImpl.ts index 52cdfeadee7d..7ef1ec244cf6 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookKernelServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookKernelServiceImpl.ts @@ -74,7 +74,7 @@ export class NotebookKernelService implements INotebookKernelService { // auto associate kernels to new notebook documents, also emit event when // a notebook has been closed (but don't update the memento) this._disposables.add(_notebookService.onDidAddNotebookDocument(this._tryAutoBindNotebook, this)); - this._disposables.add(_notebookService.onDidRemoveNotebookDocument(notebook => { + this._disposables.add(_notebookService.onWillRemoveNotebookDocument(notebook => { const kernelId = this._notebookBindings.get(NotebookTextModelLikeId.str(notebook)); if (kernelId) { this._onDidChangeNotebookKernelBinding.fire({ notebook: notebook.uri, oldKernel: kernelId, newKernel: undefined }); @@ -191,7 +191,7 @@ export class NotebookKernelService implements INotebookKernelService { const selectedId = this._notebookBindings.get(NotebookTextModelLikeId.str(notebook)); const selected = selectedId ? this._kernels.get(selectedId)?.kernel : undefined; - return { all, selected }; + return { all, selected, suggested: all.length === 1 ? all[0] : undefined }; } // default kernel for notebookType diff --git a/src/vs/workbench/contrib/notebook/browser/notebookRendererMessagingServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookRendererMessagingServiceImpl.ts new file mode 100644 index 000000000000..0d816f42fb55 --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/notebookRendererMessagingServiceImpl.ts @@ -0,0 +1,70 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Emitter, Event } from 'vs/base/common/event'; +import { INotebookRendererMessagingService, IScopedRendererMessaging } from 'vs/workbench/contrib/notebook/common/notebookRendererMessagingService'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; + +type MessageToSend = { editorId: string; rendererId: string; message: unknown }; + +export class NotebookRendererMessagingService implements INotebookRendererMessagingService { + declare _serviceBrand: undefined; + /** + * Activation promises. Maps renderer IDs to a queue of messages that should + * be sent once activation finishes, or undefined if activation is complete. + */ + private readonly activations = new Map(); + private readonly receiveMessageEmitter = new Emitter<{ editorId: string; rendererId: string, message: unknown }>(); + public readonly onDidReceiveMessage = this.receiveMessageEmitter.event; + private readonly postMessageEmitter = new Emitter(); + public readonly onShouldPostMessage = this.postMessageEmitter.event; + + constructor(@IExtensionService private readonly extensionService: IExtensionService) { } + + /** @inheritdoc */ + public fireDidReceiveMessage(editorId: string, rendererId: string, message: unknown): void { + this.receiveMessageEmitter.fire({ editorId, rendererId, message }); + } + + /** @inheritdoc */ + public prepare(rendererId: string) { + if (this.activations.has(rendererId)) { + return; + } + + const queue: MessageToSend[] = []; + this.activations.set(rendererId, queue); + + this.extensionService.activateByEvent(`onRenderer:${rendererId}`).then(() => { + for (const message of queue) { + this.postMessageEmitter.fire(message); + } + + this.activations.set(rendererId, undefined); + }); + } + + /** @inheritdoc */ + public getScoped(editorId: string): IScopedRendererMessaging { + return { + onDidReceiveMessage: Event.filter(this.onDidReceiveMessage, e => e.editorId === editorId), + postMessage: (rendererId, message) => this.postMessage(editorId, rendererId, message), + }; + } + + private postMessage(editorId: string, rendererId: string, message: unknown): void { + if (!this.activations.has(rendererId)) { + this.prepare(rendererId); + } + + const activation = this.activations.get(rendererId); + const toSend = { rendererId, editorId, message }; + if (activation === undefined) { + this.postMessageEmitter.fire(toSend); + } else { + activation.push(toSend); + } + } +} diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts similarity index 80% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts rename to src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts index e3d01d128b5f..a85a27938d04 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts @@ -3,44 +3,44 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as glob from 'vs/base/common/glob'; -import { localize } from 'vs/nls'; import { getPixelRatio, getZoomLevel } from 'vs/base/browser/browser'; import { Emitter, Event } from 'vs/base/common/event'; +import * as glob from 'vs/base/common/glob'; import { Iterable } from 'vs/base/common/iterator'; +import { Lazy } from 'vs/base/common/lazy'; import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ResourceMap } from 'vs/base/common/map'; +import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; +import { localize } from 'vs/nls'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IResourceEditorInput } from 'vs/platform/editor/common/editor'; +import { IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; +import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; import { NotebookExtensionDescription } from 'vs/workbench/api/common/extHost.protocol'; +import { IEditorInput } from 'vs/workbench/common/editor'; +import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { Memento } from 'vs/workbench/common/memento'; -import { INotebookEditorContribution, notebookMarkupRendererExtensionPoint, notebookProviderExtensionPoint, notebookRendererExtensionPoint } from 'vs/workbench/contrib/notebook/browser/extensionPoint'; -import { NotebookEditorOptions, updateEditorTopPadding } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { INotebookEditorContribution, notebooksExtensionPoint, notebookRendererExtensionPoint } from 'vs/workbench/contrib/notebook/browser/extensionPoint'; +import { INotebookEditorOptions } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { NotebookDiffEditorInput } from 'vs/workbench/contrib/notebook/browser/notebookDiffEditorInput'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; -import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, BUILTIN_RENDERER_ID, CellUri, DisplayOrderKey, INotebookExclusiveDocumentFilter, INotebookMarkupRendererInfo, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, IOutputDto, mimeTypeIsAlwaysSecure, mimeTypeSupportedByCore, NotebookDataDto, NotebookEditorPriority, NotebookRendererMatch, NotebookTextDiffEditorPreview, RENDERER_NOT_AVAILABLE, sortMimeTypes, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { NotebookMarkupRendererInfo as NotebookMarkupRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookMarkdownRenderer'; +import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, BUILTIN_RENDERER_ID, CellUri, DisplayOrderKey, INotebookExclusiveDocumentFilter, INotebookContributionData, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, IOutputDto, mimeTypeIsAlwaysSecure, mimeTypeSupportedByCore, NotebookDataDto, NotebookEditorPriority, NotebookRendererMatch, NotebookTextDiffEditorPreview, RENDERER_NOT_AVAILABLE, sortMimeTypes, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput'; +import { updateEditorTopPadding } from 'vs/workbench/contrib/notebook/common/notebookOptions'; import { NotebookOutputRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookOutputRenderer'; import { NotebookEditorDescriptor, NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider'; import { ComplexNotebookProviderInfo, INotebookContentProvider, INotebookSerializer, INotebookService, SimpleNotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookService'; +import { ContributedEditorPriority, DiffEditorInputFactoryFunction, EditorInputFactoryFunction, IEditorOverrideService, IEditorType } from 'vs/workbench/services/editor/common/editorOverrideService'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { Schemas } from 'vs/base/common/network'; -import { Lazy } from 'vs/base/common/lazy'; -import { IResourceEditorInput } from 'vs/platform/editor/common/editor'; -import { NotebookDiffEditorInput } from 'vs/workbench/contrib/notebook/browser/notebookDiffEditorInput'; -import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput'; -import { ContributedEditorPriority, DiffEditorInputFactoryFunction, EditorInputFactoryFunction, IEditorAssociationsRegistry, IEditorOverrideService, IEditorType, IEditorTypesHandler } from 'vs/workbench/services/editor/common/editorOverrideService'; -import { EditorExtensions, IEditorInput } from 'vs/workbench/common/editor'; -import { IFileService } from 'vs/platform/files/common/files'; -import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; export class NotebookProviderInfoStore extends Disposable { @@ -80,7 +80,7 @@ export class NotebookProviderInfoStore extends Disposable { } })); - notebookProviderExtensionPoint.setHandler(extensions => this._setupHandler(extensions)); + notebooksExtensionPoint.setHandler(extensions => this._setupHandler(extensions)); } override dispose(): void { @@ -94,16 +94,24 @@ export class NotebookProviderInfoStore extends Disposable { for (const extension of extensions) { for (const notebookContribution of extension.value) { + + if (!notebookContribution.type) { + extension.collector.error(`Notebook does not specify type-property`); + continue; + } + + if (this.get(notebookContribution.type)) { + extension.collector.error(`Notebook type '${notebookContribution.type}' already used`); + continue; + } + this.add(new NotebookProviderInfo({ - id: notebookContribution.viewType, + extension: extension.description.identifier, + id: notebookContribution.type, displayName: notebookContribution.displayName, selectors: notebookContribution.selector || [], priority: this._convertPriority(notebookContribution.priority), - providerExtensionId: extension.description.identifier.value, - providerDescription: extension.description.description, providerDisplayName: extension.description.isBuiltin ? localize('builtinProviderDisplayName', "Built-in") : extension.description.displayName || extension.description.identifier.value, - providerExtensionLocation: extension.description.extensionLocation, - dynamicContribution: false, exclusive: false })); } @@ -127,7 +135,10 @@ export class NotebookProviderInfoStore extends Disposable { } - private _registerContributionPoint(notebookProviderInfo: NotebookProviderInfo): void { + private _registerContributionPoint(notebookProviderInfo: NotebookProviderInfo): IDisposable { + + const disposables = new DisposableStore(); + for (const selector of notebookProviderInfo.selectors) { const globPattern = (selector as INotebookExclusiveDocumentFilter).include || selector as glob.IRelativePattern | string; const notebookEditorInfo = { @@ -148,10 +159,10 @@ export class NotebookProviderInfoStore extends Disposable { if (data) { notebookUri = data.notebook; - cellOptions = { resource: resource }; + cellOptions = { resource, options }; } - const notebookOptions = new NotebookEditorOptions({ ...options, cellOptions }); + const notebookOptions: INotebookEditorOptions = { ...options, cellOptions }; return { editor: NotebookEditorInput.create(this._instantiationService, notebookUri, notebookProviderInfo.id), options: notebookOptions }; }; const notebookEditorDiffFactory: DiffEditorInputFactoryFunction = (diffEditorInput: DiffEditorInput, options, group) => { @@ -162,7 +173,7 @@ export class NotebookProviderInfoStore extends Disposable { return { editor: NotebookDiffEditorInput.create(this._instantiationService, notebookUri, modifiedInput.getName(), originalNotebookUri, originalInput.getName(), diffEditorInput.getName(), notebookProviderInfo.id) }; }; // Register the notebook editor - this._contributedEditorDisposables.add(this._editorOverrideService.registerContributionPoint( + disposables.add(this._editorOverrideService.registerContributionPoint( globPattern, notebookEditorInfo, notebookEditorOptions, @@ -170,7 +181,7 @@ export class NotebookProviderInfoStore extends Disposable { notebookEditorDiffFactory )); // Then register the schema handler as exclusive for that notebook - this._contributedEditorDisposables.add(this._editorOverrideService.registerContributionPoint( + disposables.add(this._editorOverrideService.registerContributionPoint( `${Schemas.vscodeNotebookCell}:/**/${globPattern}`, { ...notebookEditorInfo, priority: ContributedEditorPriority.exclusive }, notebookEditorOptions, @@ -178,6 +189,8 @@ export class NotebookProviderInfoStore extends Disposable { notebookEditorDiffFactory )); } + + return disposables; } @@ -190,16 +203,25 @@ export class NotebookProviderInfoStore extends Disposable { return this._contributedEditors.get(viewType); } - add(info: NotebookProviderInfo): void { + add(info: NotebookProviderInfo): IDisposable { if (this._contributedEditors.has(info.id)) { - return; + throw new Error(`notebook type '${info.id}' ALREADY EXISTS`); } this._contributedEditors.set(info.id, info); - this._registerContributionPoint(info); + const editorRegistration = this._registerContributionPoint(info); + this._contributedEditorDisposables.add(editorRegistration); const mementoObject = this._memento.getMemento(StorageScope.GLOBAL, StorageTarget.MACHINE); mementoObject[NotebookProviderInfoStore.CUSTOM_EDITORS_ENTRY_ID] = Array.from(this._contributedEditors.values()); this._memento.saveMemento(); + + return toDisposable(() => { + const mementoObject = this._memento.getMemento(StorageScope.GLOBAL, StorageTarget.MACHINE); + mementoObject[NotebookProviderInfoStore.CUSTOM_EDITORS_ENTRY_ID] = Array.from(this._contributedEditors.values()); + this._memento.saveMemento(); + editorRegistration.dispose(); + this._contributedEditors.delete(info.id); + }); } getContributedNotebook(resource: URI): readonly NotebookProviderInfo[] { @@ -238,6 +260,10 @@ export class NotebookOutputRendererInfoStore { return this.contributedRenderers.get(rendererId); } + getAll(): NotebookOutputRendererInfo[] { + return Array.from(this.contributedRenderers.values()); + } + add(info: NotebookOutputRendererInfo): void { if (this.contributedRenderers.has(info.id)) { return; @@ -283,23 +309,27 @@ class ModelData implements IDisposable { } } -export class NotebookService extends Disposable implements INotebookService, IEditorTypesHandler { +export class NotebookService extends Disposable implements INotebookService { declare readonly _serviceBrand: undefined; private readonly _notebookProviders = new Map(); private readonly _notebookProviderInfoStore: NotebookProviderInfoStore; private readonly _notebookRenderersInfoStore = this._instantiationService.createInstance(NotebookOutputRendererInfoStore); - private readonly _markdownRenderersInfos = new Set(); private readonly _models = new ResourceMap(); - private readonly _onDidCreateNotebookDocument = this._register(new Emitter()); + private readonly _onWillAddNotebookDocument = this._register(new Emitter()); private readonly _onDidAddNotebookDocument = this._register(new Emitter()); + private readonly _onWillRemoveNotebookDocument = this._register(new Emitter()); private readonly _onDidRemoveNotebookDocument = this._register(new Emitter()); - readonly onDidCreateNotebookDocument = this._onDidCreateNotebookDocument.event; + readonly onWillAddNotebookDocument = this._onWillAddNotebookDocument.event; readonly onDidAddNotebookDocument = this._onDidAddNotebookDocument.event; readonly onDidRemoveNotebookDocument = this._onDidRemoveNotebookDocument.event; + readonly onWillRemoveNotebookDocument = this._onWillRemoveNotebookDocument.event; + + private readonly _onWillRemoveViewType = this._register(new Emitter()); + readonly onWillRemoveViewType = this._onWillRemoveViewType.event; private readonly _onDidChangeEditorTypes = this._register(new Emitter()); onDidChangeEditorTypes: Event = this._onDidChangeEditorTypes.event; @@ -316,6 +346,7 @@ export class NotebookService extends Disposable implements INotebookService, IEd @IInstantiationService private readonly _instantiationService: IInstantiationService, @ICodeEditorService private readonly _codeEditorService: ICodeEditorService, @IConfigurationService private readonly configurationService: IConfigurationService, + @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService, ) { super(); @@ -329,13 +360,13 @@ export class NotebookService extends Disposable implements INotebookService, IEd for (const extension of renderers) { for (const notebookContribution of extension.value) { if (!notebookContribution.entrypoint) { // avoid crashing - console.error(`Cannot register renderer for ${extension.description.identifier.value} since it did not have an entrypoint. This is now required: https://github.com/microsoft/vscode/issues/102644`); + extension.collector.error(`Notebook renderer does not specify entry point`); continue; } - const id = notebookContribution.id ?? notebookContribution.viewType; + const id = notebookContribution.id; if (!id) { - console.error(`Notebook renderer from ${extension.description.identifier.value} is missing an 'id'`); + extension.collector.error(`Notebook renderer does not specify id-property`); continue; } @@ -347,44 +378,11 @@ export class NotebookService extends Disposable implements INotebookService, IEd mimeTypes: notebookContribution.mimeTypes || [], dependencies: notebookContribution.dependencies, optionalDependencies: notebookContribution.optionalDependencies, + requiresMessaging: notebookContribution.requiresMessaging, })); } } }); - notebookMarkupRendererExtensionPoint.setHandler((renderers) => { - this._markdownRenderersInfos.clear(); - - for (const extension of renderers) { - if (!extension.description.enableProposedApi && !extension.description.isBuiltin) { - // Only allow proposed extensions to use this extension point - return; - } - - for (const notebookContribution of extension.value) { - if (!notebookContribution.entrypoint) { // avoid crashing - console.error(`Cannot register renderer for ${extension.description.identifier.value} since it did not have an entrypoint. This is now required: https://github.com/microsoft/vscode/issues/102644`); - continue; - } - - const id = notebookContribution.id; - if (!id) { - console.error(`Notebook renderer from ${extension.description.identifier.value} is missing an 'id'`); - continue; - } - - this._markdownRenderersInfos.add(new NotebookMarkupRendererInfo({ - id, - extension: extension.description, - entrypoint: notebookContribution.entrypoint, - displayName: notebookContribution.displayName, - mimeTypes: notebookContribution.mimeTypes, - dependsOn: notebookContribution.dependsOn, - })); - } - } - }); - - this._register(Registry.as(EditorExtensions.Associations).registerEditorTypesHandler('Notebook', this)); const updateOrder = () => { const userOrder = this._configurationService.getValue(DisplayOrderKey); @@ -469,51 +467,50 @@ export class NotebookService extends Disposable implements INotebookService, IEd return this._notebookProviders.has(viewType); } - private _registerProviderData(viewType: string, data: SimpleNotebookProviderInfo | ComplexNotebookProviderInfo): void { - if (this._notebookProviders.has(viewType)) { - throw new Error(`notebook controller for viewtype '${viewType}' already exists`); - } - this._notebookProviders.set(viewType, data); - } + registerContributedNotebookType(viewType: string, data: INotebookContributionData): IDisposable { - registerNotebookController(viewType: string, extensionData: NotebookExtensionDescription, controller: INotebookContentProvider): IDisposable { - this._registerProviderData(viewType, new ComplexNotebookProviderInfo(viewType, controller, extensionData)); - if (controller.viewOptions && !this._notebookProviderInfoStore.get(viewType)) { - // register this content provider to the static contribution, if it does not exist - const info = new NotebookProviderInfo({ - displayName: controller.viewOptions.displayName, - id: viewType, - priority: ContributedEditorPriority.default, - selectors: [], - providerExtensionId: extensionData.id.value, - providerDescription: extensionData.description, - providerDisplayName: extensionData.id.value, - providerExtensionLocation: URI.revive(extensionData.location), - dynamicContribution: true, - exclusive: controller.viewOptions.exclusive - }); - - info.update({ selectors: controller.viewOptions.filenamePattern }); - info.update({ options: controller.options }); - this._notebookProviderInfoStore.add(info); - } + const info = new NotebookProviderInfo({ + extension: data.extension, + id: viewType, + displayName: data.displayName, + providerDisplayName: data.providerDisplayName, + exclusive: data.exclusive, + priority: ContributedEditorPriority.default, + selectors: [], + }); - this._notebookProviderInfoStore.get(viewType)?.update({ options: controller.options }); + info.update({ selectors: data.filenamePattern }); + const reg = this._notebookProviderInfoStore.add(info); this._onDidChangeEditorTypes.fire(); + return toDisposable(() => { - this._notebookProviders.delete(viewType); + reg.dispose(); this._onDidChangeEditorTypes.fire(); }); } - registerNotebookSerializer(viewType: string, extensionData: NotebookExtensionDescription, serializer: INotebookSerializer): IDisposable { - this._registerProviderData(viewType, new SimpleNotebookProviderInfo(viewType, serializer, extensionData)); + private _registerProviderData(viewType: string, data: SimpleNotebookProviderInfo | ComplexNotebookProviderInfo): IDisposable { + if (this._notebookProviders.has(viewType)) { + throw new Error(`notebook controller for viewtype '${viewType}' already exists`); + } + this._notebookProviders.set(viewType, data); return toDisposable(() => { + this._onWillRemoveViewType.fire(viewType); this._notebookProviders.delete(viewType); }); } + registerNotebookController(viewType: string, extensionData: NotebookExtensionDescription, controller: INotebookContentProvider): IDisposable { + this._notebookProviderInfoStore.get(viewType)?.update({ options: controller.options }); + return this._registerProviderData(viewType, new ComplexNotebookProviderInfo(viewType, controller, extensionData)); + } + + registerNotebookSerializer(viewType: string, extensionData: NotebookExtensionDescription, serializer: INotebookSerializer): IDisposable { + this._notebookProviderInfoStore.get(viewType)?.update({ options: serializer.options }); + return this._registerProviderData(viewType, new SimpleNotebookProviderInfo(viewType, serializer, extensionData)); + } + async withNotebookDataProvider(resource: URI, viewType?: string): Promise { const providers = this._notebookProviderInfoStore.getContributedNotebook(resource); // If we have a viewtype specified we want that data provider, as the resource won't always map correctly @@ -537,8 +534,8 @@ export class NotebookService extends Disposable implements INotebookService, IEd this._notebookRenderersInfoStore.setPreferred(mimeType, rendererId); } - getMarkupRendererInfo(): INotebookMarkupRendererInfo[] { - return Array.from(this._markdownRenderersInfos); + getRenderers(): INotebookRendererInfo[] { + return this._notebookRenderersInfoStore.getAll(); } // --- notebook documents: create, destory, retrieve, enumerate @@ -549,7 +546,7 @@ export class NotebookService extends Disposable implements INotebookService, IEd } const notebookModel = this._instantiationService.createInstance(NotebookTextModel, viewType, uri, data.cells, data.metadata, transientOptions); this._models.set(uri, new ModelData(notebookModel, this._onWillDisposeDocument.bind(this))); - this._onDidCreateNotebookDocument.fire(notebookModel); + this._onWillAddNotebookDocument.fire(notebookModel); this._onDidAddNotebookDocument.fire(notebookModel); return notebookModel; } @@ -569,6 +566,7 @@ export class NotebookService extends Disposable implements INotebookService, IEd private _onWillDisposeDocument(model: INotebookTextModel): void { const modelData = this._models.get(model.uri); if (modelData) { + this._onWillRemoveNotebookDocument.fire(modelData.model); this._models.delete(model.uri); modelData.dispose(); this._onDidRemoveNotebookDocument.fire(modelData.model); @@ -599,14 +597,14 @@ export class NotebookService extends Disposable implements INotebookService, IEd orderMimeTypes.push({ mimeType: mimeType, rendererId: handler.id, - isTrusted: textModel.metadata.trusted + isTrusted: true }); for (let i = 1; i < handlers.length; i++) { orderMimeTypes.push({ mimeType: mimeType, rendererId: handlers[i].id, - isTrusted: textModel.metadata.trusted + isTrusted: true }); } @@ -614,7 +612,7 @@ export class NotebookService extends Disposable implements INotebookService, IEd orderMimeTypes.push({ mimeType: mimeType, rendererId: BUILTIN_RENDERER_ID, - isTrusted: mimeTypeIsAlwaysSecure(mimeType) || textModel.metadata.trusted + isTrusted: mimeTypeIsAlwaysSecure(mimeType) || this.workspaceTrustManagementService.isWorkpaceTrusted() }); } } else { @@ -622,13 +620,13 @@ export class NotebookService extends Disposable implements INotebookService, IEd orderMimeTypes.push({ mimeType: mimeType, rendererId: BUILTIN_RENDERER_ID, - isTrusted: mimeTypeIsAlwaysSecure(mimeType) || textModel.metadata.trusted + isTrusted: mimeTypeIsAlwaysSecure(mimeType) || this.workspaceTrustManagementService.isWorkpaceTrusted() }); } else { orderMimeTypes.push({ mimeType: mimeType, rendererId: RENDERER_NOT_AVAILABLE, - isTrusted: textModel.metadata.trusted + isTrusted: true }); } } @@ -641,7 +639,7 @@ export class NotebookService extends Disposable implements INotebookService, IEd return this._notebookRenderersInfoStore.getContributedRenderer(mimeType, kernelProvides); } - getContributedNotebookProviders(resource?: URI): readonly NotebookProviderInfo[] { + getContributedNotebookTypes(resource?: URI): readonly NotebookProviderInfo[] { if (resource) { return this._notebookProviderInfoStore.getContributedNotebook(resource); } @@ -649,7 +647,7 @@ export class NotebookService extends Disposable implements INotebookService, IEd return [...this._notebookProviderInfoStore]; } - getContributedNotebookProvider(viewType: string): NotebookProviderInfo | undefined { + getContributedNotebookType(viewType: string): NotebookProviderInfo | undefined { return this._notebookProviderInfoStore.get(viewType); } diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts rename to src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts index f10680f32981..5584ff939771 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts @@ -24,8 +24,8 @@ import { CellViewModel, NotebookViewModel } from 'vs/workbench/contrib/notebook/ import { diff, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, CellKind, SelectionStateType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ICellRange, cellRangesToIndexes } from 'vs/workbench/contrib/notebook/common/notebookRange'; import { clamp } from 'vs/base/common/numbers'; -import { SCROLLABLE_ELEMENT_PADDING_TOP } from 'vs/workbench/contrib/notebook/browser/constants'; import { ISplice } from 'vs/base/common/sequence'; +import { ViewContext } from 'vs/workbench/contrib/notebook/browser/viewModel/viewContext'; export interface IFocusNextPreviousDelegate { onFocusNext(applyFocusNext: () => void): void; @@ -91,10 +91,13 @@ export class NotebookCellList extends WorkbenchList implements ID private readonly _focusNextPreviousDelegate: IFocusNextPreviousDelegate; + private readonly _viewContext: ViewContext; + constructor( private listUser: string, parentContainer: HTMLElement, container: HTMLElement, + viewContext: ViewContext, delegate: IListVirtualDelegate, renderers: IListRenderer[], contextKeyService: IContextKeyService, @@ -106,6 +109,7 @@ export class NotebookCellList extends WorkbenchList implements ID ) { super(listUser, container, delegate, renderers, options, contextKeyService, listService, themeService, configurationService, keybindingService); NOTEBOOK_CELL_LIST_FOCUSED.bindTo(this.contextKeyService).set(true); + this._viewContext = viewContext; this._focusNextPreviousDelegate = options.focusNextPreviousDelegate; this._previousFocusedElements = this.getFocusedElements(); this._localDisposableStore.add(this.onDidChangeFocus((e) => { @@ -177,7 +181,7 @@ export class NotebookCellList extends WorkbenchList implements ID this._localDisposableStore.add(this.view.onMouseDblClick(() => { const focus = this.getFocusedElements()[0]; - if (focus && focus.cellKind === CellKind.Markdown && !focus.metadata?.inputCollapsed) { + if (focus && focus.cellKind === CellKind.Markup && !focus.metadata.inputCollapsed) { focus.updateEditState(CellEditState.Editing, 'dbclick'); focus.focusMode = CellFocusMode.Editor; } @@ -900,7 +904,8 @@ export class NotebookCellList extends WorkbenchList implements ID } getViewScrollBottom() { - return this.getViewScrollTop() + this.view.renderHeight - SCROLLABLE_ELEMENT_PADDING_TOP; + const topInsertToolbarHeight = this._viewContext.notebookOptions.computeTopInserToolbarHeight(this.viewModel?.viewType); + return this.getViewScrollTop() + this.view.renderHeight - topInsertToolbarHeight; } private _revealRange(viewIndex: number, range: Range, revealType: CellRevealType, newlyCreated: boolean, alignToBottom: boolean) { @@ -1279,6 +1284,13 @@ export class NotebookCellList extends WorkbenchList implements ID this._viewModelStore.dispose(); this._localDisposableStore.dispose(); super.dispose(); + + // un-ref + this._previousFocusedElements = []; + this._viewModel = null; + this._hiddenRangeIds = []; + this.hiddenRangesPrefixSum = null; + this._visibleRanges = []; } } diff --git a/src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts new file mode 100644 index 000000000000..739111572324 --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts @@ -0,0 +1,73 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { OutputRendererRegistry } from 'vs/workbench/contrib/notebook/browser/view/output/rendererRegistry'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { ICellOutputViewModel, ICommonNotebookEditor, IOutputTransformContribution, IRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { URI } from 'vs/base/common/uri'; +import { dispose } from 'vs/base/common/lifecycle'; +import { localize } from 'vs/nls'; + +export class OutputRenderer { + + private readonly _richMimeTypeRenderers = new Map(); + + constructor( + notebookEditor: ICommonNotebookEditor, + instantiationService: IInstantiationService + ) { + for (const desc of OutputRendererRegistry.getOutputTransformContributions()) { + try { + const contribution = instantiationService.createInstance(desc.ctor, notebookEditor); + contribution.getMimetypes().forEach(mimetype => { this._richMimeTypeRenderers.set(mimetype, contribution); }); + } catch (err) { + onUnexpectedError(err); + } + } + } + + dispose(): void { + dispose(this._richMimeTypeRenderers.values()); + this._richMimeTypeRenderers.clear(); + } + + getContribution(preferredMimeType: string): IOutputTransformContribution | undefined { + return this._richMimeTypeRenderers.get(preferredMimeType); + } + + private _renderMessage(container: HTMLElement, message: string): IRenderOutput { + const contentNode = document.createElement('p'); + contentNode.innerText = message; + container.appendChild(contentNode); + return { type: RenderOutputType.Mainframe }; + } + + render(viewModel: ICellOutputViewModel, container: HTMLElement, preferredMimeType: string | undefined, notebookUri: URI): IRenderOutput { + if (!viewModel.model.outputs.length) { + return this._renderMessage(container, localize('empty', "Cell has no output")); + } + if (!preferredMimeType) { + const mimeTypes = viewModel.model.outputs.map(op => op.mime); + const mimeTypesMessage = mimeTypes.join(', '); + return this._renderMessage(container, localize('noRenderer.2', "No renderer could be found for output. It has the following MIME types: {0}", mimeTypesMessage)); + } + if (!preferredMimeType || !this._richMimeTypeRenderers.has(preferredMimeType)) { + if (preferredMimeType) { + return this._renderMessage(container, localize('noRenderer.1', "No renderer could be found for MIME type: {0}", preferredMimeType)); + } + } + const renderer = this._richMimeTypeRenderers.get(preferredMimeType); + if (!renderer) { + return this._renderMessage(container, localize('noRenderer.1', "No renderer could be found for MIME type: {0}", preferredMimeType)); + } + const first = viewModel.model.outputs.find(op => op.mime === preferredMimeType); + if (!first) { + return this._renderMessage(container, localize('empty', "Cell has no output")); + } + + return renderer.render(viewModel, [first], container, notebookUri); + } +} diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookRegistry.ts b/src/vs/workbench/contrib/notebook/browser/view/output/rendererRegistry.ts similarity index 66% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookRegistry.ts rename to src/vs/workbench/contrib/notebook/browser/view/output/rendererRegistry.ts index c382e015505d..574aa94d0155 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/notebookRegistry.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/output/rendererRegistry.ts @@ -9,20 +9,18 @@ import { ICommonNotebookEditor, IOutputTransformContribution } from 'vs/workbenc export type IOutputTransformCtor = IConstructorSignature1; export interface IOutputTransformDescription { - id: string; ctor: IOutputTransformCtor; } +export const OutputRendererRegistry = new class NotebookRegistryImpl { -export const NotebookRegistry = new class NotebookRegistryImpl { + readonly #outputTransforms: IOutputTransformDescription[] = []; - readonly outputTransforms: IOutputTransformDescription[] = []; - - registerOutputTransform(id: string, ctor: { new(editor: ICommonNotebookEditor, ...services: Services): IOutputTransformContribution }): void { - this.outputTransforms.push({ id: id, ctor: ctor as IOutputTransformCtor }); + registerOutputTransform(ctor: { new(editor: ICommonNotebookEditor, ...services: Services): IOutputTransformContribution }): void { + this.#outputTransforms.push({ ctor: ctor as IOutputTransformCtor }); } getOutputTransformContributions(): IOutputTransformDescription[] { - return this.outputTransforms.slice(0); + return this.#outputTransforms.slice(0); } }; diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts similarity index 50% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts rename to src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts index 4285b38c02a0..f8daffff9c19 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts @@ -4,81 +4,25 @@ *--------------------------------------------------------------------------------------------*/ import * as DOM from 'vs/base/browser/dom'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { dirname } from 'vs/base/common/resources'; -import { isArray } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { MarkdownRenderer } from 'vs/editor/browser/core/markdownRenderer'; +import { IEditorConstructionOptions } from 'vs/editor/browser/editorBrowser'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; -import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ILogService } from 'vs/platform/log/common/log'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { handleANSIOutput } from 'vs/workbench/contrib/debug/browser/debugANSIHandling'; import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector'; import { ICellOutputViewModel, ICommonNotebookEditor, IOutputTransformContribution as IOutputRendererContribution, IRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { NotebookRegistry } from 'vs/workbench/contrib/notebook/browser/notebookRegistry'; +import { OutputRendererRegistry } from 'vs/workbench/contrib/notebook/browser/view/output/rendererRegistry'; import { truncatedArrayOfString } from 'vs/workbench/contrib/notebook/browser/view/output/transforms/textHelper'; import { IOutputItemDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -function getStringValue(data: unknown): string { - return isArray(data) ? data.join('') : String(data); -} - -class JSONRendererContrib extends Disposable implements IOutputRendererContribution { - getType() { - return RenderOutputType.Mainframe; - } - - getMimetypes() { - return ['application/json']; - } - - constructor( - public notebookEditor: ICommonNotebookEditor, - @IInstantiationService private readonly instantiationService: IInstantiationService, - @IModelService private readonly modelService: IModelService, - @IModeService private readonly modeService: IModeService, - ) { - super(); - } - - render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI | undefined): IRenderOutput { - const str = items.map(item => JSON.stringify(item.value, null, '\t')).join(''); - - const editor = this.instantiationService.createInstance(CodeEditorWidget, container, { - ...getOutputSimpleEditorOptions(), - dimension: { - width: 0, - height: 0 - }, - automaticLayout: true, - }, { - isSimpleWidget: true - }); - - const mode = this.modeService.create('json'); - const resource = URI.parse(`notebook-output-${Date.now()}.json`); - const textModel = this.modelService.createModel(str, mode, resource, false); - editor.setModel(textModel); - - const width = this.notebookEditor.getCellOutputLayoutInfo(output.cellViewModel).width; - const fontInfo = this.notebookEditor.getCellOutputLayoutInfo(output.cellViewModel).fontInfo; - const height = Math.min(textModel.getLineCount(), 16) * (fontInfo.lineHeight || 18); - - editor.layout({ - height, - width - }); - - container.style.height = `${height + 8}px`; - - return { type: RenderOutputType.Mainframe, initHeight: height }; - } -} class JavaScriptRendererContrib extends Disposable implements IOutputRendererContribution { getType() { @@ -95,11 +39,10 @@ class JavaScriptRendererContrib extends Disposable implements IOutputRendererCon super(); } - render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI | undefined): IRenderOutput { + render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI): IRenderOutput { let scriptVal = ''; items.forEach(item => { - const data = item.value; - const str = isArray(data) ? data.join('') : data; + const str = getStringValue(item); scriptVal += ``; }); @@ -129,35 +72,43 @@ class CodeRendererContrib extends Disposable implements IOutputRendererContribut super(); } - render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI | undefined): IRenderOutput { - const str = items.map(item => getStringValue(item.value)).join(''); - const editor = this.instantiationService.createInstance(CodeEditorWidget, container, { - ...getOutputSimpleEditorOptions(), - dimension: { - width: 0, - height: 0 - } - }, { - isSimpleWidget: true - }); + render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement): IRenderOutput { + const value = items.map(getStringValue).join(''); + return this._render(output, container, value, 'javascript'); + } + + protected _render(output: ICellOutputViewModel, container: HTMLElement, value: string, modeId: string): IRenderOutput { + const disposable = new DisposableStore(); + const editor = this.instantiationService.createInstance(CodeEditorWidget, container, getOutputSimpleEditorOptions(), { isSimpleWidget: true }); - const mode = this.modeService.create('javascript'); - const resource = URI.parse(`notebook-output-${Date.now()}.js`); - const textModel = this.modelService.createModel(str, mode, resource, false); + const mode = this.modeService.create(modeId); + const textModel = this.modelService.createModel(value, mode, undefined, false); editor.setModel(textModel); const width = this.notebookEditor.getCellOutputLayoutInfo(output.cellViewModel).width; const fontInfo = this.notebookEditor.getCellOutputLayoutInfo(output.cellViewModel).fontInfo; const height = Math.min(textModel.getLineCount(), 16) * (fontInfo.lineHeight || 18); - editor.layout({ - height, - width - }); + editor.layout({ height, width }); + + disposable.add(editor); + disposable.add(textModel); container.style.height = `${height + 8}px`; - return { type: RenderOutputType.Mainframe }; + return { type: RenderOutputType.Mainframe, initHeight: height, disposable }; + } +} + +class JSONRendererContrib extends CodeRendererContrib { + + override getMimetypes() { + return ['application/json']; + } + + override render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement): IRenderOutput { + const str = items.map(getStringValue).join(''); + return this._render(output, container, str, 'jsonc'); } } @@ -167,26 +118,25 @@ class StreamRendererContrib extends Disposable implements IOutputRendererContrib } getMimetypes() { - return ['application/x.notebook.stdout', 'application/x.notebook.stream']; + return ['application/vnd.code.notebook.stdout', 'application/x.notebook.stdout', 'application/x.notebook.stream']; } constructor( public notebookEditor: ICommonNotebookEditor, @IOpenerService private readonly openerService: IOpenerService, @IThemeService private readonly themeService: IThemeService, - @ITextFileService private readonly textFileService: ITextFileService, @IInstantiationService private readonly instantiationService: IInstantiationService, ) { super(); } - render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI | undefined): IRenderOutput { + render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI): IRenderOutput { const linkDetector = this.instantiationService.createInstance(LinkDetector); items.forEach(item => { - const text = getStringValue(item.value); + const text = getStringValue(item); const contentNode = DOM.$('span.output-stream'); - truncatedArrayOfString(contentNode, [text], linkDetector, this.openerService, this.textFileService, this.themeService); + truncatedArrayOfString(notebookUri!, output.cellViewModel, contentNode, [text], linkDetector, this.openerService, this.themeService); container.appendChild(contentNode); }); @@ -200,64 +150,68 @@ class StderrRendererContrib extends StreamRendererContrib { } override getMimetypes() { - return ['application/x.notebook.stderr']; + return ['application/vnd.code.notebook.stderr', 'application/x.notebook.stderr']; } - override render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI | undefined): IRenderOutput { + override render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI): IRenderOutput { const result = super.render(output, items, container, notebookUri); container.classList.add('error'); return result; } } -class ErrorRendererContrib extends Disposable implements IOutputRendererContribution { +class JSErrorRendererContrib implements IOutputRendererContribution { + + constructor( + public notebookEditor: ICommonNotebookEditor, + @IThemeService private readonly _themeService: IThemeService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, + @ILogService private readonly _logService: ILogService, + ) { } + + dispose(): void { + // nothing + } + getType() { return RenderOutputType.Mainframe; } getMimetypes() { - return ['application/x.notebook.error-traceback']; + return ['application/vnd.code.notebook.error']; } - constructor( - public notebookEditor: ICommonNotebookEditor, - @IThemeService private readonly themeService: IThemeService, - @IInstantiationService private readonly instantiationService: IInstantiationService, + render(_output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, _notebookUri: URI): IRenderOutput { + const linkDetector = this._instantiationService.createInstance(LinkDetector); - ) { - super(); - } + type ErrorLike = Partial; + + for (let item of items) { + let err: ErrorLike; + try { + err = JSON.parse(getStringValue(item)); + } catch (e) { + this._logService.warn('INVALID output item (failed to parse)', e); + continue; + } - render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI | undefined): IRenderOutput { - const linkDetector = this.instantiationService.createInstance(LinkDetector); - items.forEach(item => { - const data: any = item.value; const header = document.createElement('div'); - const headerMessage = data.ename && data.evalue - ? `${data.ename}: ${data.evalue}` - : data.ename || data.evalue; + const headerMessage = err.name && err.message ? `${err.name}: ${err.message}` : err.name || err.message; if (headerMessage) { header.innerText = headerMessage; container.appendChild(header); } - const traceback = document.createElement('pre'); - traceback.classList.add('traceback'); - if (data.traceback) { - for (let j = 0; j < data.traceback.length; j++) { - traceback.appendChild(handleANSIOutput(data.traceback[j], linkDetector, this.themeService, undefined)); - } + const stack = document.createElement('pre'); + stack.classList.add('traceback'); + if (err.stack) { + stack.appendChild(handleANSIOutput(err.stack, linkDetector, this._themeService, undefined)); } - container.appendChild(traceback); + container.appendChild(stack); container.classList.add('error'); - return { type: RenderOutputType.Mainframe }; - - }); + } return { type: RenderOutputType.Mainframe }; } - - _render() { - } } class PlainTextRendererContrib extends Disposable implements IOutputRendererContribution { @@ -273,18 +227,17 @@ class PlainTextRendererContrib extends Disposable implements IOutputRendererCont public notebookEditor: ICommonNotebookEditor, @IOpenerService private readonly openerService: IOpenerService, @IThemeService private readonly themeService: IThemeService, - @ITextFileService private readonly textFileService: ITextFileService, @IInstantiationService private readonly instantiationService: IInstantiationService ) { super(); } - render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI | undefined): IRenderOutput { + render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI): IRenderOutput { const linkDetector = this.instantiationService.createInstance(LinkDetector); - const str = items.map(item => getStringValue(item.value)); + const str = items.map(getStringValue); const contentNode = DOM.$('.output-plaintext'); - truncatedArrayOfString(contentNode, str, linkDetector, this.openerService, this.textFileService, this.themeService); + truncatedArrayOfString(notebookUri!, output.cellViewModel, contentNode, str, linkDetector, this.openerService, this.themeService); container.appendChild(contentNode); return { type: RenderOutputType.Mainframe, supportAppend: true }; @@ -297,7 +250,7 @@ class HTMLRendererContrib extends Disposable implements IOutputRendererContribut } getMimetypes() { - return ['text/html']; + return ['text/html', 'image/svg+xml']; } constructor( @@ -306,35 +259,8 @@ class HTMLRendererContrib extends Disposable implements IOutputRendererContribut super(); } - render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI | undefined): IRenderOutput { - const data = items.map(item => getStringValue(item.value)).join(''); - - const str = (isArray(data) ? data.join('') : data) as string; - return { - type: RenderOutputType.Html, - source: output, - htmlContent: str - }; - } -} - -class SVGRendererContrib extends Disposable implements IOutputRendererContribution { - getType() { - return RenderOutputType.Html; - } - - getMimetypes() { - return ['image/svg+xml']; - } - - constructor( - public notebookEditor: ICommonNotebookEditor, - ) { - super(); - } - - render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI | undefined): IRenderOutput { - const str = items.map(item => getStringValue(item.value)).join(''); + render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI): IRenderOutput { + const str = items.map(getStringValue).join(''); return { type: RenderOutputType.Html, source: output, @@ -360,26 +286,26 @@ class MdRendererContrib extends Disposable implements IOutputRendererContributio } render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI): IRenderOutput { - items.forEach(item => { - const data = item.value; - const str = (isArray(data) ? data.join('') : data) as string; + const disposable = new DisposableStore(); + for (let item of items) { + const str = getStringValue(item); const mdOutput = document.createElement('div'); const mdRenderer = this.instantiationService.createInstance(MarkdownRenderer, { baseUrl: dirname(notebookUri) }); mdOutput.appendChild(mdRenderer.render({ value: str, isTrusted: true, supportThemeIcons: true }, undefined, { gfm: true }).element); container.appendChild(mdOutput); - }); - - return { type: RenderOutputType.Mainframe }; + disposable.add(mdRenderer); + } + return { type: RenderOutputType.Mainframe, disposable }; } } -class PNGRendererContrib extends Disposable implements IOutputRendererContribution { +class ImgRendererContrib extends Disposable implements IOutputRendererContribution { getType() { return RenderOutputType.Mainframe; } getMimetypes() { - return ['image/png']; + return ['image/png', 'image/jpeg', 'image/gif']; } constructor( @@ -388,65 +314,47 @@ class PNGRendererContrib extends Disposable implements IOutputRendererContributi super(); } - render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI | undefined): IRenderOutput { - items.forEach(item => { - const image = document.createElement('img'); - const imagedata = item.value; - image.src = `data:image/png;base64,${imagedata}`; - const display = document.createElement('div'); - display.classList.add('display'); - display.appendChild(image); - container.appendChild(display); - }); - return { type: RenderOutputType.Mainframe }; - } -} + render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI): IRenderOutput { + const disposable = new DisposableStore(); -class JPEGRendererContrib extends Disposable implements IOutputRendererContribution { - getType() { - return RenderOutputType.Mainframe; - } + for (let item of items) { - getMimetypes() { - return ['image/jpeg']; - } - - constructor( - public notebookEditor: ICommonNotebookEditor, - ) { - super(); - } + const bytes = new Uint8Array(item.valueBytes); + const blob = new Blob([bytes], { type: item.mime }); + const src = URL.createObjectURL(blob); + disposable.add(toDisposable(() => URL.revokeObjectURL(src))); - render(output: ICellOutputViewModel, items: IOutputItemDto[], container: HTMLElement, notebookUri: URI | undefined): IRenderOutput { - items.forEach(item => { const image = document.createElement('img'); - const imagedata = item.value; - image.src = `data:image/jpeg;base64,${imagedata}`; + image.src = src; const display = document.createElement('div'); display.classList.add('display'); display.appendChild(image); container.appendChild(display); - }); - - return { type: RenderOutputType.Mainframe }; + } + return { type: RenderOutputType.Mainframe, disposable }; } } -NotebookRegistry.registerOutputTransform('json', JSONRendererContrib); -NotebookRegistry.registerOutputTransform('javascript', JavaScriptRendererContrib); -NotebookRegistry.registerOutputTransform('html', HTMLRendererContrib); -NotebookRegistry.registerOutputTransform('svg', SVGRendererContrib); -NotebookRegistry.registerOutputTransform('markdown', MdRendererContrib); -NotebookRegistry.registerOutputTransform('png', PNGRendererContrib); -NotebookRegistry.registerOutputTransform('jpeg', JPEGRendererContrib); -NotebookRegistry.registerOutputTransform('plain', PlainTextRendererContrib); -NotebookRegistry.registerOutputTransform('code', CodeRendererContrib); -NotebookRegistry.registerOutputTransform('error-trace', ErrorRendererContrib); -NotebookRegistry.registerOutputTransform('stream-text', StreamRendererContrib); -NotebookRegistry.registerOutputTransform('stderr', StderrRendererContrib); - -export function getOutputSimpleEditorOptions(): IEditorOptions { +OutputRendererRegistry.registerOutputTransform(JSONRendererContrib); +OutputRendererRegistry.registerOutputTransform(JavaScriptRendererContrib); +OutputRendererRegistry.registerOutputTransform(HTMLRendererContrib); +OutputRendererRegistry.registerOutputTransform(MdRendererContrib); +OutputRendererRegistry.registerOutputTransform(ImgRendererContrib); +OutputRendererRegistry.registerOutputTransform(PlainTextRendererContrib); +OutputRendererRegistry.registerOutputTransform(CodeRendererContrib); +OutputRendererRegistry.registerOutputTransform(JSErrorRendererContrib); +OutputRendererRegistry.registerOutputTransform(StreamRendererContrib); +OutputRendererRegistry.registerOutputTransform(StderrRendererContrib); + +// --- utils --- +function getStringValue(item: IOutputItemDto): string { + // todo@jrieken NOT proper, should be VSBuffer + return new TextDecoder().decode(new Uint8Array(item.valueBytes)); +} + +function getOutputSimpleEditorOptions(): IEditorConstructionOptions { return { + dimension: { height: 0, width: 0 }, readOnly: true, wordWrap: 'on', overviewRulerLanes: 0, @@ -464,6 +372,7 @@ export function getOutputSimpleEditorOptions(): IEditorOptions { lineNumbers: 'off', scrollbar: { alwaysConsumeMouseWheel: false - } + }, + automaticLayout: true, }; } diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/view/output/transforms/textHelper.ts b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/textHelper.ts similarity index 79% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/view/output/transforms/textHelper.ts rename to src/vs/workbench/contrib/notebook/browser/view/output/transforms/textHelper.ts index 397636c09f45..81c0c88a7d02 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/view/output/transforms/textHelper.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/textHelper.ts @@ -12,14 +12,17 @@ import { Range } from 'vs/editor/common/core/range'; import { PieceTreeTextBufferBuilder } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { handleANSIOutput } from 'vs/workbench/contrib/debug/browser/debugANSIHandling'; import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector'; +import { CellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { Schemas } from 'vs/base/common/network'; +import { URI } from 'vs/base/common/uri'; +import { IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; const SIZE_LIMIT = 65535; const LINES_LIMIT = 500; -function generateViewMoreElement(outputs: string[], openerService: IOpenerService, textFileService: ITextFileService) { +function generateViewMoreElement(notebookUri: URI, cellViewModel: IGenericCellViewModel, outputs: string[], openerService: IOpenerService) { const md: IMarkdownString = { value: '[show more (open the raw output data in a text editor) ...](command:workbench.action.openLargeOutput)', isTrusted: true, @@ -30,14 +33,7 @@ function generateViewMoreElement(outputs: string[], openerService: IOpenerServic actionHandler: { callback: (content) => { if (content === 'command:workbench.action.openLargeOutput') { - return textFileService.untitled.resolve({ - associatedResource: undefined, - mode: 'plaintext', - initialValue: outputs.join('') - }).then(model => { - const resource = model.resource; - openerService.open(resource); - }); + openerService.open(CellUri.generateCellUri(notebookUri, cellViewModel.handle, Schemas.vscodeNotebookCellOutput)); } return; @@ -50,7 +46,7 @@ function generateViewMoreElement(outputs: string[], openerService: IOpenerServic return element; } -export function truncatedArrayOfString(container: HTMLElement, outputs: string[], linkDetector: LinkDetector, openerService: IOpenerService, textFileService: ITextFileService, themeService: IThemeService) { +export function truncatedArrayOfString(notebookUri: URI, cellViewModel: IGenericCellViewModel, container: HTMLElement, outputs: string[], linkDetector: LinkDetector, openerService: IOpenerService, themeService: IThemeService) { const fullLen = outputs.reduce((p, c) => { return p + c.length; }, 0); @@ -68,7 +64,7 @@ export function truncatedArrayOfString(container: HTMLElement, outputs: string[] const truncatedText = buffer.getValueInRange(new Range(1, 1, sizeBufferLimitPosition.lineNumber, sizeBufferLimitPosition.column), EndOfLinePreference.TextDefined); container.appendChild(handleANSIOutput(truncatedText, linkDetector, themeService, undefined)); // view more ... - container.appendChild(generateViewMoreElement(outputs, openerService, textFileService)); + container.appendChild(generateViewMoreElement(notebookUri, cellViewModel, outputs, openerService)); return; } } @@ -92,7 +88,7 @@ export function truncatedArrayOfString(container: HTMLElement, outputs: string[] pre.appendChild(handleANSIOutput(buffer.getValueInRange(new Range(1, 1, LINES_LIMIT - 5, buffer.getLineLastNonWhitespaceColumn(LINES_LIMIT - 5)), EndOfLinePreference.TextDefined), linkDetector, themeService, undefined)); // view more ... - container.appendChild(generateViewMoreElement(outputs, openerService, textFileService)); + container.appendChild(generateViewMoreElement(notebookUri, cellViewModel, outputs, openerService)); const lineCount = buffer.getLineCount(); const pre2 = DOM.$('div'); diff --git a/lib/vscode/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts similarity index 77% rename from lib/vscode/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts rename to src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 3cc75f4b805e..a04712afd062 100644 --- a/lib/vscode/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -24,14 +24,15 @@ import { IFileService } from 'vs/platform/files/common/files'; import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { asWebviewUri } from 'vs/workbench/api/common/shared/webview'; import { CellEditState, ICellOutputViewModel, ICommonCellInfo, ICommonNotebookEditor, IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { preloadsScriptStr } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads'; +import { PreloadOptions, preloadsScriptStr, RendererMetadata } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads'; import { transformWebviewThemeVars } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewThemeMapping'; import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel'; -import { INotebookRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookKernel, INotebookRendererInfo, RendererMessagingSpec } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { IScopedRendererMessaging } from 'vs/workbench/contrib/notebook/common/notebookRendererMessagingService'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IWebviewService, WebviewContentPurpose, WebviewElement } from 'vs/workbench/contrib/webview/browser/webview'; -import { asWebviewUri } from 'vs/workbench/contrib/webview/common/webviewUri'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; interface BaseToWebviewMessage { @@ -131,17 +132,13 @@ export interface IToggleMarkdownPreviewMessage extends BaseToWebviewMessage { export interface ICellDragStartMessage extends BaseToWebviewMessage { type: 'cell-drag-start'; readonly cellId: string; - readonly position: { - readonly clientY: number; - }; + readonly dragOffsetY: number; } export interface ICellDragMessage extends BaseToWebviewMessage { type: 'cell-drag'; readonly cellId: string; - readonly position: { - readonly clientY: number; - }; + readonly dragOffsetY: number; } export interface ICellDropMessage extends BaseToWebviewMessage { @@ -149,9 +146,7 @@ export interface ICellDropMessage extends BaseToWebviewMessage { readonly cellId: string; readonly ctrlKey: boolean readonly altKey: boolean; - readonly position: { - readonly clientY: number; - }; + readonly dragOffsetY: number; } export interface ICellDragEndMessage extends BaseToWebviewMessage { @@ -197,15 +192,15 @@ export interface ICreationRequestMessage { type: 'html'; content: | { type: RenderOutputType.Html; htmlContent: string } - | { type: RenderOutputType.Extension; outputId: string; value: unknown; metadata: unknown; mimeType: string }; + | { type: RenderOutputType.Extension; outputId: string; valueBytes: Uint8Array, metadata: unknown; metadata2: unknown, mimeType: string }; cellId: string; outputId: string; cellTop: number; outputOffset: number; left: number; - requiredPreloads: ReadonlyArray; + requiredPreloads: ReadonlyArray; readonly initiallyHidden?: boolean; - apiNamespace?: string | undefined; + rendererId?: string | undefined; } export interface IContentWidgetTopRequest { @@ -234,7 +229,7 @@ export interface IClearOutputRequestMessage { cellId: string; outputId: string; cellUri: string; - apiNamespace: string | undefined; + rendererId: string | undefined; } export interface IHideOutputMessage { @@ -263,15 +258,15 @@ export interface IAckOutputHeightMessage { height: number; } -export interface IPreloadResource { + +export interface IControllerPreload { originalUri: string; uri: string; } -export interface IUpdatePreloadResourceMessage { +export interface IUpdateControllerPreloadsMessage { type: 'preload'; - resources: IPreloadResource[]; - source: 'renderer' | 'kernel'; + resources: IControllerPreload[]; } export interface IUpdateDecorationsMessage { @@ -281,6 +276,11 @@ export interface IUpdateDecorationsMessage { removedClassNames: string[]; } +export interface ICustomKernelMessage extends BaseToWebviewMessage { + type: 'customKernelMessage'; + message: unknown; +} + export interface ICustomRendererMessage extends BaseToWebviewMessage { type: 'customRendererMessage'; rendererId: string; @@ -289,10 +289,7 @@ export interface ICustomRendererMessage extends BaseToWebviewMessage { export interface ICreateMarkdownMessage { type: 'createMarkdownPreview', - id: string; - handle: number; - content: string; - top: number; + cell: IMarkdownCellInitialization; } export interface IDeleteMarkdownMessage { type: 'deleteMarkdownPreview', @@ -322,9 +319,29 @@ export interface IUpdateSelectedMarkdownPreviews { readonly selectedCellIds: readonly string[] } +export interface IMarkdownCellInitialization { + cellId: string; + cellHandle: number; + content: string; + offset: number; + visible: boolean; +} + export interface IInitializeMarkdownMessage { type: 'initializeMarkdownPreview'; - cells: Array<{ cellId: string, cellHandle: number, content: string, offset: number }>; + cells: ReadonlyArray; +} + +export interface INotebookStylesMessage { + type: 'notebookStyles'; + styles: { + [key: string]: string; + }; +} + +export interface INotebookOptionsMessage { + type: 'notebookOptions'; + options: PreloadOptions; } export type FromWebviewMessage = @@ -337,6 +354,7 @@ export type FromWebviewMessage = | IWheelMessage | IScrollAckMessage | IBlurOutputMessage + | ICustomKernelMessage | ICustomRendererMessage | IClickedDataUrlMessage | IClickMarkdownPreviewMessage @@ -363,8 +381,9 @@ export type ToWebviewMessage = | IClearOutputRequestMessage | IHideOutputMessage | IShowOutputMessage - | IUpdatePreloadResourceMessage + | IUpdateControllerPreloadsMessage | IUpdateDecorationsMessage + | ICustomKernelMessage | ICustomRendererMessage | ICreateMarkdownMessage | IDeleteMarkdownMessage @@ -372,7 +391,9 @@ export type ToWebviewMessage = | IHideMarkdownMessage | IUnhideMarkdownMessage | IUpdateSelectedMarkdownPreviews - | IInitializeMarkdownMessage; + | IInitializeMarkdownMessage + | INotebookStylesMessage + | INotebookOptionsMessage; export type AnyMessage = FromWebviewMessage | ToWebviewMessage; @@ -393,7 +414,6 @@ function html(strings: TemplateStringsArray, ...values: any[]): string { export interface INotebookWebviewMessage { message: unknown; - forRenderer?: string; } export interface IResolvedBackLayerWebview { @@ -404,31 +424,34 @@ export class BackLayerWebView extends Disposable { element: HTMLElement; webview: WebviewElement | undefined = undefined; insetMapping: Map> = new Map(); - readonly markdownPreviewMapping = new Map(); + readonly markdownPreviewMapping = new Map(); hiddenInsetMapping: Set = new Set(); reversedInsetMapping: Map = new Map(); localResourceRootsCache: URI[] | undefined = undefined; rendererRootsCache: URI[] = []; - kernelRootsCache: URI[] = []; private readonly _onMessage = this._register(new Emitter()); private readonly _preloadsCache = new Set(); public readonly onMessage: Event = this._onMessage.event; - private _loaded!: Promise; private _initalized?: Promise; private _disposed = false; + private _currentKernel?: INotebookKernel; constructor( - public notebookEditor: ICommonNotebookEditor, - public id: string, - public documentUri: URI, - public options: { + public readonly notebookEditor: ICommonNotebookEditor, + public readonly id: string, + public readonly documentUri: URI, + private options: { outputNodePadding: number, outputNodeLeftPadding: number, previewNodePadding: number, + markdownLeftMargin: number, leftMargin: number, rightMargin: number, runGutter: number, + dragAndDropEnabled: boolean, + fontSize: number }, + private readonly rendererMessaging: IScopedRendererMessaging | undefined, @IWebviewService readonly webviewService: IWebviewService, @IOpenerService readonly openerService: IOpenerService, @INotebookService private readonly notebookService: INotebookService, @@ -447,11 +470,67 @@ export class BackLayerWebView extends Disposable { this.element.style.height = '1400px'; this.element.style.position = 'absolute'; + + if (rendererMessaging) { + this._register(rendererMessaging.onDidReceiveMessage(evt => { + this._sendMessageToWebview({ + __vscode_notebook_message: true, + type: 'customRendererMessage', + rendererId: evt.rendererId, + message: evt.message + }); + })); + } + } + + updateOptions(options: { + outputNodePadding: number, + outputNodeLeftPadding: number, + previewNodePadding: number, + markdownLeftMargin: number, + leftMargin: number, + rightMargin: number, + runGutter: number, + dragAndDropEnabled: boolean, + fontSize: number + }) { + this.options = options; + this._updateStyles(); + this._updateOptions(); + } + + private _updateStyles() { + this._sendMessageToWebview({ + type: 'notebookStyles', + styles: this._generateStyles() + }); } + + private _updateOptions() { + this._sendMessageToWebview({ + type: 'notebookOptions', + options: { + dragAndDropEnabled: this.options.dragAndDropEnabled + } + }); + } + + private _generateStyles() { + return { + 'notebook-output-left-margin': `${this.options.leftMargin + this.options.runGutter}px`, + 'notebook-output-width': `calc(100% - ${this.options.leftMargin + this.options.rightMargin + this.options.runGutter}px)`, + 'notebook-output-node-padding': `${this.options.outputNodePadding}px`, + 'notebook-run-gutter': `${this.options.runGutter}px`, + 'notebook-preivew-node-padding': `${this.options.previewNodePadding}px`, + 'notebook-markdown-left-margin': `${this.options.markdownLeftMargin}px`, + 'notebook-output-node-left-padding': `${this.options.outputNodeLeftPadding}px`, + 'notebook-markdown-min-height': `${this.options.previewNodePadding * 2}px`, + 'notebook-cell-output-font-size': `${this.options.fontSize}px` + }; + } + private generateContent(coreDependencies: string, baseUrl: string) { - const markupRenderer = this.getMarkdownRenderer(); - const outputWidth = `calc(100% - ${this.options.leftMargin + this.options.rightMargin + this.options.runGutter}px)`; - const outputMarginLeft = `${this.options.leftMargin + this.options.runGutter}px`; + const renderersData = this.getRendererData(); return html` @@ -533,7 +612,7 @@ export class BackLayerWebView extends Disposable { /* makes all markdown cells consistent */ div { - min-height: ${this.options.previewNodePadding * 2}px; + min-height: var(--notebook-markdown-min-height); } table { @@ -580,22 +659,8 @@ export class BackLayerWebView extends Disposable { white-space: pre-wrap; } - .latex-block { - display: block; - } - - .latex { - vertical-align: middle; - display: inline-block; - } - - .latex img, - .latex-block img { - filter: brightness(0) invert(0) - } - dragging { - background-color: var(--vscode-editor-background); + background-color: var(--theme-background); } @@ -609,31 +674,37 @@ export class BackLayerWebView extends Disposable { } #container > div > div > div.output { - width: ${outputWidth}; - margin-left: ${outputMarginLeft}; - padding: ${this.options.outputNodePadding}px ${this.options.outputNodePadding}px ${this.options.outputNodePadding}px ${this.options.outputNodeLeftPadding}px; + font-size: var(--notebook-cell-output-font-size); + width: var(--notebook-output-width); + margin-left: var(--notebook-output-left-margin); + padding-top: var(--notebook-output-node-padding); + padding-right: var(--notebook-output-node-padding); + padding-bottom: var(--notebook-output-node-padding); + padding-left: var(--notebook-output-node-left-padding); box-sizing: border-box; - background-color: var(--vscode-notebook-outputContainerBackgroundColor); + background-color: var(--theme-notebook-output-background); } /* markdown */ #container > div.preview { width: 100%; - padding-right: ${this.options.previewNodePadding}px; - padding-left: ${this.options.leftMargin}px; - padding-top: ${this.options.previewNodePadding}px; - padding-bottom: ${this.options.previewNodePadding}px; + padding-right: var(--notebook-preivew-node-padding); + padding-left: var(--notebook-markdown-left-margin); + padding-top: var(--notebook-preivew-node-padding); + padding-bottom: var(--notebook-preivew-node-padding); box-sizing: border-box; white-space: nowrap; overflow: hidden; + white-space: initial; + color: var(--theme-ui-foreground); + } + + #container > div.preview.draggable { user-select: none; -webkit-user-select: none; -ms-user-select: none; - white-space: initial; cursor: grab; - - color: var(--vscode-foreground); } #container > div.preview.emptyMarkdownCell::before { @@ -643,11 +714,11 @@ export class BackLayerWebView extends Disposable { } #container > div.preview.selected { - background: var(--vscode-notebook-selectedCellBackground); + background: var(--theme-notebook-cell-selected-background); } #container > div.preview.dragging { - background-color: var(--vscode-editor-background); + background-color: var(--theme-background); } .monaco-workbench.vs-dark .notebookOverlay .cell.markdown .latex img, @@ -655,16 +726,16 @@ export class BackLayerWebView extends Disposable { filter: brightness(0) invert(1) } - #container > div.nb-symbolHighlight > div { - background-color: var(--vscode-notebook-symbolHighlightBackground); + #container > div.nb-symbolHighlight { + background-color: var(--theme-notebook-symbol-highlight-background); } - #container > div.nb-cellDeleted > div { - background-color: var(--vscode-diffEditor-removedTextBackground); + #container > div.nb-cellDeleted { + background-color: var(--theme-notebook-diff-removed-background); } - #container > div.nb-cellAdded > div { - background-color: var(--vscode-diffEditor-insertedTextBackground); + #container > div.nb-cellAdded { + background-color: var(--theme-notebook-diff-inserted-background); } #container > div > div:not(.preview) > div { @@ -717,50 +788,33 @@ export class BackLayerWebView extends Disposable { ${coreDependencies}
    - + `; } - private getMarkdownRenderer(): Array<{ entrypoint: string, dependencies: Array<{ entrypoint: string }> }> { - const allRenderers = this.notebookService.getMarkupRendererInfo(); - - const topLevelMarkdownRenderers = allRenderers - .filter(renderer => !renderer.dependsOn) - .filter(renderer => renderer.mimeTypes?.includes('text/markdown')); - - const subRenderers = new Map>(); - for (const renderer of allRenderers) { - if (renderer.dependsOn) { - if (!subRenderers.has(renderer.dependsOn)) { - subRenderers.set(renderer.dependsOn, []); - } - const entryPoint = asWebviewUri(this.environmentService, this.id, renderer.entrypoint); - subRenderers.get(renderer.dependsOn)!.push({ entrypoint: entryPoint.toString(true) }); - } - } - - return topLevelMarkdownRenderers.map((renderer) => { - const src = asWebviewUri(this.environmentService, this.id, renderer.entrypoint); + private getRendererData(): RendererMetadata[] { + return this.notebookService.getRenderers().map((renderer): RendererMetadata => { + const entrypoint = this.asWebviewUri(renderer.entrypoint, renderer.extensionLocation).toString(); return { - entrypoint: src.toString(), - dependencies: subRenderers.get(renderer.id) || [], + id: renderer.id, + entrypoint, + mimeTypes: renderer.mimeTypes, + extends: renderer.extends, + messaging: renderer.messaging !== RendererMessagingSpec.Never, }; }); } - postRendererMessage(rendererId: string, message: any) { + private asWebviewUri(uri: URI, fromExtension: URI | undefined) { + return asWebviewUri(uri, fromExtension?.scheme === Schemas.vscodeRemote ? { isRemote: true, authority: fromExtension.authority } : undefined); + } + + postKernelMessage(message: any) { this._sendMessageToWebview({ __vscode_notebook_message: true, - type: 'customRendererMessage', + type: 'customKernelMessage', message, - rendererId }); } @@ -779,6 +833,16 @@ export class BackLayerWebView extends Disposable { } async createWebview(): Promise { + const baseUrl = this.asWebviewUri(dirname(this.documentUri), undefined); + + // Python hasn't moved to use a preload to load require support yet. + // For all other notebooks, we no longer want to include our loader. + if (!this.documentUri.path.toLowerCase().endsWith('.ipynb')) { + const htmlContent = this.generateContent('', baseUrl.toString()); + this._initialize(htmlContent); + return; + } + let coreDependencies = ''; let resolveFunc: () => void; @@ -786,11 +850,10 @@ export class BackLayerWebView extends Disposable { resolveFunc = resolve; }); - const baseUrl = asWebviewUri(this.environmentService, this.id, dirname(this.documentUri)); if (!isWeb) { const loaderUri = FileAccess.asFileUri('vs/loader.js', require); - const loader = asWebviewUri(this.environmentService, this.id, loaderUri); + const loader = this.asWebviewUri(loaderUri, undefined); coreDependencies = ` `; } @@ -674,7 +901,7 @@ export class GettingStartedPage extends EditorPane { $('button.button-link', { 'x-dispatch': 'selectCategory:' + entry.id, - title: entry.description + this.getKeybindingLabel(entry.content.command), + title: entry.description + ' ' + this.getKeybindingLabel(entry.content.command), }, this.iconWidgetFor(entry), $('span', {}, entry.title))); @@ -749,6 +976,8 @@ export class GettingStartedPage extends EditorPane { this.gettingStartedList?.layout(size); this.recentlyOpenedList?.layout(size); + this.layoutMarkdown?.(); + this.container.classList[size.height <= 600 ? 'add' : 'remove']('height-constrained'); this.container.classList[size.width <= 400 ? 'add' : 'remove']('width-constrained'); this.container.classList[size.width <= 800 ? 'add' : 'remove']('width-semi-constrained'); @@ -772,22 +1001,26 @@ export class GettingStartedPage extends EditorPane { bar.setAttribute('aria-valuemin', '0'); bar.setAttribute('aria-valuenow', '' + numDone); bar.setAttribute('aria-valuemax', '' + numTotal); - const progress = Math.max((numDone / numTotal) * 100, 3); + const progress = (numDone / numTotal) * 100; bar.style.width = `${progress}%`; + + (element.parentElement as HTMLElement).classList[numDone === 0 ? 'add' : 'remove']('no-progress'); + if (numTotal === numDone) { - bar.title = `All steps complete!`; + bar.title = localize('gettingStarted.allStepsComplete', "All {0} steps complete!", numTotal); } else { - bar.title = `${numDone} of ${numTotal} steps complete`; + bar.title = localize('gettingStarted.someStepsComplete', "{0} of {1} steps complete", numDone, numTotal); } }); } - private async scrollToCategory(categoryID: string) { + private async scrollToCategory(categoryID: string, stepId?: string) { this.inProgressScroll = this.inProgressScroll.then(async () => { reset(this.stepsContent); this.editorInput.selectedCategory = categoryID; + this.editorInput.selectedStep = stepId; this.currentCategory = this.gettingStartedCategories.find(category => category.id === categoryID); this.buildCategorySlide(categoryID); this.setSlide('details'); @@ -845,6 +1078,10 @@ export class GettingStartedPage extends EditorPane { } this.openerService.open(command, { allowCommands: true }); + if (!isCommand && (node.href.startsWith('https://') || node.href.startsWith('http://'))) { + this.gettingStartedService.progressByEvent('onLink:' + node.href); + } + }, null, this.detailsPageDisposables); if (isCommand) { @@ -862,11 +1099,10 @@ export class GettingStartedPage extends EditorPane { if (typeof node === 'string') { append(p, renderFormattedText(node, { inline: true, renderCodeSegements: true })); } else { - const link = this.instantiationService.createInstance(Link, node); + const link = this.instantiationService.createInstance(Link, node, {}); append(p, link.el); this.detailsPageDisposables.add(link); - this.detailsPageDisposables.add(attachLinkStyler(link, this.themeService)); } } } @@ -931,14 +1167,26 @@ export class GettingStartedPage extends EditorPane { stepDescription); }); - const stepsContainer = $('.getting-started-detail-container', { 'role': 'list' }, ...categoryElements); + const showNextCategory = + this.gettingStartedCategories.find(_category => _category.id === category.next && _category.content.type === 'steps' && !_category.content.done); + + const stepsContainer = $( + '.getting-started-detail-container', { 'role': 'list' }, + ...categoryElements, + $('.done-next-container', {}, + $('button.button-link.all-done', { 'x-dispatch': 'allDone' }, $('span.codicon.codicon-check-all'), localize('allDone', "Mark Done")), + ...(showNextCategory + ? [$('button.button-link.next', { 'x-dispatch': 'nextSection' }, localize('nextOne', "Next Section"), $('span.codicon.codicon-arrow-small-right'))] + : []), + ) + ); this.detailsScrollbar = this._register(new DomScrollableElement(stepsContainer, { className: 'steps-container' })); const stepListComponent = this.detailsScrollbar.getDomNode(); reset(this.stepsContent, categoryDescriptorComponent, stepListComponent, this.stepMediaComponent); const toExpand = category.content.steps.find(step => !step.done) ?? category.content.steps[0]; - this.selectStep(selectedStep ?? toExpand.id, false); + this.selectStep(selectedStep ?? toExpand.id, !selectedStep, true); this.detailsScrollbar.scanDomNode(); this.detailsPageScrollbar?.scanDomNode(); @@ -962,6 +1210,7 @@ export class GettingStartedPage extends EditorPane { this.editorInput.selectedStep = undefined; this.selectStep(undefined); this.setSlide('categories'); + this.container.focus(); }); } @@ -983,7 +1232,7 @@ export class GettingStartedPage extends EditorPane { if (allSteps) { const toFind = this.editorInput.selectedStep ?? this.previousSelection; const selectedIndex = allSteps.findIndex(step => step.id === toFind); - if (allSteps[selectedIndex + 1]?.id) { this.selectStep(allSteps[selectedIndex + 1]?.id, true, false); } + if (allSteps[selectedIndex + 1]?.id) { this.selectStep(allSteps[selectedIndex + 1]?.id, false); } } } else { (document.activeElement?.nextElementSibling as HTMLElement)?.focus?.(); @@ -996,7 +1245,7 @@ export class GettingStartedPage extends EditorPane { if (allSteps) { const toFind = this.editorInput.selectedStep ?? this.previousSelection; const selectedIndex = allSteps.findIndex(step => step.id === toFind); - if (allSteps[selectedIndex - 1]?.id) { this.selectStep(allSteps[selectedIndex - 1]?.id, true, false); } + if (allSteps[selectedIndex - 1]?.id) { this.selectStep(allSteps[selectedIndex - 1]?.id, false); } } } else { (document.activeElement?.previousElementSibling as HTMLElement)?.focus?.(); @@ -1011,7 +1260,6 @@ export class GettingStartedPage extends EditorPane { this.container.querySelector('.gettingStartedSlideDetails')!.querySelectorAll('button').forEach(button => button.disabled = true); this.container.querySelector('.gettingStartedSlideCategories')!.querySelectorAll('button').forEach(button => button.disabled = false); this.container.querySelector('.gettingStartedSlideCategories')!.querySelectorAll('input').forEach(button => button.disabled = false); - this.container.focus(); } else { slideManager.classList.add('showDetails'); slideManager.classList.remove('showCategories'); @@ -1020,6 +1268,10 @@ export class GettingStartedPage extends EditorPane { this.container.querySelector('.gettingStartedSlideCategories')!.querySelectorAll('input').forEach(button => button.disabled = true); } } + + override focus() { + this.container.focus(); + } } export class GettingStartedInputSerializer implements IEditorInputSerializer { @@ -1052,6 +1304,8 @@ class GettingStartedIndexList extends Disposable { public itemCount: number; + private isDisposed = false; + constructor( title: string, klass: string, @@ -1083,7 +1337,12 @@ class GettingStartedIndexList extends Disposable { this._register(this.onDidChangeEntries(listener)); } - register(d: IDisposable) { this._register(d); } + register(d: IDisposable) { if (this.isDisposed) { d.dispose(); } else { this._register(d); } } + + override dispose() { + this.isDisposed = true; + super.dispose(); + } setLimit(limit: number) { this.limit = limit; @@ -1191,7 +1450,7 @@ registerThemingParticipant((theme, collector) => { if (link) { collector.addRule(`.monaco-workbench .part.editor > .content .gettingStartedContainer a:not(.codicon-close) { color: ${link}; }`); collector.addRule(`.monaco-workbench .part.editor > .content .gettingStartedContainer .button-link { color: ${link}; }`); - collector.addRule(`.monaco-workbench .part.editor > .content .gettingStartedContainer .button-link .scroll-button { color: ${link}; }`); + collector.addRule(`.monaco-workbench .part.editor > .content .gettingStartedContainer .button-link .codicon { color: ${link}; }`); } const activeLink = theme.getColor(textLinkActiveForeground); if (activeLink) { diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts similarity index 69% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts rename to src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts index ae51f02cf0a9..d3cc402e9055 100644 --- a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts @@ -11,7 +11,7 @@ export const walkthroughsExtensionPoint = ExtensionsRegistry.registerExtensionPo extensionPoint: 'walkthroughs', jsonSchema: { doNotSuggest: true, - description: localize('walkthroughs', "Contribute collections of steps to help users with your extension. Experimental, available in VS Code Insiders only."), + description: localize('walkthroughs', "Contribute walkthroughs to help users getting started with your extension."), type: 'array', items: { type: 'object', @@ -31,8 +31,7 @@ export const walkthroughsExtensionPoint = ExtensionsRegistry.registerExtensionPo description: localize('walkthroughs.description', "Description of walkthrough.") }, primary: { - type: 'boolean', - description: localize('walkthroughs.primary', "if this is a `primary` walkthrough, hinting if it should be opened on install of the extension. The first `primary` walkthough with a `when` condition matching the current context may be opened by core on install of the extension.") + deprecationMessage: localize('walkthroughs.primary.deprecated', "Deprecated. The first walkthrough with a satisfied when condition will be opened on install.") }, when: { type: 'string', @@ -46,11 +45,11 @@ export const walkthroughsExtensionPoint = ExtensionsRegistry.registerExtensionPo description: localize('walkthroughs.steps', "Steps to complete as part of this walkthrough."), items: { type: 'object', - required: ['id', 'title', 'description', 'media'], + required: ['id', 'title', 'media'], defaultSnippets: [{ body: { 'id': '$1', 'title': '$2', 'description': '$3', - 'doneOn': { 'command': '$5' }, + 'completionEvents': ['$5'], 'media': { 'path': '$6', 'type': '$7' } } }], @@ -76,10 +75,13 @@ export const walkthroughsExtensionPoint = ExtensionsRegistry.registerExtensionPo defaultSnippets: [{ 'body': { 'type': '$1', 'path': '$2' } }], oneOf: [ { - required: ['path', 'altText'], + required: ['image', 'altText'], additionalProperties: false, properties: { path: { + deprecationMessage: localize('pathDeprecated', "Deprecated. Please use `image` or `markdown` instead") + }, + image: { description: localize('walkthroughs.steps.media.image.path.string', "Path to an image - or object consisting of paths to light, dark, and hc images - relative to extension directory. Depending on context, the image will be displayed from 400px to 800px wide, with similar bounds on height. To support HIDPI displays, the image will be rendered at 1.5x scaling, for example a 900 physical pixels wide image will be displayed as 600 logical pixels wide."), oneOf: [ { @@ -111,10 +113,13 @@ export const walkthroughsExtensionPoint = ExtensionsRegistry.registerExtensionPo } } }, { - required: ['path'], + required: ['markdown'], additionalProperties: false, properties: { path: { + deprecationMessage: localize('pathDeprecated', "Deprecated. Please use `image` or `markdown` instead") + }, + markdown: { description: localize('walkthroughs.steps.media.markdown.path', "Path to the markdown document, relative to extension directory."), type: 'string', } @@ -122,8 +127,53 @@ export const walkthroughsExtensionPoint = ExtensionsRegistry.registerExtensionPo } ] }, + completionEvents: { + description: localize('walkthroughs.steps.completionEvents', "Events that should trigger this step to become checked off. If empty or not defined, the step will check off when any of the step's buttons or links are clicked; if the step has no buttons or links it will check on when it is selected."), + type: 'array', + items: { + type: 'string', + defaultSnippets: [ + { + label: 'onCommand', + description: localize('walkthroughs.steps.completionEvents.onCommand', 'Check off step when a given command is executed anywhere in VS Code.'), + body: 'onCommand:${1:commandId}' + }, + { + label: 'onLink', + description: localize('walkthroughs.steps.completionEvents.onLink', 'Check off step when a given link is opened via a Getting Started step.'), + body: 'onLink:${2:linkId}' + }, + { + label: 'onView', + description: localize('walkthroughs.steps.completionEvents.onView', 'Check off step when a given view is opened'), + body: 'onView:${2:viewId}' + }, + { + label: 'onSettingChanged', + description: localize('walkthroughs.steps.completionEvents.onSettingChanged', 'Check off step when a given setting is changed'), + body: 'onSettingChanged:${2:settingName}' + }, + { + label: 'onContext', + description: localize('walkthroughs.steps.completionEvents.onContext', 'Check off step when a context key expression is true.'), + body: 'onContext:${2:key}' + }, + { + label: 'extensionInstalled', + description: localize('walkthroughs.steps.completionEvents.extensionInstalled', 'Check off step when an extension with the given id is installed. If the extension is already installed, the step will start off checked.'), + body: 'extensionInstalled:${3:extensionId}' + }, + { + label: 'stepSelected', + description: localize('walkthroughs.steps.completionEvents.stepSelected', 'Check off step as soon as it is selected.'), + body: 'stepSelected' + }, + ] + } + }, doneOn: { description: localize('walkthroughs.steps.doneOn', "Signal to mark step as complete."), + deprecationMessage: localize('walkthroughs.steps.doneOn.deprecation', "doneOn is deprecated. By default steps will be checked off when their buttons are clicked, to configure further use completionEvents"), type: 'object', required: ['command'], defaultSnippets: [{ 'body': { command: '$1' } }], diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedIcons.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedIcons.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedIcons.ts rename to src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedIcons.ts diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedInput.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedInput.ts similarity index 85% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedInput.ts rename to src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedInput.ts index a6639f10062c..fab174551d91 100644 --- a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedInput.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedInput.ts @@ -5,7 +5,7 @@ import 'vs/css!./gettingStarted'; import { localize } from 'vs/nls'; -import { EditorInput } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; @@ -14,13 +14,14 @@ export const gettingStartedInputTypeId = 'workbench.editors.gettingStartedInput' export class GettingStartedInput extends EditorInput { static readonly ID = gettingStartedInputTypeId; + static readonly RESOURCE = URI.from({ scheme: Schemas.walkThrough, authority: 'vscode_getting_started_page' }); override get typeId(): string { return GettingStartedInput.ID; } get resource(): URI | undefined { - return URI.from({ scheme: Schemas.walkThrough, authority: 'vscode_getting_started_page' }); + return GettingStartedInput.RESOURCE; } override matches(other: unknown) { diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedService.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedService.ts similarity index 58% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedService.ts rename to src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedService.ts index 3ed42ffabc31..8153b4273bdb 100644 --- a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedService.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedService.ts @@ -3,13 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator, IInstantiationService, optional, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator, optional, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { Emitter, Event } from 'vs/base/common/event'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { Memento } from 'vs/workbench/common/memento'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { ContextKeyExpr, ContextKeyExpression, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, ContextKeyExpression, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { Disposable } from 'vs/base/common/lifecycle'; import { IUserDataAutoSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync'; import { IExtensionDescription, IStartEntry } from 'vs/platform/extensions/common/extensions'; @@ -23,15 +23,18 @@ import { BuiltinGettingStartedCategory, BuiltinGettingStartedStep, BuiltinGettin import { ITASExperimentService } from 'vs/workbench/services/experiment/common/experimentService'; import { assertIsDefined } from 'vs/base/common/types'; import { IHostService } from 'vs/workbench/services/host/browser/host'; -import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; -import { GettingStartedInput } from 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedInput'; -import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { GettingStartedPage } from 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { LinkedText, parseLinkedText } from 'vs/base/common/linkedText'; +import { ILink, LinkedText, parseLinkedText } from 'vs/base/common/linkedText'; import { walkthroughsExtensionPoint } from 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { dirname } from 'vs/base/common/path'; +import { coalesce, flatten } from 'vs/base/common/arrays'; +import { IViewsService } from 'vs/workbench/common/views'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { isLinux, isMacintosh, isWindows, OperatingSystem as OS } from 'vs/base/common/platform'; +import { localize } from 'vs/nls'; + +export const WorkspacePlatform = new RawContextKey<'mac' | 'linux' | 'windows' | undefined>('workspacePlatform', undefined, localize('workspacePlatform', "The platform of the current workspace, which in remote contexts may be different from the platform of the UI")); export const IGettingStartedService = createDecorator('gettingStartedService'); @@ -52,10 +55,12 @@ export interface IGettingStartedStep { category: GettingStartedCategory | string when: ContextKeyExpression order: number - doneOn: { commandExecuted: string, eventFired?: never } | { eventFired: string, commandExecuted?: never } + /** @deprecated */ + doneOn?: { commandExecuted: string, eventFired?: never } | { eventFired: string, commandExecuted?: never } + completionEvents: string[] media: | { type: 'image', path: { hc: URI, light: URI, dark: URI }, altText: string } - | { type: 'markdown', path: URI, base: URI, } + | { type: 'markdown', path: URI, base: URI, root: URI } } export interface IGettingStartedWalkthroughDescriptor { @@ -63,6 +68,7 @@ export interface IGettingStartedWalkthroughDescriptor { title: string description: string order: number + next?: string icon: | { type: 'icon', icon: ThemeIcon } | { type: 'image', path: string } @@ -89,6 +95,7 @@ export interface IGettingStartedCategory { title: string description: string order: number + next?: string icon: | { type: 'icon', icon: ThemeIcon } | { type: 'image', path: string } @@ -116,8 +123,9 @@ export interface IGettingStartedCategoryWithProgress extends Omit - readonly onDidRemoveCategory: Event + readonly onDidAddCategory: Event + readonly onDidRemoveCategory: Event + readonly onDidChangeStep: Event readonly onDidChangeCategory: Event @@ -125,19 +133,23 @@ export interface IGettingStartedService { getCategories(): IGettingStartedCategoryWithProgress[] + registerWalkthrough(categoryDescriptor: IGettingStartedWalkthroughDescriptor, steps: IGettingStartedStep[]): void; + progressByEvent(eventName: string): void; progressStep(id: string): void; deprogressStep(id: string): void; + + installedExtensionsRegistered: Promise; } export class GettingStartedService extends Disposable implements IGettingStartedService { declare readonly _serviceBrand: undefined; - private readonly _onDidAddCategory = new Emitter(); - onDidAddCategory: Event = this._onDidAddCategory.event; + private readonly _onDidAddCategory = new Emitter(); + onDidAddCategory: Event = this._onDidAddCategory.event; - private readonly _onDidRemoveCategory = new Emitter(); - onDidRemoveCategory: Event = this._onDidRemoveCategory.event; + private readonly _onDidRemoveCategory = new Emitter(); + onDidRemoveCategory: Event = this._onDidRemoveCategory.event; private readonly _onDidChangeCategory = new Emitter(); onDidChangeCategory: Event = this._onDidChangeCategory.event; @@ -151,8 +163,8 @@ export class GettingStartedService extends Disposable implements IGettingStarted private memento: Memento; private stepProgress: Record; - private commandListeners = new Map(); - private eventListeners = new Map(); + private sessionEvents = new Set(); + private completionListeners = new Map>(); private gettingStartedContributions = new Map(); private steps = new Map(); @@ -160,18 +172,24 @@ export class GettingStartedService extends Disposable implements IGettingStarted private tasExperimentService?: ITASExperimentService; private sessionInstalledExtensions = new Set(); + private categoryVisibilityContextKeys = new Set(); + private stepCompletionContextKeyExpressions = new Set(); + private stepCompletionContextKeys = new Set(); + + private triggerInstalledExtensionsRegistered!: () => void; + installedExtensionsRegistered: Promise; + constructor( @IStorageService private readonly storageService: IStorageService, @ICommandService private readonly commandService: ICommandService, @IContextKeyService private readonly contextService: IContextKeyService, @IUserDataAutoSyncEnablementService readonly userDataAutoSyncEnablementService: IUserDataAutoSyncEnablementService, @IProductService private readonly productService: IProductService, - @IEditorService private readonly editorService: IEditorService, - @IEditorGroupsService private readonly editorGroupsService: IEditorGroupsService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IInstantiationService private readonly instantiationService: IInstantiationService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, @IHostService private readonly hostService: IHostService, + @IViewsService private readonly viewsService: IViewsService, + @IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService, @optional(ITASExperimentService) tasExperimentService: ITASExperimentService, ) { super(); @@ -186,19 +204,67 @@ export class GettingStartedService extends Disposable implements IGettingStarted removed.forEach(e => this.unregisterExtensionContributions(e.description)); }); - this._register(this.commandService.onDidExecuteCommand(command => this.progressByCommand(command.commandId))); + this._register(this.commandService.onDidExecuteCommand(command => this.progressByEvent(`onCommand:${command.commandId}`))); + + this.extensionManagementService.getInstalled().then(installed => { + installed.forEach(ext => this.progressByEvent(`extensionInstalled:${ext.identifier.id.toLowerCase()}`)); + }); this._register(this.extensionManagementService.onDidInstallExtension(async e => { if (await this.hostService.hadLastFocus()) { - this.sessionInstalledExtensions.add(e.identifier.id); + this.sessionInstalledExtensions.add(e.identifier.id.toLowerCase()); + } + this.progressByEvent(`extensionInstalled:${e.identifier.id.toLowerCase()}`); + })); + + this._register(this.contextService.onDidChangeContext(event => { + if (event.affectsSome(this.categoryVisibilityContextKeys)) { this._onDidAddCategory.fire(); } + if (event.affectsSome(this.stepCompletionContextKeys)) { + this.stepCompletionContextKeyExpressions.forEach(expression => { + if (event.affectsSome(new Set(expression.keys())) && this.contextService.contextMatchesRules(expression)) { + this.progressByEvent(`onContext:` + expression.serialize()); + } + }); } })); - if (userDataAutoSyncEnablementService.isEnabled()) { this.progressByEvent('sync-enabled'); } + this._register(this.viewsService.onDidChangeViewVisibility(e => { + if (e.visible) { this.progressByEvent('onView:' + e.id); } + })); + + this._register(this.configurationService.onDidChangeConfiguration(e => { + e.affectedKeys.forEach(key => { this.progressByEvent('onSettingChanged:' + key); }); + })); + + this.remoteAgentService.getEnvironment().then(env => { + const remoteOS = env?.os; + + const remotePlatform = + remoteOS === OS.Macintosh ? 'mac' + : remoteOS === OS.Windows ? 'windows' + : remoteOS === OS.Linux ? 'linux' + : undefined; + + if (remotePlatform) { + WorkspacePlatform.bindTo(this.contextService).set(remotePlatform); + } else if (isMacintosh) { + WorkspacePlatform.bindTo(this.contextService).set('mac'); + } else if (isLinux) { + WorkspacePlatform.bindTo(this.contextService).set('linux'); + } else if (isWindows) { + WorkspacePlatform.bindTo(this.contextService).set('windows'); + } else { + WorkspacePlatform.bindTo(this.contextService).set(undefined); + } + }); + + if (userDataAutoSyncEnablementService.isEnabled()) { this.progressByEvent('onEvent:sync-enabled'); } this._register(userDataAutoSyncEnablementService.onDidChangeEnablement(() => { - if (userDataAutoSyncEnablementService.isEnabled()) { this.progressByEvent('sync-enabled'); } + if (userDataAutoSyncEnablementService.isEnabled()) { this.progressByEvent('onEvent:sync-enabled'); } })); + this.installedExtensionsRegistered = new Promise(r => this.triggerInstalledExtensionsRegistered = r); + startEntries.forEach(async (entry, index) => { this.getCategoryOverrides(entry); this.registerStartEntry({ @@ -221,13 +287,23 @@ export class GettingStartedService extends Disposable implements IGettingStarted this.getStepOverrides(step, category.id); return ({ ...step, + completionEvents: step.completionEvents ?? [], description: parseDescription(step.description), category: category.id, order: index, when: ContextKeyExpr.deserialize(step.when) ?? ContextKeyExpr.true(), media: step.media.type === 'image' - ? { type: 'image', altText: step.media.altText, path: convertInternalMediaPathsToBrowserURIs(step.media.path) } - : { type: 'markdown', path: convertInternalMediaPathToFileURI(step.media.path), base: FileAccess.asFileUri('vs/workbench/contrib/welcome/gettingStarted/common/media/', require) }, + ? { + type: 'image', + altText: step.media.altText, + path: convertInternalMediaPathsToBrowserURIs(step.media.path) + } + : { + type: 'markdown', + path: convertInternalMediaPathToFileURI(step.media.path).with({ query: JSON.stringify({ moduleId: 'vs/workbench/contrib/welcome/gettingStarted/common/media/' + step.media.path }) }), + base: FileAccess.asFileUri('vs/workbench/contrib/welcome/gettingStarted/common/media/', require), + root: FileAccess.asFileUri('vs/workbench/contrib/welcome/gettingStarted/common/media/', require), + }, }); })); }); @@ -270,7 +346,7 @@ export class GettingStartedService extends Disposable implements IGettingStarted this._onDidChangeStep.fire(this.getStepProgress(existingStep)); } - private registerExtensionContributions(extension: IExtensionDescription) { + private async registerExtensionContributions(extension: IExtensionDescription) { const convertExtensionPathToFileURI = (path: string) => path.startsWith('https://') ? URI.parse(path, true) : FileAccess.asFileUri(joinPath(extension.extensionLocation, path)); @@ -292,55 +368,56 @@ export class GettingStartedService extends Disposable implements IGettingStarted } }; - let sectionToOpen: string | undefined; - if (!(extension.contributes?.walkthroughs?.length)) { return; } - if (this.productService.quality === 'stable') { - console.warn('Extension', extension.identifier.value, 'contributes welcome page content but this is a Stable build and extension contributions are only available in Insiders. The contributed content will be disregarded.'); - return; + if (this.configurationService.getValue('workbench.welcomePage.experimental.startEntryContributions') && this.productService.quality !== 'stable') { + extension.contributes.startEntries?.forEach(entry => { + const entryID = extension.identifier.value + '#startEntry#' + idForStartEntry(entry); + this.registerStartEntry({ + content: { + type: 'startEntry', + command: entry.command, + }, + description: entry.description, + title: entry.title, + id: entryID, + order: 0, + when: ContextKeyExpr.deserialize(entry.when) ?? ContextKeyExpr.true(), + icon: { + type: 'image', + path: extension.icon + ? FileAccess.asBrowserUri(joinPath(extension.extensionLocation, extension.icon)).toString(true) + : DefaultIconPath + } + }); + }); } - if (!this.configurationService.getValue('workbench.welcomePage.experimental.extensionContributions')) { - console.warn('Extension', extension.identifier.value, 'contributes welcome page content but the welcome page extension contribution feature flag has not been set. Set `workbench.welcomePage.experimental.extensionContributions` to begin using this experimental feature.'); - return; - } - extension.contributes.startEntries?.forEach(entry => { - const entryID = extension.identifier.value + '#startEntry#' + idForStartEntry(entry); - this.registerStartEntry({ - content: { - type: 'startEntry', - command: entry.command, - }, - description: entry.description, - title: entry.title, - id: entryID, - order: 0, - when: ContextKeyExpr.deserialize(entry.when) ?? ContextKeyExpr.true(), - icon: { - type: 'image', - path: extension.icon - ? FileAccess.asBrowserUri(joinPath(extension.extensionLocation, extension.icon)).toString(true) - : DefaultIconPath - } - }); - }); + let sectionToOpen: string | undefined; + let sectionToOpenIndex = Math.min(); // '+Infinity'; + await Promise.all(extension.contributes?.walkthroughs?.map(async (walkthrough, index) => { + const categoryID = extension.identifier.value + '#' + walkthrough.id; + const override = await Promise.race([ + this.tasExperimentService?.getTreatment(`gettingStarted.overrideCategory.${categoryID}.when`), + new Promise(resolve => setTimeout(() => resolve(walkthrough.when), 5000)) + ]); - extension.contributes?.walkthroughs?.forEach(walkthrough => { - const categoryID = extension.identifier.value + '#walkthrough#' + walkthrough.id; if ( - this.sessionInstalledExtensions.has(extension.identifier.value) - && walkthrough.primary - && this.contextService.contextMatchesRules(ContextKeyExpr.deserialize(walkthrough.when) ?? ContextKeyExpr.true()) + this.sessionInstalledExtensions.has(extension.identifier.value.toLowerCase()) + && this.contextService.contextMatchesRules(ContextKeyExpr.deserialize(override ?? walkthrough.when) ?? ContextKeyExpr.true()) ) { - this.sessionInstalledExtensions.delete(extension.identifier.value); - sectionToOpen = categoryID; + this.sessionInstalledExtensions.delete(extension.identifier.value.toLowerCase()); + if (index < sectionToOpenIndex) { + sectionToOpen = categoryID; + sectionToOpenIndex = index; + } } - this.registerWalkthrough({ + + const walkthoughDescriptior = { content: { type: 'steps' }, description: walkthrough.description, title: walkthrough.title, @@ -352,60 +429,73 @@ export class GettingStartedService extends Disposable implements IGettingStarted ? FileAccess.asBrowserUri(joinPath(extension.extensionLocation, extension.icon)).toString(true) : DefaultIconPath }, - when: ContextKeyExpr.deserialize(walkthrough.when) ?? ContextKeyExpr.true(), - }, - (walkthrough.steps ?? (walkthrough as any).tasks).map((step, index) => { - const description = parseDescription(step.description); - const buttonDescription = (step as any as { button: LegacyButtonConfig }).button; - if (buttonDescription) { - description.push({ nodes: [{ href: buttonDescription.link ?? `command:${buttonDescription.command}`, label: buttonDescription.title }] }); + when: ContextKeyExpr.deserialize(override ?? walkthrough.when) ?? ContextKeyExpr.true(), + } as const; + + const steps = (walkthrough.steps ?? (walkthrough as any).tasks).map((step, index) => { + const description = parseDescription(step.description || ''); + const buttonDescription = (step as any as { button: LegacyButtonConfig }).button; + if (buttonDescription) { + description.push({ nodes: [{ href: buttonDescription.link ?? `command:${buttonDescription.command}`, label: buttonDescription.title }] }); + } + const fullyQualifiedID = extension.identifier.value + '#' + walkthrough.id + '#' + step.id; + + let media: IGettingStartedStep['media']; + + if (step.media.image) { + const altText = (step.media as any).altText; + if (altText === undefined) { + console.error('Getting Started: item', fullyQualifiedID, 'is missing altText for its media element.'); } - const fullyQualifiedID = extension.identifier.value + '#' + walkthrough.id + '#' + step.id; + media = { type: 'image', altText, path: convertExtensionRelativePathsToBrowserURIs(step.media.image) }; + } + else if (step.media.markdown) { + media = { + type: 'markdown', + path: convertExtensionPathToFileURI(step.media.markdown), + base: convertExtensionPathToFileURI(dirname(step.media.markdown)), + root: FileAccess.asFileUri(extension.extensionLocation), + }; + } - let media: IGettingStartedStep['media']; - if (typeof step.media.path === 'string' && step.media.path.endsWith('.md')) { + // Legacy media config + else { + const legacyMedia = step.media as unknown as { path: string, altText: string }; + if (typeof legacyMedia.path === 'string' && legacyMedia.path.endsWith('.md')) { media = { type: 'markdown', - path: convertExtensionPathToFileURI(step.media.path), - base: convertExtensionPathToFileURI(dirname(step.media.path)) + path: convertExtensionPathToFileURI(legacyMedia.path), + base: convertExtensionPathToFileURI(dirname(legacyMedia.path)), + root: FileAccess.asFileUri(extension.extensionLocation), }; - } else { - const altText = (step.media as any).altText; - if (!altText) { + } + else { + const altText = legacyMedia.altText; + if (altText === undefined) { console.error('Getting Started: item', fullyQualifiedID, 'is missing altText for its media element.'); } - media = { type: 'image', altText, path: convertExtensionRelativePathsToBrowserURIs(step.media.path) }; + media = { type: 'image', altText, path: convertExtensionRelativePathsToBrowserURIs(legacyMedia.path) }; } + } - return ({ - description, media, - doneOn: step.doneOn?.command - ? { commandExecuted: step.doneOn.command } - : { eventFired: 'markDone:' + fullyQualifiedID }, - id: fullyQualifiedID, - title: step.title, - when: ContextKeyExpr.deserialize(step.when) ?? ContextKeyExpr.true(), - category: categoryID, - order: index, - }); - })); - }); + return ({ + description, media, + completionEvents: step.completionEvents?.filter(x => typeof x === 'string') ?? [], + id: fullyQualifiedID, + title: step.title, + when: ContextKeyExpr.deserialize(step.when) ?? ContextKeyExpr.true(), + category: categoryID, + order: index, + }); + }); - if (sectionToOpen) { - for (const group of this.editorGroupsService.groups) { - if (group.activeEditor instanceof GettingStartedInput) { - (group.activeEditorPane as GettingStartedPage).makeCategoryVisibleWhenAvailable(sectionToOpen); - return; - } - } + this.registerWalkthrough(walkthoughDescriptior, steps); + })); - if (this.configurationService.getValue('workbench.welcomePage.experimental.extensionContributions') === 'openToSide') { - this.editorService.openEditor(this.instantiationService.createInstance(GettingStartedInput, { selectedCategory: sectionToOpen }), {}, SIDE_GROUP); - } else if (this.configurationService.getValue('workbench.welcomePage.experimental.extensionContributions') === 'open') { - this.editorService.openEditor(this.instantiationService.createInstance(GettingStartedInput, { selectedCategory: sectionToOpen }), {}); - } else if (this.configurationService.getValue('workbench.welcomePage.experimental.extensionContributions') === 'openInBackground') { - this.editorService.openEditor(this.instantiationService.createInstance(GettingStartedInput, { selectedCategory: sectionToOpen }), { inactive: true }); - } + this.triggerInstalledExtensionsRegistered(); + + if (sectionToOpen && this.configurationService.getValue('workbench.welcomePage.walkthroughs.openOnInstall')) { + this.commandService.executeCommand('workbench.action.openWalkthrough', sectionToOpen); } } @@ -417,7 +507,7 @@ export class GettingStartedService extends Disposable implements IGettingStarted extension.contributes?.startEntries?.forEach(section => { const categoryID = extension.identifier.value + '#startEntry#' + idForStartEntry(section); this.gettingStartedContributions.delete(categoryID); - this._onDidRemoveCategory.fire(categoryID); + this._onDidRemoveCategory.fire(); }); extension.contributes?.walkthroughs?.forEach(section => { @@ -427,25 +517,86 @@ export class GettingStartedService extends Disposable implements IGettingStarted this.steps.delete(fullyQualifiedID); }); this.gettingStartedContributions.delete(categoryID); - this._onDidRemoveCategory.fire(categoryID); + this._onDidRemoveCategory.fire(); }); } private registerDoneListeners(step: IGettingStartedStep) { - if (step.doneOn.commandExecuted) { - const existing = this.commandListeners.get(step.doneOn.commandExecuted); - if (existing) { existing.push(step.id); } - else { - this.commandListeners.set(step.doneOn.commandExecuted, [step.id]); - } + if (step.doneOn) { + if (step.doneOn.commandExecuted) { step.completionEvents.push(`onCommand:${step.doneOn.commandExecuted}`); } + if (step.doneOn.eventFired) { step.completionEvents.push(`onEvent:${step.doneOn.eventFired}`); } } - if (step.doneOn.eventFired) { - const existing = this.eventListeners.get(step.doneOn.eventFired); - if (existing) { existing.push(step.id); } - else { - this.eventListeners.set(step.doneOn.eventFired, [step.id]); + + if (!step.completionEvents.length) { + step.completionEvents = coalesce(flatten( + step.description + .filter(linkedText => linkedText.nodes.length === 1) // only buttons + .map(linkedText => + linkedText.nodes + .filter(((node): node is ILink => typeof node !== 'string')) + .map(({ href }) => { + if (href.startsWith('command:')) { + return 'onCommand:' + href.slice('command:'.length, href.includes('?') ? href.indexOf('?') : undefined); + } + if (href.startsWith('https://') || href.startsWith('http://')) { + return 'onLink:' + href; + } + return undefined; + })))); + } + + if (!step.completionEvents.length) { + step.completionEvents.push('stepSelected'); + } + + for (let event of step.completionEvents) { + const [_, eventType, argument] = /^([^:]*):?(.*)$/.exec(event) ?? []; + + if (!eventType) { + console.error(`Unknown completionEvent ${event} when registering step ${step.id}`); + continue; } + + switch (eventType) { + case 'onLink': case 'onEvent': case 'onView': case 'onSettingChanged': + break; + case 'onContext': { + const expression = ContextKeyExpr.deserialize(argument); + if (expression) { + this.stepCompletionContextKeyExpressions.add(expression); + expression.keys().forEach(key => this.stepCompletionContextKeys.add(key)); + event = eventType + ':' + expression.serialize(); + } else { + console.error('Unable to parse context key expression:', expression, 'in getting started step', step.id); + } + break; + } + case 'stepSelected': + event = eventType + ':' + step.id; + break; + case 'onCommand': + event = eventType + ':' + argument.replace(/^toSide:/, ''); + break; + case 'extensionInstalled': + event = eventType + ':' + argument.toLowerCase(); + break; + default: + console.error(`Unknown completionEvent ${event} when registering step ${step.id}`); + continue; + } + + this.registerCompletionListener(event, step); + if (this.sessionEvents.has(event)) { + this.progressStep(step.id); + } + } + } + + private registerCompletionListener(event: string, step: IGettingStartedStep) { + if (!this.completionListeners.has(event)) { + this.completionListeners.set(event, new Set()); } + this.completionListeners.get(event)?.add(step.id); } getCategories(): IGettingStartedCategoryWithProgress[] { @@ -515,14 +666,11 @@ export class GettingStartedService extends Disposable implements IGettingStarted this._onDidProgressStep.fire(this.getStepProgress(step)); } - private progressByCommand(command: string) { - const listening = this.commandListeners.get(command) ?? []; - listening.forEach(id => this.progressStep(id)); - } - progressByEvent(event: string): void { - const listening = this.eventListeners.get(event) ?? []; - listening.forEach(id => this.progressStep(id)); + if (this.sessionEvents.has(event)) { return; } + + this.sessionEvents.add(event); + this.completionListeners.get(event)?.forEach(id => this.progressStep(id)); } private registerStartEntry(categoryDescriptor: IGettingStartedStartEntryDescriptor): void { @@ -535,10 +683,10 @@ export class GettingStartedService extends Disposable implements IGettingStarted const category: IGettingStartedCategory = { ...categoryDescriptor }; this.gettingStartedContributions.set(categoryDescriptor.id, category); - this._onDidAddCategory.fire(this.getCategoryProgress(category)); + this._onDidAddCategory.fire(); } - private registerWalkthrough(categoryDescriptor: IGettingStartedWalkthroughDescriptor, steps: IGettingStartedStep[]): void { + registerWalkthrough(categoryDescriptor: IGettingStartedWalkthroughDescriptor, steps: IGettingStartedStep[]): void { const oldCategory = this.gettingStartedContributions.get(categoryDescriptor.id); if (oldCategory) { console.error(`Skipping attempt to overwrite getting started category. (${categoryDescriptor.id})`); @@ -551,8 +699,28 @@ export class GettingStartedService extends Disposable implements IGettingStarted if (this.steps.has(step.id)) { throw Error('Attempting to register step with id ' + step.id + ' twice. Second is dropped.'); } this.steps.set(step.id, step); this.registerDoneListeners(step); + step.when.keys().forEach(key => this.categoryVisibilityContextKeys.add(key)); + }); + + if (this.contextService.contextMatchesRules(category.when)) { + this._onDidAddCategory.fire(); + } + + this.tasExperimentService?.getTreatment(`gettingStarted.overrideCategory.${categoryDescriptor.id.replace('#', '.')}.when`).then(override => { + if (override) { + const old = category.when; + const gnu = ContextKeyExpr.deserialize(override) ?? old; + this.categoryVisibilityContextKeys.add(override); + category.when = gnu; + + if (this.contextService.contextMatchesRules(old) && !this.contextService.contextMatchesRules(gnu)) { + this._onDidRemoveCategory.fire(); + } else if (!this.contextService.contextMatchesRules(old) && this.contextService.contextMatchesRules(gnu)) { + this._onDidAddCategory.fire(); + } + } }); - this._onDidAddCategory.fire(this.getCategoryProgress(category)); + category.when.keys().forEach(key => this.categoryVisibilityContextKeys.add(key)); } private getStep(id: string): IGettingStartedStep { diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/gettingStartedContent.ts b/src/vs/workbench/contrib/welcome/gettingStarted/common/gettingStartedContent.ts similarity index 67% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/gettingStartedContent.ts rename to src/vs/workbench/contrib/welcome/gettingStarted/common/gettingStartedContent.ts index eae3e4395227..5188d25939cf 100644 --- a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/gettingStartedContent.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/common/gettingStartedContent.ts @@ -3,6 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import 'vs/workbench/contrib/welcome/gettingStarted/common/media/example_markdown_media'; +import 'vs/workbench/contrib/welcome/gettingStarted/common/media/notebookProfile'; import { localize } from 'vs/nls'; import { Codicon } from 'vs/base/common/codicons'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; @@ -12,14 +14,13 @@ import { registerIcon } from 'vs/platform/theme/common/iconRegistry'; const setupIcon = registerIcon('getting-started-setup', Codicon.zap, localize('getting-started-setup-icon', "Icon used for the setup category of getting started")); const beginnerIcon = registerIcon('getting-started-beginner', Codicon.lightbulb, localize('getting-started-beginner-icon', "Icon used for the beginner category of getting started")); const intermediateIcon = registerIcon('getting-started-intermediate', Codicon.mortarBoard, localize('getting-started-intermediate-icon', "Icon used for the intermediate category of getting started")); -const codespacesIcon = registerIcon('getting-started-codespaces', Codicon.github, localize('getting-started-codespaces-icon', "Icon used for the codespaces category of getting started")); export type BuiltinGettingStartedStep = { id: string title: string, description: string, - doneOn: { commandExecuted: string, eventFired?: never } | { eventFired: string, commandExecuted?: never, } + completionEvents?: string[] when?: string, media: | { type: 'image', path: string | { hc: string, light: string, dark: string }, altText: string } @@ -30,6 +31,7 @@ export type BuiltinGettingStartedCategory = { id: string title: string, description: string, + next?: string, icon: ThemeIcon, when?: string, content: @@ -117,82 +119,26 @@ export const startEntries: GettingStartedStartEntryContent = [ ]; export const walkthroughs: GettingStartedWalkthroughContent = [ - { - id: 'Codespaces', - title: localize('gettingStarted.codespaces.title', "Primer on Codespaces"), - icon: codespacesIcon, - when: 'remoteName == codespaces', - description: localize('gettingStarted.codespaces.description', "Get up and running with your instant code environment."), - content: { - type: 'steps', - steps: [ - { - id: 'runProjectStep', - title: localize('gettingStarted.runProject.title', "Build & run your app"), - description: localize('gettingStarted.runProject.description', "Build, run & debug your code in the cloud, right from the browser.\n[Start Debugging](command:workbench.action.debug.selectandstart)"), - doneOn: { commandExecuted: 'workbench.action.debug.selectandstart' }, - media: { type: 'image', altText: 'Node.js project running debug mode and paused.', path: 'runProject.png' }, - }, - { - id: 'forwardPortsStep', - title: localize('gettingStarted.forwardPorts.title', "Access your running application"), - description: localize('gettingStarted.forwardPorts.description', "Ports running within your codespace are automatically forwarded to the web, so you can open them in your browser.\n[Show Ports Panel](command:~remote.forwardedPorts.focus)"), - doneOn: { commandExecuted: '~remote.forwardedPorts.focus' }, - media: { type: 'image', altText: 'Ports panel.', path: 'forwardPorts.png' }, - }, - { - id: 'pullRequests', - title: localize('gettingStarted.pullRequests.title', "Pull requests at your fingertips"), - description: localize('gettingStarted.pullRequests.description', "Bring your GitHub workflow closer to your code, so you can review pull requests, add comments, merge branches, and more.\n[Open GitHub View](command:workbench.view.extension.github-pull-requests)"), - doneOn: { commandExecuted: 'workbench.view.extension.github-pull-requests' }, - media: { type: 'image', altText: 'Preview for reviewing a pull request.', path: 'pullRequests.png' }, - }, - { - id: 'remoteTerminal', - title: localize('gettingStarted.remoteTerminal.title', "Run tasks in the integrated terminal"), - description: localize('gettingStarted.remoteTerminal.description', "Perform quick command-line tasks using the built-in terminal.\n[Focus Terminal](command:terminal.focus)"), - doneOn: { commandExecuted: 'terminal.focus' }, - media: { type: 'image', altText: 'Remote terminal showing npm commands.', path: 'remoteTerminal.png' }, - }, - { - id: 'openVSC', - title: localize('gettingStarted.openVSC.title', "Develop remotely in VS Code"), - description: localize('gettingStarted.openVSC.description', "Access the power of your cloud development environment from your local VS Code. Set it up by installing the GitHub Codespaces extension and connecting your GitHub account.\n[Open in VS Code](command:github.codespaces.openInStable)"), - when: 'isWeb', - doneOn: { commandExecuted: 'github.codespaces.openInStable' }, - media: { - type: 'image', altText: 'Preview of the Open in VS Code command.', path: { - dark: 'dark/openVSC.png', - light: 'light/openVSC.png', - hc: 'light/openVSC.png', - } - }, - } - ] - } - }, - { id: 'Setup', - title: localize('gettingStarted.setup.title', "Customize your Setup"), - description: localize('gettingStarted.setup.description', "Extend and customize VS Code to make it yours."), + title: localize('gettingStarted.setup.title', "Get Started with VS Code"), + description: localize('gettingStarted.setup.description', "Discover the best customizations to make VS Code yours."), icon: setupIcon, - when: 'remoteName != codespaces', + next: 'Beginner', content: { type: 'steps', steps: [ { id: 'pickColorTheme', - title: localize('gettingStarted.pickColor.title', "Customize the look with themes"), - description: localize('gettingStarted.pickColor.description', "Pick a color theme to match your taste and mood while coding.\n[Pick a Theme](command:workbench.action.selectTheme)"), - doneOn: { commandExecuted: 'workbench.action.selectTheme' }, - media: { type: 'image', altText: 'Color theme preview for dark and light theme.', path: 'colorTheme.png', } + title: localize('gettingStarted.pickColor.title', "Choose the look you want"), + description: localize('gettingStarted.pickColor.description', "The right color palette helps you focus on your code, is easy on your eyes, and is simply more fun to use.\n[Browse Color Themes](command:workbench.action.selectTheme)"), + completionEvents: ['onSettingChanged:workbench.colorTheme'], + media: { type: 'markdown', path: 'example_markdown_media', } }, { id: 'findLanguageExtensions', - title: localize('gettingStarted.findLanguageExts.title', "Code in any language"), - description: localize('gettingStarted.findLanguageExts.description', "VS Code supports over 50+ programming languages. While many are built-in, others can be easily installed as extensions in one click.\n[Browse Language Extensions](command:workbench.extensions.action.showLanguageExtensions)"), - doneOn: { commandExecuted: 'workbench.extensions.action.showLanguageExtensions' }, + title: localize('gettingStarted.findLanguageExts.title', "Rich support for all your languages"), + description: localize('gettingStarted.findLanguageExts.description', "Code smarter with syntax highlighting, code completion, linting and debugging. While many languages are built-in, many more can be added as extensions.\n[Browse Language Extensions](command:workbench.extensions.action.showLanguageExtensions)"), media: { type: 'image', altText: 'Language extensions', path: { dark: 'dark/languageExtensions.png', @@ -202,38 +148,35 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ } }, { - id: 'keymaps', - title: localize('gettingStarted.keymaps.title', "Switch from other editors"), - description: localize('gettingStarted.keymaps.description', "Bring your favorite keyboard shortcuts from other editors into VS Code with keymaps.\n[Browse Keymap Extensions](command:workbench.extensions.action.showRecommendedKeymapExtensions)"), - doneOn: { commandExecuted: 'workbench.extensions.action.showRecommendedKeymapExtensions' }, + id: 'commandPaletteTask', + title: localize('gettingStarted.commandPalette.title', "One shortcut to access everything"), + description: localize('gettingStarted.commandPalette.description', "Commands Palette is the keyboard way to accomplish any task in VS Code. **Practice** by looking up your frequently used commands to save time and keep in the flow.\n[Open Command Palette](command:workbench.action.showCommands)\n__Try searching for 'view toggle'.__"), media: { - type: 'image', altText: 'List of keymap extensions.', path: { - dark: 'dark/keymaps.png', - light: 'light/keymaps.png', - hc: 'hc/keymaps.png', - }, - } + type: 'image', altText: 'Command Palette overlay for searching and executing commands.', path: { + dark: 'dark/commandPalette.png', + light: 'light/commandPalette.png', + hc: 'hc/commandPalette.png', + } + }, }, { - id: 'settingsSync', - title: localize('gettingStarted.settingsSync.title', "Sync your favorite setup"), - description: localize('gettingStarted.settingsSync.description', "Never lose the perfect VS Code setup! Settings Sync will back up and share settings, keybindings & extensions across several VS Code instances.\n[Enable Settings Sync](command:workbench.userDataSync.actions.turnOn)"), - when: 'syncStatus != uninitialized', - doneOn: { eventFired: 'sync-enabled' }, + id: 'workspaceTrust', + title: localize('gettingStarted.workspaceTrust.title', "Safely browse and edit code"), + description: localize('gettingStarted.workspaceTrust.description', "[Workspace Trust](https://github.com/microsoft/vscode-docs/blob/workspaceTrust/docs/editor/workspace-trust.md) lets you decide whether your project folders should **allow or restrict** automatic code execution __(required for extensions, debugging, etc)__.\nOpening a file/folder will prompt to grant trust. You can always [enable trust](command:toSide:workbench.action.manageTrustedDomain) later."), + when: '!isWorkspaceTrusted && workspaceFolderCount == 0', media: { - type: 'image', altText: 'The "Turn on Sync" entry in the settings gear menu.', path: { - dark: 'dark/settingsSync.png', - light: 'light/settingsSync.png', - hc: 'hc/settingsSync.png', + type: 'image', altText: 'Workspace Trust editor in Restricted mode and a primary button for switching to Trusted mode.', path: { + dark: 'dark/workspaceTrust.svg', + light: 'light/workspaceTrust.svg', + hc: 'dark/workspaceTrust.svg', }, - } + }, }, { id: 'pickAFolderTask-Mac', - title: localize('gettingStarted.setup.OpenFolder.title', "Open your project folder"), - description: localize('gettingStarted.setup.OpenFolder.description', "Open a project folder to start coding!\n[Pick a Folder](command:workbench.action.files.openFileFolder)"), + title: localize('gettingStarted.setup.OpenFolder.title', "Open up your code"), + description: localize('gettingStarted.setup.OpenFolder.description', "You're all set to start coding. Open a project folder to get your files into VS Code.\n[Pick a Folder](command:workbench.action.files.openFileFolder)"), when: 'isMac && workspaceFolderCount == 0', - doneOn: { commandExecuted: 'workbench.action.files.openFileFolder' }, media: { type: 'image', altText: 'Explorer view showing buttons for opening folder and cloning repository.', path: { dark: 'dark/openFolder.png', @@ -244,10 +187,9 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ }, { id: 'pickAFolderTask-Other', - title: localize('gettingStarted.setup.OpenFolder.title', "Open your project folder"), - description: localize('gettingStarted.setup.OpenFolder.description2', "Open a project folder to start coding!\n[Pick a Folder](command:workbench.action.files.openFolder)"), + title: localize('gettingStarted.setup.OpenFolder.title', "Open up your code"), + description: localize('gettingStarted.setup.OpenFolder.description2', "You're all set to start coding. Open a project folder to get your files into VS Code.\n[Pick a Folder](command:workbench.action.files.openFolder)"), when: '!isMac && workspaceFolderCount == 0', - doneOn: { commandExecuted: 'workbench.action.files.openFolder' }, media: { type: 'image', altText: 'Explorer view showing buttons for opening folder and cloning repository.', path: { dark: 'dark/openFolder.png', @@ -258,10 +200,9 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ }, { id: 'quickOpen', - title: localize('gettingStarted.quickOpen.title', "Quick open files"), + title: localize('gettingStarted.quickOpen.title', "Quickly navigate between your files"), description: localize('gettingStarted.quickOpen.description', "Navigate between files in an instant with one keystroke. Tip: Open multiple files by pressing the right arrow key.\n[Quick Open a File](command:toSide:workbench.action.quickOpen)"), when: 'workspaceFolderCount != 0', - doneOn: { commandExecuted: 'workbench.action.quickOpen' }, media: { type: 'image', altText: 'Go to file in quick search.', path: { dark: 'dark/openFolder.png', @@ -278,21 +219,21 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ id: 'Beginner', title: localize('gettingStarted.beginner.title', "Learn the Fundamentals"), icon: beginnerIcon, + next: 'Intermediate', description: localize('gettingStarted.beginner.description', "Jump right into VS Code and get an overview of the must-have features."), content: { type: 'steps', steps: [ { - id: 'commandPaletteTask', - title: localize('gettingStarted.commandPalette.title', "Find & run commands"), - description: localize('gettingStarted.commandPalette.description', "The easiest way to find everything VS Code can do. If you're ever looking for a feature or a shortcut, check here first!\n[Open Command Palette](command:workbench.action.showCommands)"), - doneOn: { commandExecuted: 'workbench.action.showCommands' }, + id: 'playground', + title: localize('gettingStarted.playground.title', "Redefine your editing skills"), + description: localize('gettingStarted.playground.description', "Want to code faster and smarter? Practice powerful code editing features in the interactive playground.\n[Open Interactive Playground](command:toSide:workbench.action.showInteractivePlayground)"), media: { - type: 'image', altText: 'Command Palette overlay for searching and executing commands.', path: { - dark: 'dark/commandPalette.png', - light: 'light/commandPalette.png', - hc: 'hc/commandPalette.png', - } + type: 'image', altText: 'Interactive Playground.', path: { + dark: 'dark/playground.png', + light: 'light/playground.png', + hc: 'light/playground.png' + }, }, }, { @@ -300,7 +241,6 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ title: localize('gettingStarted.terminal.title', "Convenient built-in terminal"), description: localize('gettingStarted.terminal.description', "Quickly run shell commands and monitor build output, right next to your code.\n[Show Terminal Panel](command:workbench.action.terminal.toggleTerminal)"), when: 'remoteName != codespaces && !terminalIsOpen', - doneOn: { commandExecuted: 'workbench.action.terminal.toggleTerminal' }, media: { type: 'image', altText: 'Integrated terminal running a few npm commands', path: { dark: 'dark/terminal.png', @@ -313,7 +253,6 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ id: 'extensions', title: localize('gettingStarted.extensions.title', "Limitless extensibility"), description: localize('gettingStarted.extensions.description', "Extensions are VS Code's power-ups. They range from handy productivity hacks, expanding out-of-the-box features, to adding completely new capabilities.\n[Browse Recommended Extensions](command:workbench.extensions.action.showRecommendedExtensions)"), - doneOn: { commandExecuted: 'workbench.extensions.action.showRecommendedExtensions' }, media: { type: 'image', altText: 'VS Code extension marketplace with featured language extensions', path: { dark: 'dark/extensions.png', @@ -326,7 +265,6 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ id: 'settings', title: localize('gettingStarted.settings.title', "Tune your settings"), description: localize('gettingStarted.settings.description', "Tweak every aspect of VS Code and your extensions to your liking. Commonly used settings are listed first to get you started.\n[Tweak my Settings](command:toSide:workbench.action.openSettings)"), - doneOn: { commandExecuted: 'workbench.action.openSettings' }, media: { type: 'image', altText: 'VS Code Settings', path: { dark: 'dark/settings.png', @@ -335,11 +273,24 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ } }, }, + { + id: 'settingsSync', + title: localize('gettingStarted.settingsSync.title', "Sync your stuff across devices"), + description: localize('gettingStarted.settingsSync.description', "Never lose the perfect VS Code setup! Settings Sync will back up and share settings, keybindings & extensions across several installations.\n[Enable Settings Sync](command:workbench.userDataSync.actions.turnOn)"), + when: 'syncStatus != uninitialized', + completionEvents: ['onEvent:sync-enabled'], + media: { + type: 'image', altText: 'The "Turn on Sync" entry in the settings gear menu.', path: { + dark: 'dark/settingsSync.png', + light: 'light/settingsSync.png', + hc: 'hc/settingsSync.png', + }, + } + }, { id: 'videoTutorial', title: localize('gettingStarted.videoTutorial.title', "Lean back and learn"), description: localize('gettingStarted.videoTutorial.description', "Watch the first in a series of short & practical video tutorials for VS Code's key features.\n[Watch Tutorial](https://aka.ms/vscode-getting-started-video)"), - doneOn: { eventFired: 'linkOpened:https://aka.ms/vscode-getting-started-video' }, media: { type: 'image', altText: 'VS Code Settings', path: 'tutorialVideo.png' }, } ] @@ -354,24 +305,10 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ content: { type: 'steps', steps: [ - { - id: 'playground', - title: localize('gettingStarted.playground.title', "Redefine your editing skills"), - description: localize('gettingStarted.playground.description', "Want to code faster and smarter? Practice powerful code editing features in the interactive playground.\n[Open Interactive Playground](command:toSide:workbench.action.showInteractivePlayground)"), - doneOn: { commandExecuted: 'workbench.action.showInteractivePlayground' }, - media: { - type: 'image', altText: 'Interactive Playground.', path: { - dark: 'dark/playground.png', - light: 'light/playground.png', - hc: 'light/playground.png' - }, - }, - }, { id: 'splitview', title: localize('gettingStarted.splitview.title', "Side by side editing"), description: localize('gettingStarted.splitview.description', "Make the most of your screen estate by opening files side by side, vertically and horizontally.\n[Split Editor](command:workbench.action.splitEditor)"), - doneOn: { commandExecuted: 'workbench.action.splitEditor' }, media: { type: 'image', altText: 'Multiple editors in split view.', path: { dark: 'dark/splitview.png', @@ -385,7 +322,6 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ title: localize('gettingStarted.debug.title', "Watch your code in action"), description: localize('gettingStarted.debug.description', "Accelerate your edit, build, test, and debug loop by setting up a launch configuration.\n[Run your Project](command:workbench.action.debug.selectandstart)"), when: 'workspaceFolderCount != 0', - doneOn: { commandExecuted: 'workbench.action.debug.selectandstart' }, media: { type: 'image', altText: 'Run and debug view.', path: { dark: 'dark/debug.png', @@ -399,7 +335,6 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ title: localize('gettingStarted.scm.title', "Track your code with Git"), description: localize('gettingStarted.scmClone.description', "Set up the built-in version control for your project to track your changes and collaborate with others.\n[Clone Repository](command:git.clone)"), when: 'config.git.enabled && !git.missing && workspaceFolderCount == 0', - doneOn: { commandExecuted: 'git.clone' }, media: { type: 'image', altText: 'Source Control view.', path: { dark: 'dark/scm.png', @@ -413,7 +348,6 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ title: localize('gettingStarted.scm.title', "Track your code with Git"), description: localize('gettingStarted.scmSetup.description', "Set up the built-in version control for your project to track your changes and collaborate with others.\n[Initialize Git Repository](command:git.init)"), when: 'config.git.enabled && !git.missing && workspaceFolderCount != 0 && gitOpenRepositoryCount == 0', - doneOn: { commandExecuted: 'git.init' }, media: { type: 'image', altText: 'Source Control view.', path: { dark: 'dark/scm.png', @@ -425,9 +359,8 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'scm', title: localize('gettingStarted.scm.title', "Track your code with Git"), - description: localize('gettingStarted.scm.description', "No more looking up Git commands! Git and GitHub workflows are seamlessly integrated.[Open Source Control](command:workbench.view.scm)"), + description: localize('gettingStarted.scm.description', "No more looking up Git commands! Git and GitHub workflows are seamlessly integrated.\n[Open Source Control](command:workbench.view.scm)"), when: 'config.git.enabled && !git.missing && workspaceFolderCount != 0 && gitOpenRepositoryCount != 0 && activeViewlet != \'workbench.view.scm\'', - doneOn: { commandExecuted: 'workbench.view.scm.focus' }, media: { type: 'image', altText: 'Source Control view.', path: { dark: 'dark/scm.png', @@ -441,7 +374,6 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ title: localize('gettingStarted.tasks.title', "Automate your project tasks"), when: 'workspaceFolderCount != 0', description: localize('gettingStarted.tasks.description', "Create tasks for your common workflows and enjoy the integrated experience of running scripts and automatically checking results.\n[Run Auto-detected Tasks](command:workbench.action.tasks.runTask)"), - doneOn: { commandExecuted: 'workbench.action.tasks.runTask' }, media: { type: 'image', altText: 'Task runner.', path: { dark: 'dark/tasks.png', @@ -454,7 +386,6 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ id: 'shortcuts', title: localize('gettingStarted.shortcuts.title', "Customize your shortcuts"), description: localize('gettingStarted.shortcuts.description', "Once you have discovered your favorite commands, create custom keyboard shortcuts for instant access.\n[Keyboard Shortcuts](command:toSide:workbench.action.openGlobalKeybindings)"), - doneOn: { commandExecuted: 'workbench.action.openGlobalKeybindings' }, media: { type: 'image', altText: 'Interactive shortcuts.', path: { dark: 'dark/shortcuts.png', @@ -465,5 +396,27 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ } ] } + }, + { + id: 'notebooks', + title: localize('gettingStarted.notebook.title', "Customize Notebooks"), + description: '', + icon: setupIcon, + when: 'config.notebook.experimental.gettingStarted && userHasOpenedNotebook', + content: { + type: 'steps', + steps: [ + { + completionEvents: ['onCommand:notebook.setProfile'], + id: 'notebookProfile', + title: localize('gettingStarted.notebookProfile.title', "Select the layout for your notebooks"), + description: localize('gettingStarted.notebookProfile.description', "Get notebooks to feel just the way you prefer"), + when: 'userHasOpenedNotebook', + media: { + type: 'markdown', path: 'notebookProfile' + } + }, + ] + } } ]; diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/colorTheme.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/colorTheme.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/colorTheme.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/colorTheme.png diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark.png new file mode 100644 index 0000000000000000000000000000000000000000..bac2bc8d2d80329b01a1906e0266b503b46bc4f6 GIT binary patch literal 14165 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 Gq5lURohw@a literal 0 HcmV?d00001 diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/commandPalette.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/commandPalette.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/commandPalette.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/commandPalette.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/debug.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/debug.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/debug.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/debug.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/extensions.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/extensions.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/extensions.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/extensions.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/languageExtensions.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/languageExtensions.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/languageExtensions.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/languageExtensions.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/openFolder.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/openFolder.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/openFolder.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/openFolder.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/playground.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/playground.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/playground.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/playground.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/scm.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/scm.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/scm.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/scm.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/settings.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/settings.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/settings.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/settings.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/settingsSync.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/settingsSync.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/settingsSync.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/settingsSync.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/shortcuts.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/shortcuts.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/shortcuts.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/shortcuts.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/splitview.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/splitview.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/splitview.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/splitview.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/tasks.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/tasks.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/tasks.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/tasks.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/terminal.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/terminal.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/terminal.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/terminal.png diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/workspaceTrust.svg b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/workspaceTrust.svg new file mode 100644 index 000000000000..f1cf7fe5053f --- /dev/null +++ b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/dark/workspaceTrust.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/common/media/example_markdown_media.ts b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/example_markdown_media.ts new file mode 100644 index 000000000000..148374b5544c --- /dev/null +++ b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/example_markdown_media.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 { escape } from 'vs/base/common/strings'; +import { localize } from 'vs/nls'; + +export default () => ` + + + + + ${escape(localize('light', "Light"))} + + + + ${escape(localize('dark', "Dark"))} + + + + ${escape(localize('HighContrast', "High Contrast"))} + + + + ${escape(localize('seeMore', "See More Themes..."))} + + +`; diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/github.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/github.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/github.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/github.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/commandPalette.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/commandPalette.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/commandPalette.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/commandPalette.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/extensions.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/extensions.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/extensions.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/extensions.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/languageExtensions.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/languageExtensions.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/languageExtensions.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/languageExtensions.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/openFolder.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/openFolder.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/openFolder.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/openFolder.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/settings.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/settings.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/settings.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/settings.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/settingsSync.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/settingsSync.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/settingsSync.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/settingsSync.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/terminal.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/terminal.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/terminal.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/hc/terminal.png diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light.png new file mode 100644 index 0000000000000000000000000000000000000000..81aa74dc4de3356a4e08f2c718061dfe20bd7f9b GIT binary patch literal 14341 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%0ASBCcObGd5?`qN0Z1Q%qBYm$o{^F$hItfd=okDf zRso5s^tuiy9xd}o`@ca51S$1^g-2Ej+t$)}oRwgaxRp;)vJ*oMfy}rT;QK9Dfr_mJ zUCs@CydYRRuZrpMvpb?zc)1%upkcs#cx3+T8Y+>$lKh4Z6US%CM zvNzw_{tyR$jmSOg3l9`7-Mc@_-dU8Q!SrAjAsTh}-D^e_WSE*=;TyUkRfWZr)qRV@ zDvMI>L*36OCYLLlFO{3QpTwau~T%c*#R72 zH<#Z5a$1Hg5`)lzc|iw%uRaDqIxYou1~X6G?i-)gdJ5{Rw)t`iOh8(?JV0{IomuAJAx_BOAWl60-l>UnO{)r49gUyfTZP?Qh zfHd+|aY`Yh*GWxlg*aMrn{j9cBN1=QBW4NeqP{rd2&8psw zugza3Tz6t>O(g!*&O4x-)S8xMWt@L=kI$kuz?iqsY^XtDi9kkoog?}W{(&&icr(zr z3d@{zhs~#zOin}su%`WL%@0)E06XdRuvA6;nZMBm0AtW;4iCb~`&|1;>;S7pUR|CA zwK#xIiN(CZh@UWk92e38;>^4aPee5@GSd>bsAF$Q zHNmy7x>d#NuU&%|5qBomghSXJmteF%>oOw=YPY+Z4HObft$)S3NnkW3claQ#dvGj? z7r4V~A<|~C!2j1`0RwQcZD|IA)-kT&xE=5_-T=={@bCIp@Q((fxiR7ozGhHwKAHkt z!G7$$%y%$f^*1nY3u?;yqkcvJsj1ph>&7R#CEvk0nCxnEPho)QZ@Dvrf}ER%~+$2}jANDExIzkhwYSbfD?zNl=A^0n$$3*`Qdb?-sa z;!)4avtA##VhS~Pz;y8_Yqj4yivplzN0|QK%-0+QW@%h0cKY|8r5h;jEkJjY zHu{e~Bn_2i{eM}eHhcezsOWz#W#HX!DK_)$xY4c8z^6HLu?Kz>RO$#R@a{L9b{9^j z7Y@u1nr}A&qCb)<0cGk_RfTTJ9sal^nfX|HX9H{c@u{-ZKDzP0qRph829<#VfJ z1uYA~tg~Fc_knJwz}jEB^;QI!O!2VhRuFLz4WKap1q;W|!(j90lY%8cn;Ugw$M0~j z`#ms+_Y&(E(CfC4{=`%Trm6?8`L511$Qo+YjrWw4tS(Mw2C~s`bcO-v z4qh3_?x~GrUqsuz7Gx@?Y^?U^3I`R|zKuCD@QU^mZ2pz5W}N0OOv~987e4`NG1Bb3 z#smOzGw5qXOj`a4PO$&P1o1Cs_)i5n=p%SbizbK{GptI|&3!tDGNj4%>?H8H$K|q= zLD>8k*7X<548XlLH@Y%i*h7}*m#fQ0%ouu?XRA70*5|VA-A$6!DnKG%XUo`!LkI1Q zqa;+b!$HW%3t99jj-)I!vD?kc!o6jtNEH8-f~w`Radyh*EDNjJsa4Q&`B=vJd-M7` z#O{3szLZ-6mGieRA-;8RZ|VW3Y~AbQP6g9DHv#pxUyIl!0BBj*WYG&?eBK|;!W2;? zM%>v0;j@MC@xp(D4E6YH(=El6jfEc2=jZU{#fgU;q!@0@FqawjfXF9byO!>2( zfZ+bE5I28Z^q*eR{>Rne|1$hgP(^L zSoD_r&5~zkW_YTGm0~5Px-aB8yH>3)YzcX9xaFqQRJ~MQV?|mj=)(>)!Yh|PMN!y^ z3S}jup#1v&!$LUoT0bR}Pc4)B3yJSz%|}2H)%C(68T52P&_>3irmFN()Or_3ALN79 PEJW|%(F3{rtwa9@81|s` literal 0 HcmV?d00001 diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/commandPalette.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/commandPalette.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/commandPalette.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/commandPalette.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/debug.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/debug.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/debug.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/debug.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/extensions.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/extensions.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/extensions.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/extensions.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/languageExtensions.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/languageExtensions.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/languageExtensions.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/languageExtensions.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/openFolder.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/openFolder.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/openFolder.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/openFolder.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/playground.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/playground.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/playground.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/playground.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/scm.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/scm.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/scm.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/scm.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/settings.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/settings.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/settings.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/settings.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/settingsSync.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/settingsSync.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/settingsSync.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/settingsSync.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/shortcuts.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/shortcuts.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/shortcuts.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/shortcuts.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/splitview.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/splitview.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/splitview.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/splitview.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/tasks.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/tasks.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/tasks.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/tasks.png diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/terminal.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/terminal.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/terminal.png rename to src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/terminal.png diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/workspaceTrust.svg b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/workspaceTrust.svg new file mode 100644 index 000000000000..486ed7dd305e --- /dev/null +++ b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/light/workspaceTrust.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/common/media/monokai.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/monokai.png new file mode 100644 index 0000000000000000000000000000000000000000..ea0926178e0f8abd66e0665c996ed3b7cb8b942b GIT binary patch literal 14287 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 E1BYg#Bme*a literal 0 HcmV?d00001 diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/common/media/more.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/more.png new file mode 100644 index 0000000000000000000000000000000000000000..e1b741da46a12c56dc4730fb6a38dac1cafaab24 GIT binary patch literal 17121 zcmeHu2{_d4-v1bbv6Ur+Fp*T&NMs$Uw2&#uP9^Wnr7ynd;5Ox@ACP4?_Z&)vpVc70xS>+ zg#FaXW9K0dC>{c#dj)3%Em@}C?;sGCZhLKQ)G2Lk1nRo0t-X^C1adO;Ni-8Gs*@Kp zNlR6N?>VOOOi4?H?!~RI(0wPF&M}`tJgazk^PYu?`Nv$G=uI9Ao^x4J$DQsnbU*J{ zy(tB)Da41dD^4;AU#=})98QdlpRND$A+=|DvhD)}CF*!sz+K%3F-`QIQ5Q z1;Q9cMhwiYEUG&COlMQmBgi9ns*!KdcBI%!Uiry4LF+WD<7SA*vvipAoM-tyFMojN zBOD*fKG_dJ3TcfG&+cgEEDe^kxU=J~TOZsmVmg}htccAaFQSCZo!~46h>!dOiCP$D z{8mTo@|y0RZASzyON1h&w0!tK1^RR9W8@A^SXUnT!VAi(QUh z8YM5OS-y&^UJ>B&e`qXIKOnuN`CvHcj7!9IwGf{7pG8fK*`9knn)Q3Au5`3Ma&Gk8 zkQDFzl?U%n^7Cpo_#ct5Nnj|(!RLDuMjs6&?A|u;dT3vP`;gRQrs{}nCztywMtAO) z3)>|*iDt^HS~~MFe;_Y0JTItlZ{U;A6|wX6cB;6wUB@|kzcq25Rs0#2+gF=dGEze$ zX2zuVrgK!@PV*blBg#I`lDJY6Ma*TsrS*|pW7;7oO%#=QCXV~<0^jhh*Ap{q#`Bg8 zGwx@{!!IUZ=9N{uk)X8)&Y;V&{W=Ev8M6Hrb$$-# zmjA$2I&}3_SX7t-L~Ic~9_3TLvm}~hh(=tj;

    yLTFQ5!?g;)mMt=nK!^!Wn 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 encodeURIComponent(JSON.stringify({ profile })); +const imageSize = 400; + +export default () => ` + + + + + ${escape(localize('default', "Default"))} + + + + ${escape(localize('jupyter', "Jupyter"))} + + + + ${escape(localize('colab', "Colab"))} + + + +`; diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/common/media/notebookThemes/colab.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/notebookThemes/colab.png new file mode 100644 index 0000000000000000000000000000000000000000..3e54f9875fc0d2e686ebbed1051fe2ffdbce1c69 GIT binary patch literal 2473 zcmdT`eN>az8NVSVDiU#n5``&rSlb>?)qxFG3Iw47M?z?jIX=T$4xk~V$fssNv<@3v z$gxm?P=pjA%@D$OG!a3qIs%Ca0*MJ!1DE7H;qh4GK7vhnN||lgpxA?mQ^1l%Cb;+(Uw5 z0{-wJb@XzkPW0Dl2ew;4C1LUaMvyV~cueS&Rk!g2+3ig(NpoL+6IzAa=Edn{V|=+6 ziIzjYQF2?hvwn!pEqdDML#X!h#A3T*0HCMGEC(Y15QL{90gf(30Xkr#p>z9PVIZfm z(6hA^0M>4zYpd&rV*q0XQR`K;W6KGX5>F5eB`{y#oQJbLv#pJI!M|`EYq&I_(yNYSCW`+S8w|j{tbcsVKnEv8ks>)QBRZYl`yjNPrS3h6 ztdG=OA@?qJ#}~GDeYbUHM#V4pN|BVs3v;p;xF0D7#Nsc#spDn!_4PKuz9Gvox`(eh z{DhHHtX+@US(d+KU}&@VWvL@HzKyyq0EnF&W+FM^>$Dq&jF-%>!gEVLdnTt^GFW+{ z5uTRyw;a&ICiWJ0Q)cYxgRXxh*qNb%6=V?vTxnGHOMuY zOkMInL5Hd5VZPK6%YIRBOuXO7t7Nf`(yH||p*eXuQ#amiiP4;@DOlu6<9u?oZvxzH zqi&*qbTsaM7eys7iW!8trIB&&$EFYV)rWq{|>MhgzrnF@lFoV^8_^-4J+m06n0; zJy;f+)^k)zLWR8uqAOk~AMb0MDkrT6plWvd2%EN8Pq6&Opkm#vvH}{XV&n*kYd|7p z4YtKHZzAm&i_Fzn}S$-9I78a`wY7Tp(C1ZC_tsTT4p>0JW|~AIi`5WSZu_ zw~XyPW-%|%%|5tk1HhPP7CWA!kn>2?EyD>MMegI#&3`Zb6f$}f+l~^M25QSowpgz0 zey`~F9r#uRP#i_NDH{|3$6J14Hr|-stdL@Fp`a8B+d&-@44>FzoncTrI|{>^Cc0@U zXVCz6*FG*)es62dd&h~+7z~8mf(UoP{;f6yP>YKIh(FRTM8|^Z##+b++_x zAmGXi3=eKD+2D--0z0p?yP3^I_u8Db2ZJNJNCHv`mUFd!h9!rmg8_5Y?o}Pmz(sJX6X96ie zars8R-V>;(iaa&HUD z{SwKcC?gS#D}zlHxCgB2&OhJw6I1Vw0gB)HZ}=3ExVPd*BEjM+JS2#s(*LI4zewW? rF9!chLAuOhz65Eav)Cyy(2TU)TZ2@)+#7*6D-imAcu@2H#8dwSja|h8 literal 0 HcmV?d00001 diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/common/media/notebookThemes/default.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/notebookThemes/default.png new file mode 100644 index 0000000000000000000000000000000000000000..301bb1129f1bda09ec3ea5f6c5151689165c6abb GIT binary patch literal 2476 zcmds3eNa_-BO)^v9|pvaHfrJIt&~tgC;+!EpyxiZg$qI>BSH^lA@mvo1R>l`6ySnVdk8Mf z9U5|WH$=8F4SnTM5&yb&KN;4@? z;Q2ytBbyaKA33BO&3o~}cw!e0cf{M<`{BUAv3Ru3#IT%madUNzPt@D2P-2Ua6yPb^ z*O!alpj?-gb6YAsl-Q7^*lql_zt_-vB9qi!eFP6cAnnb|RyscMqa>oJN;y7m@IL_e zrVT&8e?~~8)KQwucN22Tb`NdRd*B$CYEn9`Xyi=hR7G-SK|#T`^!~;jXf)auxE$1a zS98);k^v{Z+tUrciQ8vQ;~Sn*Xw$D>C|Pm+H~qkrVM$^^DpSyyGTwI=F2)k~NOkM! z9VJ1S;)F7{o~yw*)VnD%6B3ZcggU!BsKM#!ECg`bOb@v-7j@adlF#o8aCHQN@X5(Z zA+e^WCQWh+0`A`mL)BSoX8$#+@lSC{n4LQn#=u2inqM`tXXkILZF^;DK3LVGVjLP= zoEU7m;D^BwWzh2SoJ`7d_N?*d?f3@+1J?|*r!0)dQ!~{gli^-oUTu{LRTPytEYl;9 zb_0M;HlNS047xk2d>c|>`A9EvM!jjxy}Ys=+MtC60J57S{*_1nX7Nvi`!57ZcOV7n za}T0($7U?e=|a1MRysC81SCH8xMQ!R(3p>Kva)$8QKG%;L`GUa*UVKozO-?8KJb?fdya{Mf0(9IT@7DZGfnA7T15+M;@X_6DrlCGLg z&fN4L>gc*Soq`6@U&{AQVql%cl9Q7^5PEfmjhwD2nkvuSDvXj5Y7yYT%)Etl66S89 zNWLp3m~HOPCb0DaxE1@BZhvvADmr9WwXS2REx)b3$iHoBiiQ9^2U0)Zn={{V9m}?O zYm3-Yt0I@pY$oX(%Q||CebVo`7M3G|N`9DFfP0`7!Bm2Zj_xe_i zPE1Vr`THLRKwxJ+rpmjQIrQ-Ig66$9ux7l0(XoLF6wJ~DQI9|M8QJ4WqNs;C-skZ> z|1E-}tfVAYwhaO~^KD8g z%rL#OY;i{J3TGWpwLr^>pFx)^tuEJ3XuCwmIh;lSwT!g3UVPUba6_#IK-fgP<*2%3 zg{*~cdF63`P3MZ#-zUi#X-_CT z9`EA|dU0hv`-VNx`Ty9O{}>bXq- literal 0 HcmV?d00001 diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/common/media/notebookThemes/jupyter.png b/src/vs/workbench/contrib/welcome/gettingStarted/common/media/notebookThemes/jupyter.png new file mode 100644 index 0000000000000000000000000000000000000000..a81eecb1b80441e501d7a1956ff94879facb6206 GIT binary patch literal 2489 zcmds3YgAKL7CtcwC}OllsJx=BTD1y{6|qvnD-f8a0U=uCVZav%5?%uV(j;`MJlav( z!iYc-0h@pfL5yN01R@WeA<8RaBq3m{v?lQqsN_Znj~+6!7Ry=ES<|2Wk(+z(x%=$B zzi)qgpWFa4$!vwy3IKqapD!^GfF&|`|J=j~UVGcTn&98^1mDBS09b6A|6%+BH;%!V znB+i`C*XD2DB;7>D3ARf0MzH1PDd_-24p{?2PF-ID8w<8P`i8Me;-X)X{&KweT7H~ zpuEU^JL)_W=r??7gjgnQtRUOyuzToRp0|InErU3cxjKG}pY@*t6g6bV*tY~u=hf*z z#wP^4iARiP6J_)8G(Wbsn#`5#06_F-)$DiB`v>G`EO5{4F#?&O+zf{1X${jjvm3@` z5(j|E#Zmg57cWki3mf9(hX4ppcc3d?qKq^PJU>3L82 zb=J&OIZGWJJJggObm`;tKnqJtQy>Z{pxy0{?t4WP_@LuY?}>kUP~wedHpCAPF}hU@ zW8m)6;iVUShF!ui(Yn^KArF^Je=HB@@>g;RF%TfQ%s6$b+R=u+9DwM$wCL{cZp*Bf zQ(E4f$$ z-FbG_l)16(>7#?|(lWxZuiCP4LWW8>4^B`inJXAv#^>|TqOyj#Q0Qbt_~~TQ?Lxuk z-{#9e`Yv5U+M)Is8;2D@H1{E-=FMfXKz+nPwD(d`(bnu$w%gRwItPhlW=`xJKUDC( z|D}SCj*gusYAop4wGh?`bEkLn@NR?vcUCNfbg(g{CVpQC^)wdzt*y1SHOYbgH1E94 zo`fga?_IyDd$_euOA5t<%<-IT6qb(onyS+L5k8Iyz}?DTe3s40zF2r)EaJWQo5g5I zuH8#ux0W_DUW)^ww018Bi`BeRtyN2zb@c=Q_CwCHarjkEH*0ktGpBB7QXUzD%ek|S zrz9MR^&Nk=8H&$=&l6}g-u?Uc3kC)TKI6@e{or+*p`#rR3%fC!12g?HMlfkmY9n%+FhW-u6#=@wZ5<@4WqTmb%!np@cD|NGD} z{GBfq40P?GE(ZseJ;dUu!TDy{v6FAPSh3eZggc3^cZLNAPqOK@lk(xYaRGZykG8;m zIL0v4S_B@kxCm>5lxMfYdiUuqur}DolarH2dMimM5)&>w)OkECjLkq zxPC(H{&fg4c$-i67t;Hr#vpoIxgxILpb|S*j~;sKbFC$}v*}YNU`K z)r~fn(AdMD8{@KyS4bIlZmdCFbY zbO}^ukHxuFh}EO0u5Xph7P{t0QCXP-06j+M9;ZCZQyH)KFWuW;a#Ttp@s0>Xc;Ny# zDK77@vXoJ|kF{0k-j3$9@rpPoh3L||XV8$+qnaUp9RQB$R%>LO#}L-y`YberWuY&$ zbh89tv-Gj2+#EJ}zugTz1omu`tv3J{gKO+$DKX(#{Qy78VDt|I7f&CQIE!0bJ)vU! zoG#>V@P^GXpVv#e2D^6X{P_4^W9s)xX7R!IhuV>2>MBS@wgPZ1(4dxx2mUvx!i)p3 zuYFharm??h_96;bqO^c^n^N{KdT3bGdhsL5LL)M?M9~DhrEwXENDo@}YQr2Rk-2u9 TgFdk+Lc)qPo68KthQj6hv=w!Q3N1A(Z8-i@O`#dI=ZX13BL z;D=SD(?#X_4G(g;i?L(VJW5r%VvB3nUmldTr)+tHtml#FZ$K zyGJ2NcE!ozg?*pt%L7GCgZJHZ>4)1z&c)GdbJ`sDXyFqM4$L8gc#GZU`vAjC26fzD zUDrHJBXz)%FBB=L=*{{jz>i)BBO1-D+1QXQ^M(}Ojo8$K9B~giKZd?_e>HApY`6lH+JXIkQAWZIgF-6`w};UhPLWq-L-xOX$93Ll&jXJ;3%*fu5=srx-^X-^1ewCu zZogDxWm0JLlj5^UA}htg7yFXN?hGXzq8WTTbmW!mkYFrDZDgK!Xr{>p<7R|`!U9~48 z&ZSy1iOBjSDISKCY0}YN#X#RdXoDcfq9AEXlIF)g@3G5r$7&`W)f4S}7r`i2%uqgL z{Uj_VOdP_!>@^wVUCUAyM>jMc6KD0lov=PUYpLcxL@a(rP_0S*@ERd;-CulQWS?Z^t{qi z6!qKd>o|)e47ae+X~&N+MkCK$qR(gG$DT=}x+Gz+m;Ht|as(%UqWDfXetj*i=%XDA zS&XH$1I*;Lz6Dc#F!z9@H&YVj$ZIl}L#0f@Aw z`-ZVflgv0`K*dkWqb#Jj|6v{KY=*Ic_|v@}Y^|XOkp4;+KOH~LIE7hK3`raMcUaVeTQ*M}RSojIW0!LW2 zSWcUfjswd{*2Ej8H%$Y3BVSY%TFB(|b{slLlOB>+yZYsUi)<3qFsS>MOpr`i$&HEE z{%>PudA*ta;PPZ5ud^%T25G-E4LA?_&Q-zqUq=sU-Qq4vcV#M;+gs}rwN-J1~nklauimuv7)@1f$*y_zdp*PlG* zHE}Dn#oFElfT&GtRy}sPM_!?CUs>#I`|_~SOTkn3Oa!|H z6^zcC@EE^%X`ery*H$oW%xu(dq>!7|vC{pu)1b2_x4P@4L!M(%cVB+sRL_)(=Uq>U zNlRZ^-`ovPLgf4S_hvCXG0%AWy$~`v?DOpQ2k{44Bkx2C9AslR*U62K7PF~}Ej-$v z)RTNQX-Qhnv(1yn%WSY`a=op(@y3ka*wxy*Uk-f1w-mfzj7Tg?{OB0cP3o0EIKF&# z`o*-loUEKRM*+u13RBAEly2FXywT^E+77hYh=d#B+V!&a%~DI{O858GmZFzkXWuVL zjW$cP`aE?R@5}5hw=I|L?=4Rb(5yIKVH%LU`D9aei+^i`WSHbS#-F6j!Nik^Ku7Sv z>Ei@*(q_Q}n5>whS@jsjSjIW6V;&@BU#ddMrX0af_|s*!bmq z4|lWg?^!!oKZ*0(mELrXJio7*Nh2(o(N}cI|AIvi{#EVV$+^0fHdsSYOVD@_ZKz`C z`5uUW~=km*IswL?0j3^a1&n41nt>4+3a?F zWOn$VPSqoxC+wPpH(_7S&INxi9_#*0v3hWmX;VNEV-bTh9~BVXzht{&8*BUBX3f^A zev)}LtWJg0D)N=mI6}z^O$&AU3&ZkLllkgY(oQ$U_Lkka^T(!)a>sfV^d9?JI z>#|*nSKn}{;`tzl)PvDY(Go{T-{IU%FF#z@?z}q_XMTUn)$C2_&_cnm#<01$MUlng z^}g#-*EyLVFwZj=3X7TM`{}k@Eq&?L!10V}7{?`u2wmvP6LjyyetY|^^8?y!F#myj zHKzch;YsEL`-KH2H-*2KBydG=o&U6PR{oi1!0k=5b$^0=d#i~dT7YSvxsWUWQGwN$ z!4<>fw2ca}TR7vy+(Q54T0Hwi?gY=ojN@#-3(nwKJ}%#PC_iFvVtnE)iH+QAjl%*q zPBt<{bVWys-0!L0lW;8Pzz0mkQR!Cq)>YQw9fP~iITLbBb2i!{G3*605uW!Z*Gn}@ zCtgo~?A?3z+*upn9N+on(vHNOqAAt3+pUD}%XcRUc=MMP3&?sbb!$p%E5%;gtY_FO zu_rb{^k{o!54yj~Y)kX>Vt<(R6)yQec7Fa+*C*dvuE+uoJNE32_w(tFi}`C`$TKVz zt1KR7F#i}6Cs$%dsGwZLZ3Z<7SS%7b>f0oh1pgfp=oi7 zV`{I2tn=~S@A%H1V+BL?LR%&yP87Z6?jgP-UA<#oGSk)lzAg%j0VAZZ1It6CX!~XB z(8t%kI~nU^zNELL+cfP-J-cB=&@fF`9U05QWlc0)OjVd3_NrJryEze;@`gE<*`|!Q ztkqxGKYdMk&AB{j_2tOj@2#`QPtL{_j=qiyYw7)@0TuG`$2%5IFP&cWY>+AQB5b)3 z9(o+{8SNzWELU;fQW*D_oef>goO1gz(l>a`+{L`EqAS30lWA@$l;7}i^t^THCtb)5 zK}l{>OcCMEsw6AqfS59!U1UT1Luf=9T(@9K_NW=$wR!9N~ zBs~0-D+$EY<7_rMOtz}kMv#g1zVI>5vroNFLk1E^R`~TZgNvRSm@jix%foOy&JJ0e z^cTNI9Mh-9NRKC*Zuw<}H>{(_=VlIs8w`+dW^IvCKjLUgiP3TcZ1PT7fP%U@_|(66)yBrj?UJ)Q&C!E^jYBA1)Xsz5G4T)&5_P@9 zvta(V%LYd7Mp~NE7o8o2Ev=ocY=pfXU5N8QWWA-qsiTd%CBoa$!O2b9TaIh{32AUn z{91$yvHghq6*(>=Efhl8`Kk@#q_C*4D3?4H0)dddYHcg6r*e8{IJlDIy5#QeA}u1~ z<>e*pB`)lI)lTG?l$4Z+sF;YDm=JhE$nBbwyQQ~~lNSY)A%g#;+ z;=Gnt&K~Y^TwKJ3e*OK}r;YdJzgBW`+Yt*0C_=m=a!goM>@K5wh5C>nT^O!nwx*m|(n&bi&~e5`Aq@Oi4DDqia7#eEO<95%q`D6ka?-#Vw8 zuby^F5vxc>rlf|0J3c^n!Ue?`&Wbg8mtSp?YAPOCkXdeh zaxGw?$E|#1QSO~gXh~j4iSOpp?fyd+S;o#fKXHaPCm7nt==y(vQhi#TD z#L2hEV8_{ijlIc0m!Uf$y65Lu404g?=R$B5N_b0#2TSmejUkXooDapXZ9IU%>|3Pw zDDP|=fk2g!{#*g73x%GrXAeH~a}#tKeLq)#V2_Ys4;0W;{aOZYF!OT-3^Epjj4%$d z{Iv}1sn^dHkccx#-02rpqQ91bw#xim;g6U=EC0i+X`z5pa2tuk_g=~F=bV14Rnj{b zGt;*CWVG!th4ZW=?oz?nS5v>oqS&t$_k$+1Kc{nv)_#|N9Q_L2qq93u<|W)o?Y> z-yjBopZY1*aD$+MkYJ@DS33X< zubjy~x(p$whI%m5C^KEghVZd;=n32XkWPMb~UjekrC%_D82y~E7!wSf$~V8P!C8OgZX|?k(StnL7@fJFYez5Gi`v=ex6~2KW6yP znBhLwC!mtCez7&VSXg!v5A}$TbLKR~K0<1(sCInvXOxv9f$GDQ=F`KdTg+vb2-6Bp zathU+0t&wUhSObj9#70vaN7I7FQ}eE@Sr#etqLW1O{Lxj9ddjmPyxo37WSD@?cSB8 z>QsJV6nZuy)ng>Z*U~lKS>C<>i}>VT1d6-O;wCwa0qQZ+pAj3~VfN@3&)2AWjkh-d5vb_9R2`$PADgOv7`DsX+;eW4Z(_z_@B63_$z~ z*BBAw{}2L2eH?3CDalL6k3cCiUlatP84iM+ECDHGagY(dpDrUUYl+-R>KAIADjeh zjHCQr?MRCtp!bh|w)^kWF7g6ylTgfjTDE2h{ngR1)P}&!?pl4Z){J#dKOm^`6C+)Q zs`E%nJOsN)^_FbhC$m=WK9YT8I6X22gOu};S$+$HKQ{y(GjnbmHI4y$f)o#USEV(; zv->W6Aa`H$H}#hTd04LG`(fZ#Ap6h!03|D!9(1utL9RL3_vFx)24~*Ez;Gt-nUL&h zr{V?Dhv+_9hD&F`erd zawJlwo|8T!By-A42&{gu$ZiSnwsT^Q?L?%K5G0~iDGP{f04+ombfRy5Obm;`2?ioA znS}!e2tb60cSSeH^t1p8o%Nt3B9O>wInRX8QCf5yFMHVZ0iy0vmsJKw)c>6Q7$mhdQ0-S z1Y-Ix)DM*D2Yxp%E0MkC6W9lHafSvUJ;4IZ(9Y8RGKwgLed$4|U4bX^@MUTZr zaAR@ua}3xc*hK~DZmq#V&f*0ccptQ2hQu{aOpH$esV6!g^8p_NUWBIDt$sQnj3yIZ zMhxXh84$L;y|o?Kr9DqW2ka5-Vv}Z@N&K`U&|$nF0>#JJ=nI@RJNsF-DiW7v7nefZ zBlN^N`!-Se=@7&`c^-+==1p1#!kU>In%~ACO`C+}h=mW>h0Hb&`srE!TZKE2kDGWc zpVCIJS$nNbCoU@xs>HyYtX^J@I)IiHi8B&u8AAtcO9*GcBN>nJhpo#=B8L$u=IdVF z!(cHt0dY~V>KTwTKU=TgKsIy)9-Rjnb~92_4Ok-(cwyifq3?27JY8w`Nj?NB(d0fB zFgFyq5zRX!0<*8-(7Xfmzu;x91eA6VWPJ_;`?ML#mKy`Tg;IcW_SEemvQIrE?%r`$ z^dXe^lEp1Q5^O>RHzNZAIe>#g7jb&j{yI2e*i2yq2$JD*wiaNjSdiTxyDv6nBkBeW4zQyo(&Q0gN{#Ni`?Scx6c`kTOd0Lu+qy&SVu2Cp?^g z)gYe^XlwE|b=}SqpHw-g8dK!hhOB^%Pm)a+kEBe0eIJt;B3})bes$M@<}gY^&W{TP zuFli|F2M{Wr9N?WOAzJewa{h#n@?dc0beLf*%*Y4%byzNgxL?9Y2F1&TJW^uf`$Ui zy9zibspHB&9UfQNF8E%9@4Tf>bJGD61m2tDeF$%nc&)x7fKA9D6VC@eZqgCWN+}5R z8Q1?>krxQ6Ydk9h^-%OHass*MWPxxMgOMf@Cwy9AvOw31o_lq&UKkFW2lE_DjhbSrdy&r1U-uFl6*J^EJp{xn7a){dkA%f4Xr$&M1u86 z3sxYyi6b$*6n65-pAh@+%xSLJwGjom*0S}_Tf7P#E!0W)jg=M+hi@Zfr>Qrp-$-%x?RkfG`wL*vzQy zrj%Fif+TtON`%i5tnqW@f6Sf3WaIs*t5-6jbKwrE1A*Ba37MQuBUV{TH~=S0xJmXM zR*MZn_CCBe_jts7kCcJ zhS0@cz%6@u%jwhrA9&w=j19o06Ugz*W>623A@RRTJETPjfN@ZHkcBtxu2R^6uYuZy zSyX;^o#P1yH28zariCw|V#}`ftTusL2R$68<2%sUysn`qGq~PC1f(#NVroW&s1ZUK zMPV|7PeAro4~Gb&fQ1J>o8E_DbBXk@;5SeL`>O*!ui4=X+Bb_HYX<=(v5RxsAui;9 zr#Z0z?eFI-L$F;F6W^u4UK@pbcWBGrzmuFJz<O>kAr7EuD?)R`6Rc;EuX~2ZFVPrf&777xk}{*`4k=gA2~q{k^mq&;-;+ zb2e_}3fVZ1Q*ZJz(2bmZKrjTW4$ScRWYrAU@66kU7l1YIipF{YbdjNGy3rR{fa8RM zGN$q{u<_-@K`;8_XL`d zJk~RY5-qrA{XMJ2n<3Fu-y z_3Q*K$W^p?{DBM|LI{*sGy60Jnf*%L@9EePY(3)Sv<3D+Q8a;qA!FHhMI0&s3hd~) zwRe`Kg^}G%T^90Gc*FA)w2pGKBUtNKSnrHp1OG^*i z%_3Zn!9i-#k>99aN;6;YcqCB#0kk=UE%fB6TVl21xlKVS)tp>UY%7$DpCHPaMg_Jn%mqOf?(-2Gh*#vEm^;g7I! zXpPrI@n8sP2Kx5#!J;V5?Po5DuP6hUFV3B_}f-E@FkXMJ+%vBJvNPuZ3MP+HJv zqvqPNIZ_GNN1#YYf3FpB7O9x$1Z9IXzETxEm^<~s+-G>ST~q-}0jhqoJ4n;Ym0yi) zK9CdmzPTIa0G21Hy4$Os$AG6}u1X66uoJ$=y_@Q_se=xcx)eJTU^vVl=y!YQ#3KOz zkCJGp0Z|J32A2DaHhSoRw4TljIomr`x`f9akW$R-_HCoRgW4uS`fg<2guSN^!ztb%zp%W{$n{jsJbTl z*Au4}(Z1X@)d-mOq1k7tD=SNxiCcugN&@&TNWaKfa)l~xI%we{GhY-#26}14ynAyl zB-=cxg1U)mWil_dD`2D3JkejhC~W)ZA>PZPKWaH|5rFq*{N?nL5r82_Jk;j^O=0=c z*7KX%SRW?OitiW@n-~r8c}oBxmgi2`q5z_VBtFl-q&W;Sb!4fRY4`SNNJ8~Z?W6RT4uU@vE1fLh_gS2b96swAx>|QY4eGy z4VXPz3j|F>Sft48XAO}JG>&77-|5#c{6tR;Y;97G$9{N40iFT9EAW ` @@ -12,7 +11,7 @@ export default () => `

    ${escape(localize('welcomePage.vscode', "Visual Studio Code"))}

    -

    VS Code v${product.version}

    +

    ${escape(localize({ key: 'welcomePage.editingEvolved', comment: ['Shown as subtitle on the Welcome page.'] }, "Editing evolved"))}

    @@ -32,19 +31,6 @@ export default () => `

    ${escape(localize('welcomePage.noRecentFolders', "No recent folders"))}

    -
    -

    code-server ${escape(localize('welcomePage.help', "Help"))}

    - -

    ${escape(localize('welcomePage.help', "Help"))}

      diff --git a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts new file mode 100644 index 000000000000..ca012b9fd548 --- /dev/null +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts @@ -0,0 +1,55 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { WelcomePageContribution, WelcomePageAction, WelcomeInputSerializer } from 'vs/workbench/contrib/welcome/page/browser/welcomePage'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions, CATEGORIES } from 'vs/workbench/common/actions'; +import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; +import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; +import { IEditorInputFactoryRegistry, EditorExtensions } from 'vs/workbench/common/editor'; +import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; +import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; + +Registry.as(ConfigurationExtensions.Configuration) + .registerConfiguration({ + ...workbenchConfigurationNodeBase, + 'properties': { + 'workbench.startupEditor': { + 'scope': ConfigurationScope.RESOURCE, + 'type': 'string', + 'enum': ['none', 'welcomePage', 'readme', 'newUntitledFile', 'welcomePageInEmptyWorkbench', 'gettingStarted', 'gettingStartedInEmptyWorkbench'], + 'enumDescriptions': [ + localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.none' }, "Start without an editor."), + localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.welcomePage' }, "Open the legacy Welcome page."), + localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.readme' }, "Open the README when opening a folder that contains one, fallback to 'welcomePage' otherwise."), + localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.newUntitledFile' }, "Open a new untitled file (only applies when opening an empty window)."), + localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.welcomePageInEmptyWorkbench' }, "Open the legacy Welcome page when opening an empty workbench."), + localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.gettingStarted' }, "Open the new Welcome Page with content to aid in getting started with VS Code and extensions."), + localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.gettingStartedInEmptyWorkbench' }, "When opening an empty workbench, open the new Welcome Page with content to aid in getting started with VS Code and extensions.") + ], + 'default': 'gettingStarted', + 'description': localize('workbench.startupEditor', "Controls which editor is shown at startup, if none are restored from the previous session.") + }, + } + }); + +Registry.as(WorkbenchExtensions.Workbench) + .registerWorkbenchContribution(WelcomePageContribution, LifecyclePhase.Restored); + +Registry.as(ActionExtensions.WorkbenchActions) + .registerWorkbenchAction(SyncActionDescriptor.from(WelcomePageAction), 'Help: Welcome', CATEGORIES.Help.value); + +Registry.as(EditorExtensions.EditorInputFactories).registerEditorInputSerializer(WelcomeInputSerializer.ID, WelcomeInputSerializer); + +MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { + group: '1_welcome', + command: { + id: 'workbench.action.showWelcomePage', + title: localize({ key: 'miWelcome', comment: ['&& denotes a mnemonic'] }, "&&Welcome") + }, + order: 1 +}); diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/page/browser/welcomePage.css b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.css similarity index 99% rename from lib/vscode/src/vs/workbench/contrib/welcome/page/browser/welcomePage.css rename to src/vs/workbench/contrib/welcome/page/browser/welcomePage.css index 2608762fccc5..76546c30d4e4 100644 --- a/lib/vscode/src/vs/workbench/contrib/welcome/page/browser/welcomePage.css +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.css @@ -94,7 +94,7 @@ } .monaco-workbench .part.editor > .content .welcomePage .splash .section { - margin-bottom: 3em; + margin-bottom: 5em; } .monaco-workbench .part.editor > .content .welcomePage .splash ul { diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts similarity index 80% rename from lib/vscode/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts rename to src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts index cb20a4cd8fc6..0824a9edbbb3 100644 --- a/lib/vscode/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts @@ -10,7 +10,7 @@ import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/c import * as arrays from 'vs/base/common/arrays'; import { WalkThroughInput } from 'vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IInstantiationService, optional } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { onUnexpectedError, isPromiseCanceledError } from 'vs/base/common/errors'; import { IWindowOpenable } from 'vs/platform/windows/common/windows'; @@ -32,7 +32,7 @@ import { registerThemingParticipant } from 'vs/platform/theme/common/themeServic import { focusBorder, textLinkForeground, textLinkActiveForeground, foreground, descriptionForeground, contrastBorder, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { getExtraColor } from 'vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils'; import { IExtensionsViewPaneContainer, IExtensionsWorkbenchService, VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions'; -import { IEditorInputSerializer, EditorInput } from 'vs/workbench/common/editor'; +import { IEditorInputSerializer } from 'vs/workbench/common/editor'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { TimeoutTimer } from 'vs/base/common/async'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; @@ -48,54 +48,8 @@ import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/la import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { GettingStartedInput, gettingStartedInputTypeId } from 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedInput'; import { welcomeButtonBackground, welcomeButtonHoverBackground, welcomePageBackground } from 'vs/workbench/contrib/welcome/page/browser/welcomePageColors'; -import { ITASExperimentService } from 'vs/workbench/services/experiment/common/experimentService'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { IConfigurationRegistry, Extensions as ConfigurationExtensions, IConfigurationNode, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; -import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; -import { ILogService } from 'vs/platform/log/common/log'; - - -export const DEFAULT_STARTUP_EDITOR_CONFIG: IConfigurationNode = { - ...workbenchConfigurationNodeBase, - 'properties': { - 'workbench.startupEditor': { - 'scope': ConfigurationScope.RESOURCE, - 'type': 'string', - 'enum': ['none', 'welcomePage', 'readme', 'newUntitledFile', 'welcomePageInEmptyWorkbench', 'gettingStarted'], - 'enumDescriptions': [...[ - localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.none' }, "Start without an editor."), - localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.welcomePage' }, "Open the Welcome page."), - localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.readme' }, "Open the README when opening a folder that contains one, fallback to 'welcomePage' otherwise."), - localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.newUntitledFile' }, "Open a new untitled file (only applies when opening an empty window)."), - localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.welcomePageInEmptyWorkbench' }, "Open the Welcome page when opening an empty workbench."), - localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.gettingStarted' }, "Open the Getting Started page.")] - ], - 'default': 'welcomePage', - 'description': localize('workbench.startupEditor', "Controls which editor is shown at startup, if none are restored from the previous session.") - }, - } -}; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; -export const EXPERIMENTAL_GETTING_STARTED_STARTUP_EDITOR_CONFIG: IConfigurationNode = { - ...workbenchConfigurationNodeBase, - 'properties': { - 'workbench.startupEditor': { - 'scope': ConfigurationScope.RESOURCE, - 'type': 'string', - 'enum': ['none', 'welcomePage', 'readme', 'newUntitledFile', 'welcomePageInEmptyWorkbench', 'gettingStarted'], - 'enumDescriptions': [...[ - localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.none' }, "Start without an editor."), - localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.welcomePage' }, "Open the Welcome page."), - localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.readme' }, "Open the README when opening a folder that contains one, fallback to 'welcomePage' otherwise."), - localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.newUntitledFile' }, "Open a new untitled file (only applies when opening an empty window)."), - localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.welcomePageInEmptyWorkbench' }, "Open the Welcome page when opening an empty workbench."), - localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'workbench.startupEditor.gettingStarted' }, "Open the Getting Started page.")] - ], - 'default': 'gettingStarted', - 'description': localize('workbench.startupEditor', "Controls which editor is shown at startup, if none are restored from the previous session.") - }, - } -}; const configurationKey = 'workbench.startupEditor'; const oldConfigurationKey = 'workbench.welcome.enabled'; @@ -103,7 +57,6 @@ const telemetryFrom = 'welcomePage'; export class WelcomePageContribution implements IWorkbenchContribution { private experimentManagementComplete: Promise; - private tasExperimentService: ITASExperimentService | undefined; constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -115,11 +68,7 @@ export class WelcomePageContribution implements IWorkbenchContribution { @ILifecycleService private readonly lifecycleService: ILifecycleService, @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, @ICommandService private readonly commandService: ICommandService, - @ITelemetryService private readonly telemetryService: ITelemetryService, - @ILogService private readonly logService: ILogService, - @optional(ITASExperimentService) tasExperimentService: ITASExperimentService, ) { - this.tasExperimentService = tasExperimentService; // Run immediately to minimize time spent waiting for exp service. this.experimentManagementComplete = this.manageDefaultValuesForGettingStartedExperiment().catch(onUnexpectedError); @@ -132,43 +81,6 @@ export class WelcomePageContribution implements IWorkbenchContribution { if (this.lifecycleService.startupKind === StartupKind.ReloadedWindow || config.value !== config.defaultValue) { return; } - - if (this.configurationService.getValue('workbench.gettingStartedTreatmentOverride')) { - await new Promise(resolve => setTimeout(resolve, 1000)); - Registry.as(ConfigurationExtensions.Configuration).deregisterConfigurations([DEFAULT_STARTUP_EDITOR_CONFIG]); - Registry.as(ConfigurationExtensions.Configuration).registerConfiguration(EXPERIMENTAL_GETTING_STARTED_STARTUP_EDITOR_CONFIG); - } - - let someValueReturned = false; - type GettingStartedTreatmentData = { value: string; }; - type GettingStartedTreatmentClassification = { value: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; }; - - const tasUseGettingStartedAsDefault = this.tasExperimentService?.getTreatment('StartupGettingStarted') - .then(result => { - this.logService.trace('StartupGettingStarted:', result); - this.telemetryService.publicLog2('gettingStartedTreatmentValue', { value: '' + !!result }); - someValueReturned = true; - return result; - }) - .catch(error => { - this.logService.error('Recieved error when consulting experiment service for getting started experiment', error); - this.telemetryService.publicLog2('gettingStartedTreatmentValue', { value: 'err' }); - someValueReturned = true; - return false; - }); - - const fallback = new Promise(c => setTimeout(() => c(false), 2000)).then( - () => { - if (!someValueReturned) { this.logService.trace('Unable to read getting started treatment data in time, falling back to welcome'); } - someValueReturned = true; - } - ); - - const useGettingStartedAsDefault = !!await Promise.race([tasUseGettingStartedAsDefault, fallback]); - if (useGettingStartedAsDefault) { - Registry.as(ConfigurationExtensions.Configuration).deregisterConfigurations([DEFAULT_STARTUP_EDITOR_CONFIG]); - Registry.as(ConfigurationExtensions.Configuration).registerConfiguration(EXPERIMENTAL_GETTING_STARTED_STARTUP_EDITOR_CONFIG); - } } private async run() { @@ -224,7 +136,7 @@ export class WelcomePageContribution implements IWorkbenchContribution { await this.experimentManagementComplete; const startupEditorSetting = this.configurationService.getValue(configurationKey); - const startupEditorTypeID = startupEditorSetting === 'gettingStarted' ? gettingStartedInputTypeId : welcomeInputTypeId; + const startupEditorTypeID = (startupEditorSetting === 'gettingStarted' || startupEditorSetting === 'gettingStartedInEmptyWorkbench') ? gettingStartedInputTypeId : welcomeInputTypeId; const editor = this.editorService.activeEditor; // Ensure that the welcome editor won't get opened more than once @@ -251,7 +163,10 @@ function isWelcomePageEnabled(configurationService: IConfigurationService, conte if (startupEditor.value === 'readme' && startupEditor.userValue !== 'readme') { console.error('Warning: `workbench.startupEditor: readme` setting ignored due to being set somewhere other than user settings'); } - return startupEditor.value === 'welcomePage' || startupEditor.value === 'gettingStarted' || startupEditor.userValue === 'readme' || startupEditor.value === 'welcomePageInEmptyWorkbench' && contextService.getWorkbenchState() === WorkbenchState.EMPTY; + return startupEditor.value === 'welcomePage' + || startupEditor.value === 'gettingStarted' + || startupEditor.userValue === 'readme' + || (contextService.getWorkbenchState() === WorkbenchState.EMPTY && (startupEditor.value === 'welcomePageInEmptyWorkbench' || startupEditor.value === 'gettingStartedInEmptyWorkbench')); } export class WelcomePageAction extends Action { @@ -450,7 +365,7 @@ class WelcomePage extends Disposable { const prodName = container.querySelector('.welcomePage .title .caption') as HTMLElement; if (prodName) { - prodName.textContent = `code-server v${this.productService.codeServerVersion}`; + prodName.textContent = this.productService.nameLong; } recentlyOpened.then(({ workspaces }) => { @@ -748,10 +663,10 @@ export class WelcomeInputSerializer implements IEditorInputSerializer { } public serialize(editorInput: EditorInput): string { - return '{}'; + return ''; } - public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): WalkThroughInput { + public deserialize(instantiationService: IInstantiationService): WalkThroughInput { return instantiationService.createInstance(WelcomePage) .editorInput; } diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/page/browser/welcomePageColors.ts b/src/vs/workbench/contrib/welcome/page/browser/welcomePageColors.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/page/browser/welcomePageColors.ts rename to src/vs/workbench/contrib/welcome/page/browser/welcomePageColors.ts diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut.contribution.ts b/src/vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut.contribution.ts rename to src/vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut.ts b/src/vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut.ts rename to src/vs/workbench/contrib/welcome/telemetryOptOut/browser/telemetryOptOut.ts diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/telemetryOptOut/electron-sandbox/telemetryOptOut.contribution.ts b/src/vs/workbench/contrib/welcome/telemetryOptOut/electron-sandbox/telemetryOptOut.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/telemetryOptOut/electron-sandbox/telemetryOptOut.contribution.ts rename to src/vs/workbench/contrib/welcome/telemetryOptOut/electron-sandbox/telemetryOptOut.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/telemetryOptOut/electron-sandbox/telemetryOptOut.ts b/src/vs/workbench/contrib/welcome/telemetryOptOut/electron-sandbox/telemetryOptOut.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/telemetryOptOut/electron-sandbox/telemetryOptOut.ts rename to src/vs/workbench/contrib/welcome/telemetryOptOut/electron-sandbox/telemetryOptOut.ts diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/browser/editor/editorWalkThrough.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/editor/editorWalkThrough.ts similarity index 91% rename from lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/browser/editor/editorWalkThrough.ts rename to src/vs/workbench/contrib/welcome/walkThrough/browser/editor/editorWalkThrough.ts index 4c055d9f81ee..f174ef7a7fc0 100644 --- a/lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/browser/editor/editorWalkThrough.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/editor/editorWalkThrough.ts @@ -10,8 +10,9 @@ import { Action } from 'vs/base/common/actions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { WalkThroughInput, WalkThroughInputOptions } from 'vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput'; import { FileAccess, Schemas } from 'vs/base/common/network'; -import { IEditorInputSerializer, EditorInput } from 'vs/workbench/common/editor'; +import { IEditorInputSerializer } from 'vs/workbench/common/editor'; import { EditorOverride } from 'vs/platform/editor/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; const typeId = 'workbench.editors.walkThroughInput'; const inputOptions: WalkThroughInputOptions = { @@ -55,10 +56,10 @@ export class EditorWalkThroughInputSerializer implements IEditorInputSerializer } public serialize(editorInput: EditorInput): string { - return '{}'; + return ''; } - public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): WalkThroughInput { + public deserialize(instantiationService: IInstantiationService): WalkThroughInput { return instantiationService.createInstance(WalkThroughInput, inputOptions); } } diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/browser/editor/vs_code_editor_walkthrough.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/editor/vs_code_editor_walkthrough.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/browser/editor/vs_code_editor_walkthrough.ts rename to src/vs/workbench/contrib/welcome/walkThrough/browser/editor/vs_code_editor_walkthrough.ts diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution.ts rename to src/vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution.ts diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughActions.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughActions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughActions.ts rename to src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughActions.ts diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput.ts similarity index 94% rename from lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput.ts rename to src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput.ts index be87363368f7..30f595f01d2d 100644 --- a/lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput.ts @@ -3,7 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { EditorInput, EditorModel } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; +import { EditorModel } from 'vs/workbench/common/editor/editorModel'; import { URI } from 'vs/base/common/uri'; import { DisposableStore, IReference } from 'vs/base/common/lifecycle'; import { ITextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; @@ -130,10 +131,7 @@ export class WalkThroughInput extends EditorInput { } if (otherInput instanceof WalkThroughInput) { - let otherResourceEditorInput = otherInput; - - // Compare by properties - return isEqual(otherResourceEditorInput.options.resource, this.options.resource); + return isEqual(otherInput.options.resource, this.options.resource); } return false; diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.css b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.css similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.css rename to src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.css diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts similarity index 98% rename from lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts rename to src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts index 7b1af8906969..676462d52b6b 100644 --- a/lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts @@ -10,7 +10,7 @@ import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import * as strings from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { EditorOptions, IEditorMemento, IEditorOpenContext } from 'vs/workbench/common/editor'; +import { IEditorMemento, IEditorOpenContext } from 'vs/workbench/common/editor'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { WalkThroughInput } from 'vs/workbench/contrib/welcome/walkThrough/browser/walkThroughInput'; @@ -26,7 +26,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { Event } from 'vs/base/common/event'; import { isObject } from 'vs/base/common/types'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { IEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; +import { IEditorOptions as ICodeEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { registerColor, focusBorder, textLinkForeground, textLinkActiveForeground, textPreformatForeground, contrastBorder, textBlockQuoteBackground, textBlockQuoteBorder } from 'vs/platform/theme/common/colorRegistry'; import { getExtraColor } from 'vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils'; @@ -39,6 +39,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor import { CancellationToken } from 'vs/base/common/cancellation'; import { domEvent } from 'vs/base/browser/event'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { IEditorOptions } from 'vs/platform/editor/common/editor'; export const WALK_THROUGH_FOCUS = new RawContextKey('interactivePlaygroundFocus', false); @@ -267,7 +268,7 @@ export class WalkThroughPart extends EditorPane { this.scrollbar.setScrollPosition({ scrollTop: scrollPosition.scrollTop + scrollDimensions.height }); } - override setInput(input: WalkThroughInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + override setInput(input: WalkThroughInput, options: IEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { if (this.input instanceof WalkThroughInput) { this.saveTextEditorViewState(this.input); } @@ -420,7 +421,7 @@ export class WalkThroughPart extends EditorPane { }); } - private getEditorOptions(language: string): IEditorOptions { + private getEditorOptions(language: string): ICodeEditorOptions { const config = deepClone(this.configurationService.getValue('editor', { overrideIdentifier: language })); return { ...isObject(config) ? config : Object.create(null), diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughContentProvider.ts b/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughContentProvider.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughContentProvider.ts rename to src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughContentProvider.ts diff --git a/lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils.ts b/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils.ts rename to src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils.ts diff --git a/lib/vscode/src/vs/workbench/contrib/workspace/browser/media/trusted-badge.png b/src/vs/workbench/contrib/workspace/browser/media/trusted-badge.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/workspace/browser/media/trusted-badge.png rename to src/vs/workbench/contrib/workspace/browser/media/trusted-badge.png diff --git a/lib/vscode/src/vs/workbench/contrib/workspace/browser/media/untrusted-status.png b/src/vs/workbench/contrib/workspace/browser/media/untrusted-status.png similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/workspace/browser/media/untrusted-status.png rename to src/vs/workbench/contrib/workspace/browser/media/untrusted-status.png diff --git a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts new file mode 100644 index 000000000000..acc89ff6576c --- /dev/null +++ b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts @@ -0,0 +1,766 @@ +/*--------------------------------------------------------------------------------------------- + * 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!./workspaceTrustEditor'; +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; +import { localize } from 'vs/nls'; +import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; +import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { Severity } from 'vs/platform/notification/common/notification'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IWorkspaceTrustManagementService, IWorkspaceTrustRequestService, workspaceTrustToString } from 'vs/platform/workspace/common/workspaceTrust'; +import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; +import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; +import { Codicon } from 'vs/base/common/codicons'; +import { ThemeColor } from 'vs/workbench/api/common/extHostTypes'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/workbench/services/statusbar/common/statusbar'; +import { IEditorRegistry, EditorDescriptor } from 'vs/workbench/browser/editor'; +import { shieldIcon, WorkspaceTrustEditor } from 'vs/workbench/contrib/workspace/browser/workspaceTrustEditor'; +import { WorkspaceTrustEditorInput } from 'vs/workbench/services/workspaces/browser/workspaceTrustEditorInput'; +import { WorkspaceTrustContext, WORKSPACE_TRUST_EMPTY_WINDOW, WORKSPACE_TRUST_ENABLED, WORKSPACE_TRUST_STARTUP_PROMPT, WORKSPACE_TRUST_UNTRUSTED_FILES } from 'vs/workbench/services/workspaces/common/workspaceTrust'; +import { IEditorInputSerializer, IEditorInputFactoryRegistry, EditorExtensions, EditorResourceAccessor } from 'vs/workbench/common/editor'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { isWeb } from 'vs/base/common/platform'; +import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; +import { dirname, resolve } from 'vs/base/common/path'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import product from 'vs/platform/product/common/product'; +import { IMarkdownString, MarkdownString } from 'vs/base/common/htmlContent'; +import { isSingleFolderWorkspaceIdentifier, toWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { Schemas } from 'vs/base/common/network'; +import { STATUS_BAR_PROMINENT_ITEM_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_FOREGROUND } from 'vs/workbench/common/theme'; +import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; +import { splitName } from 'vs/base/common/labels'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IBannerItem, IBannerService } from 'vs/workbench/services/banner/browser/bannerService'; +import { isVirtualWorkspace } from 'vs/platform/remote/common/remoteHosts'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; +import { LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID } from 'vs/workbench/contrib/extensions/common/extensions'; + +const BANNER_RESTRICTED_MODE = 'workbench.banner.restrictedMode'; +const STARTUP_PROMPT_SHOWN_KEY = 'workspace.trust.startupPrompt.shown'; +const BANNER_RESTRICTED_MODE_DISMISSED_KEY = 'workbench.banner.restrictedMode.dismissed'; + +/* + * Trust Request via Service UX handler + */ + +export class WorkspaceTrustRequestHandler extends Disposable implements IWorkbenchContribution { + constructor( + @IDialogService private readonly dialogService: IDialogService, + @ICommandService private readonly commandService: ICommandService, + @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, + @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService, + @IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService) { + super(); + + this.registerListeners(); + } + + private get useWorkspaceLanguage(): boolean { + return !isSingleFolderWorkspaceIdentifier(toWorkspaceIdentifier(this.workspaceContextService.getWorkspace())); + } + + private get modalTitle(): string { + return this.useWorkspaceLanguage ? + localize('workspaceTrust', "Do you trust the authors of the files in this workspace?") : + localize('folderTrust', "Do you trust the authors of the files in this folder?"); + } + + private async registerListeners(): Promise { + await this.workspaceTrustManagementService.workspaceResolved; + this._register(this.workspaceTrustRequestService.onDidInitiateWorkspaceTrustRequest(async requestOptions => { + // Message + const defaultMessage = localize('immediateTrustRequestMessage', "A feature you are trying to use may be a security risk if you do not trust the source of the files or folders you currently have open."); + const message = requestOptions?.message ?? defaultMessage; + + // Buttons + const buttons = requestOptions?.buttons ?? [ + { label: this.useWorkspaceLanguage ? localize('grantWorkspaceTrustButton', "Trust Workspace & Continue") : localize('grantFolderTrustButton', "Trust Folder & Continue"), type: 'ContinueWithTrust' }, + { label: localize('manageWorkspaceTrustButton', "Manage"), type: 'Manage' } + ]; + // Add Cancel button if not provided + if (!buttons.some(b => b.type === 'Cancel')) { + buttons.push({ label: localize('cancelWorkspaceTrustButton', "Cancel"), type: 'Cancel' }); + } + + // Dialog + const result = await this.dialogService.show( + Severity.Info, + this.modalTitle, + buttons.map(b => b.label), + { + cancelId: buttons.findIndex(b => b.type === 'Cancel'), + custom: { + icon: Codicon.shield, + markdownDetails: [ + { markdown: new MarkdownString(message) }, + { markdown: new MarkdownString(localize('immediateTrustRequestLearnMore', "If you don't trust the authors of these files, we do not recommend continuing as the files may be malicious. See [our docs](https://aka.ms/vscode-workspace-trust) to learn more.")) } + ] + } + } + ); + + // Dialog result + switch (buttons[result.choice].type) { + case 'ContinueWithTrust': + await this.workspaceTrustRequestService.completeRequest(true); + break; + case 'ContinueWithoutTrust': + await this.workspaceTrustRequestService.completeRequest(undefined); + break; + case 'Manage': + this.workspaceTrustRequestService.cancelRequest(); + await this.commandService.executeCommand(MANAGE_TRUST_COMMAND_ID); + break; + case 'Cancel': + this.workspaceTrustRequestService.cancelRequest(); + break; + } + })); + } +} + + +/* + * Trust UX and Startup Handler + */ +export class WorkspaceTrustUXHandler extends Disposable implements IWorkbenchContribution { + + private readonly entryId = `status.workspaceTrust.${this.workspaceContextService.getWorkspace().id}`; + + private readonly statusbarEntryAccessor: MutableDisposable; + + // try showing the banner only after some files have been opened + private showIndicatorsInEmptyWindow = false; + + constructor( + @IDialogService private readonly dialogService: IDialogService, + @IEditorService private readonly editorService: IEditorService, + @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, + @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService, + @IConfigurationService private readonly configurationService: IConfigurationService, + @IStatusbarService private readonly statusbarService: IStatusbarService, + @IStorageService private readonly storageService: IStorageService, + @IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService, + @IBannerService private readonly bannerService: IBannerService, + @IHostService private readonly hostService: IHostService, + ) { + super(); + + this.statusbarEntryAccessor = this._register(new MutableDisposable()); + + (async () => { + + await this.workspaceTrustManagementService.workspaceTrustInitialized; + + if (this.workspaceTrustManagementService.workspaceTrustEnabled) { + this.registerListeners(); + this.createStatusbarEntry(); + + // Set empty workspace trust state + await this.setEmptyWorkspaceTrustState(); + + // Show modal dialog + if (this.hostService.hasFocus) { + this.showModalOnStart(); + } else { + const focusDisposable = this.hostService.onDidChangeFocus(focused => { + if (focused) { + focusDisposable.dispose(); + this.showModalOnStart(); + } + }); + } + } + })(); + } + + private get startupPromptSetting(): 'always' | 'once' | 'never' { + return this.configurationService.getValue(WORKSPACE_TRUST_STARTUP_PROMPT); + } + + private get useWorkspaceLanguage(): boolean { + return !isSingleFolderWorkspaceIdentifier(toWorkspaceIdentifier(this.workspaceContextService.getWorkspace())); + } + + private get modalTitle(): string { + return this.useWorkspaceLanguage ? + localize('workspaceTrust', "Do you trust the authors of the files in this workspace?") : + localize('folderTrust', "Do you trust the authors of the files in this folder?"); + } + + private async doShowModal(question: string, trustedOption: { label: string, sublabel: string }, untrustedOption: { label: string, sublabel: string }, markdownStrings: string[], trustParentString?: string): Promise { + const result = await this.dialogService.show( + Severity.Info, + question, + [ + trustedOption.label, + untrustedOption.label, + ], + { + checkbox: trustParentString ? { + label: trustParentString + } : undefined, + custom: { + buttonDetails: [ + trustedOption.sublabel, + untrustedOption.sublabel + ], + disableCloseAction: true, + icon: Codicon.shield, + markdownDetails: markdownStrings.map(md => { return { markdown: new MarkdownString(md) }; }) + }, + } + ); + + // Dialog result + switch (result.choice) { + case 0: + if (result.checkboxChecked) { + await this.workspaceTrustManagementService.setParentFolderTrust(true); + } else { + await this.workspaceTrustRequestService.completeRequest(true); + } + break; + case 1: + this.updateWorkbenchIndicators(false); + this.workspaceTrustRequestService.cancelRequest(); + break; + } + + this.storageService.store(STARTUP_PROMPT_SHOWN_KEY, true, StorageScope.WORKSPACE, StorageTarget.MACHINE); + } + + private async showModalOnStart(): Promise { + if (this.workspaceTrustManagementService.isWorkpaceTrusted()) { + this.updateWorkbenchIndicators(true); + return; + } + + // Don't show modal prompt if workspace trust cannot be changed + if (!(this.workspaceTrustManagementService.canSetWorkspaceTrust())) { + return; + } + + // Don't show modal prompt for virtual workspaces by default + if (isVirtualWorkspace(this.workspaceContextService.getWorkspace())) { + this.updateWorkbenchIndicators(false); + return; + } + + // Don't show modal prompt for empty workspaces by default + if (this.workspaceContextService.getWorkbenchState() === WorkbenchState.EMPTY) { + this.updateWorkbenchIndicators(false); + return; + } + + if (this.startupPromptSetting === 'never') { + this.updateWorkbenchIndicators(false); + return; + } + + if (this.startupPromptSetting === 'once' && this.storageService.getBoolean(STARTUP_PROMPT_SHOWN_KEY, StorageScope.WORKSPACE, false)) { + this.updateWorkbenchIndicators(false); + return; + } + + let checkboxText: string | undefined; + const workspaceIdentifier = toWorkspaceIdentifier(this.workspaceContextService.getWorkspace())!; + const isSingleFolderWorkspace = isSingleFolderWorkspaceIdentifier(workspaceIdentifier); + if (isSingleFolderWorkspaceIdentifier(workspaceIdentifier) && workspaceIdentifier.uri.scheme === Schemas.file) { + const { parentPath } = splitName(workspaceIdentifier.uri.fsPath); + const { name } = splitName(parentPath); + checkboxText = localize('checkboxString', "Trust the authors of all files in the parent folder '{0}'", name); + } + + // Show Workspace Trust Start Dialog + this.doShowModal( + this.modalTitle, + { label: localize('trustOption', "Yes, I trust the authors"), sublabel: isSingleFolderWorkspace ? localize('trustFolderOptionDescription', "Trust folder and enable all features") : localize('trustWorkspaceOptionDescription', "Trust workspace and enable all features") }, + { label: localize('dontTrustOption', "No, I don't trust the authors"), sublabel: isSingleFolderWorkspace ? localize('dontTrustFolderOptionDescription', "Browse folder in restricted mode") : localize('dontTrustWorkspaceOptionDescription', "Browse workspace in restricted mode") }, + [ + !isSingleFolderWorkspace ? + localize('workspaceStartupTrustDetails', "{0} provides features that may automatically execute files in this workspace.", product.nameShort) : + localize('folderStartupTrustDetails', "{0} provides features that may automatically execute files in this folder.", product.nameShort), + localize('startupTrustRequestLearnMore', "If you don't trust the authors of these files, we recommend to continue in restricted mode as the files may be malicious. See [our docs](https://aka.ms/vscode-workspace-trust) to learn more.") + ], + checkboxText + ); + } + + private createStatusbarEntry(): void { + const entry = this.getStatusbarEntry(this.workspaceTrustManagementService.isWorkpaceTrusted()); + this.statusbarEntryAccessor.value = this.statusbarService.addEntry(entry, this.entryId, StatusbarAlignment.LEFT, 0.99 * Number.MAX_VALUE /* Right of remote indicator */); + this.statusbarService.updateEntryVisibility(this.entryId, false); + } + + private getBannerItem(restrictedMode: boolean): IBannerItem | undefined { + + const dismissedRestricted = this.storageService.getBoolean(BANNER_RESTRICTED_MODE_DISMISSED_KEY, StorageScope.WORKSPACE, false); + + // info has been dismissed + if (dismissedRestricted) { + return undefined; + } + + const actions = + [ + { + label: localize('restrictedModeBannerManage', "Manage"), + href: 'command:' + MANAGE_TRUST_COMMAND_ID + }, + { + label: localize('restrictedModeBannerLearnMore', "Learn More"), + href: 'https://aka.ms/vscode-workspace-trust' + } + ]; + + return { + id: BANNER_RESTRICTED_MODE, + icon: shieldIcon, + ariaLabel: this.getBannerItemAriaLabels(), + message: this.getBannerItemMessages(), + actions, + onClose: () => { + if (restrictedMode) { + this.storageService.store(BANNER_RESTRICTED_MODE_DISMISSED_KEY, true, StorageScope.WORKSPACE, StorageTarget.MACHINE); + } + } + }; + } + + private getBannerItemAriaLabels(): string { + switch (this.workspaceContextService.getWorkbenchState()) { + case WorkbenchState.EMPTY: + return localize('restrictedModeBannerAriaLabelWindow', "Restricted Mode is intended for safe code browsing. Trust this window to enable all features. Use navigation keys to access banner actions."); + case WorkbenchState.FOLDER: + return localize('restrictedModeBannerAriaLabelFolder', "Restricted Mode is intended for safe code browsing. Trust this folder to enable all features. Use navigation keys to access banner actions."); + case WorkbenchState.WORKSPACE: + return localize('restrictedModeBannerAriaLabelWorkspace', "Restricted Mode is intended for safe code browsing. Trust this workspace to enable all features. Use navigation keys to access banner actions."); + } + } + + private getBannerItemMessages(): string { + switch (this.workspaceContextService.getWorkbenchState()) { + case WorkbenchState.EMPTY: + return localize('restrictedModeBannerMessageWindow', "Restricted Mode is intended for safe code browsing. Trust this window to enable all features."); + case WorkbenchState.FOLDER: + return localize('restrictedModeBannerMessageFolder', "Restricted Mode is intended for safe code browsing. Trust this folder to enable all features."); + case WorkbenchState.WORKSPACE: + return localize('restrictedModeBannerMessageWorkspace', "Restricted Mode is intended for safe code browsing. Trust this workspace to enable all features."); + } + } + + private getStatusbarEntry(trusted: boolean): IStatusbarEntry { + const text = workspaceTrustToString(trusted); + const backgroundColor = new ThemeColor(STATUS_BAR_PROMINENT_ITEM_BACKGROUND); + const color = new ThemeColor(STATUS_BAR_PROMINENT_ITEM_FOREGROUND); + + let ariaLabel = ''; + let toolTip: IMarkdownString | string | undefined; + switch (this.workspaceContextService.getWorkbenchState()) { + case WorkbenchState.EMPTY: { + ariaLabel = trusted ? localize('status.ariaTrustedWindow', "This window is trusted.") : + localize('status.ariaUntrustedWindow', "Restricted Mode: Some features are disabled because this window is not trusted."); + toolTip = trusted ? ariaLabel : { + value: localize('status.tooltipUntrustedWindow', "Running in Restricted Mode\n\n\Some [features are disabled](command:{0}) because this [window is not trusted](command:{1}).", LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID, MANAGE_TRUST_COMMAND_ID), + isTrusted: true, + supportThemeIcons: true + }; + break; + } + case WorkbenchState.FOLDER: { + ariaLabel = trusted ? localize('status.ariaTrustedFolder', "This folder is trusted.") : + localize('status.ariaUntrustedFolder', "Restricted Mode: Some features are disabled because this folder is not trusted."); + toolTip = trusted ? ariaLabel : { + value: localize('status.tooltipUntrustedFolder', "Running in Restricted Mode\n\n\Some [features are disabled](command:{0}) because this [folder is not trusted](command:{1}).", LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID, MANAGE_TRUST_COMMAND_ID), + isTrusted: true, + supportThemeIcons: true + }; + break; + } + case WorkbenchState.WORKSPACE: { + ariaLabel = trusted ? localize('status.ariaTrustedWorkspace', "This workspace is trusted.") : + localize('status.ariaUntrustedWorkspace', "Restricted Mode: Some features are disabled because this workspace is not trusted."); + toolTip = trusted ? ariaLabel : { + value: localize('status.tooltipUntrustedWorkspace', "Running in Restricted Mode\n\n\Some [features are disabled](command:{0}) because this [workspace is not trusted](command:{1}).", LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID, MANAGE_TRUST_COMMAND_ID), + isTrusted: true, + supportThemeIcons: true + }; + break; + } + } + + return { + name: localize('status.WorkspaceTrust', "Workspace Trust"), + text: trusted ? `$(shield)` : `$(shield) ${text}`, + ariaLabel: ariaLabel, + tooltip: toolTip, + command: MANAGE_TRUST_COMMAND_ID, + backgroundColor, + color + }; + } + + private async setEmptyWorkspaceTrustState(): Promise { + if (this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY) { + return; + } + + // Open files + const openFiles = this.editorService.editors.map(editor => EditorResourceAccessor.getCanonicalUri(editor, { filterByScheme: Schemas.file })).filter(uri => !!uri); + + if (openFiles.length) { + this.showIndicatorsInEmptyWindow = true; + + // If all open files are trusted, transition to a trusted workspace + const openFilesTrustInfo = await Promise.all(openFiles.map(uri => this.workspaceTrustManagementService.getUriTrustInfo(uri!))); + + if (openFilesTrustInfo.map(info => info.trusted).every(trusted => trusted)) { + this.workspaceTrustManagementService.setWorkspaceTrust(true); + } + } else { + // No open files, use the setting to set workspace trust state + const disposable = this._register(this.editorService.onDidActiveEditorChange(() => { + const editor = this.editorService.activeEditor; + if (editor && !!EditorResourceAccessor.getCanonicalUri(editor, { filterByScheme: Schemas.file })) { + this.showIndicatorsInEmptyWindow = true; + this.updateWorkbenchIndicators(this.workspaceTrustManagementService.isWorkpaceTrusted()); + disposable.dispose(); + } + })); + // TODO: Consider moving the check into setWorkspaceTrust() + if (this.workspaceTrustManagementService.canSetWorkspaceTrust()) { + this.workspaceTrustManagementService.setWorkspaceTrust(this.configurationService.getValue(WORKSPACE_TRUST_EMPTY_WINDOW) ?? false); + } + } + } + + private updateStatusbarEntry(trusted: boolean): void { + this.statusbarEntryAccessor.value?.update(this.getStatusbarEntry(trusted)); + this.updateStatusbarEntryVisibility(trusted); + } + + private updateStatusbarEntryVisibility(trusted: boolean): void { + this.statusbarService.updateEntryVisibility(this.entryId, !trusted); + } + + private updateWorkbenchIndicators(trusted: boolean): void { + const isEmptyWorkspace = this.workspaceContextService.getWorkbenchState() === WorkbenchState.EMPTY; + const bannerItem = this.getBannerItem(!trusted); + + if (!isEmptyWorkspace || this.showIndicatorsInEmptyWindow) { + this.updateStatusbarEntry(trusted); + + if (bannerItem) { + if (!trusted) { + this.bannerService.show(bannerItem); + } else { + this.bannerService.hide(BANNER_RESTRICTED_MODE); + } + } + } + } + + private registerListeners(): void { + + this._register(this.workspaceContextService.onWillChangeWorkspaceFolders(e => { + if (e.fromCache) { + return; + } + if (!this.workspaceTrustManagementService.workspaceTrustEnabled) { + return; + } + const trusted = this.workspaceTrustManagementService.isWorkpaceTrusted(); + + return e.join(new Promise(async resolve => { + // Workspace is trusted and there are added/changed folders + if (trusted && (e.changes.added.length || e.changes.changed.length)) { + const addedFoldersTrustInfo = await Promise.all(e.changes.added.map(folder => this.workspaceTrustManagementService.getUriTrustInfo(folder.uri))); + + if (!addedFoldersTrustInfo.map(info => info.trusted).every(trusted => trusted)) { + const result = await this.dialogService.show( + Severity.Info, + localize('addWorkspaceFolderMessage', "Do you trust the authors of the files in this folder?"), + [localize('yes', 'Yes'), localize('no', 'No')], + { + detail: localize('addWorkspaceFolderDetail', "You are adding files to a trusted workspace that are not currently trusted. Do you trust the authors of these new files?"), + cancelId: 1, + custom: { icon: Codicon.shield } + } + ); + + // Mark added/changed folders as trusted + await this.workspaceTrustManagementService.setUrisTrust(addedFoldersTrustInfo.map(i => i.uri), result.choice === 0); + + resolve(); + } + } + + resolve(); + })); + })); + + this._register(this.workspaceTrustManagementService.onDidChangeTrust(trusted => { + this.updateWorkbenchIndicators(trusted); + })); + } +} + +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceTrustRequestHandler, LifecyclePhase.Ready); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceTrustUXHandler, LifecyclePhase.Restored); + +/** + * Trusted Workspace GUI Editor + */ +class WorkspaceTrustEditorInputSerializer implements IEditorInputSerializer { + + canSerialize(editorInput: EditorInput): boolean { + return true; + } + + serialize(input: WorkspaceTrustEditorInput): string { + return ''; + } + + deserialize(instantiationService: IInstantiationService): WorkspaceTrustEditorInput { + return instantiationService.createInstance(WorkspaceTrustEditorInput); + } +} + +Registry.as(EditorExtensions.EditorInputFactories) + .registerEditorInputSerializer(WorkspaceTrustEditorInput.ID, WorkspaceTrustEditorInputSerializer); + +Registry.as(EditorExtensions.Editors).registerEditor( + EditorDescriptor.create( + WorkspaceTrustEditor, + WorkspaceTrustEditor.ID, + localize('workspaceTrustEditor', "Workspace Trust Editor") + ), + [ + new SyncDescriptor(WorkspaceTrustEditorInput) + ] +); + +/* + * Actions + */ + +const MANAGE_TRUST_COMMAND_ID = 'workbench.trust.manage'; + +// Manage Workspace Trust +registerAction2(class extends Action2 { + constructor() { + super({ + id: MANAGE_TRUST_COMMAND_ID, + title: { + original: 'Manage Workspace Trust', + value: localize('manageWorkspaceTrust', "Manage Workspace Trust") + }, + category: localize('workspacesCategory', "Workspaces"), + menu: { + id: MenuId.GlobalActivity, + group: '6_workspace_trust', + order: 40, + when: ContextKeyExpr.and(WorkspaceTrustContext.IsEnabled, IsWebContext.negate(), ContextKeyExpr.equals(`config.${WORKSPACE_TRUST_ENABLED}`, true)) + }, + }); + } + + run(accessor: ServicesAccessor) { + const editorService = accessor.get(IEditorService); + const instantiationService = accessor.get(IInstantiationService); + + const input = instantiationService.createInstance(WorkspaceTrustEditorInput); + + editorService.openEditor(input, { pinned: true, revealIfOpened: true }); + return; + } +}); + +/* + * Configuration + */ +Registry.as(ConfigurationExtensions.Configuration) + .registerConfiguration({ + id: 'security', + scope: ConfigurationScope.APPLICATION, + title: localize('securityConfigurationTitle', "Security"), + type: 'object', + order: 7, + properties: { + [WORKSPACE_TRUST_ENABLED]: { + type: 'boolean', + default: true, + included: !isWeb, + description: localize('workspace.trust.description', "Controls whether or not workspace trust is enabled within VS Code."), + scope: ConfigurationScope.APPLICATION, + }, + [WORKSPACE_TRUST_STARTUP_PROMPT]: { + type: 'string', + default: 'once', + included: !isWeb, + description: localize('workspace.trust.startupPrompt.description', "Controls when the startup prompt to trust a workspace is shown."), + scope: ConfigurationScope.APPLICATION, + enum: ['always', 'once', 'never'], + enumDescriptions: [ + localize('workspace.trust.startupPrompt.always', "Ask for trust every time an untrusted workspace is opened."), + localize('workspace.trust.startupPrompt.once', "Ask for trust the first time an untrusted workspace is opened."), + localize('workspace.trust.startupPrompt.never', "Do not ask for trust when an untrusted workspace is opened."), + ] + }, + [WORKSPACE_TRUST_UNTRUSTED_FILES]: { + type: 'string', + default: 'prompt', + included: !isWeb, + markdownDescription: localize('workspace.trust.untrustedFiles.description', "Controls how to handle opening untrusted files in a trusted workspace. This setting also applies to opening files in an empty window which is trusted via `#{0}#`.", WORKSPACE_TRUST_EMPTY_WINDOW), + scope: ConfigurationScope.APPLICATION, + enum: ['prompt', 'open', 'newWindow'], + enumDescriptions: [ + localize('workspace.trust.untrustedFiles.prompt', "Ask how to handle untrusted files for each workspace. Once untrusted files are introduced to a trusted workspace, you will not be prompted again."), + localize('workspace.trust.untrustedFiles.open', "Always allow untrusted files to be introduced to a trusted workspace without prompting."), + localize('workspace.trust.untrustedFiles.newWindow', "Always open untrusted files in a separate window in restricted mode without prompting."), + ] + }, + [WORKSPACE_TRUST_EMPTY_WINDOW]: { + type: 'boolean', + default: false, + included: !isWeb, + markdownDescription: localize('workspace.trust.emptyWindow.description', "Controls whether or not the empty window is trusted by default within VS Code. When used with `#{0}#`, you can enable the full functionality of VS Code without prompting in an empty window.", WORKSPACE_TRUST_UNTRUSTED_FILES), + scope: ConfigurationScope.APPLICATION + } + } + }); + +/** + * Telemetry + */ +class WorkspaceTrustTelemetryContribution extends Disposable implements IWorkbenchContribution { + constructor( + @IExtensionService private readonly extensionService: IExtensionService, + @ITelemetryService private readonly telemetryService: ITelemetryService, + @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, + @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService, + @IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService + ) { + super(); + + this._register(this.workspaceTrustManagementService.onDidChangeTrust(isTrusted => this.logWorkspaceTrustChangeEvent(isTrusted))); + this._register(this.workspaceTrustRequestService.onDidInitiateWorkspaceTrustRequest(_ => this.logWorkspaceTrustRequest())); + + this.logInitialWorkspaceTrustInfo(); + } + + private logInitialWorkspaceTrustInfo(): void { + if (!this.workspaceTrustManagementService.workspaceTrustEnabled) { + return; + } + + type WorkspaceTrustInfoEventClassification = { + trustedFoldersCount: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + }; + + type WorkspaceTrustInfoEvent = { + trustedFoldersCount: number, + }; + + this.telemetryService.publicLog2('workspaceTrustFolderCounts', { + trustedFoldersCount: this.workspaceTrustManagementService.getTrustedUris().length, + }); + } + + private async logWorkspaceTrustChangeEvent(isTrusted: boolean): Promise { + if (!this.workspaceTrustManagementService.workspaceTrustEnabled) { + return; + } + + type WorkspaceTrustStateChangedEvent = { + workspaceId: string, + isTrusted: boolean + }; + + type WorkspaceTrustStateChangedEventClassification = { + workspaceId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + isTrusted: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + }; + + this.telemetryService.publicLog2('workspaceTrustStateChanged', { + workspaceId: this.workspaceContextService.getWorkspace().id, + isTrusted: isTrusted + }); + + if (isTrusted) { + type WorkspaceTrustFolderInfoEventClassification = { + trustedFolderDepth: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + workspaceFolderDepth: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + delta: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + }; + + type WorkspaceTrustFolderInfoEvent = { + trustedFolderDepth: number, + workspaceFolderDepth: number, + delta: number + }; + + const getDepth = (folder: string): number => { + let resolvedPath = resolve(folder); + + let depth = 0; + while (dirname(resolvedPath) !== resolvedPath && depth < 100) { + resolvedPath = dirname(resolvedPath); + depth++; + } + + return depth; + }; + + for (const folder of this.workspaceContextService.getWorkspace().folders) { + const { trusted, uri } = await this.workspaceTrustManagementService.getUriTrustInfo(folder.uri); + if (!trusted) { + continue; + } + + const workspaceFolderDepth = getDepth(folder.uri.fsPath); + const trustedFolderDepth = getDepth(uri.fsPath); + const delta = workspaceFolderDepth - trustedFolderDepth; + + this.telemetryService.publicLog2('workspaceFolderDepthBelowTrustedFolder', { workspaceFolderDepth, trustedFolderDepth, delta }); + } + } + } + + private async logWorkspaceTrustRequest(): Promise { + if (!this.workspaceTrustManagementService.workspaceTrustEnabled) { + return; + } + + type WorkspaceTrustRequestedEventClassification = { + workspaceId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + extensions: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + + type WorkspaceTrustRequestedEvent = { + workspaceId: string, + extensions: string[] + }; + + this.telemetryService.publicLog2('workspaceTrustRequested', { + workspaceId: this.workspaceContextService.getWorkspace().id, + extensions: (await this.extensionService.getExtensions()).filter(ext => !!ext.capabilities?.untrustedWorkspaces).map(ext => ext.identifier.value) + }); + } +} + +Registry.as(WorkbenchExtensions.Workbench) + .registerWorkbenchContribution(WorkspaceTrustTelemetryContribution, LifecyclePhase.Restored); diff --git a/lib/vscode/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css similarity index 68% rename from lib/vscode/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css rename to src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css index de08b35453c9..b26d4cc9aa5b 100644 --- a/lib/vscode/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css +++ b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.css @@ -6,13 +6,13 @@ .monaco-icon-label.file-icon.workspacetrusteditor-name-file-icon.ext-file-icon.tab-label::before { font-family: 'codicon'; content: '\eb53'; + background-image: none; + font-size: 150%; } .workspace-trust-editor { max-width: 1000px; padding-top: 11px; - padding-left: 15px; - padding-right: 15px; margin: auto; height: calc(100% - 11px); } @@ -42,7 +42,7 @@ } .workspace-trust-editor .workspace-trust-header .workspace-trust-title .workspace-trust-title-icon { - color: var(--workspace-trust-selected-state-color) !important; + color: var(--workspace-trust-selected-color) !important; } .workspace-trust-editor .workspace-trust-header .workspace-trust-description { @@ -74,21 +74,23 @@ user-select: text; display: flex; flex-direction: row; + flex-flow: wrap; justify-content: space-evenly; } .workspace-trust-editor .workspace-trust-features .workspace-trust-limitations { min-height: 315px; + border: 1px solid var(--workspace-trust-unselected-color); + margin: 4px 4px; + display: flex; + flex-direction: column; + padding: 10px 40px; } -.workspace-trust-editor.trusted .workspace-trust-features .workspace-trust-limitations.trusted { - border-width: 2px; - border-color: var(--workspace-trust-selected-state-color) !important; -} - +.workspace-trust-editor.trusted .workspace-trust-features .workspace-trust-limitations.trusted, .workspace-trust-editor.untrusted .workspace-trust-features .workspace-trust-limitations.untrusted { border-width: 2px; - border-color: var(--workspace-trust-selected-state-color) !important; + border-color: var(--workspace-trust-selected-color) !important; } .workspace-trust-editor .workspace-trust-features .workspace-trust-limitations ul { @@ -107,12 +109,12 @@ } .workspace-trust-editor .workspace-trust-features .workspace-trust-limitations.trusted .list-item-icon { - color: var(--workspace-trust-trusted-color) !important; + color: var(--workspace-trust-check-color) !important; font-size: 18px; } .workspace-trust-editor .workspace-trust-features .workspace-trust-limitations.untrusted .list-item-icon { - color: var(--workspace-trust-untrusted-color) !important; + color: var(--workspace-trust-x-color) !important; font-size: 20px; } @@ -141,14 +143,10 @@ display: none; } -.workspace-trust-editor.trusted .workspace-trust-features .workspace-trust-limitations.trusted .workspace-trust-limitations-header .workspace-trust-limitations-title .workspace-trust-title-icon { - display: unset; - color: var(--workspace-trust-selected-state-color) !important; -} - +.workspace-trust-editor.trusted .workspace-trust-features .workspace-trust-limitations.trusted .workspace-trust-limitations-header .workspace-trust-limitations-title .workspace-trust-title-icon, .workspace-trust-editor.untrusted .workspace-trust-features .workspace-trust-limitations.untrusted .workspace-trust-limitations-header .workspace-trust-limitations-title .workspace-trust-title-icon { display: unset; - color: var(--workspace-trust-selected-state-color) !important; + color: var(--workspace-trust-selected-color) !important; } .workspace-trust-editor .workspace-trust-features .workspace-trust-untrusted-description { @@ -179,79 +177,104 @@ padding: 5px 10px; overflow: hidden; text-overflow: ellipsis; - margin: 4px 5px; /* allows button focus outline to be visible */ outline-offset: 2px !important; } -.workspace-trust-editor .workspace-trust-features .workspace-trust-buttons-row .workspace-trust-buttons .monaco-button-dropdown { - padding: 0 2px; -} - -.workspace-trust-editor .workspace-trust-features .workspace-trust-buttons-row .workspace-trust-buttons .monaco-button-dropdown .monaco-button { - margin-left: 1px; - margin-right: 1px; +.workspace-trust-editor .workspace-trust-features .workspace-trust-buttons-row .workspace-trust-buttons > .monaco-button, +.workspace-trust-editor .workspace-trust-features .workspace-trust-buttons-row .workspace-trust-buttons > .monaco-button-dropdown { + margin: 4px 5px; /* allows button focus outline to be visible */ } .workspace-trust-editor .workspace-trust-features .workspace-trust-buttons-row .workspace-trust-buttons .monaco-button-dropdown .monaco-dropdown-button { - padding: 5px 0px; + padding: 5px; } .workspace-trust-limitations { width: 50%; max-width: 350px; + min-width: 250px; + flex: 1; } -/** Settings */ -.workspace-trust-editor .workspace-trust-settings .workspace-trust-section-title { - padding: 14px; +.workspace-trust-intro-dialog { + min-width: min(50vw, 500px); + padding-right: 24px; } -.workspace-trust-editor .settings-editor .settings-body { - margin-top: 0; +.workspace-trust-intro-dialog .workspace-trust-dialog-image-row p { + display: flex; + align-items: center; } -.workspace-trust-editor .settings-editor .settings-body .settings-tree-container .shadow.top { - left: initial; - margin-left: initial; - max-width: initial; +.workspace-trust-intro-dialog .workspace-trust-dialog-image-row.badge-row img { + max-height: 40px; + padding-right: 10px; } -.workspace-trust-editor .settings-editor .settings-body .settings-tree-container .monaco-list-rows { - background: unset; +.workspace-trust-intro-dialog .workspace-trust-dialog-image-row.status-bar img { + max-height: 32px; + padding-right: 10px; } -.workspace-trust-editor .settings-editor .settings-body .settings-tree-container .monaco-list-row .monaco-tl-contents { - padding-left: 0; - padding-right: 0; +.workspace-trust-editor .workspace-trust-settings { + padding: 20px 14px; } -.workspace-trust-editor .settings-editor .settings-body .settings-tree-container .monaco-list-row .monaco-tl-contents .setting-list-edit-row > .setting-list-valueInput { - width: 100%; - max-width: 100%; +.workspace-trust-editor .workspace-trust-settings .workspace-trusted-folders-title { + font-weight: 600; } -.workspace-trust-editor .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-object-widget .setting-list-object-key, -.workspace-trust-editor .settings-editor > .settings-body > .settings-tree-container .setting-item.setting-item-list .setting-list-object-widget .setting-list-object-input-key { - margin-left: 4px; - min-width: 20%; +.workspace-trust-editor .monaco-table-tr .monaco-table-td .path:not(.input-mode) .monaco-inputbox, +.workspace-trust-editor .monaco-table-tr .monaco-table-td .path.input-mode .path-label { + display: none; } -.workspace-trust-intro-dialog { - min-width: min(50vw, 500px); - padding-right: 24px; +.workspace-trust-editor .monaco-table-tr .monaco-table-td .current-workspace-parent .path-label, +.workspace-trust-editor .monaco-table-tr .monaco-table-td .current-workspace-parent .host-label { + font-weight: bold; + font-style: italic; } -.workspace-trust-intro-dialog .workspace-trust-dialog-image-row p { + +.workspace-trust-editor .monaco-table-tr .monaco-table-td .path .monaco-inputbox input { + padding-left: 5px; +} + +.workspace-trust-editor .monaco-table-th, +.workspace-trust-editor .monaco-table-td { + padding-left: 5px; +} + +.workspace-trust-editor .workspace-trust-settings .monaco-action-bar .action-item > .codicon { display: flex; align-items: center; + justify-content: center; + color: inherit; } -.workspace-trust-intro-dialog .workspace-trust-dialog-image-row.badge-row img { - max-height: 40px; - padding-right: 10px; +.workspace-trust-editor .workspace-trust-settings .monaco-table-tr .monaco-table-td { + align-items: center; + display: flex; + overflow: hidden; } -.workspace-trust-intro-dialog .workspace-trust-dialog-image-row.status-bar img { - max-height: 32px; - padding-right: 10px; +.workspace-trust-editor .workspace-trust-settings .monaco-table-tr .monaco-table-td .path { + width: 100%; +} + +.workspace-trust-editor .workspace-trust-settings .monaco-table-tr .monaco-table-td .monaco-button { + height: 18px; + padding-left: 8px; + padding-right: 8px; +} + +.workspace-trust-editor .workspace-trust-settings .monaco-table-tr .monaco-table-td .actions .monaco-action-bar { + display: none; + flex: 1; +} + +.workspace-trust-editor .workspace-trust-settings .monaco-list-row.selected .monaco-table-tr .monaco-table-td .actions .monaco-action-bar, +.workspace-trust-editor .workspace-trust-settings .monaco-table .monaco-list-row.focused .monaco-table-tr .monaco-table-td .actions .monaco-action-bar, +.workspace-trust-editor .workspace-trust-settings .monaco-list-row:hover .monaco-table-tr .monaco-table-td .actions .monaco-action-bar { + display: flex; } diff --git a/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts new file mode 100644 index 000000000000..230f468978cd --- /dev/null +++ b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts @@ -0,0 +1,978 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { $, addDisposableListener, addStandardDisposableListener, append, clearNode, Dimension, EventHelper, EventType } from 'vs/base/browser/dom'; +import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ButtonBar } from 'vs/base/browser/ui/button/button'; +import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; +import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; +import { ITableRenderer, ITableVirtualDelegate } from 'vs/base/browser/ui/table/table'; +import { Action, IAction } from 'vs/base/common/actions'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { Codicon, registerCodicon } from 'vs/base/common/codicons'; +import { debounce } from 'vs/base/common/decorators'; +import { Emitter, Event } from 'vs/base/common/event'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { splitName } from 'vs/base/common/labels'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { parseLinkedText } from 'vs/base/common/linkedText'; +import { Schemas } from 'vs/base/common/network'; +import { ScrollbarVisibility } from 'vs/base/common/scrollable'; +import { URI } from 'vs/base/common/uri'; +import { localize } from 'vs/nls'; +import { ConfigurationScope, Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; +import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; +import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { ExtensionUntrustedWorkpaceSupportType } from 'vs/platform/extensions/common/extensions'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ILabelService } from 'vs/platform/label/common/label'; +import { WorkbenchTable } from 'vs/platform/list/browser/listService'; +import { IPromptChoiceWithMenu } from 'vs/platform/notification/common/notification'; +import { Link } from 'vs/platform/opener/browser/link'; +import product from 'vs/platform/product/common/product'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { isVirtualWorkspace } from 'vs/platform/remote/common/remoteHosts'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { buttonBackground, buttonSecondaryBackground, editorErrorForeground } from 'vs/platform/theme/common/colorRegistry'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { attachButtonStyler, attachInputBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; +import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; +import { isSingleFolderWorkspaceIdentifier, toWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; +import { IEditorOpenContext } from 'vs/workbench/common/editor'; +import { ChoiceAction } from 'vs/workbench/common/notifications'; +import { debugIconStartForeground } from 'vs/workbench/contrib/debug/browser/debugColors'; +import { IExtensionsWorkbenchService, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID } from 'vs/workbench/contrib/extensions/common/extensions'; +import { getInstalledExtensions, IExtensionStatus } from 'vs/workbench/contrib/extensions/common/extensionsUtils'; +import { settingsEditIcon, settingsRemoveIcon } from 'vs/workbench/contrib/preferences/browser/preferencesIcons'; +import { IWorkbenchConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; +import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; +import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; +import { WorkspaceTrustEditorInput } from 'vs/workbench/services/workspaces/browser/workspaceTrustEditorInput'; +import { IEditorOptions } from 'vs/platform/editor/common/editor'; + +export const shieldIcon = registerCodicon('workspace-trust-icon', Codicon.shield); + +const checkListIcon = registerCodicon('workspace-trusted-check-icon', Codicon.check); +const xListIcon = registerCodicon('workspace-trusted-x-icon', Codicon.x); + +const enum TrustedUriItemType { + Existing = 1, + Add = 2 +} + +interface ITrustedUriItem { + entryType: TrustedUriItemType; + parentOfWorkspaceItem: boolean; + uri: URI; +} + +class WorkspaceTrustedUrisTable extends Disposable { + private readonly _onDidAcceptEdit: Emitter = this._register(new Emitter()); + readonly onDidAcceptEdit: Event = this._onDidAcceptEdit.event; + + private readonly _onDidRejectEdit: Emitter = this._register(new Emitter()); + readonly onDidRejectEdit: Event = this._onDidRejectEdit.event; + + private _onEdit: Emitter = this._register(new Emitter()); + readonly onEdit: Event = this._onEdit.event; + + private _onDelete: Emitter = this._register(new Emitter()); + readonly onDelete: Event = this._onDelete.event; + + private readonly table: WorkbenchTable; + + constructor( + private readonly container: HTMLElement, + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService, + @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService, + @IUriIdentityService private readonly uriService: IUriIdentityService, + @IFileDialogService private readonly fileDialogService: IFileDialogService + ) { + super(); + + this.table = this.instantiationService.createInstance( + WorkbenchTable, + 'WorkspaceTrust', + this.container, + new TrustedUriTableVirtualDelegate(), + [ + { + label: localize('hostColumnLabel', "Host"), + tooltip: '', + weight: 1, + templateId: TrustedUriHostColumnRenderer.TEMPLATE_ID, + project(row: ITrustedUriItem): ITrustedUriItem { return row; } + }, + { + label: localize('pathColumnLabel', "Path"), + tooltip: '', + weight: 9, + templateId: TrustedUriPathColumnRenderer.TEMPLATE_ID, + project(row: ITrustedUriItem): ITrustedUriItem { return row; } + }, + { + label: '', + tooltip: '', + weight: 0, + minimumWidth: 55, + maximumWidth: 55, + templateId: TrustedUriActionsColumnRenderer.TEMPLATE_ID, + project(row: ITrustedUriItem): ITrustedUriItem { return row; } + }, + ], + [ + this.instantiationService.createInstance(TrustedUriHostColumnRenderer, this), + this.instantiationService.createInstance(TrustedUriPathColumnRenderer, this), + this.instantiationService.createInstance(TrustedUriActionsColumnRenderer, this), + ], + { + horizontalScrolling: false, + alwaysConsumeMouseWheel: false, + openOnSingleClick: false, + } + ) as WorkbenchTable; + + this._register(this.table.onDidOpen(item => { + // default prevented when input box is double clicked #125052 + if (item && item.element && !item.browserEvent?.defaultPrevented) { + this.edit(item.element); + } + })); + + this._register(this.workspaceTrustManagementService.onDidChangeTrustedFolders(() => { + this.updateTable(); + })); + } + + private getIndexOfTrustedUriEntry(item: ITrustedUriItem): number { + const index = this.trustedUriEntries.indexOf(item); + if (index === -1) { + for (let i = 0; i < this.trustedUriEntries.length; i++) { + if (this.trustedUriEntries[i].entryType !== item.entryType) { + continue; + } + + if (item.entryType === TrustedUriItemType.Add || this.trustedUriEntries[i].uri === item.uri) { + return i; + } + } + } + + return index; + } + + private selectTrustedUriEntry(item: ITrustedUriItem, focus: boolean = true): void { + const index = this.getIndexOfTrustedUriEntry(item); + if (index !== -1) { + if (focus) { + this.table.domFocus(); + this.table.setFocus([index]); + } + this.table.setSelection([index]); + } + } + + private get currentWorkspaceUri(): URI { + return this.workspaceService.getWorkspace().folders[0]?.uri || URI.file('/'); + } + + private get trustedUriEntries(): ITrustedUriItem[] { + const currentWorkspace = this.workspaceService.getWorkspace(); + const currentWorkspaceUris = currentWorkspace.folders.map(folder => folder.uri); + if (currentWorkspace.configuration) { + currentWorkspaceUris.push(currentWorkspace.configuration); + } + + const entries = this.workspaceTrustManagementService.getTrustedUris().map(uri => { + + let relatedToCurrentWorkspace = false; + for (const workspaceUri of currentWorkspaceUris) { + relatedToCurrentWorkspace = relatedToCurrentWorkspace || this.uriService.extUri.isEqualOrParent(workspaceUri, uri); + } + + return { + uri, + entryType: TrustedUriItemType.Existing, + parentOfWorkspaceItem: relatedToCurrentWorkspace + }; + }); + entries.push({ uri: this.currentWorkspaceUri, entryType: TrustedUriItemType.Add, parentOfWorkspaceItem: false }); + return entries; + } + + layout(): void { + this.table.layout((this.trustedUriEntries.length * TrustedUriTableVirtualDelegate.ROW_HEIGHT) + TrustedUriTableVirtualDelegate.HEADER_ROW_HEIGHT, undefined); + } + + updateTable(): void { + this.table.splice(0, Number.POSITIVE_INFINITY, this.trustedUriEntries); + this.layout(); + } + + acceptEdit(item: ITrustedUriItem, uri: URI) { + const trustedFolders = this.workspaceTrustManagementService.getTrustedUris(); + const index = this.getIndexOfTrustedUriEntry(item); + + if (index >= trustedFolders.length) { + trustedFolders.push(uri); + } else { + trustedFolders[index] = uri; + } + + this.workspaceTrustManagementService.setTrustedUris(trustedFolders); + this._onDidAcceptEdit.fire(item); + } + + rejectEdit(item: ITrustedUriItem) { + this._onDidRejectEdit.fire(item); + } + + async delete(item: ITrustedUriItem) { + await this.workspaceTrustManagementService.setUrisTrust([item.uri], false); + this._onDelete.fire(item); + } + + async edit(item: ITrustedUriItem) { + const canUseOpenDialog = item.uri.scheme === Schemas.file || + (item.uri.scheme === this.currentWorkspaceUri.scheme && this.uriService.extUri.isEqualAuthority(this.currentWorkspaceUri.authority, item.uri.authority)); + if (canUseOpenDialog) { + const uri = await this.fileDialogService.showOpenDialog({ + canSelectFiles: false, + canSelectFolders: true, + canSelectMany: false, + defaultUri: item.uri, + openLabel: localize('trustUri', "Trust Folder"), + title: localize('selectTrustedUri', "Select Folder To Trust") + }); + + if (uri) { + this.acceptEdit(item, uri[0]); + } else { + this.rejectEdit(item); + } + } else { + this.selectTrustedUriEntry(item); + this._onEdit.fire(item); + } + } +} + +class TrustedUriTableVirtualDelegate implements ITableVirtualDelegate { + static readonly HEADER_ROW_HEIGHT = 30; + static readonly ROW_HEIGHT = 24; + readonly headerRowHeight = TrustedUriTableVirtualDelegate.HEADER_ROW_HEIGHT; + getHeight(item: ITrustedUriItem) { + return TrustedUriTableVirtualDelegate.ROW_HEIGHT; + } +} + +interface IActionsColumnTemplateData { + readonly actionBar: ActionBar; +} + +class TrustedUriActionsColumnRenderer implements ITableRenderer { + + static readonly TEMPLATE_ID = 'actions'; + + readonly templateId: string = TrustedUriActionsColumnRenderer.TEMPLATE_ID; + + constructor(private readonly table: WorkspaceTrustedUrisTable) { } + + renderTemplate(container: HTMLElement): IActionsColumnTemplateData { + const element = container.appendChild($('.actions')); + const actionBar = new ActionBar(element, { animated: false }); + return { actionBar }; + } + + renderElement(item: ITrustedUriItem, index: number, templateData: IActionsColumnTemplateData, height: number | undefined): void { + templateData.actionBar.clear(); + + if (item.entryType !== TrustedUriItemType.Add) { + const actions: IAction[] = []; + actions.push(this.createEditAction(item)); + actions.push(this.createDeleteAction(item)); + templateData.actionBar.push(actions, { icon: true }); + } + } + + private createEditAction(item: ITrustedUriItem): IAction { + return { + class: ThemeIcon.asClassName(settingsEditIcon), + enabled: true, + id: 'editTrustedUri', + tooltip: localize('editTrustedUri', "Change Path"), + run: () => { + this.table.edit(item); + } + }; + } + + private createDeleteAction(item: ITrustedUriItem): IAction { + return { + class: ThemeIcon.asClassName(settingsRemoveIcon), + enabled: true, + id: 'deleteTrustedUri', + tooltip: localize('deleteTrustedUri', "Delete Path"), + run: async () => { + await this.table.delete(item); + } + }; + } + + disposeTemplate(templateData: IActionsColumnTemplateData): void { + templateData.actionBar.dispose(); + } + +} + +interface ITrustedUriPathColumnTemplateData { + element: HTMLElement; + pathLabel: HTMLElement; + pathInput: InputBox; + renderDisposables: DisposableStore; + disposables: DisposableStore; +} + +class TrustedUriPathColumnRenderer implements ITableRenderer { + static readonly TEMPLATE_ID = 'path'; + + readonly templateId: string = TrustedUriPathColumnRenderer.TEMPLATE_ID; + + constructor( + private readonly table: WorkspaceTrustedUrisTable, + @IContextViewService private readonly contextViewService: IContextViewService, + @IThemeService private readonly themeService: IThemeService, + ) { + } + + renderTemplate(container: HTMLElement): ITrustedUriPathColumnTemplateData { + const element = container.appendChild($('.path')); + const pathLabel = element.appendChild($('div.path-label')); + + const pathInput = new InputBox(element, this.contextViewService); + + const disposables = new DisposableStore(); + disposables.add(attachInputBoxStyler(pathInput, this.themeService)); + + const renderDisposables = disposables.add(new DisposableStore()); + + return { + element, + pathLabel, + pathInput, + disposables, + renderDisposables + }; + } + + renderElement(item: ITrustedUriItem, index: number, templateData: ITrustedUriPathColumnTemplateData, height: number | undefined): void { + templateData.renderDisposables.clear(); + + templateData.renderDisposables.add(this.table.onEdit(async (e) => { + if (item === e) { + templateData.element.classList.add('input-mode'); + templateData.pathInput.focus(); + templateData.pathInput.select(); + templateData.element.parentElement!.style.paddingLeft = '0px'; + } + })); + + // stop double click action from re-rendering the element on the table #125052 + templateData.renderDisposables.add(addDisposableListener(templateData.pathInput.element, EventType.DBLCLICK, e => { + EventHelper.stop(e); + })); + + + const hideInputBox = () => { + templateData.element.classList.remove('input-mode'); + templateData.element.parentElement!.style.paddingLeft = '5px'; + }; + + const accept = () => { + hideInputBox(); + const uri = item.uri.with({ path: templateData.pathInput.value }); + templateData.pathLabel.innerText = templateData.pathInput.value; + + if (uri) { + this.table.acceptEdit(item, uri); + } + }; + + const reject = () => { + hideInputBox(); + templateData.pathInput.value = stringValue; + this.table.rejectEdit(item); + }; + + templateData.renderDisposables.add(addStandardDisposableListener(templateData.pathInput.inputElement, EventType.KEY_DOWN, e => { + let handled = false; + if (e.equals(KeyCode.Enter)) { + accept(); + handled = true; + } else if (e.equals(KeyCode.Escape)) { + reject(); + handled = true; + } + + if (handled) { + e.preventDefault(); + e.stopPropagation(); + } + })); + templateData.renderDisposables.add((addDisposableListener(templateData.pathInput.inputElement, EventType.BLUR, () => { + reject(); + }))); + + const stringValue = item.uri.scheme === Schemas.file ? URI.revive(item.uri).fsPath : item.uri.path; + templateData.pathInput.value = stringValue; + templateData.pathLabel.innerText = stringValue; + templateData.element.classList.toggle('current-workspace-parent', item.parentOfWorkspaceItem); + + templateData.pathLabel.style.display = item.entryType === TrustedUriItemType.Add ? 'none' : ''; + } + + disposeTemplate(templateData: ITrustedUriPathColumnTemplateData): void { + templateData.disposables.dispose(); + templateData.renderDisposables.dispose(); + } + +} + + +interface ITrustedUriHostColumnTemplateData { + element: HTMLElement; + hostContainer: HTMLElement; + buttonBarContainer: HTMLElement; + disposables: DisposableStore; + renderDisposables: DisposableStore; +} + +class TrustedUriHostColumnRenderer implements ITableRenderer { + static readonly TEMPLATE_ID = 'host'; + + readonly templateId: string = TrustedUriHostColumnRenderer.TEMPLATE_ID; + + constructor( + private readonly table: WorkspaceTrustedUrisTable, + @ILabelService private readonly labelService: ILabelService, + @IThemeService private readonly themeService: IThemeService, + ) { } + + renderTemplate(container: HTMLElement): ITrustedUriHostColumnTemplateData { + const disposables = new DisposableStore(); + const renderDisposables = disposables.add(new DisposableStore()); + + const element = container.appendChild($('.host')); + const hostContainer = element.appendChild($('div.host-label')); + const buttonBarContainer = element.appendChild($('div.button-bar')); + + return { + element, + hostContainer, + buttonBarContainer, + disposables, + renderDisposables + }; + } + + renderElement(item: ITrustedUriItem, index: number, templateData: ITrustedUriHostColumnTemplateData, height: number | undefined): void { + templateData.renderDisposables.clear(); + templateData.renderDisposables.add({ dispose: () => { clearNode(templateData.buttonBarContainer); } }); + + templateData.hostContainer.innerText = item.uri.authority ? this.labelService.getHostLabel(item.uri.scheme, item.uri.authority) : localize('localAuthority', "Local"); + templateData.element.classList.toggle('current-workspace-parent', item.parentOfWorkspaceItem); + + if (item.entryType === TrustedUriItemType.Add) { + templateData.hostContainer.style.display = 'none'; + templateData.buttonBarContainer.style.display = ''; + + const buttonBar = templateData.renderDisposables.add(new ButtonBar(templateData.buttonBarContainer)); + const addButton = templateData.renderDisposables.add(buttonBar.addButton({ title: localize('addButton', "Add Folder") })); + addButton.label = localize('addButton', "Add Folder"); + + templateData.renderDisposables.add(attachButtonStyler(addButton, this.themeService)); + + templateData.renderDisposables.add(addButton.onDidClick(() => { + this.table.edit(item); + })); + + templateData.renderDisposables.add(this.table.onEdit(e => { + if (item === e) { + templateData.hostContainer.style.display = ''; + templateData.buttonBarContainer.style.display = 'none'; + } + })); + + templateData.renderDisposables.add(this.table.onDidRejectEdit(e => { + if (item === e) { + templateData.hostContainer.style.display = 'none'; + templateData.buttonBarContainer.style.display = ''; + } + })); + } else { + templateData.hostContainer.style.display = ''; + templateData.buttonBarContainer.style.display = 'none'; + } + } + + disposeTemplate(templateData: ITrustedUriHostColumnTemplateData): void { + templateData.disposables.dispose(); + } + +} + +export class WorkspaceTrustEditor extends EditorPane { + static readonly ID: string = 'workbench.editor.workspaceTrust'; + private rootElement!: HTMLElement; + + // Header Section + private headerContainer!: HTMLElement; + private headerTitleContainer!: HTMLElement; + private headerTitleIcon!: HTMLElement; + private headerTitleText!: HTMLElement; + private headerDescription!: HTMLElement; + + private bodyScrollBar!: DomScrollableElement; + + // Affected Features Section + private affectedFeaturesContainer!: HTMLElement; + + // Settings Section + private configurationContainer!: HTMLElement; + private workpaceTrustedUrisTable!: WorkspaceTrustedUrisTable; + + constructor( + @ITelemetryService telemetryService: ITelemetryService, + @IThemeService themeService: IThemeService, + @IStorageService storageService: IStorageService, + @IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService, + @IExtensionsWorkbenchService private readonly extensionWorkbenchService: IExtensionsWorkbenchService, + @IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService, + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IContextMenuService private readonly contextMenuService: IContextMenuService, + @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService, + @IWorkbenchConfigurationService private readonly configurationService: IWorkbenchConfigurationService, + ) { super(WorkspaceTrustEditor.ID, telemetryService, themeService, storageService); } + + protected createEditor(parent: HTMLElement): void { + this.rootElement = append(parent, $('.workspace-trust-editor', { tabindex: '0' })); + this.rootElement.style.visibility = 'hidden'; + + this.createHeaderElement(this.rootElement); + + const scrollableContent = $('.workspace-trust-editor-body'); + this.bodyScrollBar = this._register(new DomScrollableElement(scrollableContent, { + horizontal: ScrollbarVisibility.Hidden, + vertical: ScrollbarVisibility.Auto, + })); + + append(this.rootElement, this.bodyScrollBar.getDomNode()); + + this.createAffectedFeaturesElement(scrollableContent); + this.createConfigurationElement(scrollableContent); + + this._register(attachStylerCallback(this.themeService, { debugIconStartForeground, editorErrorForeground, buttonBackground, buttonSecondaryBackground }, colors => { + this.rootElement.style.setProperty('--workspace-trust-selected-color', colors.buttonBackground?.toString() || ''); + this.rootElement.style.setProperty('--workspace-trust-unselected-color', colors.buttonSecondaryBackground?.toString() || ''); + this.rootElement.style.setProperty('--workspace-trust-check-color', colors.debugIconStartForeground?.toString() || ''); + this.rootElement.style.setProperty('--workspace-trust-x-color', colors.editorErrorForeground?.toString() || ''); + })); + } + + override focus() { + this.rootElement.focus(); + } + + override async setInput(input: WorkspaceTrustEditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { + + await super.setInput(input, options, context, token); + if (token.isCancellationRequested) { return; } + + await this.workspaceTrustManagementService.workspaceTrustInitialized; + this.registerListeners(); + this.render(); + } + + private registerListeners(): void { + this._register(this.extensionWorkbenchService.onChange(() => this.render())); + this._register(this.configurationService.onDidChangeRestrictedSettings(() => this.render())); + this._register(this.workspaceTrustManagementService.onDidChangeTrust(() => this.render())); + this._register(this.workspaceTrustManagementService.onDidChangeTrustedFolders(() => this.render())); + } + + private getHeaderContainerClass(trusted: boolean): string { + if (trusted) { + return 'workspace-trust-header workspace-trust-trusted'; + } + + return 'workspace-trust-header workspace-trust-untrusted'; + } + + private getHeaderTitleText(trusted: boolean): string { + if (trusted) { + if (this.workspaceTrustManagementService.isWorkspaceTrustForced()) { + return localize('trustedUnsettableWindow', "This window is trusted"); + } + + switch (this.workspaceService.getWorkbenchState()) { + case WorkbenchState.EMPTY: + return localize('trustedHeaderWindow', "You trust this window"); + case WorkbenchState.FOLDER: + return localize('trustedHeaderFolder', "You trust this folder"); + case WorkbenchState.WORKSPACE: + return localize('trustedHeaderWorkspace', "You trust this workspace"); + } + } + + return localize('untrustedHeader', "You are in Restricted Mode"); + } + + private getHeaderDescriptionText(trusted: boolean): string { + if (trusted) { + return localize('trustedDescription', "All features are enabled because trust has been granted to the workspace. [Learn more](https://aka.ms/vscode-workspace-trust)."); + } + + return localize('untrustedDescription', "{0} is in a restricted mode intended for safe code browsing. [Learn more](https://aka.ms/vscode-workspace-trust).", product.nameShort); + } + + private getHeaderTitleIconClassNames(trusted: boolean): string[] { + return shieldIcon.classNamesArray; + } + + private getFeaturesHeaderText(trusted: boolean): [string, string] { + let title: string = ''; + let subTitle: string = ''; + + switch (this.workspaceService.getWorkbenchState()) { + case WorkbenchState.EMPTY: { + title = trusted ? localize('trustedWindow', "In a trusted window") : localize('untrustedWorkspace', "In Restricted Mode"); + subTitle = trusted ? localize('trustedWindowSubtitle', "You trust the authors of the files in the current window. All features are enabled:") : + localize('untrustedWindowSubtitle', "You do not trust the authors of the files in the current window. The following features are disabled:"); + break; + } + case WorkbenchState.FOLDER: { + title = trusted ? localize('trustedFolder', "In a trusted folder") : localize('untrustedWorkspace', "In Restricted Mode"); + subTitle = trusted ? localize('trustedFolderSubtitle', "You trust the authors of the files in the current folder. All features are enabled:") : + localize('untrustedFolderSubtitle', "You do not trust the authors of the files in the current folder. The following features are disabled:"); + break; + } + case WorkbenchState.WORKSPACE: { + title = trusted ? localize('trustedWorkspace', "In a trusted workspace") : localize('untrustedWorkspace', "In Restricted Mode"); + subTitle = trusted ? localize('trustedWorkspaceSubtitle', "You trust the authors of the files in the current workspace. All features are enabled:") : + localize('untrustedWorkspaceSubtitle', "You do not trust the authors of the files in the current workspace. The following features are disabled:"); + break; + } + } + + return [title, subTitle]; + } + + private rendering = false; + private rerenderDisposables: DisposableStore = this._register(new DisposableStore()); + @debounce(100) + private async render() { + if (this.rendering) { + return; + } + + this.rendering = true; + this.rerenderDisposables.clear(); + + const isWorkspaceTrusted = this.workspaceTrustManagementService.isWorkpaceTrusted(); + this.rootElement.classList.toggle('trusted', isWorkspaceTrusted); + this.rootElement.classList.toggle('untrusted', !isWorkspaceTrusted); + + // Header Section + this.headerTitleText.innerText = this.getHeaderTitleText(isWorkspaceTrusted); + this.headerTitleIcon.className = 'workspace-trust-title-icon'; + this.headerTitleIcon.classList.add(...this.getHeaderTitleIconClassNames(isWorkspaceTrusted)); + this.headerDescription.innerText = ''; + + const linkedText = parseLinkedText(this.getHeaderDescriptionText(isWorkspaceTrusted)); + const p = append(this.headerDescription, $('p')); + for (const node of linkedText.nodes) { + if (typeof node === 'string') { + append(p, document.createTextNode(node)); + } else { + const link = this.instantiationService.createInstance(Link, node, {}); + append(p, link.el); + this.rerenderDisposables.add(link); + } + } + + this.headerContainer.className = this.getHeaderContainerClass(isWorkspaceTrusted); + this.rootElement.setAttribute('aria-label', `${localize('root element label', "Manage Workspace Trust")}: ${this.headerContainer.innerText}`); + + // Settings + const restrictedSettings = this.configurationService.restrictedSettings; + const configurationRegistry = Registry.as(Extensions.Configuration); + const settingsRequiringTrustedWorkspaceCount = restrictedSettings.default.filter(key => { + const property = configurationRegistry.getConfigurationProperties()[key]; + + // cannot be configured in workspace + if (property.scope === ConfigurationScope.APPLICATION || property.scope === ConfigurationScope.MACHINE) { + return false; + } + + // If deprecated include only those configured in the workspace + if (property.deprecationMessage || property.markdownDeprecationMessage) { + if (restrictedSettings.workspace?.includes(key)) { + return true; + } + if (restrictedSettings.workspaceFolder) { + for (const workspaceFolderSettings of restrictedSettings.workspaceFolder.values()) { + if (workspaceFolderSettings.includes(key)) { + return true; + } + } + } + return false; + } + + return true; + }).length; + + // Features List + const installedExtensions = await this.instantiationService.invokeFunction(getInstalledExtensions); + const onDemandExtensionCount = this.getExtensionCountByUntrustedWorkspaceSupport(installedExtensions, 'limited'); + const onStartExtensionCount = this.getExtensionCountByUntrustedWorkspaceSupport(installedExtensions, false); + + this.renderAffectedFeatures(settingsRequiringTrustedWorkspaceCount, onDemandExtensionCount + onStartExtensionCount); + + // Configuration Tree + this.workpaceTrustedUrisTable.updateTable(); + + this.bodyScrollBar.getDomNode().style.height = `calc(100% - ${this.headerContainer.clientHeight}px)`; + this.bodyScrollBar.scanDomNode(); + this.rootElement.style.visibility = ''; + this.rendering = false; + } + + private getExtensionCountByUntrustedWorkspaceSupport(extensions: IExtensionStatus[], trustRequestType: ExtensionUntrustedWorkpaceSupportType): number { + const filtered = extensions.filter(ext => this.extensionManifestPropertiesService.getExtensionUntrustedWorkspaceSupportType(ext.local.manifest) === trustRequestType); + const set = new Set(); + const inVirtualWorkspace = isVirtualWorkspace(this.workspaceService.getWorkspace()); + for (const ext of filtered) { + if (!inVirtualWorkspace || this.extensionManifestPropertiesService.getExtensionVirtualWorkspaceSupportType(ext.local.manifest) !== false) { + set.add(ext.identifier.id); + } + } + + return set.size; + } + + private createHeaderElement(parent: HTMLElement): void { + this.headerContainer = append(parent, $('.workspace-trust-header')); + this.headerTitleContainer = append(this.headerContainer, $('.workspace-trust-title')); + this.headerTitleIcon = append(this.headerTitleContainer, $('.workspace-trust-title-icon')); + this.headerTitleText = append(this.headerTitleContainer, $('.workspace-trust-title-text')); + this.headerDescription = append(this.headerContainer, $('.workspace-trust-description')); + } + + private createConfigurationElement(parent: HTMLElement): void { + this.configurationContainer = append(parent, $('.workspace-trust-settings')); + const configurationTitle = append(this.configurationContainer, $('.workspace-trusted-folders-title')); + configurationTitle.innerText = localize('trustedFoldersAndWorkspaces', "Trusted Folders & Workspaces"); + + const configurationDescription = append(this.configurationContainer, $('.workspace-trusted-folders-description')); + configurationDescription.innerText = localize('trustedFoldersDescription', "You trust the following folders, their children, and workspace files."); + + this.workpaceTrustedUrisTable = this._register(this.instantiationService.createInstance(WorkspaceTrustedUrisTable, this.configurationContainer)); + + + } + + private createAffectedFeaturesElement(parent: HTMLElement): void { + this.affectedFeaturesContainer = append(parent, $('.workspace-trust-features')); + } + + private async renderAffectedFeatures(numSettings: number, numExtensions: number): Promise { + clearNode(this.affectedFeaturesContainer); + + // Trusted features + const trustedContainer = append(this.affectedFeaturesContainer, $('.workspace-trust-limitations.trusted')); + const [trustedTitle, trustedSubTitle] = this.getFeaturesHeaderText(true); + + this.renderLimitationsHeaderElement(trustedContainer, trustedTitle, trustedSubTitle); + const trustedContainerItems = this.workspaceService.getWorkbenchState() === WorkbenchState.EMPTY ? + [ + localize('trustedTasks', "Tasks are allowed to run"), + localize('trustedDebugging', "Debugging is enabled"), + localize('trustedExtensions', "All extensions are enabled") + ] : + [ + localize('trustedTasks', "Tasks are allowed to run"), + localize('trustedDebugging', "Debugging is enabled"), + localize('trustedSettings', "All workspace settings are applied"), + localize('trustedExtensions', "All extensions are enabled") + ]; + this.renderLimitationsListElement(trustedContainer, trustedContainerItems, checkListIcon.classNamesArray); + + // Restricted Mode features + const untrustedContainer = append(this.affectedFeaturesContainer, $('.workspace-trust-limitations.untrusted')); + const [untrustedTitle, untrustedSubTitle] = this.getFeaturesHeaderText(false); + + this.renderLimitationsHeaderElement(untrustedContainer, untrustedTitle, untrustedSubTitle); + const untrustedContainerItems = this.workspaceService.getWorkbenchState() === WorkbenchState.EMPTY ? + [ + localize('untrustedTasks', "Tasks are disabled"), + localize('untrustedDebugging', "Debugging is disabled"), + localize('untrustedExtensions', "[{0} extensions](command:{1}) are disabled or have limited functionality", numExtensions, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID) + ] : + [ + localize('untrustedTasks', "Tasks are disabled"), + localize('untrustedDebugging', "Debugging is disabled"), + numSettings ? localize('untrustedSettings', "[{0} workspace settings](command:{1}) are not applied", numSettings, 'settings.filterUntrusted') : localize('no untrustedSettings', "Workspace settings requiring trust are not applied"), + localize('untrustedExtensions', "[{0} extensions](command:{1}) are disabled or have limited functionality", numExtensions, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID) + ]; + this.renderLimitationsListElement(untrustedContainer, untrustedContainerItems, xListIcon.classNamesArray); + + if (this.workspaceTrustManagementService.isWorkpaceTrusted()) { + if (this.workspaceTrustManagementService.canSetWorkspaceTrust()) { + this.addDontTrustButtonToElement(untrustedContainer); + } else { + this.addTrustedTextToElement(untrustedContainer); + } + } else { + if (this.workspaceTrustManagementService.canSetWorkspaceTrust()) { + this.addTrustButtonToElement(trustedContainer); + } + } + } + + private createButton(parent: HTMLElement, action: Action, enabled?: boolean): void { + const buttonRow = append(parent, $('.workspace-trust-buttons-row')); + const buttonContainer = append(buttonRow, $('.workspace-trust-buttons')); + const buttonBar = this.rerenderDisposables.add(new ButtonBar(buttonContainer)); + + const button = + action instanceof ChoiceAction && action.menu?.length ? + buttonBar.addButtonWithDropdown({ + title: true, + actions: action.menu ?? [], + contextMenuProvider: this.contextMenuService + }) : + buttonBar.addButton(); + + button.label = action.label; + button.enabled = enabled !== undefined ? enabled : action.enabled; + + this.rerenderDisposables.add(button.onDidClick(e => { + if (e) { + EventHelper.stop(e, true); + } + + action.run(); + })); + + this.rerenderDisposables.add(attachButtonStyler(button, this.themeService)); + } + + private addTrustButtonToElement(parent: HTMLElement): void { + const trustUris = async (uris?: URI[]) => { + if (!uris) { + await this.workspaceTrustManagementService.setWorkspaceTrust(true); + } else { + await this.workspaceTrustManagementService.setUrisTrust(uris, true); + } + }; + + const trustChoiceWithMenu: IPromptChoiceWithMenu = { + isSecondary: false, + label: localize('trustButton', "Trust"), + menu: [], + run: () => { + trustUris(); + } + }; + + const workspaceIdentifier = toWorkspaceIdentifier(this.workspaceService.getWorkspace()); + if (isSingleFolderWorkspaceIdentifier(workspaceIdentifier) && workspaceIdentifier.uri.scheme === Schemas.file) { + const { parentPath } = splitName(workspaceIdentifier.uri.fsPath); + if (parentPath) { + trustChoiceWithMenu.menu.push({ + label: localize('trustParentButton', "Trust All in Parent Folder"), + run: () => { + trustUris([URI.file(parentPath)]); + } + }); + } + } + + const isWorkspaceTrusted = this.workspaceTrustManagementService.isWorkpaceTrusted(); + this.createButton(parent, new ChoiceAction('workspace.trust.button.action', trustChoiceWithMenu), !isWorkspaceTrusted); + } + + private addDontTrustButtonToElement(parent: HTMLElement): void { + this.createButton(parent, new Action('workspace.trust.button.action.deny', localize('dontTrustButton', "Don't Trust"), undefined, true, async () => { + await this.workspaceTrustManagementService.setWorkspaceTrust(false); + })); + } + + private addTrustedTextToElement(parent: HTMLElement): void { + if (this.workspaceService.getWorkbenchState() === WorkbenchState.EMPTY) { + return; + } + + const textElement = append(parent, $('.workspace-trust-untrusted-description')); + if (!this.workspaceTrustManagementService.isWorkspaceTrustForced()) { + textElement.innerText = this.workspaceService.getWorkbenchState() === WorkbenchState.WORKSPACE ? localize('untrustedWorkspaceReason', "This workspace is trusted via the bolded entries in the trusted folders below.") : localize('untrustedFolderReason', "This folder is trusted via the bolded entries in the the trusted folders below."); + } else { + textElement.innerText = localize('trustedForcedReason', "This window is trusted by nature of the workspace that is opened."); + } + } + + private renderLimitationsHeaderElement(parent: HTMLElement, headerText: string, subtitleText: string): void { + const limitationsHeaderContainer = append(parent, $('.workspace-trust-limitations-header')); + const titleElement = append(limitationsHeaderContainer, $('.workspace-trust-limitations-title')); + const textElement = append(titleElement, $('.workspace-trust-limitations-title-text')); + const subtitleElement = append(limitationsHeaderContainer, $('.workspace-trust-limitations-subtitle')); + + textElement.innerText = headerText; + subtitleElement.innerText = subtitleText; + } + + private renderLimitationsListElement(parent: HTMLElement, limitations: string[], iconClassNames: string[]): void { + const listContainer = append(parent, $('.workspace-trust-limitations-list-container')); + const limitationsList = append(listContainer, $('ul')); + for (const limitation of limitations) { + const limitationListItem = append(limitationsList, $('li')); + const icon = append(limitationListItem, $('.list-item-icon')); + const text = append(limitationListItem, $('.list-item-text')); + + icon.classList.add(...iconClassNames); + + const linkedText = parseLinkedText(limitation); + for (const node of linkedText.nodes) { + if (typeof node === 'string') { + append(text, document.createTextNode(node)); + } else { + const link = this.instantiationService.createInstance(Link, node, {}); + append(text, link.el); + this.rerenderDisposables.add(link); + } + } + } + } + + private layoutParticipants: { layout: () => void; }[] = []; + layout(dimension: Dimension): void { + if (!this.isVisible()) { + return; + } + + this.workpaceTrustedUrisTable.layout(); + + this.layoutParticipants.forEach(participant => { + participant.layout(); + }); + + this.bodyScrollBar.scanDomNode(); + } +} diff --git a/lib/vscode/src/vs/workbench/contrib/workspaces/browser/workspaces.contribution.ts b/src/vs/workbench/contrib/workspaces/browser/workspaces.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/contrib/workspaces/browser/workspaces.contribution.ts rename to src/vs/workbench/contrib/workspaces/browser/workspaces.contribution.ts diff --git a/lib/vscode/src/vs/workbench/electron-browser/desktop.main.ts b/src/vs/workbench/electron-browser/desktop.main.ts similarity index 100% rename from lib/vscode/src/vs/workbench/electron-browser/desktop.main.ts rename to src/vs/workbench/electron-browser/desktop.main.ts diff --git a/lib/vscode/src/vs/workbench/electron-sandbox/actions/developerActions.ts b/src/vs/workbench/electron-sandbox/actions/developerActions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/electron-sandbox/actions/developerActions.ts rename to src/vs/workbench/electron-sandbox/actions/developerActions.ts diff --git a/src/vs/workbench/electron-sandbox/actions/installActions.ts b/src/vs/workbench/electron-sandbox/actions/installActions.ts new file mode 100644 index 000000000000..37b8f4130e01 --- /dev/null +++ b/src/vs/workbench/electron-sandbox/actions/installActions.ts @@ -0,0 +1,74 @@ +/*--------------------------------------------------------------------------------------------- + * 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 Severity from 'vs/base/common/severity'; +import { Action2, ILocalizedString } from 'vs/platform/actions/common/actions'; +import product from 'vs/platform/product/common/product'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; +import { toErrorMessage } from 'vs/base/common/errorMessage'; +import { IProductService } from 'vs/platform/product/common/productService'; + +const shellCommandCategory: ILocalizedString = { value: localize('shellCommand', "Shell Command"), original: 'Shell Command' }; + +export class InstallShellScriptAction extends Action2 { + + constructor() { + super({ + id: 'workbench.action.installCommandLine', + title: { + value: localize('install', "Install '{0}' command in PATH", product.applicationName), + original: `Install \'${product.applicationName}\' command in PATH` + }, + category: shellCommandCategory, + f1: true + }); + } + + async run(accessor: ServicesAccessor): Promise { + const nativeHostService = accessor.get(INativeHostService); + const dialogService = accessor.get(IDialogService); + const productService = accessor.get(IProductService); + + try { + await nativeHostService.installShellCommand(); + + dialogService.show(Severity.Info, localize('successIn', "Shell command '{0}' successfully installed in PATH.", productService.applicationName), []); + } catch (error) { + dialogService.show(Severity.Error, toErrorMessage(error), [localize('ok', "OK"),]); + } + } +} + +export class UninstallShellScriptAction extends Action2 { + + constructor() { + super({ + id: 'workbench.action.uninstallCommandLine', + title: { + value: localize('uninstall', "Uninstall '{0}' command from PATH", product.applicationName), + original: `Uninstall \'${product.applicationName}\' command from PATH` + }, + category: shellCommandCategory, + f1: true + }); + } + + async run(accessor: ServicesAccessor): Promise { + const nativeHostService = accessor.get(INativeHostService); + const dialogService = accessor.get(IDialogService); + const productService = accessor.get(IProductService); + + try { + await nativeHostService.uninstallShellCommand(); + + dialogService.show(Severity.Info, localize('successFrom', "Shell command '{0}' successfully uninstalled from PATH.", productService.applicationName), []); + } catch (error) { + dialogService.show(Severity.Error, toErrorMessage(error), [localize('ok', "OK"),]); + } + } +} diff --git a/lib/vscode/src/vs/workbench/electron-sandbox/actions/media/actions.css b/src/vs/workbench/electron-sandbox/actions/media/actions.css similarity index 100% rename from lib/vscode/src/vs/workbench/electron-sandbox/actions/media/actions.css rename to src/vs/workbench/electron-sandbox/actions/media/actions.css diff --git a/src/vs/workbench/electron-sandbox/actions/windowActions.ts b/src/vs/workbench/electron-sandbox/actions/windowActions.ts new file mode 100644 index 000000000000..e6dbac49746c --- /dev/null +++ b/src/vs/workbench/electron-sandbox/actions/windowActions.ts @@ -0,0 +1,297 @@ +/*--------------------------------------------------------------------------------------------- + * 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!./media/actions'; +import { URI } from 'vs/base/common/uri'; +import { localize } from 'vs/nls'; +import { applyZoom } from 'vs/platform/windows/electron-sandbox/window'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { getZoomLevel } from 'vs/base/browser/browser'; +import { FileKind } from 'vs/platform/files/common/files'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { IQuickInputService, IQuickInputButton } from 'vs/platform/quickinput/common/quickInput'; +import { getIconClasses } from 'vs/editor/common/services/getIconClasses'; +import { ICommandHandler } from 'vs/platform/commands/common/commands'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; +import { Codicon } from 'vs/base/common/codicons'; +import { isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { Action2, IAction2Options, MenuId } from 'vs/platform/actions/common/actions'; +import { CATEGORIES } from 'vs/workbench/common/actions'; +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; + +export class CloseWindowAction extends Action2 { + + constructor() { + super({ + id: 'workbench.action.closeWindow', + title: { + value: localize('closeWindow', "Close Window"), + mnemonicTitle: localize({ key: 'miCloseWindow', comment: ['&& denotes a mnemonic'] }, "Clos&&e Window"), + original: 'Close Window' + }, + f1: true, + keybinding: { + weight: KeybindingWeight.WorkbenchContrib, + mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W }, + linux: { primary: KeyMod.Alt | KeyCode.F4, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W] }, + win: { primary: KeyMod.Alt | KeyCode.F4, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W] } + }, + menu: { + id: MenuId.MenubarFileMenu, + group: '6_close', + order: 4 + } + }); + } + + override async run(accessor: ServicesAccessor): Promise { + const nativeHostService = accessor.get(INativeHostService); + + return nativeHostService.closeWindow(); + } +} + +abstract class BaseZoomAction extends Action2 { + + private static readonly SETTING_KEY = 'window.zoomLevel'; + + private static readonly MAX_ZOOM_LEVEL = 8; + private static readonly MIN_ZOOM_LEVEL = -8; + + constructor(desc: Readonly) { + super(desc); + } + + protected async setConfiguredZoomLevel(accessor: ServicesAccessor, level: number): Promise { + const configurationService = accessor.get(IConfigurationService); + + level = Math.round(level); // when reaching smallest zoom, prevent fractional zoom levels + + if (level > BaseZoomAction.MAX_ZOOM_LEVEL || level < BaseZoomAction.MIN_ZOOM_LEVEL) { + return; // https://github.com/microsoft/vscode/issues/48357 + } + + await configurationService.updateValue(BaseZoomAction.SETTING_KEY, level); + + applyZoom(level); + } +} + +export class ZoomInAction extends BaseZoomAction { + + constructor() { + super({ + id: 'workbench.action.zoomIn', + title: { + value: localize('zoomIn', "Zoom In"), + mnemonicTitle: localize({ key: 'miZoomIn', comment: ['&& denotes a mnemonic'] }, "&&Zoom In"), + original: 'Zoom In' + }, + category: CATEGORIES.View.value, + f1: true, + keybinding: { + weight: KeybindingWeight.WorkbenchContrib, + primary: KeyMod.CtrlCmd | KeyCode.US_EQUAL, + secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_EQUAL, KeyMod.CtrlCmd | KeyCode.NUMPAD_ADD] + }, + menu: { + id: MenuId.MenubarAppearanceMenu, + group: '3_zoom', + order: 1 + } + }); + } + + override run(accessor: ServicesAccessor): Promise { + return super.setConfiguredZoomLevel(accessor, getZoomLevel() + 1); + } +} + +export class ZoomOutAction extends BaseZoomAction { + + constructor() { + super({ + id: 'workbench.action.zoomOut', + title: { + value: localize('zoomOut', "Zoom Out"), + mnemonicTitle: localize({ key: 'miZoomOut', comment: ['&& denotes a mnemonic'] }, "&&Zoom Out"), + original: 'Zoom Out' + }, + category: CATEGORIES.View.value, + f1: true, + keybinding: { + weight: KeybindingWeight.WorkbenchContrib, + primary: KeyMod.CtrlCmd | KeyCode.US_MINUS, + secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_MINUS, KeyMod.CtrlCmd | KeyCode.NUMPAD_SUBTRACT], + linux: { + primary: KeyMod.CtrlCmd | KeyCode.US_MINUS, + secondary: [KeyMod.CtrlCmd | KeyCode.NUMPAD_SUBTRACT] + } + }, + menu: { + id: MenuId.MenubarAppearanceMenu, + group: '3_zoom', + order: 2 + } + }); + } + + override run(accessor: ServicesAccessor): Promise { + return super.setConfiguredZoomLevel(accessor, getZoomLevel() - 1); + } +} + +export class ZoomResetAction extends BaseZoomAction { + + constructor() { + super({ + id: 'workbench.action.zoomReset', + title: { + value: localize('zoomReset', "Reset Zoom"), + mnemonicTitle: localize({ key: 'miZoomReset', comment: ['&& denotes a mnemonic'] }, "&&Reset Zoom"), + original: 'Reset Zoom' + }, + category: CATEGORIES.View.value, + f1: true, + keybinding: { + weight: KeybindingWeight.WorkbenchContrib, + primary: KeyMod.CtrlCmd | KeyCode.NUMPAD_0 + }, + menu: { + id: MenuId.MenubarAppearanceMenu, + group: '3_zoom', + order: 3 + } + }); + } + + override run(accessor: ServicesAccessor): Promise { + return super.setConfiguredZoomLevel(accessor, 0); + } +} + +abstract class BaseSwitchWindow extends Action2 { + + private readonly closeWindowAction: IQuickInputButton = { + iconClass: Codicon.removeClose.classNames, + tooltip: localize('close', "Close Window") + }; + + private readonly closeDirtyWindowAction: IQuickInputButton = { + iconClass: 'dirty-window ' + Codicon.closeDirty, + tooltip: localize('close', "Close Window"), + alwaysVisible: true + }; + + constructor(desc: Readonly) { + super(desc); + } + + protected abstract isQuickNavigate(): boolean; + + override async run(accessor: ServicesAccessor): Promise { + const quickInputService = accessor.get(IQuickInputService); + const keybindingService = accessor.get(IKeybindingService); + const modelService = accessor.get(IModelService); + const modeService = accessor.get(IModeService); + const nativeHostService = accessor.get(INativeHostService); + + const currentWindowId = nativeHostService.windowId; + + const windows = await nativeHostService.getWindows(); + const placeHolder = localize('switchWindowPlaceHolder', "Select a window to switch to"); + const picks = windows.map(window => { + const resource = window.filename ? URI.file(window.filename) : isSingleFolderWorkspaceIdentifier(window.workspace) ? window.workspace.uri : isWorkspaceIdentifier(window.workspace) ? window.workspace.configPath : undefined; + const fileKind = window.filename ? FileKind.FILE : isSingleFolderWorkspaceIdentifier(window.workspace) ? FileKind.FOLDER : isWorkspaceIdentifier(window.workspace) ? FileKind.ROOT_FOLDER : FileKind.FILE; + return { + payload: window.id, + label: window.title, + ariaLabel: window.dirty ? localize('windowDirtyAriaLabel', "{0}, dirty window", window.title) : window.title, + iconClasses: getIconClasses(modelService, modeService, resource, fileKind), + description: (currentWindowId === window.id) ? localize('current', "Current Window") : undefined, + buttons: currentWindowId !== window.id ? window.dirty ? [this.closeDirtyWindowAction] : [this.closeWindowAction] : undefined + }; + }); + const autoFocusIndex = (picks.indexOf(picks.filter(pick => pick.payload === currentWindowId)[0]) + 1) % picks.length; + + const pick = await quickInputService.pick(picks, { + contextKey: 'inWindowsPicker', + activeItem: picks[autoFocusIndex], + placeHolder, + quickNavigate: this.isQuickNavigate() ? { keybindings: keybindingService.lookupKeybindings(this.desc.id) } : undefined, + onDidTriggerItemButton: async context => { + await nativeHostService.closeWindowById(context.item.payload); + context.removeItem(); + } + }); + + if (pick) { + nativeHostService.focusWindow({ windowId: pick.payload }); + } + } +} + +export class SwitchWindowAction extends BaseSwitchWindow { + + constructor() { + super({ + id: 'workbench.action.switchWindow', + title: { value: localize('switchWindow', "Switch Window..."), original: 'Switch Window...' }, + f1: true, + keybinding: { + weight: KeybindingWeight.WorkbenchContrib, + primary: 0, + mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_W } + } + }); + } + + protected isQuickNavigate(): boolean { + return false; + } +} + +export class QuickSwitchWindowAction extends BaseSwitchWindow { + + constructor() { + super({ + id: 'workbench.action.quickSwitchWindow', + title: { value: localize('quickSwitchWindow', "Quick Switch Window..."), original: 'Quick Switch Window...' }, + f1: true + }); + } + + protected isQuickNavigate(): boolean { + return true; + } +} + +export const NewWindowTabHandler: ICommandHandler = function (accessor: ServicesAccessor) { + return accessor.get(INativeHostService).newWindowTab(); +}; + +export const ShowPreviousWindowTabHandler: ICommandHandler = function (accessor: ServicesAccessor) { + return accessor.get(INativeHostService).showPreviousWindowTab(); +}; + +export const ShowNextWindowTabHandler: ICommandHandler = function (accessor: ServicesAccessor) { + return accessor.get(INativeHostService).showNextWindowTab(); +}; + +export const MoveWindowTabToNewWindowHandler: ICommandHandler = function (accessor: ServicesAccessor) { + return accessor.get(INativeHostService).moveWindowTabToNewWindow(); +}; + +export const MergeWindowTabsHandlerHandler: ICommandHandler = function (accessor: ServicesAccessor) { + return accessor.get(INativeHostService).mergeAllWindowTabs(); +}; + +export const ToggleWindowTabsBarHandler: ICommandHandler = function (accessor: ServicesAccessor) { + return accessor.get(INativeHostService).toggleWindowTabsBar(); +}; diff --git a/lib/vscode/src/vs/workbench/electron-sandbox/desktop.contribution.ts b/src/vs/workbench/electron-sandbox/desktop.contribution.ts similarity index 66% rename from lib/vscode/src/vs/workbench/electron-sandbox/desktop.contribution.ts rename to src/vs/workbench/electron-sandbox/desktop.contribution.ts index 6b1eacf88676..01564b51c732 100644 --- a/lib/vscode/src/vs/workbench/electron-sandbox/desktop.contribution.ts +++ b/src/vs/workbench/electron-sandbox/desktop.contribution.ts @@ -5,115 +5,87 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { localize } from 'vs/nls'; -import product from 'vs/platform/product/common/product'; -import { SyncActionDescriptor, MenuRegistry, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; +import { MenuRegistry, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; -import { IWorkbenchActionRegistry, Extensions, CATEGORIES } from 'vs/workbench/common/actions'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { isLinux, isMacintosh } from 'vs/base/common/platform'; import { ConfigureRuntimeArgumentsAction, ToggleDevToolsAction, ToggleSharedProcessAction, ReloadWindowWithExtensionsDisabledAction } from 'vs/workbench/electron-sandbox/actions/developerActions'; -import { ZoomResetAction, ZoomOutAction, ZoomInAction, CloseCurrentWindowAction, SwitchWindow, QuickSwitchWindow, NewWindowTabHandler, ShowPreviousWindowTabHandler, ShowNextWindowTabHandler, MoveWindowTabToNewWindowHandler, MergeWindowTabsHandlerHandler, ToggleWindowTabsBarHandler } from 'vs/workbench/electron-sandbox/actions/windowActions'; +import { ZoomResetAction, ZoomOutAction, ZoomInAction, CloseWindowAction, SwitchWindowAction, QuickSwitchWindowAction, NewWindowTabHandler, ShowPreviousWindowTabHandler, ShowNextWindowTabHandler, MoveWindowTabToNewWindowHandler, MergeWindowTabsHandlerHandler, ToggleWindowTabsBarHandler } from 'vs/workbench/electron-sandbox/actions/windowActions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IsMacContext } from 'vs/platform/contextkey/common/contextkeys'; -import { EditorsVisibleContext, SingleEditorGroupsContext } from 'vs/workbench/common/editor'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; +import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { PartsSplash } from 'vs/workbench/electron-sandbox/splash'; +import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; +import { InstallShellScriptAction, UninstallShellScriptAction } from 'vs/workbench/electron-sandbox/actions/installActions'; // Actions (function registerActions(): void { - const registry = Registry.as(Extensions.WorkbenchActions); // Actions: Zoom - (function registerZoomActions(): void { - registry.registerWorkbenchAction(SyncActionDescriptor.from(ZoomInAction, { primary: KeyMod.CtrlCmd | KeyCode.US_EQUAL, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_EQUAL, KeyMod.CtrlCmd | KeyCode.NUMPAD_ADD] }), 'View: Zoom In', CATEGORIES.View.value); - registry.registerWorkbenchAction(SyncActionDescriptor.from(ZoomOutAction, { primary: KeyMod.CtrlCmd | KeyCode.US_MINUS, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_MINUS, KeyMod.CtrlCmd | KeyCode.NUMPAD_SUBTRACT], linux: { primary: KeyMod.CtrlCmd | KeyCode.US_MINUS, secondary: [KeyMod.CtrlCmd | KeyCode.NUMPAD_SUBTRACT] } }), 'View: Zoom Out', CATEGORIES.View.value); - registry.registerWorkbenchAction(SyncActionDescriptor.from(ZoomResetAction, { primary: KeyMod.CtrlCmd | KeyCode.NUMPAD_0 }), 'View: Reset Zoom', CATEGORIES.View.value); - })(); + registerAction2(ZoomInAction); + registerAction2(ZoomOutAction); + registerAction2(ZoomResetAction); // Actions: Window - (function registerWindowActions(): void { - registry.registerWorkbenchAction(SyncActionDescriptor.from(SwitchWindow, { primary: 0, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_W } }), 'Switch Window...'); - registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickSwitchWindow), 'Quick Switch Window...'); + registerAction2(SwitchWindowAction); + registerAction2(QuickSwitchWindowAction); + registerAction2(CloseWindowAction); - // Close window - registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseCurrentWindowAction, { - mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W }, - linux: { primary: KeyMod.Alt | KeyCode.F4, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W] }, - win: { primary: KeyMod.Alt | KeyCode.F4, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W] } - } - ), 'Close Window'); - - // Close the window when the last editor is closed by reusing the same keybinding - KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: CloseCurrentWindowAction.ID, - weight: KeybindingWeight.WorkbenchContrib, - when: ContextKeyExpr.and(EditorsVisibleContext.toNegated(), SingleEditorGroupsContext), - primary: KeyMod.CtrlCmd | KeyCode.KEY_W, - handler: accessor => { - const nativeHostService = accessor.get(INativeHostService); - nativeHostService.closeWindow(); - } - }); + // Actions: Install Shell Script (macOS only) + if (isMacintosh) { + registerAction2(InstallShellScriptAction); + registerAction2(UninstallShellScriptAction); + } - // Quit - KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: 'workbench.action.quit', - weight: KeybindingWeight.WorkbenchContrib, - handler(accessor: ServicesAccessor) { - const nativeHostService = accessor.get(INativeHostService); - nativeHostService.quit(); - }, - when: undefined, - mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_Q }, - linux: { primary: KeyMod.CtrlCmd | KeyCode.KEY_Q } - }); - })(); + // Quit + KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'workbench.action.quit', + weight: KeybindingWeight.WorkbenchContrib, + handler(accessor: ServicesAccessor) { + const nativeHostService = accessor.get(INativeHostService); + nativeHostService.quit(); + }, + when: undefined, + mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_Q }, + linux: { primary: KeyMod.CtrlCmd | KeyCode.KEY_Q } + }); // Actions: macOS Native Tabs - (function registerMacOSNativeTabsActions(): void { - if (isMacintosh) { - [ - { handler: NewWindowTabHandler, id: 'workbench.action.newWindowTab', title: { value: localize('newTab', "New Window Tab"), original: 'New Window Tab' } }, - { handler: ShowPreviousWindowTabHandler, id: 'workbench.action.showPreviousWindowTab', title: { value: localize('showPreviousTab', "Show Previous Window Tab"), original: 'Show Previous Window Tab' } }, - { handler: ShowNextWindowTabHandler, id: 'workbench.action.showNextWindowTab', title: { value: localize('showNextWindowTab', "Show Next Window Tab"), original: 'Show Next Window Tab' } }, - { handler: MoveWindowTabToNewWindowHandler, id: 'workbench.action.moveWindowTabToNewWindow', title: { value: localize('moveWindowTabToNewWindow', "Move Window Tab to New Window"), original: 'Move Window Tab to New Window' } }, - { handler: MergeWindowTabsHandlerHandler, id: 'workbench.action.mergeAllWindowTabs', title: { value: localize('mergeAllWindowTabs', "Merge All Windows"), original: 'Merge All Windows' } }, - { handler: ToggleWindowTabsBarHandler, id: 'workbench.action.toggleWindowTabsBar', title: { value: localize('toggleWindowTabsBar', "Toggle Window Tabs Bar"), original: 'Toggle Window Tabs Bar' } } - ].forEach(command => { - CommandsRegistry.registerCommand(command.id, command.handler); + if (isMacintosh) { + [ + { handler: NewWindowTabHandler, id: 'workbench.action.newWindowTab', title: { value: localize('newTab', "New Window Tab"), original: 'New Window Tab' } }, + { handler: ShowPreviousWindowTabHandler, id: 'workbench.action.showPreviousWindowTab', title: { value: localize('showPreviousTab', "Show Previous Window Tab"), original: 'Show Previous Window Tab' } }, + { handler: ShowNextWindowTabHandler, id: 'workbench.action.showNextWindowTab', title: { value: localize('showNextWindowTab', "Show Next Window Tab"), original: 'Show Next Window Tab' } }, + { handler: MoveWindowTabToNewWindowHandler, id: 'workbench.action.moveWindowTabToNewWindow', title: { value: localize('moveWindowTabToNewWindow', "Move Window Tab to New Window"), original: 'Move Window Tab to New Window' } }, + { handler: MergeWindowTabsHandlerHandler, id: 'workbench.action.mergeAllWindowTabs', title: { value: localize('mergeAllWindowTabs', "Merge All Windows"), original: 'Merge All Windows' } }, + { handler: ToggleWindowTabsBarHandler, id: 'workbench.action.toggleWindowTabsBar', title: { value: localize('toggleWindowTabsBar', "Toggle Window Tabs Bar"), original: 'Toggle Window Tabs Bar' } } + ].forEach(command => { + CommandsRegistry.registerCommand(command.id, command.handler); - MenuRegistry.appendMenuItem(MenuId.CommandPalette, { - command, - when: ContextKeyExpr.equals('config.window.nativeTabs', true) - }); + MenuRegistry.appendMenuItem(MenuId.CommandPalette, { + command, + when: ContextKeyExpr.equals('config.window.nativeTabs', true) }); - } - })(); + }); + } // Actions: Developer - (function registerDeveloperActions(): void { - registerAction2(ReloadWindowWithExtensionsDisabledAction); - registerAction2(ConfigureRuntimeArgumentsAction); - registerAction2(ToggleSharedProcessAction); - registerAction2(ToggleDevToolsAction); - })(); + registerAction2(ReloadWindowWithExtensionsDisabledAction); + registerAction2(ConfigureRuntimeArgumentsAction); + registerAction2(ToggleSharedProcessAction); + registerAction2(ToggleDevToolsAction); })(); // Menu (function registerMenu(): void { - MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '6_close', - command: { - id: CloseCurrentWindowAction.ID, - title: localize({ key: 'miCloseWindow', comment: ['&& denotes a mnemonic'] }, "Clos&&e Window") - }, - order: 4 - }); + // Quit MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { group: 'z_Exit', command: { @@ -123,56 +95,6 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema'; order: 1, when: IsMacContext.toNegated() }); - - // Zoom - - MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '3_zoom', - command: { - id: ZoomInAction.ID, - title: localize({ key: 'miZoomIn', comment: ['&& denotes a mnemonic'] }, "&&Zoom In") - }, - order: 1 - }); - - MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '3_zoom', - command: { - id: ZoomOutAction.ID, - title: localize({ key: 'miZoomOut', comment: ['&& denotes a mnemonic'] }, "&&Zoom Out") - }, - order: 2 - }); - - MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '3_zoom', - command: { - id: ZoomResetAction.ID, - title: localize({ key: 'miZoomReset', comment: ['&& denotes a mnemonic'] }, "&&Reset Zoom") - }, - order: 3 - }); - - if (!!product.reportIssueUrl) { - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '3_feedback', - command: { - id: 'workbench.action.openIssueReporter', - title: localize({ key: 'miReportIssue', comment: ['&& denotes a mnemonic', 'Translate this to "Report Issue in English" in all languages please!'] }, "Report &&Issue") - }, - order: 3 - }); - } - - // Tools - MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, { - group: '5_tools', - command: { - id: 'workbench.action.openProcessExplorer', - title: localize({ key: 'miOpenProcessExplorerer', comment: ['&& denotes a mnemonic'] }, "Open &&Process Explorer") - }, - order: 2 - }); })(); // Configuration @@ -386,3 +308,10 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema'; jsonRegistry.registerSchema(argvDefinitionFileSchemaId, schema); })(); + +// Workbench Contributions +(function registerWorkbenchContributions() { + + // Splash + Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(PartsSplash, LifecyclePhase.Starting); +})(); diff --git a/lib/vscode/src/vs/workbench/electron-sandbox/desktop.main.ts b/src/vs/workbench/electron-sandbox/desktop.main.ts similarity index 100% rename from lib/vscode/src/vs/workbench/electron-sandbox/desktop.main.ts rename to src/vs/workbench/electron-sandbox/desktop.main.ts diff --git a/lib/vscode/src/vs/workbench/electron-sandbox/parts/dialogs/dialog.contribution.ts b/src/vs/workbench/electron-sandbox/parts/dialogs/dialog.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/electron-sandbox/parts/dialogs/dialog.contribution.ts rename to src/vs/workbench/electron-sandbox/parts/dialogs/dialog.contribution.ts diff --git a/lib/vscode/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts b/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts similarity index 100% rename from lib/vscode/src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts rename to src/vs/workbench/electron-sandbox/parts/dialogs/dialogHandler.ts diff --git a/lib/vscode/src/vs/workbench/electron-sandbox/parts/titlebar/menubarControl.ts b/src/vs/workbench/electron-sandbox/parts/titlebar/menubarControl.ts similarity index 95% rename from lib/vscode/src/vs/workbench/electron-sandbox/parts/titlebar/menubarControl.ts rename to src/vs/workbench/electron-sandbox/parts/titlebar/menubarControl.ts index 46ad42f83615..266f21e127c2 100644 --- a/lib/vscode/src/vs/workbench/electron-sandbox/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/electron-sandbox/parts/titlebar/menubarControl.ts @@ -3,9 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { localize } from 'vs/nls'; import { Separator } from 'vs/base/common/actions'; -import { IMenuService, MenuId, IMenu, SubmenuItemAction } from 'vs/platform/actions/common/actions'; +import { IMenuService, IMenu, SubmenuItemAction } from 'vs/platform/actions/common/actions'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { isMacintosh } from 'vs/base/common/platform'; @@ -48,11 +47,6 @@ export class NativeMenubarControl extends MenubarControl { ) { super(menuService, workspacesService, contextKeyService, keybindingService, configurationService, labelService, updateService, storageService, notificationService, preferencesService, environmentService, accessibilityService, hostService, commandService); - if (isMacintosh) { - this.menus['Preferences'] = this._register(this.menuService.createMenu(MenuId.MenubarPreferencesMenu, this.contextKeyService)); - this.topLevelTitles['Preferences'] = localize('mPreferences', "Preferences"); - } - for (const topLevelMenuName of Object.keys(this.topLevelTitles)) { const menu = this.menus[topLevelMenuName]; if (menu) { diff --git a/lib/vscode/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts b/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts similarity index 100% rename from lib/vscode/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts rename to src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts diff --git a/lib/vscode/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts b/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts similarity index 78% rename from lib/vscode/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts rename to src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts index fc7dbe32bfb3..4f84e7b6ea46 100644 --- a/lib/vscode/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts +++ b/src/vs/workbench/electron-sandbox/sandbox.simpleservices.ts @@ -11,14 +11,11 @@ import { Event } from 'vs/base/common/event'; import { IAddressProvider } from 'vs/platform/remote/common/remoteAgentConnection'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IExtensionService, NullExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { IProcessEnvironment, isWindows, OperatingSystem } from 'vs/base/common/platform'; -import { IWebviewService, WebviewContentOptions, WebviewElement, WebviewExtensionDescription, WebviewOptions, WebviewOverlay } from 'vs/workbench/contrib/webview/browser/webview'; +import { isWindows } from 'vs/base/common/platform'; import { ITunnelProvider, ITunnelService, RemoteTunnel, TunnelProviderFeatures } from 'vs/platform/remote/common/tunnel'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { joinPath } from 'vs/base/common/resources'; import { VSBuffer } from 'vs/base/common/buffer'; -import { TerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminalInstanceService'; -import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { SearchService } from 'vs/workbench/services/search/common/searchService'; import { ISearchService } from 'vs/workbench/services/search/common/search'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -28,8 +25,6 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; -import { IShellLaunchConfigResolveOptions, ITerminalProfile, ITerminalProfileResolverService } from 'vs/workbench/contrib/terminal/common/terminal'; -import { IShellLaunchConfig } from 'vs/platform/terminal/common/terminal'; //#region Environment @@ -268,23 +263,6 @@ registerSingleton(IExtensionService, SimpleExtensionService); //#endregion -//#region Webview - -class SimpleWebviewService implements IWebviewService { - declare readonly _serviceBrand: undefined; - - readonly activeWebview = undefined; - readonly onDidChangeActiveWebview = Event.None; - - createWebviewElement(id: string, options: WebviewOptions, contentOptions: WebviewContentOptions, extension: WebviewExtensionDescription | undefined): WebviewElement { throw new Error('Method not implemented.'); } - createWebviewOverlay(id: string, options: WebviewOptions, contentOptions: WebviewContentOptions, extension: WebviewExtensionDescription | undefined): WebviewOverlay { throw new Error('Method not implemented.'); } -} - -registerSingleton(IWebviewService, SimpleWebviewService); - -//#endregion - - //#region Tunnel class SimpleTunnelService implements ITunnelService { @@ -296,6 +274,7 @@ class SimpleTunnelService implements ITunnelService { canMakePublic = false; onTunnelOpened = Event.None; onTunnelClosed = Event.None; + hasTunnelProvider = false; canTunnel(uri: URI): boolean { return false; } openTunnel(addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localPort?: number): Promise | undefined { return undefined; } @@ -309,34 +288,6 @@ registerSingleton(ITunnelService, SimpleTunnelService); //#endregion -//#region Terminal Instance - -class SimpleTerminalInstanceService extends TerminalInstanceService { } - -registerSingleton(ITerminalInstanceService, SimpleTerminalInstanceService); - -//#endregion - - -//#region Terminal Profile Resolver Service - -class SimpleTerminalProfileResolverService implements ITerminalProfileResolverService { - - _serviceBrand: undefined; - - resolveIcon(shellLaunchConfig: IShellLaunchConfig, os: OperatingSystem): void { } - async resolveShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig, options: IShellLaunchConfigResolveOptions): Promise { } - getDefaultProfile(options: IShellLaunchConfigResolveOptions): Promise { throw new Error('Method not implemented.'); } - getDefaultShell(options: IShellLaunchConfigResolveOptions): Promise { throw new Error('Method not implemented.'); } - getDefaultShellArgs(options: IShellLaunchConfigResolveOptions): Promise { throw new Error('Method not implemented.'); } - getShellEnvironment(remoteAuthority: string | undefined): Promise { throw new Error('Method not implemented.'); } - getSafeConfigValue(key: string, os: OperatingSystem): unknown | undefined { throw new Error('Method not implemented.'); } - getSafeConfigValueFullKey(key: string): unknown | undefined { throw new Error('Method not implemented.'); } -} - -registerSingleton(ITerminalProfileResolverService, SimpleTerminalProfileResolverService); - - //#region Search Service class SimpleSearchService extends SearchService { diff --git a/lib/vscode/src/vs/workbench/electron-sandbox/shared.desktop.main.ts b/src/vs/workbench/electron-sandbox/shared.desktop.main.ts similarity index 98% rename from lib/vscode/src/vs/workbench/electron-sandbox/shared.desktop.main.ts rename to src/vs/workbench/electron-sandbox/shared.desktop.main.ts index fa857a32a3d7..26bbfa796cfb 100644 --- a/lib/vscode/src/vs/workbench/electron-sandbox/shared.desktop.main.ts +++ b/src/vs/workbench/electron-sandbox/shared.desktop.main.ts @@ -208,7 +208,7 @@ export abstract class SharedDesktopMain extends Disposable { await result; } - // Uri Identity + // URI Identity const uriIdentityService = new UriIdentityService(fileService); serviceCollection.set(IUriIdentityService, uriIdentityService); @@ -264,7 +264,7 @@ export abstract class SharedDesktopMain extends Disposable { ]); // Workspace Trust Service - const workspaceTrustManagementService = new WorkspaceTrustManagementService(configurationService, environmentService, storageService, uriIdentityService, configurationService); + const workspaceTrustManagementService = new WorkspaceTrustManagementService(configurationService, storageService, uriIdentityService, environmentService, configurationService, remoteAuthorityResolverService); serviceCollection.set(IWorkspaceTrustManagementService, workspaceTrustManagementService); // Update workspace trust so that configuration is updated accordingly diff --git a/src/vs/workbench/electron-sandbox/splash.ts b/src/vs/workbench/electron-sandbox/splash.ts new file mode 100644 index 000000000000..0ccd99880c89 --- /dev/null +++ b/src/vs/workbench/electron-sandbox/splash.ts @@ -0,0 +1,112 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { onDidChangeFullscreen, isFullscreen } from 'vs/base/browser/browser'; +import { getTotalHeight, getTotalWidth } from 'vs/base/browser/dom'; +import { Color } from 'vs/base/common/color'; +import { Event } from 'vs/base/common/event'; +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; +import { editorBackground, foreground } from 'vs/platform/theme/common/colorRegistry'; +import { getThemeTypeSelector, IThemeService } from 'vs/platform/theme/common/themeService'; +import { DEFAULT_EDITOR_MIN_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor'; +import * as themes from 'vs/workbench/common/theme'; +import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import * as perf from 'vs/base/common/performance'; +import { assertIsDefined } from 'vs/base/common/types'; +import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; + +export class PartsSplash { + + private static readonly _splashElementId = 'monaco-parts-splash'; + + private readonly _disposables = new DisposableStore(); + + private _didChangeTitleBarStyle?: boolean; + + constructor( + @IThemeService private readonly _themeService: IThemeService, + @IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService, + @IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService, + @ILifecycleService lifecycleService: ILifecycleService, + @IEditorGroupsService editorGroupsService: IEditorGroupsService, + @IConfigurationService configService: IConfigurationService, + @INativeHostService private readonly _nativeHostService: INativeHostService + ) { + lifecycleService.when(LifecyclePhase.Restored).then(_ => { + this._removePartsSplash(); + perf.mark('code/didRemovePartsSplash'); + }); + + Event.debounce(Event.any( + onDidChangeFullscreen, + editorGroupsService.onDidLayout + ), () => { }, 800)(this._savePartsSplash, this, this._disposables); + + configService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('window.titleBarStyle')) { + this._didChangeTitleBarStyle = true; + this._savePartsSplash(); + } + }, this, this._disposables); + + _themeService.onDidColorThemeChange(_ => { + this._savePartsSplash(); + }, this, this._disposables); + } + + private _savePartsSplash() { + const theme = this._themeService.getColorTheme(); + + this._nativeHostService.saveWindowSplash({ + baseTheme: getThemeTypeSelector(theme.type), + colorInfo: { + foreground: theme.getColor(foreground)?.toString(), + background: Color.Format.CSS.formatHex(theme.getColor(editorBackground) || themes.WORKBENCH_BACKGROUND(theme)), + editorBackground: theme.getColor(editorBackground)?.toString(), + titleBarBackground: theme.getColor(themes.TITLE_BAR_ACTIVE_BACKGROUND)?.toString(), + activityBarBackground: theme.getColor(themes.ACTIVITY_BAR_BACKGROUND)?.toString(), + sideBarBackground: theme.getColor(themes.SIDE_BAR_BACKGROUND)?.toString(), + statusBarBackground: theme.getColor(themes.STATUS_BAR_BACKGROUND)?.toString(), + statusBarNoFolderBackground: theme.getColor(themes.STATUS_BAR_NO_FOLDER_BACKGROUND)?.toString(), + windowBorder: theme.getColor(themes.WINDOW_ACTIVE_BORDER)?.toString() ?? theme.getColor(themes.WINDOW_INACTIVE_BORDER)?.toString() + }, + layoutInfo: !this._shouldSaveLayoutInfo() ? undefined : { + sideBarSide: this._layoutService.getSideBarPosition() === Position.RIGHT ? 'right' : 'left', + editorPartMinWidth: DEFAULT_EDITOR_MIN_DIMENSIONS.width, + titleBarHeight: this._layoutService.isVisible(Parts.TITLEBAR_PART) ? getTotalHeight(assertIsDefined(this._layoutService.getContainer(Parts.TITLEBAR_PART))) : 0, + activityBarWidth: this._layoutService.isVisible(Parts.ACTIVITYBAR_PART) ? getTotalWidth(assertIsDefined(this._layoutService.getContainer(Parts.ACTIVITYBAR_PART))) : 0, + sideBarWidth: this._layoutService.isVisible(Parts.SIDEBAR_PART) ? getTotalWidth(assertIsDefined(this._layoutService.getContainer(Parts.SIDEBAR_PART))) : 0, + statusBarHeight: this._layoutService.isVisible(Parts.STATUSBAR_PART) ? getTotalHeight(assertIsDefined(this._layoutService.getContainer(Parts.STATUSBAR_PART))) : 0, + windowBorder: this._layoutService.hasWindowBorder(), + windowBorderRadius: this._layoutService.getWindowBorderRadius() + } + }); + } + + private _shouldSaveLayoutInfo(): boolean { + return !isFullscreen() && !this._environmentService.isExtensionDevelopment && !this._didChangeTitleBarStyle; + } + + private _removePartsSplash(): void { + const element = document.getElementById(PartsSplash._splashElementId); + if (element) { + element.style.display = 'none'; + } + + // remove initial colors + const defaultStyles = document.head.getElementsByClassName('initialShellColors'); + if (defaultStyles.length) { + document.head.removeChild(defaultStyles[0]); + } + } + + dispose(): void { + this._disposables.dispose(); + } +} diff --git a/lib/vscode/src/vs/workbench/electron-sandbox/window.ts b/src/vs/workbench/electron-sandbox/window.ts similarity index 94% rename from lib/vscode/src/vs/workbench/electron-sandbox/window.ts rename to src/vs/workbench/electron-sandbox/window.ts index d4e4e0ed71f8..de32fcf338db 100644 --- a/lib/vscode/src/vs/workbench/electron-sandbox/window.ts +++ b/src/vs/workbench/electron-sandbox/window.ts @@ -10,7 +10,7 @@ import { equals } from 'vs/base/common/objects'; import { EventType, EventHelper, addDisposableListener, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; import { Separator } from 'vs/base/common/actions'; import { IFileService } from 'vs/platform/files/common/files'; -import { EditorResourceAccessor, IUntitledTextResourceEditorInput, SideBySideEditor, pathsToEditors } from 'vs/workbench/common/editor'; +import { EditorResourceAccessor, IUntitledTextResourceEditorInput, SideBySideEditor, pathsToEditors, IResourceDiffEditorInput } from 'vs/workbench/common/editor'; import { IEditorService, IResourceEditorInputType } from 'vs/workbench/services/editor/common/editorService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { WindowMinimumSize, IOpenFileRequest, IWindowsConfiguration, getTitleBarStyle, IAddFoldersRequest, INativeRunActionInWindowRequest, INativeRunKeybindingInWindowRequest, INativeOpenFileRequest } from 'vs/platform/windows/common/windows'; @@ -19,7 +19,7 @@ import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/work import { applyZoom } from 'vs/platform/windows/electron-sandbox/window'; import { setFullscreen, getZoomLevel } from 'vs/base/browser/browser'; import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { IResourceEditorInput } from 'vs/platform/editor/common/editor'; +import { IBaseResourceEditorInput, IResourceEditorInput } from 'vs/platform/editor/common/editor'; import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals'; import { env } from 'vs/base/common/process'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; @@ -32,7 +32,7 @@ import { IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/work import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity'; import { isWindows, isMacintosh } from 'vs/base/common/platform'; import { IProductService } from 'vs/platform/product/common/productService'; -import { INotificationService, IPromptChoice, NeverShowAgainScope, Severity } from 'vs/platform/notification/common/notification'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; @@ -186,28 +186,6 @@ export class NativeWindow extends Disposable { // Message support ipcRenderer.on('vscode:showInfoMessage', (event: unknown, message: string) => this.notificationService.info(message)); - // Shell Environment Issue Notifications - const choices: IPromptChoice[] = [{ - label: localize('learnMore', "Learn More"), - run: () => this.openerService.open('https://go.microsoft.com/fwlink/?linkid=2149667') - }]; - - ipcRenderer.on('vscode:showShellEnvSlowWarning', () => this.notificationService.prompt( - Severity.Warning, - localize('shellEnvSlowWarning', "Resolving your shell environment is taking very long. Please review your shell configuration."), - choices, - { - sticky: true, - neverShowAgain: { id: 'ignoreShellEnvSlowWarning', scope: NeverShowAgainScope.GLOBAL } - } - )); - - ipcRenderer.on('vscode:showShellEnvTimeoutError', () => this.notificationService.prompt( - Severity.Error, - localize('shellEnvTimeoutError', "Unable to resolve your shell environment in a reasonable time. Please review your shell configuration."), - choices - )); - // Fullscreen Events ipcRenderer.on('vscode:enterFullScreen', async () => { await this.lifecycleService.when(LifecyclePhase.Ready); @@ -547,6 +525,21 @@ export class NativeWindow extends Disposable { } } } + + // Assume `uri` this is a workspace uri, let's see if we can handle it + await this.fileService.activateProvider(uri.scheme); + + if (this.fileService.canHandleResource(uri)) { + return { + resolved: URI.from({ + scheme: this.productService.urlProtocol, + path: 'workspace', + query: uri.toString() + }), + dispose() { } + }; + } + return undefined; } }); @@ -662,7 +655,7 @@ export class NativeWindow extends Disposable { // In wait mode, listen to changes to the editors and wait until the files // are closed that the user wants to wait for. When this happens we delete // the wait marker file to signal to the outside that editing is done. - this.trackClosedWaitFiles(URI.revive(request.filesToWait.waitMarkerFileUri), coalesce(request.filesToWait.paths.map(p => URI.revive(p.fileUri)))); + this.trackClosedWaitFiles(URI.revive(request.filesToWait.waitMarkerFileUri), coalesce(request.filesToWait.paths.map(path => URI.revive(path.fileUri)))); } } @@ -678,17 +671,21 @@ export class NativeWindow extends Disposable { private async openResources(resources: Array, diffMode: boolean): Promise { await this.lifecycleService.when(LifecyclePhase.Ready); + const editors: IBaseResourceEditorInput[] = []; + // In diffMode we open 2 resources as diff if (diffMode && resources.length === 2 && resources[0].resource && resources[1].resource) { - return this.editorService.openEditor({ leftResource: resources[0].resource, rightResource: resources[1].resource, options: { pinned: true } }); - } - - // For one file, just put it into the current active editor - if (resources.length === 1) { - return this.editorService.openEditor(resources[0]); + const diffEditor: IResourceDiffEditorInput = { + originalInput: { resource: resources[0].resource }, + modifiedInput: { resource: resources[1].resource }, + options: { pinned: true } + }; + editors.push(diffEditor); + } else { + editors.push(...resources); } - // Otherwise open all - return this.editorService.openEditors(resources); + // Open as editors + return this.editorService.openEditors(editors, undefined, { validateTrust: true }); } } diff --git a/lib/vscode/src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts b/src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts rename to src/vs/workbench/services/accessibility/electron-sandbox/accessibilityService.ts diff --git a/lib/vscode/src/vs/workbench/services/activity/browser/activityService.ts b/src/vs/workbench/services/activity/browser/activityService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/activity/browser/activityService.ts rename to src/vs/workbench/services/activity/browser/activityService.ts diff --git a/lib/vscode/src/vs/workbench/services/activity/common/activity.ts b/src/vs/workbench/services/activity/common/activity.ts similarity index 85% rename from lib/vscode/src/vs/workbench/services/activity/common/activity.ts rename to src/vs/workbench/services/activity/common/activity.ts index 8eda8c67e8eb..1f9fc1f0d1f8 100644 --- a/lib/vscode/src/vs/workbench/services/activity/common/activity.ts +++ b/src/vs/workbench/services/activity/common/activity.ts @@ -46,7 +46,7 @@ export interface IBadge { class BaseBadge implements IBadge { - constructor(public readonly descriptorFn: (arg: any) => string) { + constructor(readonly descriptorFn: (arg: any) => string) { this.descriptorFn = descriptorFn; } @@ -57,7 +57,7 @@ class BaseBadge implements IBadge { export class NumberBadge extends BaseBadge { - constructor(public readonly number: number, descriptorFn: (num: number) => string) { + constructor(readonly number: number, descriptorFn: (num: number) => string) { super(descriptorFn); this.number = number; @@ -70,13 +70,13 @@ export class NumberBadge extends BaseBadge { export class TextBadge extends BaseBadge { - constructor(public readonly text: string, descriptorFn: () => string) { + constructor(readonly text: string, descriptorFn: () => string) { super(descriptorFn); } } export class IconBadge extends BaseBadge { - constructor(public readonly icon: ThemeIcon, descriptorFn: () => string) { + constructor(readonly icon: ThemeIcon, descriptorFn: () => string) { super(descriptorFn); } } diff --git a/lib/vscode/src/vs/workbench/services/activityBar/browser/activityBarService.ts b/src/vs/workbench/services/activityBar/browser/activityBarService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/activityBar/browser/activityBarService.ts rename to src/vs/workbench/services/activityBar/browser/activityBarService.ts diff --git a/lib/vscode/src/vs/workbench/services/authentication/browser/authenticationService.ts b/src/vs/workbench/services/authentication/browser/authenticationService.ts similarity index 97% rename from lib/vscode/src/vs/workbench/services/authentication/browser/authenticationService.ts rename to src/vs/workbench/services/authentication/browser/authenticationService.ts index bc5357496edb..8652c0c8dd20 100644 --- a/lib/vscode/src/vs/workbench/services/authentication/browser/authenticationService.ts +++ b/src/vs/workbench/services/authentication/browser/authenticationService.ts @@ -37,7 +37,7 @@ export interface IAccountUsage { lastUsed: number; } -const VSO_ALLOWED_EXTENSIONS = ['github.vscode-pull-request-github', 'github.vscode-pull-request-github-insiders', 'vscode.git', 'ms-vsonline.vsonline', 'vscode.github-browser', 'ms-vscode.github-browser', 'ms-vscode.remotehub', 'ms-vscode.remotehub-insiders', 'github.codespaces']; +const VSO_ALLOWED_EXTENSIONS = ['github.vscode-pull-request-github', 'github.vscode-pull-request-github-insiders', 'vscode.git', 'ms-vsonline.vsonline', 'ms-vscode.remotehub', 'ms-vscode.remotehub-insiders', 'github.remotehub', 'github.remotehub-insiders', 'github.codespaces']; export function readAccountUsages(storageService: IStorageService, providerId: string, accountName: string,): IAccountUsage[] { const accountKey = `${providerId}-${accountName}-usages`; @@ -338,7 +338,7 @@ export class AuthenticationService extends Disposable implements IAuthentication } Object.keys(existingRequestsForProvider).forEach(requestedScopes => { - if (addedSessions.some(session => session.scopes.slice().sort().join('') === requestedScopes)) { + if (addedSessions.some(session => session.scopes.slice().join('') === requestedScopes)) { const sessionRequest = existingRequestsForProvider[requestedScopes]; sessionRequest?.disposables.forEach(item => item.dispose()); @@ -565,9 +565,11 @@ export class AuthenticationService extends Disposable implements IAuthentication id: `${providerId}${extensionId}Access`, title: nls.localize({ key: 'accessRequest', - comment: ['The placeholder {0} will be replaced with an extension name. (1) is to indicate that this menu item contributes to a badge count'] + comment: [`The placeholder {0} will be replaced with an authentication provider''s label. {1} will be replaced with an extension name. (1) is to indicate that this menu item contributes to a badge count`] }, - "Grant access to {0}... (1)", extensionName) + "Grant access to {0} for {1}... (1)", + this.getLabel(providerId), + extensionName) } }); @@ -602,7 +604,7 @@ export class AuthenticationService extends Disposable implements IAuthentication if (provider) { const providerRequests = this._signInRequestItems.get(providerId); - const scopesList = scopes.sort().join(''); + const scopesList = scopes.join(''); const extensionHasExistingRequest = providerRequests && providerRequests[scopesList] && providerRequests[scopesList].requestingExtensionIds.includes(extensionId); @@ -615,12 +617,12 @@ export class AuthenticationService extends Disposable implements IAuthentication group: '2_signInRequests', command: { id: `${extensionId}signIn`, - title: nls.localize( - { - key: 'signInRequest', - comment: ['The placeholder {0} will be replaced with an extension name. (1) is to indicate that this menu item contributes to a badge count.'] - }, - "Sign in to use {0} (1)", + title: nls.localize({ + key: 'signInRequest', + comment: [`The placeholder {0} will be replaced with an authentication provider's label. {1} will be replaced with an extension name. (1) is to indicate that this menu item contributes to a badge count.`] + }, + "Sign in with {0} to use {1} (1)", + provider.label, extensionName) } }); diff --git a/src/vs/workbench/services/banner/browser/bannerService.ts b/src/vs/workbench/services/banner/browser/bannerService.ts new file mode 100644 index 000000000000..15f9fe15afda --- /dev/null +++ b/src/vs/workbench/services/banner/browser/bannerService.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 { Codicon } from 'vs/base/common/codicons'; +import { MarkdownString } from 'vs/base/common/htmlContent'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { ILinkDescriptor } from 'vs/platform/opener/browser/link'; + + +export interface IBannerItem { + readonly id: string; + readonly icon: Codicon; + readonly message: string | MarkdownString; + readonly actions?: ILinkDescriptor[]; + readonly ariaLabel?: string; + readonly onClose?: () => void; +} + +export const IBannerService = createDecorator('bannerService'); + +export interface IBannerService { + readonly _serviceBrand: undefined; + + focus(): void; + focusNextAction(): void; + focusPreviousAction(): void; + hide(id: string): void; + show(item: IBannerItem): void; +} diff --git a/lib/vscode/src/vs/workbench/services/clipboard/browser/clipboardService.ts b/src/vs/workbench/services/clipboard/browser/clipboardService.ts similarity index 86% rename from lib/vscode/src/vs/workbench/services/clipboard/browser/clipboardService.ts rename to src/vs/workbench/services/clipboard/browser/clipboardService.ts index 7e0402782855..50e847ce24d4 100644 --- a/lib/vscode/src/vs/workbench/services/clipboard/browser/clipboardService.ts +++ b/src/vs/workbench/services/clipboard/browser/clipboardService.ts @@ -12,13 +12,16 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { once } from 'vs/base/common/functional'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { isSafari } from 'vs/base/browser/browser'; +import { ILogService } from 'vs/platform/log/common/log'; export class BrowserClipboardService extends BaseBrowserClipboardService { constructor( @INotificationService private readonly notificationService: INotificationService, @IOpenerService private readonly openerService: IOpenerService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, + @ILogService private readonly logService: ILogService ) { super(); } @@ -31,10 +34,16 @@ export class BrowserClipboardService extends BaseBrowserClipboardService { try { return await navigator.clipboard.readText(); } catch (error) { + this.logService.error(error); + if (!!this.environmentService.extensionTestsLocationURI) { return ''; // do not ask for input in tests (https://github.com/microsoft/vscode/issues/112264) } + if (isSafari) { + return ''; // Safari does not seem to provide anyway to enable cipboard access (https://github.com/microsoft/vscode-internalbacklog/issues/2162#issuecomment-852042867) + } + return new Promise(resolve => { // Inform user about permissions problem (https://github.com/microsoft/vscode/issues/112089) diff --git a/lib/vscode/src/vs/workbench/services/clipboard/electron-sandbox/clipboardService.ts b/src/vs/workbench/services/clipboard/electron-sandbox/clipboardService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/clipboard/electron-sandbox/clipboardService.ts rename to src/vs/workbench/services/clipboard/electron-sandbox/clipboardService.ts diff --git a/lib/vscode/src/vs/workbench/services/commands/common/commandService.ts b/src/vs/workbench/services/commands/common/commandService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/commands/common/commandService.ts rename to src/vs/workbench/services/commands/common/commandService.ts diff --git a/lib/vscode/src/vs/workbench/services/commands/test/common/commandService.test.ts b/src/vs/workbench/services/commands/test/common/commandService.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/commands/test/common/commandService.test.ts rename to src/vs/workbench/services/commands/test/common/commandService.test.ts diff --git a/lib/vscode/src/vs/workbench/services/configuration/browser/configuration.ts b/src/vs/workbench/services/configuration/browser/configuration.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/configuration/browser/configuration.ts rename to src/vs/workbench/services/configuration/browser/configuration.ts diff --git a/lib/vscode/src/vs/workbench/services/configuration/browser/configurationCache.ts b/src/vs/workbench/services/configuration/browser/configurationCache.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/configuration/browser/configurationCache.ts rename to src/vs/workbench/services/configuration/browser/configurationCache.ts diff --git a/lib/vscode/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/configuration/browser/configurationService.ts rename to src/vs/workbench/services/configuration/browser/configurationService.ts diff --git a/lib/vscode/src/vs/workbench/services/configuration/common/configuration.ts b/src/vs/workbench/services/configuration/common/configuration.ts similarity index 86% rename from lib/vscode/src/vs/workbench/services/configuration/common/configuration.ts rename to src/vs/workbench/services/configuration/common/configuration.ts index 9cff28447ca7..105b65223d71 100644 --- a/lib/vscode/src/vs/workbench/services/configuration/common/configuration.ts +++ b/src/vs/workbench/services/configuration/common/configuration.ts @@ -3,13 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ConfigurationScope, Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; +import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { URI } from 'vs/base/common/uri'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { refineServiceDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event } from 'vs/base/common/event'; import { ResourceMap } from 'vs/base/common/map'; -import { Registry } from 'vs/platform/registry/common/platform'; export const FOLDER_CONFIG_FOLDER_NAME = '.vscode'; export const FOLDER_SETTINGS_NAME = 'settings'; @@ -48,14 +47,6 @@ export interface IConfigurationCache { } -export function filterSettingsRequireWorkspaceTrust(settings: ReadonlyArray): ReadonlyArray { - const configurationRegistry = Registry.as(Extensions.Configuration); - return settings.filter(key => { - const property = configurationRegistry.getConfigurationProperties()[key]; - return property.restricted && property.scope !== ConfigurationScope.APPLICATION && property.scope !== ConfigurationScope.MACHINE; - }); -} - export type RestrictedSettings = { default: ReadonlyArray; userLocal?: ReadonlyArray; diff --git a/lib/vscode/src/vs/workbench/services/configuration/common/configurationEditingService.ts b/src/vs/workbench/services/configuration/common/configurationEditingService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/configuration/common/configurationEditingService.ts rename to src/vs/workbench/services/configuration/common/configurationEditingService.ts diff --git a/lib/vscode/src/vs/workbench/services/configuration/common/configurationModels.ts b/src/vs/workbench/services/configuration/common/configurationModels.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/configuration/common/configurationModels.ts rename to src/vs/workbench/services/configuration/common/configurationModels.ts diff --git a/lib/vscode/src/vs/workbench/services/configuration/common/jsonEditing.ts b/src/vs/workbench/services/configuration/common/jsonEditing.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/configuration/common/jsonEditing.ts rename to src/vs/workbench/services/configuration/common/jsonEditing.ts diff --git a/lib/vscode/src/vs/workbench/services/configuration/common/jsonEditingService.ts b/src/vs/workbench/services/configuration/common/jsonEditingService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/configuration/common/jsonEditingService.ts rename to src/vs/workbench/services/configuration/common/jsonEditingService.ts diff --git a/lib/vscode/src/vs/workbench/services/configuration/electron-sandbox/configurationCache.ts b/src/vs/workbench/services/configuration/electron-sandbox/configurationCache.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/configuration/electron-sandbox/configurationCache.ts rename to src/vs/workbench/services/configuration/electron-sandbox/configurationCache.ts diff --git a/lib/vscode/src/vs/workbench/services/configuration/test/browser/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/browser/configurationEditingService.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/configuration/test/browser/configurationEditingService.test.ts rename to src/vs/workbench/services/configuration/test/browser/configurationEditingService.test.ts diff --git a/lib/vscode/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts b/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts rename to src/vs/workbench/services/configuration/test/browser/configurationService.test.ts diff --git a/lib/vscode/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts b/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/configuration/test/common/configurationModels.test.ts rename to src/vs/workbench/services/configuration/test/common/configurationModels.test.ts diff --git a/lib/vscode/src/vs/workbench/services/configuration/test/common/testServices.ts b/src/vs/workbench/services/configuration/test/common/testServices.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/configuration/test/common/testServices.ts rename to src/vs/workbench/services/configuration/test/common/testServices.ts diff --git a/lib/vscode/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts rename to src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts diff --git a/lib/vscode/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts b/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts similarity index 89% rename from lib/vscode/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts rename to src/vs/workbench/services/configurationResolver/common/configurationResolver.ts index 68a71a2b08c1..be8987984e41 100644 --- a/lib/vscode/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/configurationResolver.ts @@ -26,6 +26,13 @@ export interface IConfigurationResolverService { */ resolveAnyAsync(folder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): Promise; + /** + * Recursively resolves all variables in the given config. + * Returns a copy of it with substituted values and a map of variables and their resolution. + * Keys in the map will be of the format input:variableName or command:variableName. + */ + resolveAnyMap(folder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): Promise<{ newConfig: any, resolvedVariables: Map }>; + /** * Recursively resolves all variables (including commands and user input) in the given config and returns a copy of it with substituted values. * If a "variables" dictionary (with names -> command ids) is given, command variables are first mapped through it before being resolved. diff --git a/lib/vscode/src/vs/workbench/services/configurationResolver/common/configurationResolverSchema.ts b/src/vs/workbench/services/configurationResolver/common/configurationResolverSchema.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/configurationResolver/common/configurationResolverSchema.ts rename to src/vs/workbench/services/configurationResolver/common/configurationResolverSchema.ts diff --git a/lib/vscode/src/vs/workbench/services/configurationResolver/common/configurationResolverUtils.ts b/src/vs/workbench/services/configurationResolver/common/configurationResolverUtils.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/configurationResolver/common/configurationResolverUtils.ts rename to src/vs/workbench/services/configurationResolver/common/configurationResolverUtils.ts diff --git a/lib/vscode/src/vs/workbench/services/configurationResolver/common/variableResolver.ts b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts similarity index 96% rename from lib/vscode/src/vs/workbench/services/configurationResolver/common/variableResolver.ts rename to src/vs/workbench/services/configurationResolver/common/variableResolver.ts index cb4efa5ee73c..0e5a3781144c 100644 --- a/lib/vscode/src/vs/workbench/services/configurationResolver/common/variableResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts @@ -99,7 +99,7 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe return this.resolveAnyBase(workspaceFolder, config, commandValueMapping); } - protected async resolveAnyMap(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): Promise<{ newConfig: any, resolvedVariables: Map }> { + public async resolveAnyMap(workspaceFolder: IWorkspaceFolder | undefined, config: any, commandValueMapping?: IStringDictionary): Promise<{ newConfig: any, resolvedVariables: Map }> { const resolvedVariables = new Map(); const newConfig = await this.resolveAnyBase(workspaceFolder, config, commandValueMapping, resolvedVariables); return { newConfig, resolvedVariables }; @@ -141,7 +141,7 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe // loop through all variables occurrences in 'value' const replaced = value.replace(AbstractVariableResolverService.VARIABLE_REGEXP, (match: string, variable: string) => { - // disallow attempted nesting, see #77289 + // disallow attempted nesting, see #77289. This doesn't exclude variables that resolve to other variables. if (variable.includes(AbstractVariableResolverService.VARIABLE_LHS)) { return match; } @@ -152,6 +152,10 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe resolvedVariables.set(variable, resolvedValue); } + if ((resolvedValue !== match) && types.isString(resolvedValue) && resolvedValue.match(AbstractVariableResolverService.VARIABLE_REGEXP)) { + resolvedValue = this.resolveString(environment, folderUri, resolvedValue, commandValueMapping, resolvedVariables); + } + return resolvedValue; }); diff --git a/lib/vscode/src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts rename to src/vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService.ts diff --git a/lib/vscode/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts rename to src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts diff --git a/lib/vscode/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts b/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts similarity index 96% rename from lib/vscode/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts rename to src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts index deefcdc30ba6..b6ef5caeb414 100644 --- a/lib/vscode/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts +++ b/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts @@ -25,6 +25,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { stripIcons } from 'vs/base/common/iconLabels'; import { coalesce } from 'vs/base/common/arrays'; +import { Emitter } from 'vs/base/common/event'; export class ContextMenuService extends Disposable implements IContextMenuService { @@ -32,6 +33,9 @@ export class ContextMenuService extends Disposable implements IContextMenuServic private impl: IContextMenuService; + private readonly _onDidShowContextMenu = this._register(new Emitter()); + readonly onDidShowContextMenu = this._onDidShowContextMenu.event; + constructor( @INotificationService notificationService: INotificationService, @ITelemetryService telemetryService: ITelemetryService, @@ -56,6 +60,7 @@ export class ContextMenuService extends Disposable implements IContextMenuServic showContextMenu(delegate: IContextMenuDelegate): void { this.impl.showContextMenu(delegate); + this._onDidShowContextMenu.fire(); } } @@ -63,6 +68,8 @@ class NativeContextMenuService extends Disposable implements IContextMenuService declare readonly _serviceBrand: undefined; + readonly onDidShowContextMenu = new Emitter().event; + constructor( @INotificationService private readonly notificationService: INotificationService, @ITelemetryService private readonly telemetryService: ITelemetryService, diff --git a/lib/vscode/src/vs/workbench/services/credentials/browser/credentialsService.ts b/src/vs/workbench/services/credentials/browser/credentialsService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/credentials/browser/credentialsService.ts rename to src/vs/workbench/services/credentials/browser/credentialsService.ts diff --git a/lib/vscode/src/vs/workbench/services/credentials/common/credentials.ts b/src/vs/workbench/services/credentials/common/credentials.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/credentials/common/credentials.ts rename to src/vs/workbench/services/credentials/common/credentials.ts diff --git a/lib/vscode/src/vs/workbench/services/credentials/electron-sandbox/credentialsService.ts b/src/vs/workbench/services/credentials/electron-sandbox/credentialsService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/credentials/electron-sandbox/credentialsService.ts rename to src/vs/workbench/services/credentials/electron-sandbox/credentialsService.ts diff --git a/lib/vscode/src/vs/workbench/services/decorations/browser/decorations.ts b/src/vs/workbench/services/decorations/browser/decorations.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/decorations/browser/decorations.ts rename to src/vs/workbench/services/decorations/browser/decorations.ts diff --git a/lib/vscode/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts similarity index 95% rename from lib/vscode/src/vs/workbench/services/decorations/browser/decorationsService.ts rename to src/vs/workbench/services/decorations/browser/decorationsService.ts index 6ece15214299..0502cdfa4500 100644 --- a/lib/vscode/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -75,12 +75,9 @@ class DecorationRule { const { color, letter } = data; // label createCSSRule(`.${this.itemColorClassName}`, `color: ${getColor(theme, color)};`, element); - // icon if (ThemeIcon.isThemeIcon(letter)) { this._createIconCSSRule(letter, color, element, theme); - } - // letter - else if (letter) { + } else if (letter) { createCSSRule(`.${this.itemBadgeClassName}::after`, `content: "${letter}"; color: ${getColor(theme, color)};`, element); } } @@ -93,6 +90,7 @@ class DecorationRule { // icon (only show first) const icon = data.find(d => ThemeIcon.isThemeIcon(d.letter))?.letter as ThemeIcon | undefined; if (icon) { + // todo@jrieken this is fishy. icons should be just like letter and not mute bubble badge this._createIconCSSRule(icon, color, element, theme); } else { // badge @@ -112,14 +110,26 @@ class DecorationRule { } private _createIconCSSRule(icon: ThemeIcon, color: string | undefined, element: HTMLStyleElement, theme: IColorTheme) { - const codicon = iconRegistry.get(icon.id); + + const index = icon.id.lastIndexOf('~'); + const id = index < 0 ? icon.id : icon.id.substr(0, index); + const modifier = index < 0 ? '' : icon.id.substr(index + 1); + + const codicon = iconRegistry.get(id); if (!codicon || !('fontCharacter' in codicon.definition)) { return; } const charCode = parseInt(codicon.definition.fontCharacter.substr(1), 16); createCSSRule( `.${this.iconBadgeClassName}::after`, - `content: "${String.fromCharCode(charCode)}"; color: ${getColor(theme, color)}; font-family: codicon; font-size: 16px; padding-right: 14px; font-weight: normal`, + `content: "${String.fromCharCode(charCode)}"; + color: ${getColor(theme, color)}; + font-family: codicon; + font-size: 16px; + padding-right: 14px; + font-weight: normal; + ${modifier === 'spin' ? 'animation: codicon-spin 1.5s steps(30) infinite' : ''}; + `, element ); } diff --git a/lib/vscode/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts b/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts rename to src/vs/workbench/services/decorations/test/browser/decorationsService.test.ts diff --git a/lib/vscode/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts b/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts rename to src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts diff --git a/lib/vscode/src/vs/workbench/services/dialogs/browser/fileDialogService.ts b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/dialogs/browser/fileDialogService.ts rename to src/vs/workbench/services/dialogs/browser/fileDialogService.ts diff --git a/lib/vscode/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts b/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts rename to src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts diff --git a/lib/vscode/src/vs/workbench/services/dialogs/common/dialogService.ts b/src/vs/workbench/services/dialogs/common/dialogService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/dialogs/common/dialogService.ts rename to src/vs/workbench/services/dialogs/common/dialogService.ts diff --git a/lib/vscode/src/vs/workbench/services/dialogs/electron-sandbox/fileDialogService.ts b/src/vs/workbench/services/dialogs/electron-sandbox/fileDialogService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/dialogs/electron-sandbox/fileDialogService.ts rename to src/vs/workbench/services/dialogs/electron-sandbox/fileDialogService.ts diff --git a/lib/vscode/src/vs/workbench/services/editor/browser/codeEditorService.ts b/src/vs/workbench/services/editor/browser/codeEditorService.ts similarity index 95% rename from lib/vscode/src/vs/workbench/services/editor/browser/codeEditorService.ts rename to src/vs/workbench/services/editor/browser/codeEditorService.ts index dcef4106dfbf..05d2321431a7 100644 --- a/lib/vscode/src/vs/workbench/services/editor/browser/codeEditorService.ts +++ b/src/vs/workbench/services/editor/browser/codeEditorService.ts @@ -8,12 +8,13 @@ import { CodeEditorServiceImpl } from 'vs/editor/browser/services/codeEditorServ import { ScrollType } from 'vs/editor/common/editorCommon'; import { IResourceEditorInput } from 'vs/platform/editor/common/editor'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { IWorkbenchEditorConfiguration, TextEditorOptions } from 'vs/workbench/common/editor'; +import { IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor'; import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { isEqual } from 'vs/base/common/resources'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { applyTextEditorOptions } from 'vs/workbench/common/editor/editorOptions'; export class CodeEditorService extends CodeEditorServiceImpl { @@ -60,8 +61,7 @@ export class CodeEditorService extends CodeEditorServiceImpl { ) { const targetEditor = activeTextEditorControl.getModifiedEditor(); - const textOptions = TextEditorOptions.create(input.options); - textOptions.apply(targetEditor, ScrollType.Smooth); + applyTextEditorOptions(input.options, targetEditor, ScrollType.Smooth); return targetEditor; } diff --git a/lib/vscode/src/vs/workbench/services/editor/browser/editorDropService.ts b/src/vs/workbench/services/editor/browser/editorDropService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/editor/browser/editorDropService.ts rename to src/vs/workbench/services/editor/browser/editorDropService.ts diff --git a/lib/vscode/src/vs/workbench/services/editor/browser/editorOverrideService.ts b/src/vs/workbench/services/editor/browser/editorOverrideService.ts similarity index 73% rename from lib/vscode/src/vs/workbench/services/editor/browser/editorOverrideService.ts rename to src/vs/workbench/services/editor/browser/editorOverrideService.ts index a6816fe08994..bd54a0ec39d3 100644 --- a/lib/vscode/src/vs/workbench/services/editor/browser/editorOverrideService.ts +++ b/src/vs/workbench/services/editor/browser/editorOverrideService.ts @@ -9,7 +9,7 @@ import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle' import { basename, extname, isEqual } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { EditorActivation, EditorOverride, IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor'; +import { EditorActivation, EditorOverride, IEditorOptions } from 'vs/platform/editor/common/editor'; import { EditorResourceAccessor, IEditorInput, IEditorInputWithOptions, IEditorInputWithOptionsAndGroup } from 'vs/workbench/common/editor'; import { IEditorGroup, IEditorGroupsService, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService'; import { Schemas } from 'vs/base/common/network'; @@ -17,7 +17,6 @@ import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { ContributedEditorInfo, ContributedEditorPriority, ContributionPointOptions, DEFAULT_EDITOR_ASSOCIATION, DiffEditorInputFactoryFunction, EditorAssociation, EditorAssociations, EditorInputFactoryFunction, editorsAssociationsSettingId, globMatchesResource, IEditorOverrideService, priorityToRank } from 'vs/workbench/services/editor/common/editorOverrideService'; import { IKeyMods, IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { localize } from 'vs/nls'; -import { Codicon } from 'vs/base/common/codicons'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -41,8 +40,13 @@ type ContributionPoints = Array; export class EditorOverrideService extends Disposable implements IEditorOverrideService { readonly _serviceBrand: undefined; - private _contributionPoints: Map = new Map(); + // Constants + private static readonly configureDefaultID = 'promptOpenWith.configureDefault'; private static readonly overrideCacheStorageID = 'editorOverrideService.cache'; + private static readonly conflictingDefaultsStorageID = 'editorOverrideService.conflictingDefaults'; + + // Data Stores + private _contributionPoints: Map = new Map(); private cache: Set | undefined; constructor( @@ -58,6 +62,7 @@ export class EditorOverrideService extends Disposable implements IEditorOverride // Read in the cache on statup this.cache = new Set(JSON.parse(this.storageService.get(EditorOverrideService.overrideCacheStorageID, StorageScope.GLOBAL, JSON.stringify([])))); this.storageService.remove(EditorOverrideService.overrideCacheStorageID, StorageScope.GLOBAL); + this.convertOldAssociationFormat(); this._register(this.storageService.onWillSaveState(() => { // We want to store the glob patterns we would activate on, this allows us to know if we need to await the ext host on startup for opening a resource @@ -68,9 +73,14 @@ export class EditorOverrideService extends Disposable implements IEditorOverride this.extensionService.onDidRegisterExtensions(() => { this.cache = undefined; }); + + // When the setting changes we want to ensure that it is properly converted + this._register(this.configurationService.onDidChangeConfiguration(() => { + this.convertOldAssociationFormat(); + })); } - async resolveEditorOverride(editor: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup): Promise { + async resolveEditorOverride(editor: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup): Promise { // If it was an override before we await for the extensions to activate and then proceed with overriding or else they won't be registered if (this.cache && editor.resource && this.resourceMatchesCache(editor.resource)) { await this.extensionService.whenInstalledExtensionsRegistered(); @@ -123,11 +133,10 @@ export class EditorOverrideService extends Disposable implements IEditorOverride } const input = await this.doOverrideEditorInput(editor, options, group, selectedContribution); if (conflictingDefault && input) { - // Wait one second to give the user ample time to see the current editor then ask them to configure a default - setTimeout(() => { - this.doHandleConflictingDefaults(selectedContribution.editorInfo.label, input.editor, input.options ?? options, group); - }, 1200); + // Show the conflicting default dialog + await this.doHandleConflictingDefaults(selectedContribution.editorInfo.label, input.editor, input.options ?? options, group); } + // Add the group as we might've changed it with the quickpick if (input) { this.sendOverrideTelemetry(input.editor); @@ -156,41 +165,77 @@ export class EditorOverrideService extends Disposable implements IEditorOverride return toDisposable(() => remove()); } - hasContributionPoint(schemeOrGlob: string): boolean { - return this._contributionPoints.has(schemeOrGlob); + hasContributionPoint(glob: string): boolean { + return this._contributionPoints.has(glob); } getAssociationsForResource(resource: URI): EditorAssociations { - const rawAssociations = this.configurationService.getValue(editorsAssociationsSettingId) || []; - return rawAssociations.filter(association => association.filenamePattern && globMatchesResource(association.filenamePattern, resource)); + const associations = this.getAllUserAssociations(); + const matchingAssociations = associations.filter(association => association.filenamePattern && globMatchesResource(association.filenamePattern, resource)); + const allContributions: ContributionPoints = this._allContributions; + // Ensure that the settings are valid contribution points + return matchingAssociations.filter(association => allContributions.find(c => c.editorInfo.id === association.viewType)); + } + + private convertOldAssociationFormat(): void { + const rawAssociations = this.configurationService.getValue(editorsAssociationsSettingId) || []; + // If it's not an array, then it's the new format + if (!Array.isArray(rawAssociations)) { + return; + } + let newSettingObject = Object.create(null); + // Make the correctly formatted object from the array and then set that object + for (const association of rawAssociations) { + if (association.filenamePattern) { + newSettingObject[association.filenamePattern] = association.viewType; + } + } + this.configurationService.updateValue(editorsAssociationsSettingId, newSettingObject); + } + + private getAllUserAssociations(): EditorAssociations { + const rawAssociations = this.configurationService.getValue<{ [fileNamePattern: string]: string }>(editorsAssociationsSettingId) || []; + let associations = []; + for (const [key, value] of Object.entries(rawAssociations)) { + const association: EditorAssociation = { + filenamePattern: key, + viewType: value + }; + associations.push(association); + } + return associations; + } + + /** + * Returns all contributions as an array. Possible to contain duplicates + */ + private get _allContributions(): ContributionPoints { + return flatten(Array.from(this._contributionPoints.values())); } updateUserAssociations(globPattern: string, editorID: string): void { const newAssociation: EditorAssociation = { viewType: editorID, filenamePattern: globPattern }; - const currentAssociations = [...this.configurationService.getValue(editorsAssociationsSettingId)]; - - // First try updating existing association - for (let i = 0; i < currentAssociations.length; ++i) { - const existing = currentAssociations[i]; - if (existing.filenamePattern === newAssociation.filenamePattern) { - currentAssociations.splice(i, 1, newAssociation); - this.configurationService.updateValue(editorsAssociationsSettingId, currentAssociations); - return; + const currentAssociations = this.getAllUserAssociations(); + const newSettingObject = Object.create(null); + // Form the new setting object including the newest associations + for (const association of [...currentAssociations, newAssociation]) { + if (association.filenamePattern) { + newSettingObject[association.filenamePattern] = association.viewType; } } - - // Otherwise, create a new one - currentAssociations.unshift(newAssociation); - this.configurationService.updateValue(editorsAssociationsSettingId, currentAssociations); + this.configurationService.updateValue(editorsAssociationsSettingId, newSettingObject); } private findMatchingContributions(resource: URI): ContributionPoint[] { + // The user setting should be respected even if the editor doesn't specify that resource in package.json + const userSettings = this.getAssociationsForResource(resource); let contributions: ContributionPoint[] = []; // Then all glob patterns for (const key of this._contributionPoints.keys()) { const contributionPoints = this._contributionPoints.get(key)!; for (const contributionPoint of contributionPoints) { - if (globMatchesResource(key, resource)) { + const foundInSettings = userSettings.find(setting => setting.viewType === contributionPoint.editorInfo.id); + if (foundInSettings || globMatchesResource(key, resource)) { contributions.push(contributionPoint); } } @@ -199,6 +244,11 @@ export class EditorOverrideService extends Disposable implements IEditorOverride return contributions.sort((a, b) => priorityToRank(b.editorInfo.priority) - priorityToRank(a.editorInfo.priority)); } + public getEditorIds(resource: URI): string[] { + const contributionPoints = this.findMatchingContributions(resource); + return contributionPoints.map(contribution => contribution.editorInfo.id); + } + /** * Given a resource and an override selects the best possible contribution point * @returns The contribution point and whether there was another default which conflicted with it @@ -214,7 +264,7 @@ export class EditorOverrideService extends Disposable implements IEditorOverride }; if (override) { // Specific overried passed in doesn't have to match the reosurce, it can be anything - const contributionPoints = flatten(Array.from(this._contributionPoints.values())); + const contributionPoints = this._allContributions; return { contributionPoint: findMatchingContribPoint(contributionPoints, override), conflictingDefault: false @@ -242,7 +292,7 @@ export class EditorOverrideService extends Disposable implements IEditorOverride }; } - private async doOverrideEditorInput(editor: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup, selectedContribution: ContributionPoint): Promise { + private async doOverrideEditorInput(editor: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup, selectedContribution: ContributionPoint): Promise { // If no activation option is provided, populate it. if (options && typeof options.activation === 'undefined') { @@ -326,15 +376,26 @@ export class EditorOverrideService extends Disposable implements IEditorOverride } private async doHandleConflictingDefaults(editorName: string, currentEditor: IContributedEditorInput, options: IEditorOptions | undefined, group: IEditorGroup) { - const makeCurrentEditorDefault = () => { - const viewType = currentEditor.viewType; - if (viewType) { - this.updateUserAssociations(`*${extname(currentEditor.resource!)}`, viewType); - } + type StoredChoice = { + [key: string]: string[]; + }; + const contributionPoints = this.findMatchingContributions(currentEditor.resource!); + const storedChoices: StoredChoice = JSON.parse(this.storageService.get(EditorOverrideService.conflictingDefaultsStorageID, StorageScope.GLOBAL, '{}')); + const globForResource = `*${extname(currentEditor.resource!)}`; + // Writes to the storage service that a choice has been made for the currently installed editors + const writeCurrentEditorsToStorage = () => { + storedChoices[globForResource] = []; + contributionPoints.forEach(contrib => storedChoices[globForResource].push(contrib.editorInfo.id)); + this.storageService.store(EditorOverrideService.conflictingDefaultsStorageID, JSON.stringify(storedChoices), StorageScope.GLOBAL, StorageTarget.MACHINE); }; + // If the user has already made a choice for this editor we don't want to ask them again + if (storedChoices[globForResource] && storedChoices[globForResource].find(editorID => editorID === currentEditor.viewType)) { + return; + } + const handle = this.notificationService.prompt(Severity.Warning, - localize('editorOverride.conflictingDefaults', 'Multiple editors want to be your default editor for this resource.'), + localize('editorOverride.conflictingDefaults', 'There are multiple default editors available for the resource.'), [{ label: localize('editorOverride.configureDefault', 'Configure Default'), run: async () => { @@ -359,21 +420,23 @@ export class EditorOverrideService extends Disposable implements IEditorOverride }, { label: localize('editorOverride.keepDefault', 'Keep {0}', editorName), - run: makeCurrentEditorDefault + run: writeCurrentEditorsToStorage } ]); // If the user pressed X we assume they want to keep the current editor as default const onCloseListener = handle.onDidClose(() => { - makeCurrentEditorDefault(); + writeCurrentEditorsToStorage(); onCloseListener.dispose(); }); } - private mapContributionsToQuickPickEntry(resource: URI, group: IEditorGroup, alwaysUpdateSetting?: boolean) { + private mapContributionsToQuickPickEntry(resource: URI, group: IEditorGroup, showDefaultPicker?: boolean) { const currentEditor = firstOrDefault(group.findEditors(resource)); // If untitled, we want all contribution points - let contributionPoints = resource.scheme === Schemas.untitled ? distinct(flatten(Array.from(this._contributionPoints.values())), (contrib) => contrib.editorInfo.id) : this.findMatchingContributions(resource); - + let contributionPoints = resource.scheme === Schemas.untitled ? this._allContributions : this.findMatchingContributions(resource); + // We don't want duplicate Id entries + contributionPoints = distinct(contributionPoints, c => c.editorInfo.id); + const defaultSetting = this.getAssociationsForResource(resource)[0]?.viewType; // Not the most efficient way to do this, but we want to ensure the text editor is at the top of the quickpick contributionPoints = contributionPoints.sort((a, b) => { if (a.editorInfo.id === DEFAULT_EDITOR_ASSOCIATION.id) { @@ -384,37 +447,43 @@ export class EditorOverrideService extends Disposable implements IEditorOverride return priorityToRank(b.editorInfo.priority) - priorityToRank(a.editorInfo.priority); } }); - const contribGroups: { defaults: Array, optional: Array } = { - defaults: [ - { type: 'separator', label: localize('editorOverride.picker.default', 'Defaults') } - ], - optional: [ - { type: 'separator', label: localize('editorOverride.picker.optional', 'Optional') } - ], - }; - // Get the matching contribtuions and call resolve whether they're active for the picker + const quickPickEntries: Array = []; + const currentlyActiveLabel = localize('promptOpenWith.currentlyActive', "Active"); + const currentDefaultLabel = localize('promptOpenWith.currentDefault', "Default"); + const currentDefaultAndActiveLabel = localize('promptOpenWith.currentDefaultAndActive', "Active and Default"); + // Default order = setting -> highest priority -> text + let defaultViewType = defaultSetting; + if (!defaultViewType && contributionPoints.length > 2 && contributionPoints[1]?.editorInfo.priority !== ContributedEditorPriority.option) { + defaultViewType = contributionPoints[1]?.editorInfo.id; + } + if (!defaultViewType) { + defaultViewType = DEFAULT_EDITOR_ASSOCIATION.id; + } + // Map the contributions to quickpick entries contributionPoints.forEach(contribPoint => { const isActive = currentEditor ? contribPoint.editorInfo.describes(currentEditor) : false; - const quickPickEntry = { + const isDefault = contribPoint.editorInfo.id === defaultViewType; + const quickPickEntry: IQuickPickItem = { id: contribPoint.editorInfo.id, label: contribPoint.editorInfo.label, - description: isActive ? localize('promptOpenWith.currentlyActive', "Currently Active") : undefined, + description: isActive && isDefault ? currentDefaultAndActiveLabel : isActive ? currentlyActiveLabel : isDefault ? currentDefaultLabel : undefined, detail: contribPoint.editorInfo.detail ?? contribPoint.editorInfo.priority, - buttons: alwaysUpdateSetting ? [] : [{ - iconClass: Codicon.gear.classNames, - tooltip: localize('promptOpenWith.setDefaultTooltip', "Set as default editor for '{0}' files", extname(resource)) - }], }; - if (contribPoint.editorInfo.priority === ContributedEditorPriority.option) { - contribGroups.optional.push(quickPickEntry); - } else { - contribGroups.defaults.push(quickPickEntry); - } + quickPickEntries.push(quickPickEntry); }); - return [...contribGroups.defaults, ...contribGroups.optional]; + if (!showDefaultPicker) { + const separator: IQuickPickSeparator = { type: 'separator' }; + quickPickEntries.push(separator); + const configureDefaultEntry = { + id: EditorOverrideService.configureDefaultID, + label: localize('promptOpenWith.configureDefault', "Configure default editor for '{0}'...", `*${extname(resource)}`), + }; + quickPickEntries.push(configureDefaultEntry); + } + return quickPickEntries; } - private async doPickEditorOverride(editor: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup, alwaysUpdateSetting?: boolean): Promise<[IEditorOptions, IEditorGroup | undefined] | undefined> { + private async doPickEditorOverride(editor: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup, showDefaultPicker?: boolean): Promise<[IEditorOptions, IEditorGroup | undefined] | undefined> { type EditorOverridePick = { readonly item: IQuickPickItem; @@ -429,12 +498,12 @@ export class EditorOverrideService extends Disposable implements IEditorOverride } // Text editor has the lowest priority because we - const editorOverridePicks = this.mapContributionsToQuickPickEntry(resource, group, alwaysUpdateSetting); + const editorOverridePicks = this.mapContributionsToQuickPickEntry(resource, group, showDefaultPicker); // Create editor override picker const editorOverridePicker = this.quickInputService.createQuickPick(); - const placeHolderMessage = alwaysUpdateSetting ? - localize('prompOpenWith.updateDefaultPlaceHolder', "Select new default editor for '{0}'", basename(resource)) : + const placeHolderMessage = showDefaultPicker ? + localize('prompOpenWith.updateDefaultPlaceHolder', "Select new default editor for '{0}'", `*${extname(resource)}`) : localize('promptOpenWith.placeHolder', "Select editor for '{0}'", basename(resource)); editorOverridePicker.placeholder = placeHolderMessage; editorOverridePicker.canAcceptInBackground = true; @@ -458,7 +527,7 @@ export class EditorOverrideService extends Disposable implements IEditorOverride } // If asked to always update the setting then update it even if the gear isn't clicked - if (alwaysUpdateSetting && result?.item.id) { + if (showDefaultPicker && result?.item.id) { this.updateUserAssociations(`*${extname(resource)}`, result.item.id,); } @@ -487,6 +556,11 @@ export class EditorOverrideService extends Disposable implements IEditorOverride // options and group to use accordingly if (picked) { + // If the user selected to configure default we trigger this picker again and tell it to show the default picker + if (picked.item.id === EditorOverrideService.configureDefaultID) { + return this.doPickEditorOverride(editor, options, group, true); + } + // Figure out target group let targetGroup: IEditorGroup | undefined; if (picked.keyMods?.alt || picked.keyMods?.ctrlCmd) { @@ -540,7 +614,7 @@ export class EditorOverrideService extends Disposable implements IEditorOverride } // Also store the users settings as those would have to activate on startup as well - const userAssociations = this.configurationService.getValue(editorsAssociationsSettingId) || []; + const userAssociations = this.getAllUserAssociations(); for (const association of userAssociations) { if (association.filenamePattern) { cacheStorage.add(association.filenamePattern); diff --git a/lib/vscode/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts similarity index 77% rename from lib/vscode/src/vs/workbench/services/editor/browser/editorService.ts rename to src/vs/workbench/services/editor/browser/editorService.ts index 728db06f1cbe..8e03b938fe16 100644 --- a/lib/vscode/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -4,9 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IResourceEditorInput, ITextEditorOptions, IEditorOptions, EditorActivation, EditorOverride, IResourceEditorInputIdentifier } from 'vs/platform/editor/common/editor'; -import { SideBySideEditor, IEditorInput, IEditorPane, GroupIdentifier, IFileEditorInput, IUntitledTextResourceEditorInput, IResourceDiffEditorInput, IEditorInputFactoryRegistry, EditorExtensions, EditorInput, SideBySideEditorInput, IEditorInputWithOptions, isEditorInputWithOptions, EditorOptions, TextEditorOptions, IEditorIdentifier, IEditorCloseEvent, ITextEditorPane, ITextDiffEditorPane, IRevertOptions, SaveReason, EditorsOrder, isTextEditorPane, IWorkbenchEditorConfiguration, EditorResourceAccessor, IVisibleEditorPane, IEditorInputWithOptionsAndGroup } from 'vs/workbench/common/editor'; -import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; +import { IResourceEditorInput, IEditorOptions, EditorActivation, EditorOverride, IResourceEditorInputIdentifier, ITextEditorOptions, ITextResourceEditorInput } from 'vs/platform/editor/common/editor'; +import { SideBySideEditor, IEditorInput, IEditorPane, GroupIdentifier, IFileEditorInput, IUntitledTextResourceEditorInput, IResourceDiffEditorInput, IEditorInputFactoryRegistry, EditorExtensions, IEditorInputWithOptions, isEditorInputWithOptions, IEditorIdentifier, IEditorCloseEvent, ITextEditorPane, ITextDiffEditorPane, IRevertOptions, SaveReason, EditorsOrder, isTextEditorPane, IWorkbenchEditorConfiguration, EditorResourceAccessor, IVisibleEditorPane, IEditorInputWithOptionsAndGroup, EditorInputCapabilities } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; +import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput'; +import { TextResourceEditorInput } from 'vs/workbench/common/editor/textResourceEditorInput'; import { Registry } from 'vs/platform/registry/common/platform'; import { ResourceMap } from 'vs/base/common/map'; import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; @@ -14,30 +16,30 @@ import { IFileService, FileOperationEvent, FileOperation, FileChangesEvent, File import { Schemas } from 'vs/base/common/network'; import { Event, Emitter } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; -import { basename, joinPath, isEqual } from 'vs/base/common/resources'; +import { basename, joinPath } from 'vs/base/common/resources'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { IEditorGroupsService, IEditorGroup, GroupsOrder, IEditorReplacement, GroupChangeKind, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { IResourceEditorInputType, SIDE_GROUP, IResourceEditorReplacement, IOpenEditorOverrideHandler, IEditorService, SIDE_GROUP_TYPE, ACTIVE_GROUP_TYPE, ISaveEditorsOptions, ISaveAllEditorsOptions, IRevertAllEditorsOptions, IBaseSaveRevertAllEditorOptions, IOpenEditorOverrideEntry } from 'vs/workbench/services/editor/common/editorService'; +import { IResourceEditorInputType, SIDE_GROUP, IResourceEditorReplacement, IEditorService, SIDE_GROUP_TYPE, ACTIVE_GROUP_TYPE, ISaveEditorsOptions, ISaveAllEditorsOptions, IRevertAllEditorsOptions, IBaseSaveRevertAllEditorOptions, IOpenEditorsOptions } from 'vs/workbench/services/editor/common/editorService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { Disposable, IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { coalesce, distinct, firstOrDefault, insert } from 'vs/base/common/arrays'; +import { Disposable, IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; +import { coalesce, distinct } from 'vs/base/common/arrays'; import { isCodeEditor, isDiffEditor, ICodeEditor, IDiffEditor, isCompositeEditor } from 'vs/editor/browser/editorBrowser'; import { IEditorGroupView, EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { isUndefined, withNullAsUndefined } from 'vs/base/common/types'; import { EditorsObserver } from 'vs/workbench/browser/parts/editor/editorsObserver'; -import { IEditorViewState } from 'vs/editor/common/editorCommon'; import { IUntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput'; import { Promises, timeout } from 'vs/base/common/async'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { indexOfPath } from 'vs/base/common/extpath'; import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity'; -import { IModelService } from 'vs/editor/common/services/modelService'; -import { ILogService } from 'vs/platform/log/common/log'; import { ContributedEditorPriority, DEFAULT_EDITOR_ASSOCIATION, IEditorOverrideService } from 'vs/workbench/services/editor/common/editorOverrideService'; +import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IWorkspaceTrustRequestService, WorkspaceTrustUriResponse } from 'vs/platform/workspace/common/workspaceTrust'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; -type CachedEditorInput = ResourceEditorInput | IFileEditorInput | UntitledTextEditorInput; +type CachedEditorInput = TextResourceEditorInput | IFileEditorInput | UntitledTextEditorInput; type OpenInEditorGroup = IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE; export class EditorService extends Disposable implements EditorServiceImpl { @@ -73,8 +75,10 @@ export class EditorService extends Disposable implements EditorServiceImpl { @IConfigurationService private readonly configurationService: IConfigurationService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, - @ILogService private readonly logService: ILogService, @IEditorOverrideService private readonly editorOverrideService: IEditorOverrideService, + @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService, + @IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService, + @IHostService private readonly hostService: IHostService, ) { super(); @@ -110,6 +114,22 @@ export class EditorService extends Disposable implements EditorServiceImpl { this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getValue()))); } + private registerDefaultOverride(): void { + this._register(this.editorOverrideService.registerContributionPoint( + '*', + { + id: DEFAULT_EDITOR_ASSOCIATION.id, + label: DEFAULT_EDITOR_ASSOCIATION.displayName, + detail: DEFAULT_EDITOR_ASSOCIATION.providerDisplayName, + describes: (currentEditor) => this.fileEditorInputFactory.isFileEditorInput(currentEditor) && currentEditor.matches(this.activeEditor), + priority: ContributedEditorPriority.builtin + }, + {}, + resource => ({ editor: this.createEditorInput({ resource }) }), + diffEditor => ({ editor: diffEditor }) + )); + } + //#region Editor & group event handlers private lastActiveEditor: IEditorInput | undefined = undefined; @@ -284,7 +304,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { replacement: { ...moveResult.editor, options: { - ...moveResult.editor.options, + ...(moveResult.editor as IResourceEditorInputType).options, ...optionOverrides } } @@ -318,10 +338,11 @@ export class EditorService extends Disposable implements EditorServiceImpl { } // Handle deletes in opened editors depending on: - // - the user has not disabled the setting closeOnFileDelete - // - the file change is local - // - the input is a file that is not resolved (we need to dispose because we cannot restore otherwise since we do not have the contents) - if (this.closeOnFileDelete || !isExternal || (this.fileEditorInputFactory.isFileEditorInput(editor) && !editor.isResolved())) { + // - we close any editor when `closeOnFileDelete: true` + // - we close any editor when the delete occurred from within VSCode + // - we close any editor without resolved working copy assuming that + // this editor could not be opened after the file is gone + if (this.closeOnFileDelete || !isExternal || !this.workingCopyService.has(resource)) { // Do NOT close any opened editor that matches the resource path (either equal or being parent) of the // resource we move to (movedTo). Otherwise we would close a resource that has been renamed to the same @@ -365,7 +386,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { const editors: IEditorInput[] = []; function conditionallyAddEditor(editor: IEditorInput): void { - if (editor.isUntitled() && !options.includeUntitled) { + if (editor.hasCapability(EditorInputCapabilities.Untitled) && !options.includeUntitled) { return; } @@ -485,164 +506,48 @@ export class EditorService extends Disposable implements EditorServiceImpl { //#endregion - //#region editor overrides - - private readonly openEditorOverrides: IOpenEditorOverrideHandler[] = []; - - overrideOpenEditor(handler: IOpenEditorOverrideHandler): IDisposable { - const remove = insert(this.openEditorOverrides, handler); - - return toDisposable(() => remove()); - } - - getEditorOverrides(resource: URI, options: IEditorOptions | undefined, group: IEditorGroup | undefined): [IOpenEditorOverrideHandler, IOpenEditorOverrideEntry][] { - const overrides: [IOpenEditorOverrideHandler, IOpenEditorOverrideEntry][] = []; - - // Collect contributed editor open overrides - for (const openEditorOverride of this.openEditorOverrides) { - if (typeof openEditorOverride.getEditorOverrides === 'function') { - try { - overrides.push(...openEditorOverride.getEditorOverrides(resource, options, group).map(val => [openEditorOverride, val] as [IOpenEditorOverrideHandler, IOpenEditorOverrideEntry])); - } catch (error) { - this.logService.error(`Unexpected error getting editor overrides: ${error}`); - } - } - } - - // Ensure the default one is always present - if (!overrides.some(([, entry]) => entry.id === DEFAULT_EDITOR_ASSOCIATION.id)) { - overrides.unshift(this.getDefaultEditorOverride(resource)); - } - - return overrides; - } - - private registerDefaultOverride(): void { - this._register(this.editorOverrideService.registerContributionPoint( - '*', - { - id: DEFAULT_EDITOR_ASSOCIATION.id, - label: DEFAULT_EDITOR_ASSOCIATION.displayName, - detail: DEFAULT_EDITOR_ASSOCIATION.providerDisplayName, - describes: (currentEditor) => this.fileEditorInputFactory.isFileEditorInput(currentEditor) && currentEditor.matches(this.activeEditor), - priority: ContributedEditorPriority.builtin - }, - {}, - resource => ({ editor: this.createEditorInput({ resource }) }), - diffEditor => ({ editor: diffEditor }) - )); - } - - private getDefaultEditorOverride(resource: URI): [IOpenEditorOverrideHandler, IOpenEditorOverrideEntry] { - return [ - { - open: (editor: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup) => { - const resource = EditorResourceAccessor.getOriginalUri(editor); - if (!resource) { - return; - } - - const fileEditorInput = this.createEditorInput({ resource, forceFile: true }); - const textOptions: IEditorOptions | ITextEditorOptions = { ...options, override: EditorOverride.DISABLED }; - return { - override: (async () => { - - // Try to replace existing editors for resource - const existingEditor = firstOrDefault(this.findEditors(resource, group)); - if (existingEditor && !fileEditorInput.matches(existingEditor)) { - await this.replaceEditors([{ - editor: existingEditor, - replacement: fileEditorInput, - forceReplaceDirty: existingEditor.resource?.scheme === Schemas.untitled, - options: options ? EditorOptions.create(options) : undefined, - }], group); - } - - return this.openEditor(fileEditorInput, textOptions, group); - })() - }; - } - }, - { - id: DEFAULT_EDITOR_ASSOCIATION.id, - label: DEFAULT_EDITOR_ASSOCIATION.displayName, - detail: DEFAULT_EDITOR_ASSOCIATION.providerDisplayName, - active: this.fileEditorInputFactory.isFileEditorInput(this.activeEditor) && isEqual(this.activeEditor.resource, resource), - } - ]; - } - - private doOverrideOpenEditor(editor: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup): Promise | undefined { - for (const openEditorOverride of this.openEditorOverrides) { - const result = openEditorOverride.open(editor, options, group); - const override = result?.override; - if (override) { - return override; - } - } - - return; - } - - //#endregion - //#region openEditor() - openEditor(editor: IEditorInput, options?: IEditorOptions | ITextEditorOptions, group?: OpenInEditorGroup): Promise; + openEditor(editor: IEditorInput, options?: IEditorOptions, group?: OpenInEditorGroup): Promise; openEditor(editor: IResourceEditorInput | IUntitledTextResourceEditorInput, group?: OpenInEditorGroup): Promise; openEditor(editor: IResourceDiffEditorInput, group?: OpenInEditorGroup): Promise; - async openEditor(editor: IEditorInput | IResourceEditorInputType, optionsOrGroup?: IEditorOptions | ITextEditorOptions | OpenInEditorGroup, group?: OpenInEditorGroup): Promise { + async openEditor(editor: IEditorInput | IResourceEditorInputType, optionsOrGroup?: IEditorOptions | OpenInEditorGroup, group?: OpenInEditorGroup): Promise { const result = this.doResolveEditorOpenRequest(editor, optionsOrGroup, group); if (result) { const [resolvedGroup, resolvedEditor, resolvedOptions] = result; - // Override handling: pick editor or open specific - if (resolvedOptions?.override === EditorOverride.PICK || typeof resolvedOptions?.override === 'string') { - const resolvedInputWithOptionsAndGroup = await this.editorOverrideService.resolveEditorOverride(resolvedEditor, resolvedOptions, resolvedGroup); - if (!resolvedInputWithOptionsAndGroup) { - return undefined; // no editor was picked or registered for the identifier - } - - return (resolvedInputWithOptionsAndGroup.group ?? resolvedGroup).openEditor(resolvedInputWithOptionsAndGroup.editor, resolvedInputWithOptionsAndGroup.options ?? resolvedOptions); - } - - // Override handling: ask providers to override + // Override handling: request override from override service if (resolvedOptions?.override !== EditorOverride.DISABLED) { - // TODO@lramos15 this will get cleaned up soon, but since the override - // service no longer uses the override flow we must check that const resolvedInputWithOptionsAndGroup = await this.editorOverrideService.resolveEditorOverride(resolvedEditor, resolvedOptions, resolvedGroup); - // If we didn't override try the legacy overrides - if (!resolvedInputWithOptionsAndGroup || resolvedEditor.matches(resolvedInputWithOptionsAndGroup.editor)) { - const override = this.doOverrideOpenEditor(resolvedEditor, resolvedOptions, resolvedGroup); - if (override) { - return override; - } - } else { - return (resolvedInputWithOptionsAndGroup.group ?? resolvedGroup).openEditor(resolvedInputWithOptionsAndGroup.editor, resolvedInputWithOptionsAndGroup.options ?? resolvedOptions); + if (resolvedInputWithOptionsAndGroup) { + return (resolvedInputWithOptionsAndGroup.group ?? resolvedGroup).openEditor( + resolvedInputWithOptionsAndGroup.editor, + resolvedInputWithOptionsAndGroup.options ?? resolvedOptions + ); } } - // Override handling: disabled + // Override handling: disabled or no override found return resolvedGroup.openEditor(resolvedEditor, resolvedOptions); } return undefined; } - doResolveEditorOpenRequest(editor: IEditorInput | IResourceEditorInputType, optionsOrGroup?: IEditorOptions | ITextEditorOptions | OpenInEditorGroup, group?: OpenInEditorGroup): [IEditorGroup, EditorInput, EditorOptions | undefined] | undefined { + doResolveEditorOpenRequest(editor: IEditorInput | IResourceEditorInputType, optionsOrGroup?: IEditorOptions | OpenInEditorGroup, group?: OpenInEditorGroup): [IEditorGroup, EditorInput, IEditorOptions | undefined] | undefined { let resolvedGroup: IEditorGroup | undefined; let candidateGroup: OpenInEditorGroup | undefined; let typedEditor: EditorInput | undefined; - let typedOptions: EditorOptions | undefined; + let options: IEditorOptions | undefined; // Typed Editor Support if (editor instanceof EditorInput) { typedEditor = editor; - typedOptions = this.toOptions(optionsOrGroup as IEditorOptions); + options = optionsOrGroup as IEditorOptions; candidateGroup = group; - resolvedGroup = this.findTargetGroup(typedEditor, typedOptions, candidateGroup); + resolvedGroup = this.findTargetGroup(typedEditor, options, candidateGroup); } // Untyped Text Editor Support @@ -650,19 +555,19 @@ export class EditorService extends Disposable implements EditorServiceImpl { const textInput = editor as IResourceEditorInputType; typedEditor = this.createEditorInput(textInput); if (typedEditor) { - typedOptions = TextEditorOptions.from(textInput); + options = textInput.options; candidateGroup = optionsOrGroup as OpenInEditorGroup; - resolvedGroup = this.findTargetGroup(typedEditor, typedOptions, candidateGroup); + resolvedGroup = this.findTargetGroup(typedEditor, options, candidateGroup); } } if (typedEditor && resolvedGroup) { if ( this.editorGroupService.activeGroup !== resolvedGroup && // only if target group is not already active - typedOptions && !typedOptions.inactive && // never for inactive editors - typedOptions.preserveFocus && // only if preserveFocus - typeof typedOptions.activation !== 'number' && // only if activation is not already defined (either true or false) + options && !options.inactive && // never for inactive editors + options.preserveFocus && // only if preserveFocus + typeof options.activation !== 'number' && // only if activation is not already defined (either true or false) candidateGroup !== SIDE_GROUP // never for the SIDE_GROUP ) { // If the resolved group is not the active one, we typically @@ -674,10 +579,10 @@ export class EditorService extends Disposable implements EditorServiceImpl { // group is it is opened as `SIDE_GROUP` with `preserveFocus:true`. // repeated Alt-clicking of files in the explorer always open // into the same side group and not cause a group to be created each time. - typedOptions.overwrite({ activation: EditorActivation.ACTIVATE }); + options.activation = EditorActivation.ACTIVATE; } - return [resolvedGroup, typedEditor, typedOptions]; + return [resolvedGroup, typedEditor, options]; } return undefined; @@ -763,26 +668,23 @@ export class EditorService extends Disposable implements EditorServiceImpl { return neighbourGroup; } - private toOptions(options?: IEditorOptions | ITextEditorOptions | EditorOptions): EditorOptions { - if (!options || options instanceof EditorOptions) { - return options as EditorOptions; - } - - const textOptions: ITextEditorOptions = options; - if (textOptions.selection || textOptions.viewState) { - return TextEditorOptions.create(options); - } - - return EditorOptions.create(options); - } - //#endregion //#region openEditors() - openEditors(editors: IEditorInputWithOptions[], group?: OpenInEditorGroup): Promise; - openEditors(editors: IResourceEditorInputType[], group?: OpenInEditorGroup): Promise; - async openEditors(editors: Array, group?: OpenInEditorGroup): Promise { + openEditors(editors: IEditorInputWithOptions[], group?: OpenInEditorGroup, options?: IOpenEditorsOptions): Promise; + openEditors(editors: IResourceEditorInputType[], group?: OpenInEditorGroup, options?: IOpenEditorsOptions): Promise; + async openEditors(editors: Array, group?: OpenInEditorGroup, options?: IOpenEditorsOptions): Promise { + + // Pass all editors to trust service to determine if + // we should proceed with opening the editors if we + // are asked to validate trust. + if (options?.validateTrust) { + const editorsTrusted = await this.handleWorkspaceTrust(editors); + if (!editorsTrusted) { + return []; + } + } // Convert to typed editors and options const typedEditors: IEditorInputWithOptions[] = editors.map(editor => { @@ -792,7 +694,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { return { editor: this.createEditorInput(editor), - options: TextEditorOptions.from(editor) + options: editor.options }; }); @@ -830,7 +732,10 @@ export class EditorService extends Disposable implements EditorServiceImpl { mapGroupToEditors.set(targetGroup, targetGroupEditors); } - targetGroupEditors.push(editorOverride ?? { editor, options }); + targetGroupEditors.push(editorOverride ? + { editor: editorOverride.editor, options: editorOverride.options } : + { editor, options } + ); } } @@ -843,13 +748,82 @@ export class EditorService extends Disposable implements EditorServiceImpl { return coalesce(await Promises.settled(result)); } + private async handleWorkspaceTrust(editors: Array): Promise { + const { resources, diffMode } = this.extractEditorResources(editors); + + const trustResult = await this.workspaceTrustRequestService.requestOpenUris(resources); + switch (trustResult) { + case WorkspaceTrustUriResponse.Open: + return true; + case WorkspaceTrustUriResponse.OpenInNewWindow: + await this.hostService.openWindow(resources.map(resource => ({ fileUri: resource })), { forceNewWindow: true, diffMode }); + return false; + case WorkspaceTrustUriResponse.Cancel: + return false; + } + } + + private extractEditorResources(editors: Array): { resources: URI[], diffMode?: boolean } { + const resources = new ResourceMap(); + let diffMode = false; + + for (const editor of editors) { + + // Typed Editor + if (isEditorInputWithOptions(editor)) { + const resource = EditorResourceAccessor.getOriginalUri(editor.editor, { supportSideBySide: SideBySideEditor.BOTH }); + if (URI.isUri(resource)) { + resources.set(resource, true); + } else if (resource) { + if (resource.primary) { + resources.set(resource.primary, true); + } + + if (resource.secondary) { + resources.set(resource.secondary, true); + } + + diffMode = editor.editor instanceof DiffEditorInput; + } + } + + // Untyped editor + else { + const resourceDiffEditor = editor as IResourceDiffEditorInput; + if (resourceDiffEditor.originalInput && resourceDiffEditor.modifiedInput) { + const originalResourceEditor = resourceDiffEditor.originalInput as IResourceEditorInput; + if (URI.isUri(originalResourceEditor.resource)) { + resources.set(originalResourceEditor.resource, true); + } + + const modifiedResourceEditor = resourceDiffEditor.modifiedInput as IResourceEditorInput; + if (URI.isUri(modifiedResourceEditor.resource)) { + resources.set(modifiedResourceEditor.resource, true); + } + + diffMode = true; + } + + const resourceEditor = editor as IResourceEditorInput; + if (URI.isUri(resourceEditor.resource)) { + resources.set(resourceEditor.resource, true); + } + } + } + + return { + resources: Array.from(resources.keys()), + diffMode + }; + } + //#endregion //#region isOpened() isOpened(editor: IResourceEditorInputIdentifier): boolean { return this.editorsObserver.hasEditor({ - resource: this.asCanonicalEditorResource(editor.resource), + resource: this.uriIdentityService.asCanonicalUri(editor.resource), typeId: editor.typeId }); } @@ -956,7 +930,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { editor: replacementArg.editor, replacement: replacementArg.replacement, forceReplaceDirty: replacementArg.forceReplaceDirty, - options: this.toOptions(replacementArg.options) + options: replacementArg.options }); } else { const replacementArg = replaceEditorArg as IResourceEditorReplacement; @@ -964,7 +938,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { typedEditors.push({ editor: this.createEditorInput(replacementArg.editor), replacement: this.createEditorInput(replacementArg.replacement), - options: this.toOptions(replacementArg.replacement.options) + options: replacementArg.replacement.options }); } } @@ -995,22 +969,22 @@ export class EditorService extends Disposable implements EditorServiceImpl { // Diff Editor Support const resourceDiffInput = input as IResourceDiffEditorInput; - if (resourceDiffInput.leftResource && resourceDiffInput.rightResource) { - const leftInput = this.createEditorInput({ resource: resourceDiffInput.leftResource, forceFile: resourceDiffInput.forceFile }); - const rightInput = this.createEditorInput({ resource: resourceDiffInput.rightResource, forceFile: resourceDiffInput.forceFile }); + if (resourceDiffInput.originalInput && resourceDiffInput.modifiedInput) { + const originalInput = this.createEditorInput({ ...resourceDiffInput.originalInput, forceFile: resourceDiffInput.forceFile }); + const modifiedInput = this.createEditorInput({ ...resourceDiffInput.modifiedInput, forceFile: resourceDiffInput.forceFile }); return this.instantiationService.createInstance(DiffEditorInput, resourceDiffInput.label, resourceDiffInput.description, - leftInput, - rightInput, + originalInput, + modifiedInput, undefined ); } // Untitled file support const untitledInput = input as IUntitledTextResourceEditorInput; - if (untitledInput.forceUntitled || !untitledInput.resource || (untitledInput.resource && untitledInput.resource.scheme === Schemas.untitled)) { + if (untitledInput.forceUntitled || !untitledInput.resource || (untitledInput.resource.scheme === Schemas.untitled)) { const untitledOptions = { mode: untitledInput.mode, initialValue: untitledInput.contents, @@ -1044,31 +1018,31 @@ export class EditorService extends Disposable implements EditorServiceImpl { }) as EditorInput; } - // Resource Editor Support - const resourceEditorInput = input as IResourceEditorInput; - if (resourceEditorInput.resource instanceof URI) { + // Text Resource Editor Support + const textResourceEditorInput = input as ITextResourceEditorInput; + if (textResourceEditorInput.resource instanceof URI) { // Derive the label from the path if not provided explicitly - const label = resourceEditorInput.label || basename(resourceEditorInput.resource); + const label = textResourceEditorInput.label || basename(textResourceEditorInput.resource); // We keep track of the preferred resource this input is to be created // with but it may be different from the canonical resource (see below) - const preferredResource = resourceEditorInput.resource; + const preferredResource = textResourceEditorInput.resource; // From this moment on, only operate on the canonical resource // to ensure we reduce the chance of opening the same resource // with different resource forms (e.g. path casing on Windows) - const canonicalResource = this.asCanonicalEditorResource(preferredResource); + const canonicalResource = this.uriIdentityService.asCanonicalUri(preferredResource); return this.createOrGetCached(canonicalResource, () => { // File - if (resourceEditorInput.forceFile || this.fileService.canHandleResource(canonicalResource)) { - return this.fileEditorInputFactory.createFileEditorInput(canonicalResource, preferredResource, resourceEditorInput.label, resourceEditorInput.description, resourceEditorInput.encoding, resourceEditorInput.mode, this.instantiationService); + if (textResourceEditorInput.forceFile || this.fileService.canHandleResource(canonicalResource)) { + return this.fileEditorInputFactory.createFileEditorInput(canonicalResource, preferredResource, textResourceEditorInput.label, textResourceEditorInput.description, textResourceEditorInput.encoding, textResourceEditorInput.mode, textResourceEditorInput.contents, this.instantiationService); } // Resource - return this.instantiationService.createInstance(ResourceEditorInput, canonicalResource, resourceEditorInput.label, resourceEditorInput.description, resourceEditorInput.mode); + return this.instantiationService.createInstance(TextResourceEditorInput, canonicalResource, textResourceEditorInput.label, textResourceEditorInput.description, textResourceEditorInput.mode, textResourceEditorInput.contents); }, cachedInput => { // Untitled @@ -1077,23 +1051,27 @@ export class EditorService extends Disposable implements EditorServiceImpl { } // Files - else if (!(cachedInput instanceof ResourceEditorInput)) { + else if (!(cachedInput instanceof TextResourceEditorInput)) { cachedInput.setPreferredResource(preferredResource); - if (resourceEditorInput.label) { - cachedInput.setPreferredName(resourceEditorInput.label); + if (textResourceEditorInput.label) { + cachedInput.setPreferredName(textResourceEditorInput.label); } - if (resourceEditorInput.description) { - cachedInput.setPreferredDescription(resourceEditorInput.description); + if (textResourceEditorInput.description) { + cachedInput.setPreferredDescription(textResourceEditorInput.description); } - if (resourceEditorInput.encoding) { - cachedInput.setPreferredEncoding(resourceEditorInput.encoding); + if (textResourceEditorInput.encoding) { + cachedInput.setPreferredEncoding(textResourceEditorInput.encoding); } - if (resourceEditorInput.mode) { - cachedInput.setPreferredMode(resourceEditorInput.mode); + if (textResourceEditorInput.mode) { + cachedInput.setPreferredMode(textResourceEditorInput.mode); + } + + if (typeof textResourceEditorInput.contents === 'string') { + cachedInput.setPreferredContents(textResourceEditorInput.contents); } } @@ -1103,12 +1081,16 @@ export class EditorService extends Disposable implements EditorServiceImpl { cachedInput.setName(label); } - if (resourceEditorInput.description) { - cachedInput.setDescription(resourceEditorInput.description); + if (textResourceEditorInput.description) { + cachedInput.setDescription(textResourceEditorInput.description); + } + + if (textResourceEditorInput.mode) { + cachedInput.setPreferredMode(textResourceEditorInput.mode); } - if (resourceEditorInput.mode) { - cachedInput.setPreferredMode(resourceEditorInput.mode); + if (typeof textResourceEditorInput.contents === 'string') { + cachedInput.setPreferredContents(textResourceEditorInput.contents); } } }) as EditorInput; @@ -1117,28 +1099,6 @@ export class EditorService extends Disposable implements EditorServiceImpl { throw new Error('Unknown input type'); } - private _modelService: IModelService | undefined = undefined; - private get modelService(): IModelService | undefined { - if (!this._modelService) { - this._modelService = this.instantiationService.invokeFunction(accessor => accessor.get(IModelService)); - } - - return this._modelService; - } - - private asCanonicalEditorResource(resource: URI): URI { - const canonicalResource: URI = this.uriIdentityService.asCanonicalUri(resource); - - // In the unlikely case that a model exists for the original resource but - // differs from the canonical resource, we print a warning as this means - // the model will not be able to be opened as editor. - if (!isEqual(resource, canonicalResource) && this.modelService?.getModel(resource)) { - this.logService.warn(`EditorService: a model exists for a resource that is not canonical: ${resource.toString(true)}`); - } - - return canonicalResource; - } - private createOrGetCached(resource: URI, factoryFn: () => CachedEditorInput, cachedFn?: (input: CachedEditorInput) => void): CachedEditorInput { // Return early if already cached @@ -1185,7 +1145,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { editorsToSaveSequentially.push(...uniqueEditors); } else { for (const { groupId, editor } of uniqueEditors) { - if (editor.isUntitled()) { + if (editor.hasCapability(EditorInputCapabilities.Untitled)) { editorsToSaveSequentially.push({ groupId, editor }); } else { editorsToSaveParallel.push({ groupId, editor }); @@ -1214,11 +1174,11 @@ export class EditorService extends Disposable implements EditorServiceImpl { // Preserve view state by opening the editor first if the editor // is untitled or we "Save As". This also allows the user to review // the contents of the editor before making a decision. - let viewState: IEditorViewState | undefined = undefined; const editorPane = await this.openEditor(editor, undefined, groupId); - if (isTextEditorPane(editorPane)) { - viewState = editorPane.getViewState(); - } + const editorOptions: ITextEditorOptions = { + pinned: true, + viewState: isTextEditorPane(editorPane) ? editorPane.getViewState() : undefined + }; const result = options?.saveAs ? await editor.saveAs(groupId, options) : await editor.save(groupId, options); saveResults.push(result); @@ -1231,9 +1191,9 @@ export class EditorService extends Disposable implements EditorServiceImpl { // only selected group) if the resulting editor is different from the // current one. if (!result.matches(editor)) { - const targetGroups = editor.isUntitled() ? this.editorGroupService.groups.map(group => group.id) /* untitled replaces across all groups */ : [groupId]; + const targetGroups = editor.hasCapability(EditorInputCapabilities.Untitled) ? this.editorGroupService.groups.map(group => group.id) /* untitled replaces across all groups */ : [groupId]; for (const group of targetGroups) { - await this.replaceEditors([{ editor, replacement: result, options: { pinned: true, viewState } }], group); + await this.replaceEditors([{ editor, replacement: result, options: editorOptions }], group); } } } @@ -1280,7 +1240,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { continue; } - if (!options?.includeUntitled && editor.isUntitled()) { + if (!options?.includeUntitled && editor.hasCapability(EditorInputCapabilities.Untitled)) { continue; } @@ -1340,10 +1300,10 @@ export class DelegatingEditorService implements IEditorService { @IEditorService private editorService: EditorService ) { } - openEditor(editor: IEditorInput, options?: IEditorOptions | ITextEditorOptions, group?: OpenInEditorGroup): Promise; + openEditor(editor: IEditorInput, options?: IEditorOptions, group?: OpenInEditorGroup): Promise; openEditor(editor: IResourceEditorInput | IUntitledTextResourceEditorInput, group?: OpenInEditorGroup): Promise; openEditor(editor: IResourceDiffEditorInput, group?: OpenInEditorGroup): Promise; - async openEditor(editor: IEditorInput | IResourceEditorInputType, optionsOrGroup?: IEditorOptions | ITextEditorOptions | OpenInEditorGroup, group?: OpenInEditorGroup): Promise { + async openEditor(editor: IEditorInput | IResourceEditorInputType, optionsOrGroup?: IEditorOptions | OpenInEditorGroup, group?: OpenInEditorGroup): Promise { const result = this.editorService.doResolveEditorOpenRequest(editor, optionsOrGroup, group); if (result) { const [resolvedGroup, resolvedEditor, resolvedOptions] = result; @@ -1372,10 +1332,10 @@ export class DelegatingEditorService implements IEditorService { getEditors(order: EditorsOrder, options?: { excludeSticky?: boolean }): readonly IEditorIdentifier[] { return this.editorService.getEditors(order, options); } - openEditors(editors: IEditorInputWithOptions[], group?: OpenInEditorGroup): Promise; - openEditors(editors: IResourceEditorInputType[], group?: OpenInEditorGroup): Promise; - openEditors(editors: Array, group?: OpenInEditorGroup): Promise { - return this.editorService.openEditors(editors, group); + openEditors(editors: IEditorInputWithOptions[], group?: OpenInEditorGroup, options?: IOpenEditorsOptions): Promise; + openEditors(editors: IResourceEditorInputType[], group?: OpenInEditorGroup, options?: IOpenEditorsOptions): Promise; + openEditors(editors: Array, group?: OpenInEditorGroup, options?: IOpenEditorsOptions): Promise { + return this.editorService.openEditors(editors, group, options); } replaceEditors(editors: IResourceEditorReplacement[], group: IEditorGroup | GroupIdentifier): Promise; @@ -1392,9 +1352,6 @@ export class DelegatingEditorService implements IEditorService { findEditors(resource: IResourceEditorInputIdentifier, group: IEditorGroup | GroupIdentifier): IEditorInput | undefined; findEditors(arg1: URI | IResourceEditorInputIdentifier, arg2?: IEditorGroup | GroupIdentifier): readonly IEditorIdentifier[] | readonly IEditorInput[] | IEditorInput | undefined { return this.editorService.findEditors(arg1, arg2); } - overrideOpenEditor(handler: IOpenEditorOverrideHandler): IDisposable { return this.editorService.overrideOpenEditor(handler); } - getEditorOverrides(resource: URI, options: IEditorOptions | undefined, group: IEditorGroup | undefined) { return this.editorService.getEditorOverrides(resource, options, group); } - createEditorInput(input: IResourceEditorInputType): IEditorInput { return this.editorService.createEditorInput(input); } save(editors: IEditorIdentifier | IEditorIdentifier[], options?: ISaveEditorsOptions): Promise { return this.editorService.save(editors, options); } diff --git a/lib/vscode/src/vs/workbench/services/editor/common/editorGroupsService.ts b/src/vs/workbench/services/editor/common/editorGroupsService.ts similarity index 97% rename from lib/vscode/src/vs/workbench/services/editor/common/editorGroupsService.ts rename to src/vs/workbench/services/editor/common/editorGroupsService.ts index f5ebf2884738..f7283b6c246a 100644 --- a/lib/vscode/src/vs/workbench/services/editor/common/editorGroupsService.ts +++ b/src/vs/workbench/services/editor/common/editorGroupsService.ts @@ -5,8 +5,8 @@ import { Event } from 'vs/base/common/event'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IEditorInput, IEditorPane, GroupIdentifier, IEditorInputWithOptions, CloseDirection, IEditorPartOptions, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditorPane, IEditorCloseEvent, IEditorMoveEvent } from 'vs/workbench/common/editor'; -import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor'; +import { IEditorInput, IEditorPane, GroupIdentifier, IEditorInputWithOptions, CloseDirection, IEditorPartOptions, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditorPane, IEditorCloseEvent, IEditorMoveEvent, IEditorOpenEvent } from 'vs/workbench/common/editor'; +import { IEditorOptions } from 'vs/platform/editor/common/editor'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IDimension } from 'vs/editor/common/editorCommon'; import { IDisposable } from 'vs/base/common/lifecycle'; @@ -101,7 +101,7 @@ export interface ICloseAllEditorsOptions { export interface IEditorReplacement { editor: IEditorInput; replacement: IEditorInput; - options?: IEditorOptions | ITextEditorOptions; + options?: IEditorOptions; /** * Skips asking the user for confirmation and doesn't @@ -217,11 +217,6 @@ export interface IEditorGroupsService { */ readonly whenRestored: Promise; - /** - * Will return `true` as soon as `whenRestored` is resolved. - */ - isRestored(): boolean; - /** * Find out if the editor group service has UI state to restore * from a previous session. @@ -377,6 +372,7 @@ export const enum GroupChangeKind { EDITOR_MOVE, EDITOR_ACTIVE, EDITOR_LABEL, + EDITOR_CAPABILITIES, EDITOR_PIN, EDITOR_STICKY, EDITOR_DIRTY @@ -417,6 +413,12 @@ export interface IEditorGroup { */ readonly onWillMoveEditor: Event; + /** + * An event that is fired when an editor is about to be opened + * in the group. + */ + readonly onWillOpenEditor: Event; + /** * A unique identifier of this group that remains identical even if the * group is moved to different locations. @@ -519,7 +521,7 @@ export interface IEditorGroup { * @returns a promise that resolves around an IEditor instance unless * the call failed, or the editor was not opened as active editor. */ - openEditor(editor: IEditorInput, options?: IEditorOptions | ITextEditorOptions): Promise; + openEditor(editor: IEditorInput, options?: IEditorOptions): Promise; /** * Opens editors in this group. @@ -556,14 +558,14 @@ export interface IEditorGroup { /** * Move an editor from this group either within this group or to another group. */ - moveEditor(editor: IEditorInput, target: IEditorGroup, options?: IEditorOptions | ITextEditorOptions): void; + moveEditor(editor: IEditorInput, target: IEditorGroup, options?: IEditorOptions): void; /** * Copy an editor from this group to another group. * * Note: It is currently not supported to show the same editor more than once in the same group. */ - copyEditor(editor: IEditorInput, target: IEditorGroup, options?: IEditorOptions | ITextEditorOptions): void; + copyEditor(editor: IEditorInput, target: IEditorGroup, options?: IEditorOptions): void; /** * Close an editor from the group. This may trigger a confirmation dialog if diff --git a/lib/vscode/src/vs/workbench/services/editor/common/editorOverrideService.ts b/src/vs/workbench/services/editor/common/editorOverrideService.ts similarity index 64% rename from lib/vscode/src/vs/workbench/services/editor/common/editorOverrideService.ts rename to src/vs/workbench/services/editor/common/editorOverrideService.ts index 01bc16f3a0a6..824ea6a615fa 100644 --- a/lib/vscode/src/vs/workbench/services/editor/common/editorOverrideService.ts +++ b/src/vs/workbench/services/editor/common/editorOverrideService.ts @@ -4,8 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import * as glob from 'vs/base/common/glob'; -import { Event } from 'vs/base/common/event'; -import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { IDisposable } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; import { posix } from 'vs/base/common/path'; @@ -14,10 +12,10 @@ import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; import { Extensions as ConfigurationExtensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; -import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor'; +import { IEditorOptions } from 'vs/platform/editor/common/editor'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Registry } from 'vs/platform/registry/common/platform'; -import { EditorExtensions, IEditorInput, IEditorInputWithOptions, IEditorInputWithOptionsAndGroup } from 'vs/workbench/common/editor'; +import { IEditorInput, IEditorInputWithOptions, IEditorInputWithOptionsAndGroup } from 'vs/workbench/common/editor'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -44,40 +42,14 @@ export const DEFAULT_EDITOR_ASSOCIATION: IEditorType = { const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); -const editorTypeSchemaAddition: IJSONSchema = { - type: 'string', - enum: [] -}; - const editorAssociationsConfigurationNode: IConfigurationNode = { ...workbenchConfigurationNodeBase, properties: { 'workbench.editorAssociations': { - type: 'array', - markdownDescription: localize('editor.editorAssociations', "Configure which editor to use for specific file types."), - items: { - type: 'object', - defaultSnippets: [{ - body: { - 'viewType': '$1', - 'filenamePattern': '$2' - } - }], - properties: { - 'viewType': { - anyOf: [ - { - type: 'string', - description: localize('editor.editorAssociations.viewType', "The unique id of the editor to use."), - }, - editorTypeSchemaAddition - ] - }, - 'filenamePattern': { - type: 'string', - description: localize('editor.editorAssociations.filenamePattern', "Glob pattern specifying which files the editor should be used for."), - } - } + type: 'object', + markdownDescription: localize('editor.editorAssociations', "Configure glob patterns to editors (e.g. `\"*.hex\": \"hexEditor.hexEdit\"`). These have precedence over the default behavior."), + additionalProperties: { + type: 'string' } } } @@ -89,68 +61,6 @@ export interface IEditorType { readonly providerDisplayName: string; } -export interface IEditorTypesHandler { - readonly onDidChangeEditorTypes: Event; - - getEditorTypes(): IEditorType[]; -} - -export interface IEditorAssociationsRegistry { - - /** - * Register handlers for editor types - */ - registerEditorTypesHandler(id: string, handler: IEditorTypesHandler): IDisposable; -} - -class EditorAssociationsRegistry implements IEditorAssociationsRegistry { - - private readonly editorTypesHandlers = new Map(); - - registerEditorTypesHandler(id: string, handler: IEditorTypesHandler): IDisposable { - if (this.editorTypesHandlers.has(id)) { - throw new Error(`An editor type handler with ${id} was already registered.`); - } - - this.editorTypesHandlers.set(id, handler); - this.updateEditorAssociationsSchema(); - - const editorTypeChangeEvent = handler.onDidChangeEditorTypes(() => { - this.updateEditorAssociationsSchema(); - }); - - return { - dispose: () => { - editorTypeChangeEvent.dispose(); - this.editorTypesHandlers.delete(id); - this.updateEditorAssociationsSchema(); - } - }; - } - - private updateEditorAssociationsSchema() { - const enumValues: string[] = []; - const enumDescriptions: string[] = []; - - const editorTypes: IEditorType[] = [DEFAULT_EDITOR_ASSOCIATION]; - - for (const [, handler] of this.editorTypesHandlers) { - editorTypes.push(...handler.getEditorTypes()); - } - - for (const { id, providerDisplayName } of editorTypes) { - enumValues.push(id); - enumDescriptions.push(localize('editorAssociations.viewType.sourceDescription', "Source: {0}", providerDisplayName)); - } - - editorTypeSchemaAddition.enum = enumValues; - editorTypeSchemaAddition.enumDescriptions = enumDescriptions; - - configurationRegistry.notifyConfigurationSchemaUpdated(editorAssociationsConfigurationNode); - } -} - -Registry.add(EditorExtensions.Associations, new EditorAssociationsRegistry()); configurationRegistry.registerConfiguration(editorAssociationsConfigurationNode); //#endregion @@ -187,9 +97,9 @@ export type ContributedEditorInfo = { priority: ContributedEditorPriority; }; -export type EditorInputFactoryFunction = (resource: URI, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup) => IEditorInputWithOptions; +export type EditorInputFactoryFunction = (resource: URI, options: IEditorOptions | undefined, group: IEditorGroup) => IEditorInputWithOptions; -export type DiffEditorInputFactoryFunction = (diffEditorInput: DiffEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup) => IEditorInputWithOptions; +export type DiffEditorInputFactoryFunction = (diffEditorInput: DiffEditorInput, options: IEditorOptions | undefined, group: IEditorGroup) => IEditorInputWithOptions; export interface IEditorOverrideService { readonly _serviceBrand: undefined; @@ -229,7 +139,14 @@ export interface IEditorOverrideService { * @param group The current group * @returns An IEditorInputWithOptionsAndGroup if there is an available override or undefined if there is not */ - resolveEditorOverride(editor: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup): Promise; + resolveEditorOverride(editor: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup): Promise; + + /** + * Given a resource returns all the editor ids that match that resource + * @param resource The resource + * @returns A list of editor ids + */ + getEditorIds(resource: URI): string[]; } //#endregion @@ -261,6 +178,6 @@ export function globMatchesResource(globPattern: string | glob.IRelativePattern, } const matchOnPath = typeof globPattern === 'string' && globPattern.indexOf(posix.sep) >= 0; const target = matchOnPath ? `${resource.scheme}:${resource.path}` : basename(resource); - return glob.match(globPattern, target.toLowerCase()); + return glob.match(typeof globPattern === 'string' ? globPattern.toLowerCase() : globPattern, target.toLowerCase()); } //#endregion diff --git a/lib/vscode/src/vs/workbench/services/editor/common/editorService.ts b/src/vs/workbench/services/editor/common/editorService.ts similarity index 77% rename from lib/vscode/src/vs/workbench/services/editor/common/editorService.ts rename to src/vs/workbench/services/editor/common/editorService.ts index c3b0d1c27e5b..61982f9c4e41 100644 --- a/lib/vscode/src/vs/workbench/services/editor/common/editorService.ts +++ b/src/vs/workbench/services/editor/common/editorService.ts @@ -4,17 +4,16 @@ *--------------------------------------------------------------------------------------------*/ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IResourceEditorInput, IEditorOptions, ITextEditorOptions, IResourceEditorInputIdentifier } from 'vs/platform/editor/common/editor'; +import { IResourceEditorInput, IEditorOptions, IResourceEditorInputIdentifier, ITextResourceEditorInput } from 'vs/platform/editor/common/editor'; import { IEditorInput, IEditorPane, GroupIdentifier, IEditorInputWithOptions, IUntitledTextResourceEditorInput, IResourceDiffEditorInput, ITextEditorPane, ITextDiffEditorPane, IEditorIdentifier, ISaveOptions, IRevertOptions, EditorsOrder, IVisibleEditorPane, IEditorCloseEvent } from 'vs/workbench/common/editor'; import { Event } from 'vs/base/common/event'; import { IEditor, IDiffEditor } from 'vs/editor/common/editorCommon'; import { IEditorGroup, IEditorReplacement } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; export const IEditorService = createDecorator('editorService'); -export type IResourceEditorInputType = IResourceEditorInput | IUntitledTextResourceEditorInput | IResourceDiffEditorInput; +export type IResourceEditorInputType = IResourceEditorInput | ITextResourceEditorInput | IUntitledTextResourceEditorInput | IResourceDiffEditorInput; export interface IResourceEditorReplacement { readonly editor: IResourceEditorInputType; @@ -27,27 +26,6 @@ export type ACTIVE_GROUP_TYPE = typeof ACTIVE_GROUP; export const SIDE_GROUP = -2; export type SIDE_GROUP_TYPE = typeof SIDE_GROUP; -export interface IOpenEditorOverrideEntry { - readonly id: string; - readonly label: string; - readonly active: boolean; - readonly detail?: string; -} - -export interface IOpenEditorOverrideHandler { - open(editor: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup): IOpenEditorOverride | undefined; - getEditorOverrides?(resource: URI, options: IEditorOptions | undefined, group: IEditorGroup | undefined): IOpenEditorOverrideEntry[]; -} - -export interface IOpenEditorOverride { - - /** - * If defined, will prevent the opening of an editor and replace the resulting - * promise with the provided promise for the openEditor() call. - */ - override?: Promise; -} - export interface ISaveEditorsOptions extends ISaveOptions { /** @@ -73,6 +51,15 @@ export interface ISaveAllEditorsOptions extends ISaveEditorsOptions, IBaseSaveRe export interface IRevertAllEditorsOptions extends IRevertOptions, IBaseSaveRevertAllEditorOptions { } +export interface IOpenEditorsOptions { + + /** + * Whether to validate trust when opening editors + * that are potentially not inside the workspace. + */ + readonly validateTrust?: boolean; +} + export interface IEditorService { readonly _serviceBrand: undefined; @@ -80,14 +67,14 @@ export interface IEditorService { /** * Emitted when the currently active editor changes. * - * @see `IEditorService.activeEditorPane` + * @see {@link IEditorService.activeEditorPane} */ readonly onDidActiveEditorChange: Event; /** * Emitted when any of the current visible editors changes. * - * @see `IEditorService.visibleEditorPanes` + * @see {@link IEditorService.visibleEditorPanes} */ readonly onDidVisibleEditorsChange: Event; @@ -100,7 +87,7 @@ export interface IEditorService { * The currently active editor pane or `undefined` if none. The editor pane is * the workbench container for editors of any kind. * - * @see `IEditorService.activeEditor` for access to the active editor input + * @see {@link IEditorService.activeEditor} for access to the active editor input */ readonly activeEditorPane: IVisibleEditorPane | undefined; @@ -115,7 +102,7 @@ export interface IEditorService { * The currently active text editor control or `undefined` if there is currently no active * editor or the active editor widget is neither a text nor a diff editor. * - * @see `IEditorService.activeEditor` + * @see {@link IEditorService.activeEditor} */ readonly activeTextEditorControl: IEditor | IDiffEditor | undefined; @@ -129,7 +116,7 @@ export interface IEditorService { /** * All editor panes that are currently visible across all editor groups. * - * @see `IEditorService.visibleEditors` for access to the visible editor inputs + * @see {@link IEditorService.visibleEditors} for access to the visible editor inputs */ readonly visibleEditorPanes: readonly IVisibleEditorPane[]; @@ -179,8 +166,9 @@ export interface IEditorService { * @returns the editor that opened or `undefined` if the operation failed or the editor was not * opened to be active. */ - openEditor(editor: IEditorInput, options?: IEditorOptions | ITextEditorOptions, group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise; - openEditor(editor: IResourceEditorInput | IUntitledTextResourceEditorInput, group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise; + openEditor(editor: IEditorInput, options?: IEditorOptions, group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise; + openEditor(editor: IResourceEditorInput, group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise; + openEditor(editor: ITextResourceEditorInput | IUntitledTextResourceEditorInput, group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise; openEditor(editor: IResourceDiffEditorInput, group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise; /** @@ -194,8 +182,8 @@ export interface IEditorService { * @returns the editors that opened. The array can be empty or have less elements for editors * that failed to open or were instructed to open as inactive. */ - openEditors(editors: IEditorInputWithOptions[], group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise; - openEditors(editors: IResourceEditorInputType[], group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise; + openEditors(editors: IEditorInputWithOptions[], group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE, options?: IOpenEditorsOptions): Promise; + openEditors(editors: IResourceEditorInputType[], group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE, options?: IOpenEditorsOptions): Promise; /** * Replaces editors in an editor group with the provided replacement. @@ -233,18 +221,6 @@ export interface IEditorService { findEditors(resource: URI, group: IEditorGroup | GroupIdentifier): readonly IEditorInput[]; findEditors(resource: IResourceEditorInputIdentifier, group: IEditorGroup | GroupIdentifier): IEditorInput | undefined; - /** - * Get all available editor overrides for the editor input. - */ - getEditorOverrides(resource: URI, options: IEditorOptions | undefined, group: IEditorGroup | undefined): [IOpenEditorOverrideHandler, IOpenEditorOverrideEntry][]; - - /** - * Allows to override the opening of editors by installing a handler that will - * be called each time an editor is about to open allowing to override the - * operation to open a different editor. - */ - overrideOpenEditor(handler: IOpenEditorOverrideHandler): IDisposable; - /** * Converts a lightweight input to a workbench editor input. */ diff --git a/lib/vscode/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts similarity index 94% rename from lib/vscode/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts rename to src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts index 46301315015a..d248e6695c98 100644 --- a/lib/vscode/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { workbenchInstantiationService, registerTestEditor, TestFileEditorInput, TestEditorPart, ITestInstantiationService, TestServiceAccessor, createEditorPart } from 'vs/workbench/test/browser/workbenchTestServices'; import { GroupDirection, GroupsOrder, MergeGroupMode, GroupOrientation, GroupChangeKind, GroupLocation } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { EditorOptions, CloseDirection, IEditorPartOptions, EditorsOrder } from 'vs/workbench/common/editor'; +import { CloseDirection, IEditorPartOptions, EditorsOrder, EditorInputCapabilities } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { DisposableStore } from 'vs/base/common/lifecycle'; @@ -196,10 +196,10 @@ suite('EditorGroupsService', () => { const downGroup = part.addGroup(rightGroup, GroupDirection.DOWN); const rootGroupInput = new TestFileEditorInput(URI.file('foo/bar1'), TEST_EDITOR_INPUT_ID); - await rootGroup.openEditor(rootGroupInput, EditorOptions.create({ pinned: true })); + await rootGroup.openEditor(rootGroupInput, { pinned: true }); const rightGroupInput = new TestFileEditorInput(URI.file('foo/bar2'), TEST_EDITOR_INPUT_ID); - await rightGroup.openEditor(rightGroupInput, EditorOptions.create({ pinned: true })); + await rightGroup.openEditor(rightGroupInput, { pinned: true }); assert.strictEqual(part.groups.length, 3); @@ -293,7 +293,7 @@ suite('EditorGroupsService', () => { const input = new TestFileEditorInput(URI.file('foo/bar'), TEST_EDITOR_INPUT_ID); - await rootGroup.openEditor(input, EditorOptions.create({ pinned: true })); + await rootGroup.openEditor(input, { pinned: true }); const rightGroup = part.addGroup(rootGroup, GroupDirection.RIGHT, { activate: true }); const downGroup = part.copyGroup(rootGroup, rightGroup, GroupDirection.DOWN); assert.strictEqual(groupAddedCounter, 2); @@ -323,13 +323,13 @@ suite('EditorGroupsService', () => { const input2 = new TestFileEditorInput(URI.file('foo/bar2'), TEST_EDITOR_INPUT_ID); const input3 = new TestFileEditorInput(URI.file('foo/bar3'), TEST_EDITOR_INPUT_ID); - await rootGroup.openEditor(input1, EditorOptions.create({ pinned: true })); + await rootGroup.openEditor(input1, { pinned: true }); const rightGroup = part.addGroup(rootGroup, GroupDirection.RIGHT); - await rightGroup.openEditor(input2, EditorOptions.create({ pinned: true })); + await rightGroup.openEditor(input2, { pinned: true }); const downGroup = part.copyGroup(rootGroup, rightGroup, GroupDirection.DOWN); - await downGroup.openEditor(input3, EditorOptions.create({ pinned: true })); + await downGroup.openEditor(input3, { pinned: true }); part.activateGroup(rootGroup); @@ -347,8 +347,6 @@ suite('EditorGroupsService', () => { await part.whenReady; await part.whenRestored; - - assert.strictEqual(part.isRestored(), true); }); test('options', async () => { @@ -380,6 +378,7 @@ suite('EditorGroupsService', () => { let editorCloseCounter = 0; let editorPinCounter = 0; let editorStickyCounter = 0; + let editorCapabilitiesCounter = 0; const editorGroupChangeListener = group.onDidGroupChange(e => { if (e.kind === GroupChangeKind.EDITOR_OPEN) { assert.ok(e.editor); @@ -393,6 +392,9 @@ suite('EditorGroupsService', () => { } else if (e.kind === GroupChangeKind.EDITOR_PIN) { assert.ok(e.editor); editorPinCounter++; + } else if (e.kind === GroupChangeKind.EDITOR_CAPABILITIES) { + assert.ok(e.editor); + editorCapabilitiesCounter++; } else if (e.kind === GroupChangeKind.EDITOR_STICKY) { assert.ok(e.editor); editorStickyCounter++; @@ -412,8 +414,8 @@ suite('EditorGroupsService', () => { const input = new TestFileEditorInput(URI.file('foo/bar'), TEST_EDITOR_INPUT_ID); const inputInactive = new TestFileEditorInput(URI.file('foo/bar/inactive'), TEST_EDITOR_INPUT_ID); - await group.openEditor(input, EditorOptions.create({ pinned: true })); - await group.openEditor(inputInactive, EditorOptions.create({ inactive: true })); + await group.openEditor(input, { pinned: true }); + await group.openEditor(inputInactive, { inactive: true }); assert.strictEqual(group.isActive(input), true); assert.strictEqual(group.isActive(inputInactive), false); @@ -421,6 +423,7 @@ suite('EditorGroupsService', () => { assert.strictEqual(group.contains(inputInactive), true); assert.strictEqual(group.isEmpty, false); assert.strictEqual(group.count, 2); + assert.strictEqual(editorCapabilitiesCounter, 0); assert.strictEqual(editorDidOpenCounter, 2); assert.strictEqual(activeEditorChangeCounter, 1); assert.strictEqual(group.getEditorByIndex(0), input); @@ -428,6 +431,12 @@ suite('EditorGroupsService', () => { assert.strictEqual(group.getIndexOfEditor(input), 0); assert.strictEqual(group.getIndexOfEditor(inputInactive), 1); + input.capabilities = EditorInputCapabilities.RequiresTrust; + assert.strictEqual(editorCapabilitiesCounter, 1); + + inputInactive.capabilities = EditorInputCapabilities.Singleton; + assert.strictEqual(editorCapabilitiesCounter, 2); + assert.strictEqual(group.previewEditor, inputInactive); assert.strictEqual(group.isPinned(inputInactive), false); group.pinEditor(inputInactive); @@ -1146,8 +1155,8 @@ suite('EditorGroupsService', () => { const input = new TestFileEditorInput(URI.file('foo/bar'), TEST_EDITOR_INPUT_ID); const inputInactive = new TestFileEditorInput(URI.file('foo/bar/inactive'), TEST_EDITOR_INPUT_ID); - await group.openEditor(input, EditorOptions.create({ pinned: true })); - await group.openEditor(inputInactive, EditorOptions.create({ inactive: true })); + await group.openEditor(input, { pinned: true }); + await group.openEditor(inputInactive, { inactive: true }); assert.strictEqual(group.stickyCount, 0); assert.strictEqual(group.isSticky(input), false); @@ -1208,7 +1217,7 @@ suite('EditorGroupsService', () => { const inputSticky = new TestFileEditorInput(URI.file('foo/bar/sticky'), TEST_EDITOR_INPUT_ID); - await group.openEditor(inputSticky, EditorOptions.create({ sticky: true })); + await group.openEditor(inputSticky, { sticky: true }); assert.strictEqual(group.stickyCount, 2); assert.strictEqual(group.isSticky(input), false); @@ -1219,7 +1228,7 @@ suite('EditorGroupsService', () => { assert.strictEqual(group.getIndexOfEditor(inputSticky), 1); assert.strictEqual(group.getIndexOfEditor(input), 2); - await group.openEditor(input, EditorOptions.create({ sticky: true })); + await group.openEditor(input, { sticky: true }); assert.strictEqual(group.stickyCount, 3); assert.strictEqual(group.isSticky(input), true); @@ -1274,6 +1283,48 @@ suite('EditorGroupsService', () => { rightGroupListener.dispose(); }); + test('onWillOpenEditor', async () => { + const [part] = await createPart(); + const group = part.activeGroup; + assert.strictEqual(group.isEmpty, true); + + const rightGroup = part.addGroup(group, GroupDirection.RIGHT); + + const input = new TestFileEditorInput(URI.file('foo/bar'), TEST_EDITOR_INPUT_ID); + const secondInput = new TestFileEditorInput(URI.file('foo/bar/second'), TEST_EDITOR_INPUT_ID); + const thirdInput = new TestFileEditorInput(URI.file('foo/bar/third'), TEST_EDITOR_INPUT_ID); + + let leftFiredCount = 0; + const leftGroupListener = group.onWillOpenEditor(() => { + leftFiredCount++; + }); + + let rightFiredCount = 0; + const rightGroupListener = rightGroup.onWillOpenEditor(() => { + rightFiredCount++; + }); + + await group.openEditor(input); + assert.strictEqual(leftFiredCount, 1); + assert.strictEqual(rightFiredCount, 0); + + rightGroup.openEditor(secondInput); + assert.strictEqual(leftFiredCount, 1); + assert.strictEqual(rightFiredCount, 1); + + group.openEditor(thirdInput); + assert.strictEqual(leftFiredCount, 2); + assert.strictEqual(rightFiredCount, 1); + + // Ensure move fires the open event too + rightGroup.moveEditor(secondInput, group); + assert.strictEqual(leftFiredCount, 3); + assert.strictEqual(rightFiredCount, 1); + + leftGroupListener.dispose(); + rightGroupListener.dispose(); + }); + test('copyEditor with context (across groups)', async () => { const [part] = await createPart(); const group = part.activeGroup; diff --git a/lib/vscode/src/vs/workbench/services/editor/test/browser/editorService.test.ts b/src/vs/workbench/services/editor/test/browser/editorService.test.ts similarity index 79% rename from lib/vscode/src/vs/workbench/services/editor/test/browser/editorService.test.ts rename to src/vs/workbench/services/editor/test/browser/editorService.test.ts index 4d13117812b9..87a63784961b 100644 --- a/lib/vscode/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -4,20 +4,20 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { EditorActivation } from 'vs/platform/editor/common/editor'; +import { EditorActivation, EditorOverride } from 'vs/platform/editor/common/editor'; import { URI } from 'vs/base/common/uri'; import { Event } from 'vs/base/common/event'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; -import { EditorInput, EditorsOrder, SideBySideEditorInput } from 'vs/workbench/common/editor'; +import { EditorsOrder, IResourceDiffEditorInput } from 'vs/workbench/common/editor'; import { workbenchInstantiationService, TestServiceAccessor, registerTestEditor, TestFileEditorInput, ITestInstantiationService, registerTestResourceEditor, registerTestSideBySideEditor, createEditorPart } from 'vs/workbench/test/browser/workbenchTestServices'; -import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; +import { TextResourceEditorInput } from 'vs/workbench/common/editor/textResourceEditorInput'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; import { EditorService, DelegatingEditorService } from 'vs/workbench/services/editor/browser/editorService'; import { IEditorGroup, IEditorGroupsService, GroupDirection, GroupsArrangement } from 'vs/workbench/services/editor/common/editorGroupsService'; import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart'; import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; +import { FileEditorInput } from 'vs/workbench/contrib/files/browser/editors/fileEditorInput'; import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput'; import { timeout } from 'vs/base/common/async'; import { toResource } from 'vs/base/test/common/utils'; @@ -30,6 +30,12 @@ import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices'; import { isLinux } from 'vs/base/common/platform'; import { MockScopableContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; +import { ContributedEditorPriority } from 'vs/workbench/services/editor/common/editorOverrideService'; +import { IWorkspaceTrustRequestService, WorkspaceTrustUriResponse } from 'vs/platform/workspace/common/workspaceTrust'; +import { TestWorkspaceTrustRequestService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService'; +import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; +import { ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; suite('EditorService', () => { @@ -60,6 +66,7 @@ suite('EditorService', () => { const part = await createEditorPart(instantiationService, disposables); instantiationService.stub(IEditorGroupsService, part); + instantiationService.stub(IWorkspaceTrustRequestService, new TestWorkspaceTrustRequestService(false)); const editorService = instantiationService.createInstance(EditorService); instantiationService.stub(IEditorService, editorService); @@ -226,6 +233,104 @@ suite('EditorService', () => { assert.strictEqual(part.activeGroup.getIndexOfEditor(replaceInput), 0); }); + test('openEditors() handles workspace trust (typed editors)', async () => { + const [part, service, accessor] = await createEditorService(); + + const input1 = new TestFileEditorInput(URI.parse('my://resource1-openEditors'), TEST_EDITOR_INPUT_ID); + const input2 = new TestFileEditorInput(URI.parse('my://resource2-openEditors'), TEST_EDITOR_INPUT_ID); + + const input3 = new TestFileEditorInput(URI.parse('my://resource3-openEditors'), TEST_EDITOR_INPUT_ID); + const input4 = new TestFileEditorInput(URI.parse('my://resource4-openEditors'), TEST_EDITOR_INPUT_ID); + const sideBySideInput = new SideBySideEditorInput('side by side', undefined, input3, input4); + + const oldHandler = accessor.workspaceTrustRequestService.requestOpenUrisHandler; + + try { + + // Trust: cancel + let trustEditorUris: URI[] = []; + accessor.workspaceTrustRequestService.requestOpenUrisHandler = async uris => { + trustEditorUris = uris; + return WorkspaceTrustUriResponse.Cancel; + }; + + await service.openEditors([{ editor: input1 }, { editor: input2 }, { editor: sideBySideInput }], undefined, { validateTrust: true }); + assert.strictEqual(part.activeGroup.count, 0); + assert.strictEqual(trustEditorUris.length, 4); + assert.strictEqual(trustEditorUris.some(uri => uri.toString() === input1.resource.toString()), true); + assert.strictEqual(trustEditorUris.some(uri => uri.toString() === input2.resource.toString()), true); + assert.strictEqual(trustEditorUris.some(uri => uri.toString() === input3.resource.toString()), true); + assert.strictEqual(trustEditorUris.some(uri => uri.toString() === input4.resource.toString()), true); + + // Trust: open in new window + accessor.workspaceTrustRequestService.requestOpenUrisHandler = async uris => WorkspaceTrustUriResponse.OpenInNewWindow; + + await service.openEditors([{ editor: input1 }, { editor: input2 }, { editor: sideBySideInput }], undefined, { validateTrust: true }); + assert.strictEqual(part.activeGroup.count, 0); + + // Trust: allow + accessor.workspaceTrustRequestService.requestOpenUrisHandler = async uris => WorkspaceTrustUriResponse.Open; + + await service.openEditors([{ editor: input1 }, { editor: input2 }, { editor: sideBySideInput }], undefined, { validateTrust: true }); + assert.strictEqual(part.activeGroup.count, 3); + } finally { + accessor.workspaceTrustRequestService.requestOpenUrisHandler = oldHandler; + } + }); + + test('openEditors() ignores trust when `validateTrust: false', async () => { + const [part, service, accessor] = await createEditorService(); + + const input1 = new TestFileEditorInput(URI.parse('my://resource1-openEditors'), TEST_EDITOR_INPUT_ID); + const input2 = new TestFileEditorInput(URI.parse('my://resource2-openEditors'), TEST_EDITOR_INPUT_ID); + + const input3 = new TestFileEditorInput(URI.parse('my://resource3-openEditors'), TEST_EDITOR_INPUT_ID); + const input4 = new TestFileEditorInput(URI.parse('my://resource4-openEditors'), TEST_EDITOR_INPUT_ID); + const sideBySideInput = new SideBySideEditorInput('side by side', undefined, input3, input4); + + const oldHandler = accessor.workspaceTrustRequestService.requestOpenUrisHandler; + + try { + + // Trust: cancel + accessor.workspaceTrustRequestService.requestOpenUrisHandler = async uris => WorkspaceTrustUriResponse.Cancel; + + await service.openEditors([{ editor: input1 }, { editor: input2 }, { editor: sideBySideInput }]); + assert.strictEqual(part.activeGroup.count, 3); + } finally { + accessor.workspaceTrustRequestService.requestOpenUrisHandler = oldHandler; + } + }); + + test('openEditors() extracts proper resources from untyped editors for workspace trust', async () => { + const [part, service, accessor] = await createEditorService(); + + const input = { resource: URI.parse('my://resource-openEditors') }; + const otherInput: IResourceDiffEditorInput = { + originalInput: { resource: URI.parse('my://resource2-openEditors') }, + modifiedInput: { resource: URI.parse('my://resource3-openEditors') } + }; + + const oldHandler = accessor.workspaceTrustRequestService.requestOpenUrisHandler; + + try { + let trustEditorUris: URI[] = []; + accessor.workspaceTrustRequestService.requestOpenUrisHandler = async uris => { + trustEditorUris = uris; + return oldHandler(uris); + }; + + await service.openEditors([input, otherInput], undefined, { validateTrust: true }); + assert.strictEqual(part.activeGroup.count, 0); + assert.strictEqual(trustEditorUris.length, 3); + assert.strictEqual(trustEditorUris.some(uri => uri.toString() === input.resource.toString()), true); + assert.strictEqual(trustEditorUris.some(uri => uri.toString() === otherInput.originalInput.resource?.toString()), true); + assert.strictEqual(trustEditorUris.some(uri => uri.toString() === otherInput.modifiedInput.resource?.toString()), true); + } finally { + accessor.workspaceTrustRequestService.requestOpenUrisHandler = oldHandler; + } + }); + test('caching', function () { const instantiationService = workbenchInstantiationService(); const service = instantiationService.createInstance(EditorService); @@ -317,6 +422,16 @@ suite('EditorService', () => { assert(input instanceof FileEditorInput); contentInput = input; assert.strictEqual(contentInput.getPreferredMode(), mode); + let fileModel = (await contentInput.resolve() as ITextFileEditorModel); + assert.strictEqual(fileModel.textEditorModel?.getModeId(), mode); + + // Untyped Input (file, contents) + input = service.createEditorInput({ resource: toResource.call(this, '/index.html'), contents: 'My contents' }); + assert(input instanceof FileEditorInput); + contentInput = input; + fileModel = (await contentInput.resolve() as ITextFileEditorModel); + assert.strictEqual(fileModel.textEditorModel?.getValue(), 'My contents'); + assert.strictEqual(fileModel.isDirty(), true); // Untyped Input (file, different mode) input = service.createEditorInput({ resource: toResource.call(this, '/index.html'), mode: 'text' }); @@ -361,14 +476,20 @@ suite('EditorService', () => { // Untyped Input (resource) input = service.createEditorInput({ resource: URI.parse('custom:resource') }); - assert(input instanceof ResourceEditorInput); + assert(input instanceof TextResourceEditorInput); // Untyped Input (diff) - input = service.createEditorInput({ - leftResource: toResource.call(this, '/primary.html'), - rightResource: toResource.call(this, '/secondary.html') - }); + const resourceDiffInput = { + originalInput: { resource: toResource.call(this, '/primary.html') }, + modifiedInput: { resource: toResource.call(this, '/secondary.html') } + }; + input = service.createEditorInput(resourceDiffInput); assert(input instanceof DiffEditorInput); + assert.strictEqual(input.originalInput.resource?.toString(), resourceDiffInput.originalInput.resource.toString()); + assert.strictEqual(input.modifiedInput.resource?.toString(), resourceDiffInput.modifiedInput.resource.toString()); + const untypedDiffInput = input.asResourceEditorInput(0) as IResourceDiffEditorInput; + assert.strictEqual(untypedDiffInput.originalInput.resource?.toString(), resourceDiffInput.originalInput.resource.toString()); + assert.strictEqual(untypedDiffInput.modifiedInput.resource?.toString(), resourceDiffInput.modifiedInput.resource.toString()); }); test('delegate', function (done) { @@ -389,18 +510,18 @@ suite('EditorService', () => { createEditor(): void { } } - const ed = instantiationService.createInstance(MyEditor, 'my.editor'); + const editor = instantiationService.createInstance(MyEditor, 'my.editor'); - const inp = instantiationService.createInstance(ResourceEditorInput, URI.parse('my://resource-delegate'), 'name', 'description', undefined); + const input = instantiationService.createInstance(TextResourceEditorInput, URI.parse('my://resource-delegate'), 'name', 'description', undefined, undefined); const delegate = instantiationService.createInstance(DelegatingEditorService, async (group, delegate) => { assert.ok(group); done(); - return ed; + return editor; }); - delegate.openEditor(inp); + delegate.openEditor(input); }); test('close editor does not dispose when editor opened in other group', async () => { @@ -955,7 +1076,8 @@ suite('EditorService', () => { mtime: 0, name: 'resource2', size: 0, - isSymbolicLink: false + isSymbolicLink: false, + readonly: false })); await activeEditorChangePromise; @@ -998,32 +1120,105 @@ suite('EditorService', () => { assert.strictEqual(editorContextKeyService, part.activeGroup.activeEditorPane?.scopedContextKeyService); }); - test('overrideOpenEditor', async function () { - const [, service] = await createEditorService(); - - const input1 = new TestFileEditorInput(URI.parse('file://resource1'), TEST_EDITOR_INPUT_ID); - const input2 = new TestFileEditorInput(URI.parse('file://resource2'), TEST_EDITOR_INPUT_ID); - - let overrideCalled = false; - - const handler = service.overrideOpenEditor({ - open: editor => { - if (editor === input1) { - overrideCalled = true; - - return { override: service.openEditor(input2, { pinned: true }) }; - } - - return undefined; - } - }); - - await service.openEditor(input1, { pinned: true }); + test('editorOverrideService - openEditor', async function () { + const [, service, accessor] = await createEditorService(); + const editorOverrideService = accessor.editorOverrideService; + let overrideCount = 0; + const registrationDisposable = editorOverrideService.registerContributionPoint( + '*.md', + { + id: 'TestEditor', + label: 'Test Editor', + detail: 'Test Editor Provider', + describes: () => false, + priority: ContributedEditorPriority.builtin + }, + {}, + (resource) => { + overrideCount++; + return ({ editor: service.createEditorInput({ resource }) }); + }, + diffEditor => ({ editor: diffEditor }) + ); + assert.strictEqual(overrideCount, 0); + const input1 = new TestFileEditorInput(URI.parse('file://test/path/resource1.txt'), TEST_EDITOR_INPUT_ID); + const input2 = new TestFileEditorInput(URI.parse('file://test/path/resource2.md'), TEST_EDITOR_INPUT_ID); + // Open editor input 1 and it shouln't trigger override as the glob doesn't match + await service.openEditor(input1); + assert.strictEqual(overrideCount, 0); + // Open editor input 2 and it should trigger override as the glob doesn match + await service.openEditor(input2); + assert.strictEqual(overrideCount, 1); + // Because we specify an override we shouldn't see it triggered even if it matches + await service.openEditor(input2, { override: 'default' }); + assert.strictEqual(overrideCount, 1); + + registrationDisposable.dispose(); + }); - assert.ok(overrideCalled); - assert.strictEqual(service.activeEditor, input2); + test('editorOverrideService - openEditors', async function () { + const [, service, accessor] = await createEditorService(); + const editorOverrideService = accessor.editorOverrideService; + let overrideCount = 0; + const registrationDisposable = editorOverrideService.registerContributionPoint( + '*.md', + { + id: 'TestEditor', + label: 'Test Editor', + detail: 'Test Editor Provider', + describes: () => false, + priority: ContributedEditorPriority.builtin + }, + {}, + (resource) => { + overrideCount++; + return ({ editor: service.createEditorInput({ resource }) }); + }, + diffEditor => ({ editor: diffEditor }) + ); + assert.strictEqual(overrideCount, 0); + const input1 = new TestFileEditorInput(URI.parse('file://test/path/resource1.txt'), TEST_EDITOR_INPUT_ID); + const input2 = new TestFileEditorInput(URI.parse('file://test/path/resource2.txt'), TEST_EDITOR_INPUT_ID); + const input3 = new TestFileEditorInput(URI.parse('file://test/path/resource3.md'), TEST_EDITOR_INPUT_ID); + const input4 = new TestFileEditorInput(URI.parse('file://test/path/resource4.md'), TEST_EDITOR_INPUT_ID); + // Open editor input 1 and it shouln't trigger override as the glob doesn't match + await service.openEditors([{ editor: input1 }, { editor: input2 }, { editor: input3 }, { editor: input4 }]); + assert.strictEqual(overrideCount, 2); + + registrationDisposable.dispose(); + }); - handler.dispose(); + test('editorOverrideService - replaceEditors', async function () { + const [part, service, accessor] = await createEditorService(); + const editorOverrideService = accessor.editorOverrideService; + let overrideCount = 0; + const registrationDisposable = editorOverrideService.registerContributionPoint( + '*.md', + { + id: 'TestEditor', + label: 'Test Editor', + detail: 'Test Editor Provider', + describes: () => false, + priority: ContributedEditorPriority.builtin + }, + {}, + (resource) => { + overrideCount++; + return ({ editor: service.createEditorInput({ resource }) }); + }, + diffEditor => ({ editor: diffEditor }) + ); + assert.strictEqual(overrideCount, 0); + const input1 = new TestFileEditorInput(URI.parse('file://test/path/resource2.md'), TEST_EDITOR_INPUT_ID); + // Open editor input 1 and it shouldn't trigger because I've disabled the override logic + await service.openEditor(input1, { override: EditorOverride.DISABLED }); + assert.strictEqual(overrideCount, 0); + await service.replaceEditors([{ + editor: input1, + replacement: input1, + }], part.activeGroup); + assert.strictEqual(overrideCount, 1); + registrationDisposable.dispose(); }); test('findEditors (in group)', async () => { diff --git a/lib/vscode/src/vs/workbench/services/editor/test/browser/editorsObserver.test.ts b/src/vs/workbench/services/editor/test/browser/editorsObserver.test.ts similarity index 90% rename from lib/vscode/src/vs/workbench/services/editor/test/browser/editorsObserver.test.ts rename to src/vs/workbench/services/editor/test/browser/editorsObserver.test.ts index 8279ac530a32..d77f97eaf252 100644 --- a/lib/vscode/src/vs/workbench/services/editor/test/browser/editorsObserver.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorsObserver.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { EditorOptions, IEditorInputFactoryRegistry, EditorExtensions, SideBySideEditorInput } from 'vs/workbench/common/editor'; +import { IEditorInputFactoryRegistry, EditorExtensions } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; import { workbenchInstantiationService, TestFileEditorInput, registerTestEditor, TestEditorPart, createEditorPart, registerTestSideBySideEditor } from 'vs/workbench/test/browser/workbenchTestServices'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -17,6 +17,7 @@ import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { EditorsObserver } from 'vs/workbench/browser/parts/editor/editorsObserver'; import { timeout } from 'vs/base/common/async'; import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices'; +import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput'; suite('EditorsObserver', function () { @@ -67,7 +68,7 @@ suite('EditorsObserver', function () { const input1 = new TestFileEditorInput(URI.parse('foo://bar1'), TEST_SERIALIZABLE_EDITOR_INPUT_ID); - await part.activeGroup.openEditor(input1, EditorOptions.create({ pinned: true })); + await part.activeGroup.openEditor(input1, { pinned: true }); currentEditorsMRU = observer.editors; assert.strictEqual(currentEditorsMRU.length, 1); @@ -84,8 +85,8 @@ suite('EditorsObserver', function () { assert.strictEqual(observer.hasEditors(input2.resource), false); assert.strictEqual(observer.hasEditor({ resource: input2.resource, typeId: input2.typeId }), false); - await part.activeGroup.openEditor(input2, EditorOptions.create({ pinned: true })); - await part.activeGroup.openEditor(input3, EditorOptions.create({ pinned: true })); + await part.activeGroup.openEditor(input2, { pinned: true }); + await part.activeGroup.openEditor(input3, { pinned: true }); currentEditorsMRU = observer.editors; assert.strictEqual(currentEditorsMRU.length, 3); @@ -98,7 +99,7 @@ suite('EditorsObserver', function () { assert.strictEqual(observer.hasEditor({ resource: input2.resource, typeId: input2.typeId }), true); assert.strictEqual(observer.hasEditor({ resource: input3.resource, typeId: input3.typeId }), true); - await part.activeGroup.openEditor(input2, EditorOptions.create({ pinned: true })); + await part.activeGroup.openEditor(input2, { pinned: true }); currentEditorsMRU = observer.editors; assert.strictEqual(currentEditorsMRU.length, 3); @@ -148,8 +149,8 @@ suite('EditorsObserver', function () { const input1 = new TestFileEditorInput(URI.parse('foo://bar1'), TEST_SERIALIZABLE_EDITOR_INPUT_ID); - await rootGroup.openEditor(input1, EditorOptions.create({ pinned: true, activation: EditorActivation.ACTIVATE })); - await sideGroup.openEditor(input1, EditorOptions.create({ pinned: true, activation: EditorActivation.ACTIVATE })); + await rootGroup.openEditor(input1, { pinned: true, activation: EditorActivation.ACTIVATE }); + await sideGroup.openEditor(input1, { pinned: true, activation: EditorActivation.ACTIVATE }); currentEditorsMRU = observer.editors; assert.strictEqual(currentEditorsMRU.length, 2); @@ -160,7 +161,7 @@ suite('EditorsObserver', function () { assert.strictEqual(observer.hasEditors(input1.resource), true); assert.strictEqual(observer.hasEditor({ resource: input1.resource, typeId: input1.typeId }), true); - await rootGroup.openEditor(input1, EditorOptions.create({ pinned: true, activation: EditorActivation.ACTIVATE })); + await rootGroup.openEditor(input1, { pinned: true, activation: EditorActivation.ACTIVATE }); currentEditorsMRU = observer.editors; assert.strictEqual(currentEditorsMRU.length, 2); @@ -175,7 +176,7 @@ suite('EditorsObserver', function () { // the most recent editor, but rather put it behind const input2 = new TestFileEditorInput(URI.parse('foo://bar2'), TEST_SERIALIZABLE_EDITOR_INPUT_ID); - await rootGroup.openEditor(input2, EditorOptions.create({ inactive: true })); + await rootGroup.openEditor(input2, { inactive: true }); currentEditorsMRU = observer.editors; assert.strictEqual(currentEditorsMRU.length, 3); @@ -221,13 +222,13 @@ suite('EditorsObserver', function () { assert.strictEqual(observer.hasEditor({ resource: input1.resource, typeId: input1.typeId }), false); assert.strictEqual(observer.hasEditor({ resource: input2.resource, typeId: input2.typeId }), false); - await part.activeGroup.openEditor(input1, EditorOptions.create({ pinned: true })); + await part.activeGroup.openEditor(input1, { pinned: true }); assert.strictEqual(observer.hasEditors(input1.resource), true); assert.strictEqual(observer.hasEditor({ resource: input1.resource, typeId: input1.typeId }), true); assert.strictEqual(observer.hasEditor({ resource: input2.resource, typeId: input2.typeId }), false); - await part.activeGroup.openEditor(input2, EditorOptions.create({ pinned: true })); + await part.activeGroup.openEditor(input2, { pinned: true }); assert.strictEqual(observer.hasEditors(input1.resource), true); assert.strictEqual(observer.hasEditor({ resource: input1.resource, typeId: input1.typeId }), true); @@ -258,13 +259,13 @@ suite('EditorsObserver', function () { assert.strictEqual(observer.hasEditor({ resource: primary.resource, typeId: primary.typeId }), false); assert.strictEqual(observer.hasEditor({ resource: secondary.resource, typeId: secondary.typeId }), false); - await part.activeGroup.openEditor(input, EditorOptions.create({ pinned: true })); + await part.activeGroup.openEditor(input, { pinned: true }); assert.strictEqual(observer.hasEditors(primary.resource), true); assert.strictEqual(observer.hasEditor({ resource: primary.resource, typeId: primary.typeId }), true); assert.strictEqual(observer.hasEditor({ resource: secondary.resource, typeId: secondary.typeId }), false); - await part.activeGroup.openEditor(primary, EditorOptions.create({ pinned: true })); + await part.activeGroup.openEditor(primary, { pinned: true }); assert.strictEqual(observer.hasEditors(primary.resource), true); assert.strictEqual(observer.hasEditor({ resource: primary.resource, typeId: primary.typeId }), true); @@ -292,9 +293,9 @@ suite('EditorsObserver', function () { const rootGroup = part.activeGroup; - await rootGroup.openEditor(input1, EditorOptions.create({ pinned: true })); - await rootGroup.openEditor(input2, EditorOptions.create({ pinned: true })); - await rootGroup.openEditor(input3, EditorOptions.create({ pinned: true })); + await rootGroup.openEditor(input1, { pinned: true }); + await rootGroup.openEditor(input2, { pinned: true }); + await rootGroup.openEditor(input3, { pinned: true }); let currentEditorsMRU = observer.editors; assert.strictEqual(currentEditorsMRU.length, 3); @@ -352,9 +353,9 @@ suite('EditorsObserver', function () { const input2 = new TestFileEditorInput(URI.parse('foo://bar2'), TEST_SERIALIZABLE_EDITOR_INPUT_ID); const input3 = new TestFileEditorInput(URI.parse('foo://bar3'), TEST_SERIALIZABLE_EDITOR_INPUT_ID); - await rootGroup.openEditor(input1, EditorOptions.create({ pinned: true })); - await rootGroup.openEditor(input2, EditorOptions.create({ pinned: true })); - await rootGroup.openEditor(input3, EditorOptions.create({ pinned: true })); + await rootGroup.openEditor(input1, { pinned: true }); + await rootGroup.openEditor(input2, { pinned: true }); + await rootGroup.openEditor(input3, { pinned: true }); const storage = new TestStorageService(); const observer = disposables.add(new EditorsObserver(part, storage)); @@ -399,11 +400,11 @@ suite('EditorsObserver', function () { const input2 = new TestFileEditorInput(URI.parse('foo://bar2'), TEST_SERIALIZABLE_EDITOR_INPUT_ID); const input3 = new TestFileEditorInput(URI.parse('foo://bar3'), TEST_SERIALIZABLE_EDITOR_INPUT_ID); - await rootGroup.openEditor(input1, EditorOptions.create({ pinned: true })); - await rootGroup.openEditor(input2, EditorOptions.create({ pinned: true })); + await rootGroup.openEditor(input1, { pinned: true }); + await rootGroup.openEditor(input2, { pinned: true }); const sideGroup = part.addGroup(rootGroup, GroupDirection.RIGHT); - await sideGroup.openEditor(input3, EditorOptions.create({ pinned: true })); + await sideGroup.openEditor(input3, { pinned: true }); const storage = new TestStorageService(); const observer = disposables.add(new EditorsObserver(part, storage)); @@ -446,7 +447,7 @@ suite('EditorsObserver', function () { const input1 = new TestFileEditorInput(URI.parse('foo://bar1'), TEST_EDITOR_INPUT_ID); - await rootGroup.openEditor(input1, EditorOptions.create({ pinned: true })); + await rootGroup.openEditor(input1, { pinned: true }); const storage = new TestStorageService(); const observer = disposables.add(new EditorsObserver(part, storage)); @@ -483,10 +484,10 @@ suite('EditorsObserver', function () { const input3 = new TestFileEditorInput(URI.parse('foo://bar3'), TEST_EDITOR_INPUT_ID); const input4 = new TestFileEditorInput(URI.parse('foo://bar4'), TEST_EDITOR_INPUT_ID); - await rootGroup.openEditor(input1, EditorOptions.create({ pinned: true })); - await rootGroup.openEditor(input2, EditorOptions.create({ pinned: true })); - await rootGroup.openEditor(input3, EditorOptions.create({ pinned: true })); - await rootGroup.openEditor(input4, EditorOptions.create({ pinned: true })); + await rootGroup.openEditor(input1, { pinned: true }); + await rootGroup.openEditor(input2, { pinned: true }); + await rootGroup.openEditor(input3, { pinned: true }); + await rootGroup.openEditor(input4, { pinned: true }); assert.strictEqual(rootGroup.count, 3); assert.strictEqual(rootGroup.contains(input1), false); @@ -514,7 +515,7 @@ suite('EditorsObserver', function () { assert.strictEqual(observer.hasEditor({ resource: input4.resource, typeId: input4.typeId }), true); const input5 = new TestFileEditorInput(URI.parse('foo://bar5'), TEST_EDITOR_INPUT_ID); - await sideGroup.openEditor(input5, EditorOptions.create({ pinned: true })); + await sideGroup.openEditor(input5, { pinned: true }); assert.strictEqual(rootGroup.count, 1); assert.strictEqual(rootGroup.contains(input1), false); @@ -544,10 +545,10 @@ suite('EditorsObserver', function () { const input3 = new TestFileEditorInput(URI.parse('foo://bar3'), TEST_EDITOR_INPUT_ID); const input4 = new TestFileEditorInput(URI.parse('foo://bar4'), TEST_EDITOR_INPUT_ID); - await rootGroup.openEditor(input1, EditorOptions.create({ pinned: true })); - await rootGroup.openEditor(input2, EditorOptions.create({ pinned: true })); - await rootGroup.openEditor(input3, EditorOptions.create({ pinned: true })); - await rootGroup.openEditor(input4, EditorOptions.create({ pinned: true })); + await rootGroup.openEditor(input1, { pinned: true }); + await rootGroup.openEditor(input2, { pinned: true }); + await rootGroup.openEditor(input3, { pinned: true }); + await rootGroup.openEditor(input4, { pinned: true }); assert.strictEqual(rootGroup.count, 3); // 1 editor got closed due to our limit! assert.strictEqual(rootGroup.contains(input1), false); @@ -559,10 +560,10 @@ suite('EditorsObserver', function () { assert.strictEqual(observer.hasEditor({ resource: input3.resource, typeId: input3.typeId }), true); assert.strictEqual(observer.hasEditor({ resource: input4.resource, typeId: input4.typeId }), true); - await sideGroup.openEditor(input1, EditorOptions.create({ pinned: true })); - await sideGroup.openEditor(input2, EditorOptions.create({ pinned: true })); - await sideGroup.openEditor(input3, EditorOptions.create({ pinned: true })); - await sideGroup.openEditor(input4, EditorOptions.create({ pinned: true })); + await sideGroup.openEditor(input1, { pinned: true }); + await sideGroup.openEditor(input2, { pinned: true }); + await sideGroup.openEditor(input3, { pinned: true }); + await sideGroup.openEditor(input4, { pinned: true }); assert.strictEqual(sideGroup.count, 3); assert.strictEqual(sideGroup.contains(input1), false); @@ -610,10 +611,10 @@ suite('EditorsObserver', function () { const input3 = new TestFileEditorInput(URI.parse('foo://bar3'), TEST_EDITOR_INPUT_ID); const input4 = new TestFileEditorInput(URI.parse('foo://bar4'), TEST_EDITOR_INPUT_ID); - await rootGroup.openEditor(input1, EditorOptions.create({ pinned: true, sticky: true })); - await rootGroup.openEditor(input2, EditorOptions.create({ pinned: true })); - await rootGroup.openEditor(input3, EditorOptions.create({ pinned: true })); - await rootGroup.openEditor(input4, EditorOptions.create({ pinned: true })); + await rootGroup.openEditor(input1, { pinned: true, sticky: true }); + await rootGroup.openEditor(input2, { pinned: true }); + await rootGroup.openEditor(input3, { pinned: true }); + await rootGroup.openEditor(input4, { pinned: true }); assert.strictEqual(rootGroup.count, 3); assert.strictEqual(rootGroup.contains(input1), true); diff --git a/lib/vscode/src/vs/workbench/services/encryption/browser/encryptionService.ts b/src/vs/workbench/services/encryption/browser/encryptionService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/encryption/browser/encryptionService.ts rename to src/vs/workbench/services/encryption/browser/encryptionService.ts diff --git a/lib/vscode/src/vs/workbench/services/encryption/common/encryptionService.ts b/src/vs/workbench/services/encryption/common/encryptionService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/encryption/common/encryptionService.ts rename to src/vs/workbench/services/encryption/common/encryptionService.ts diff --git a/lib/vscode/src/vs/workbench/services/encryption/electron-sandbox/encryptionService.ts b/src/vs/workbench/services/encryption/electron-sandbox/encryptionService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/encryption/electron-sandbox/encryptionService.ts rename to src/vs/workbench/services/encryption/electron-sandbox/encryptionService.ts diff --git a/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts similarity index 86% rename from lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts rename to src/vs/workbench/services/environment/browser/environmentService.ts index 4bbd3c44e5c6..00b781462ea2 100644 --- a/lib/vscode/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -120,25 +120,8 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment @memoize get logFile(): URI { return joinPath(this.options.logsPath, 'window.log'); } - // NOTE@coder: Use the same path in // ../../../../platform/environment/node/environmentService.ts - // and don't use the user data scheme. This solves two problems: - // 1. Extensions running in the browser (like Vim) might use these paths - // directly instead of using the file service and most likely can't write - // to `/User` on disk. - // 2. Settings will be stored in the file system instead of in browser - // storage. Using browser storage makes sharing or seeding settings - // between browsers difficult. We may want to revisit this once/if we get - // settings sync. @memoize - get userRoamingDataHome(): URI { return joinPath(URI.file(this.userDataPath).with({ scheme: Schemas.vscodeRemote }), 'User'); } - @memoize - get userDataPath(): string { - const dataPath = this.payload?.get('userDataPath'); - if (!dataPath) { - throw new Error('userDataPath was not provided to environment service'); - } - return dataPath; - } + get userRoamingDataHome(): URI { return URI.file('/User').with({ scheme: Schemas.userData }); } @memoize get settingsResource(): URI { return joinPath(this.userRoamingDataHome, 'settings.json'); } @@ -243,25 +226,15 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment get disableExtensions() { return this.payload?.get('disableExtensions') === 'true'; } - private get webviewEndpoint(): string { - // TODO@matt: get fallback from product service - return this.options.webviewEndpoint || 'https://{{uuid}}.vscode-webview-test.com/{{commit}}'; - } - @memoize get webviewExternalEndpoint(): string { - return (this.webviewEndpoint).replace('{{commit}}', this.productService.commit || '23a2409675bc1bde94f3532bc7c5826a6e99e4b6'); - } + const endpoint = this.options.webviewEndpoint + || this.productService.webviewContentExternalBaseUrlTemplate + || 'https://{{uuid}}.vscode-webview.net/{{quality}}/{{commit}}/out/vs/workbench/contrib/webview/browser/pre/'; - @memoize - get webviewResourceRoot(): string { - return `${this.webviewExternalEndpoint}/vscode-resource/{{resource}}`; - } - - @memoize - get webviewCspSource(): string { - const uri = URI.parse(this.webviewEndpoint.replace('{{uuid}}', '*')); - return `${uri.scheme}://${uri.authority}`; + return endpoint + .replace('{{commit}}', this.payload?.get('webviewExternalEndpointCommit') ?? this.productService.commit ?? '97740a7d253650f9f186c211de5247e2577ce9f7') + .replace('{{quality}}', this.productService.quality || 'insider'); } @memoize @@ -273,6 +246,9 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment get skipReleaseNotes(): boolean { return false; } + @memoize + get disableWorkspaceTrust(): boolean { return true; } + private payload: Map | undefined; constructor( @@ -341,12 +317,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment extensionHostDebugEnvironment.params.port = parseInt(value); break; case 'enableProposedApi': - try { - extensionHostDebugEnvironment.extensionEnabledProposedApi = JSON.parse(value); - } catch (error) { - console.error(error); - extensionHostDebugEnvironment.extensionEnabledProposedApi = []; - } + extensionHostDebugEnvironment.extensionEnabledProposedApi = []; break; } } diff --git a/lib/vscode/src/vs/workbench/services/environment/common/environmentService.ts b/src/vs/workbench/services/environment/common/environmentService.ts similarity index 96% rename from lib/vscode/src/vs/workbench/services/environment/common/environmentService.ts rename to src/vs/workbench/services/environment/common/environmentService.ts index 6604c9823ae4..f8950d42da89 100644 --- a/lib/vscode/src/vs/workbench/services/environment/common/environmentService.ts +++ b/src/vs/workbench/services/environment/common/environmentService.ts @@ -36,8 +36,6 @@ export interface IWorkbenchEnvironmentService extends IEnvironmentService { readonly extensionEnabledProposedApi?: string[]; readonly webviewExternalEndpoint: string; - readonly webviewResourceRoot: string; - readonly webviewCspSource: string; readonly skipReleaseNotes: boolean; diff --git a/lib/vscode/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts b/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts similarity index 87% rename from lib/vscode/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts rename to src/vs/workbench/services/environment/electron-sandbox/environmentService.ts index 9fb4fb45d758..948a3aa89351 100644 --- a/lib/vscode/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts +++ b/src/vs/workbench/services/environment/electron-sandbox/environmentService.ts @@ -68,21 +68,6 @@ export class NativeWorkbenchEnvironmentService extends AbstractNativeEnvironment @memoize get webviewExternalEndpoint(): string { return `${Schemas.vscodeWebview}://{{uuid}}`; } - @memoize - get webviewResourceRoot(): string { - // On desktop, this endpoint is only used for the service worker to identify resource loads and - // should never actually be requested. - // - // Required due to https://github.com/electron/electron/issues/28528 - return 'https://{{uuid}}.vscode-webview-test.com/vscode-resource/{{resource}}'; - } - - @memoize - get webviewCspSource(): string { - const uri = URI.parse(this.webviewResourceRoot.replace('{{uuid}}', '*')); - return `${uri.scheme}://${uri.authority}`; - } - @memoize get skipReleaseNotes(): boolean { return !!this.args['skip-release-notes']; } diff --git a/lib/vscode/src/vs/workbench/services/environment/electron-sandbox/shellEnvironmentService.ts b/src/vs/workbench/services/environment/electron-sandbox/shellEnvironmentService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/environment/electron-sandbox/shellEnvironmentService.ts rename to src/vs/workbench/services/environment/electron-sandbox/shellEnvironmentService.ts diff --git a/lib/vscode/src/vs/workbench/services/experiment/common/experimentService.ts b/src/vs/workbench/services/experiment/common/experimentService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/experiment/common/experimentService.ts rename to src/vs/workbench/services/experiment/common/experimentService.ts diff --git a/lib/vscode/src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts b/src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts rename to src/vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService.ts diff --git a/lib/vscode/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts b/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts similarity index 99% rename from lib/vscode/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts rename to src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts index cd3b096a9a38..0684def27081 100644 --- a/lib/vscode/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionBisect.ts @@ -299,7 +299,6 @@ registerAction2(class extends Action2 { // DONE and identified extension const res = await dialogService.show(Severity.Info, localize('done.msg', "Extension Bisect"), [localize('report', "Report Issue & Continue"), localize('done', "Continue")], - // [], { detail: localize('done.detail', "Extension Bisect is done and has identified {0} as the extension causing the problem.", done.id), checkbox: { label: localize('done.disbale', "Keep this extension disabled"), checked: true }, diff --git a/lib/vscode/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts similarity index 93% rename from lib/vscode/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts rename to src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts index 3683aa847e99..521ab664f825 100644 --- a/lib/vscode/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts @@ -26,7 +26,7 @@ import { IExtensionBisectService } from 'vs/workbench/services/extensionManageme import { IWorkspaceTrustManagementService, IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust'; import { Promises } from 'vs/base/common/async'; import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; -import { getVirtualWorkspaceScheme } from 'vs/platform/remote/common/remoteHosts'; +import { isVirtualWorkspace } from 'vs/platform/remote/common/remoteHosts'; const SOURCE = 'IWorkbenchExtensionEnablementService'; @@ -95,7 +95,7 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench if (this._isDisabledByExtensionKind(extension)) { return EnablementState.DisabledByExtensionKind; } - if (this._isEnabled(extension) && this._isDisabledByTrustRequirement(extension)) { + if (this._isEnabled(extension) && this._isDisabledByWorkspaceTrust(extension)) { return EnablementState.DisabledByTrustRequirement; } return this._getEnablementState(extension.identifier); @@ -160,14 +160,10 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench } const result = await Promises.settled(extensions.map(e => { - if (this._isDisabledByTrustRequirement(e)) { - return this.workspaceTrustRequestService.requestWorkspaceTrust({ modal: true }) + if (this._isDisabledByWorkspaceTrust(e)) { + return this.workspaceTrustRequestService.requestWorkspaceTrust() .then(trustState => { - if (trustState) { - return this._setEnablement(e, newState); - } else { - return Promise.resolve(false); - } + return Promise.resolve(trustState ?? false); }); } else { return this._setEnablement(e, newState); @@ -233,8 +229,8 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench } private _isDisabledByVirtualWorkspace(extension: IExtension): boolean { - if (getVirtualWorkspaceScheme(this.contextService.getWorkspace()) !== undefined) { - return !this.extensionManifestPropertiesService.canSupportVirtualWorkspace(extension.manifest); + if (isVirtualWorkspace(this.contextService.getWorkspace())) { + return this.extensionManifestPropertiesService.getExtensionVirtualWorkspaceSupportType(extension.manifest) === false; } return false; } @@ -267,17 +263,21 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench } } } - return false; // NOTE@coder: Don't disable anything by extensionKind. + return true; } return false; } - private _isDisabledByTrustRequirement(extension: IExtension): boolean { + isDisabledByWorkspaceTrust(extension: IExtension): boolean { + return this._isEnabled(extension) && this.extensionManifestPropertiesService.getExtensionUntrustedWorkspaceSupportType(extension.manifest) === false; + } + + private _isDisabledByWorkspaceTrust(extension: IExtension): boolean { if (this.workspaceTrustManagementService.isWorkpaceTrusted()) { return false; } - return this.extensionManifestPropertiesService.getExtensionUntrustedWorkspaceSupportType(extension.manifest) === false; + return this.isDisabledByWorkspaceTrust(extension); } private _getEnablementState(identifier: IExtensionIdentifier): EnablementState { @@ -416,7 +416,7 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench } private _onDidInstallExtension({ local, error }: DidInstallExtensionEvent): void { - if (local && !error && this._isDisabledByTrustRequirement(local)) { + if (local && !error && this._isDisabledByWorkspaceTrust(local)) { this._onEnablementChanged.fire([local]); } } @@ -427,15 +427,12 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench } } - private async _getExtensionsByWorkspaceTrustRequirement(): Promise { - const extensions = await this.extensionManagementService.getInstalled(); - return extensions.filter(e => this.extensionManifestPropertiesService.getExtensionUntrustedWorkspaceSupportType(e.manifest) === false); - } - public async updateEnablementByWorkspaceTrustRequirement(): Promise { - const extensions = await this._getExtensionsByWorkspaceTrustRequirement(); - if (extensions.length) { - this._onEnablementChanged.fire(extensions); + const installedExtensions = await this.extensionManagementService.getInstalled(); + const disabledExtensions = installedExtensions.filter(e => this.isDisabledByWorkspaceTrust(e)); + + if (disabledExtensions.length) { + this._onEnablementChanged.fire(disabledExtensions); } } diff --git a/lib/vscode/src/vs/workbench/services/extensionManagement/browser/extensionUrlTrustService.ts b/src/vs/workbench/services/extensionManagement/browser/extensionUrlTrustService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensionManagement/browser/extensionUrlTrustService.ts rename to src/vs/workbench/services/extensionManagement/browser/extensionUrlTrustService.ts diff --git a/lib/vscode/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts similarity index 95% rename from lib/vscode/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts rename to src/vs/workbench/services/extensionManagement/common/extensionManagement.ts index edb80d1af335..64fe5d821b94 100644 --- a/lib/vscode/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts @@ -81,6 +81,12 @@ export interface IWorkbenchExtensionEnablementService { */ isDisabledGlobally(extension: IExtension): boolean; + /** + * Returns `true` if the given extension identifier is enabled by the user but it it + * disabled due to the fact that the current window/folder/workspace is not trusted. + */ + isDisabledByWorkspaceTrust(extension: IExtension): boolean; + /** * Enable or disable the given extension. * if `workspace` is `true` then enablement is done for workspace, otherwise globally. diff --git a/lib/vscode/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts rename to src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts diff --git a/lib/vscode/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts similarity index 96% rename from lib/vscode/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts rename to src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts index 367b1ba6c2dc..e4921e4e0a3a 100644 --- a/lib/vscode/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts @@ -5,7 +5,7 @@ import { Event, EventMultiplexer } from 'vs/base/common/event'; import { - ILocalExtension, IGalleryExtension, InstallExtensionEvent, DidInstallExtensionEvent, IExtensionIdentifier, DidUninstallExtensionEvent, IReportedExtension, IGalleryMetadata, IExtensionGalleryService, InstallOptions, UninstallOptions, INSTALL_ERROR_NOT_SUPPORTED + ILocalExtension, IGalleryExtension, InstallExtensionEvent, DidInstallExtensionEvent, IExtensionIdentifier, DidUninstallExtensionEvent, IReportedExtension, IGalleryMetadata, IExtensionGalleryService, InstallOptions, UninstallOptions, INSTALL_ERROR_NOT_SUPPORTED, InstallVSIXOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionManagementServer, IExtensionManagementServerService, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ExtensionType, isLanguagePackExtension, IExtensionManifest } from 'vs/platform/extensions/common/extensions'; @@ -23,7 +23,6 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import Severity from 'vs/base/common/severity'; import { canceled } from 'vs/base/common/errors'; import { IUserDataAutoSyncEnablementService, IUserDataSyncResourceEnablementService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync'; -import { isWeb } from 'vs/base/common/platform'; import { Promises } from 'vs/base/common/async'; import { IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust'; import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; @@ -172,35 +171,35 @@ export class ExtensionManagementService extends Disposable implements IWorkbench .map(({ extensionManagementService }) => extensionManagementService.unzip(zipLocation))).then(([extensionIdentifier]) => extensionIdentifier); } - async install(vsix: URI): Promise { + async install(vsix: URI, options?: InstallVSIXOptions): Promise { if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { const manifest = await this.getManifest(vsix); if (isLanguagePackExtension(manifest)) { // Install on both servers - const [local] = await Promises.settled([this.extensionManagementServerService.localExtensionManagementServer, this.extensionManagementServerService.remoteExtensionManagementServer].map(server => this.installVSIX(vsix, server))); + const [local] = await Promises.settled([this.extensionManagementServerService.localExtensionManagementServer, this.extensionManagementServerService.remoteExtensionManagementServer].map(server => this.installVSIX(vsix, server, options))); return local; } if (this.extensionManifestPropertiesService.prefersExecuteOnUI(manifest)) { // Install only on local server - return this.installVSIX(vsix, this.extensionManagementServerService.localExtensionManagementServer); + return this.installVSIX(vsix, this.extensionManagementServerService.localExtensionManagementServer, options); } // Install only on remote server - return this.installVSIX(vsix, this.extensionManagementServerService.remoteExtensionManagementServer); + return this.installVSIX(vsix, this.extensionManagementServerService.remoteExtensionManagementServer, options); } if (this.extensionManagementServerService.localExtensionManagementServer) { - return this.installVSIX(vsix, this.extensionManagementServerService.localExtensionManagementServer); + return this.installVSIX(vsix, this.extensionManagementServerService.localExtensionManagementServer, options); } if (this.extensionManagementServerService.remoteExtensionManagementServer) { - return this.installVSIX(vsix, this.extensionManagementServerService.remoteExtensionManagementServer); + return this.installVSIX(vsix, this.extensionManagementServerService.remoteExtensionManagementServer, options); } return Promise.reject('No Servers to Install'); } - protected async installVSIX(vsix: URI, server: IExtensionManagementServer): Promise { + protected async installVSIX(vsix: URI, server: IExtensionManagementServer, options: InstallVSIXOptions | undefined): Promise { const manifest = await this.getManifest(vsix); if (manifest) { await this.checkForWorkspaceTrust(manifest); - return server.extensionManagementService.install(vsix); + return server.extensionManagementService.install(vsix, options); } return Promise.reject('Unable to get the extension manifest.'); } @@ -308,11 +307,6 @@ export class ExtensionManagementService extends Disposable implements IWorkbench } } - // NOTE@coder: Fall back to installing on the remote server on web. - if (isWeb && this.extensionManagementServerService.remoteExtensionManagementServer) { - return this.extensionManagementServerService.remoteExtensionManagementServer; - } - // Local server can accept any extension. So return local server if not compatible server found. return this.extensionManagementServerService.localExtensionManagementServer; } @@ -366,7 +360,6 @@ export class ExtensionManagementService extends Disposable implements IWorkbench protected async checkForWorkspaceTrust(manifest: IExtensionManifest): Promise { if (this.extensionManifestPropertiesService.getExtensionUntrustedWorkspaceSupportType(manifest) === false) { const trustState = await this.workspaceTrustRequestService.requestWorkspaceTrust({ - modal: true, message: localize('extensionInstallWorkspaceTrustMessage', "Enabling this extension requires a trusted workspace."), buttons: [ { label: localize('extensionInstallWorkspaceTrustButton', "Trust Workspace & Install"), type: 'ContinueWithTrust' }, diff --git a/lib/vscode/src/vs/workbench/services/extensionManagement/common/remoteExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/remoteExtensionManagementService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensionManagement/common/remoteExtensionManagementService.ts rename to src/vs/workbench/services/extensionManagement/common/remoteExtensionManagementService.ts diff --git a/lib/vscode/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts rename to src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts diff --git a/lib/vscode/src/vs/workbench/services/extensionManagement/common/webExtensionsScannerService.ts b/src/vs/workbench/services/extensionManagement/common/webExtensionsScannerService.ts similarity index 95% rename from lib/vscode/src/vs/workbench/services/extensionManagement/common/webExtensionsScannerService.ts rename to src/vs/workbench/services/extensionManagement/common/webExtensionsScannerService.ts index f8faa18b51cd..ff8f2cc6a045 100644 --- a/lib/vscode/src/vs/workbench/services/extensionManagement/common/webExtensionsScannerService.ts +++ b/src/vs/workbench/services/extensionManagement/common/webExtensionsScannerService.ts @@ -25,7 +25,7 @@ import { Event } from 'vs/base/common/event'; import { localizeManifest } from 'vs/platform/extensionManagement/common/extensionNls'; import { localize } from 'vs/nls'; import * as semver from 'vs/base/common/semver/semver'; -import { isArray } from 'vs/base/common/types'; +import { isArray, isFunction } from 'vs/base/common/types'; interface IUserExtension { identifier: IExtensionIdentifier; @@ -76,8 +76,16 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten } private async readSystemExtensions(): Promise { - const extensions = await this.builtinExtensionsScannerService.scanBuiltinExtensions(); - return extensions.concat(this.getStaticExtensions(true)); + let [builtinExtensions, staticExtensions] = await Promise.all([ + this.builtinExtensionsScannerService.scanBuiltinExtensions(), + this.getStaticExtensions(true) + ]); + + if (isFunction(this.environmentService.options?.builtinExtensionsFilter)) { + builtinExtensions = builtinExtensions.filter(e => this.environmentService.options!.builtinExtensionsFilter!(e.identifier.id)); + } + + return [...builtinExtensions, ...staticExtensions]; } /** @@ -259,6 +267,10 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten } canAddExtension(galleryExtension: IGalleryExtension): boolean { + if (this.environmentService.options?.assumeGalleryExtensionsAreAddressable) { + return true; + } + return !!galleryExtension.properties.webExtension && !!galleryExtension.webResource; } @@ -267,7 +279,7 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten throw new Error(localize('cannot be installed', "Cannot install '{0}' because this extension is not a web extension.", galleryExtension.displayName || galleryExtension.name)); } - const extensionLocation = galleryExtension.webResource!; + const extensionLocation = joinPath(galleryExtension.assetUri, 'Microsoft.VisualStudio.Code.WebResources', 'extension'); const packageNLSUri = joinPath(extensionLocation, 'package.nls.json'); const context = await this.requestService.request({ type: 'GET', url: packageNLSUri.toString() }, CancellationToken.None); const packageNLSExists = isSuccess(context); diff --git a/lib/vscode/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService.ts rename to src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService.ts diff --git a/lib/vscode/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts similarity index 92% rename from lib/vscode/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts rename to src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts index 1a11ff33fa13..fad465e76c83 100644 --- a/lib/vscode/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { generateUuid } from 'vs/base/common/uuid'; -import { ILocalExtension, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ILocalExtension, IExtensionGalleryService, InstallVSIXOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { URI } from 'vs/base/common/uri'; import { ExtensionManagementService as BaseExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagementService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -38,7 +38,7 @@ export class ExtensionManagementService extends BaseExtensionManagementService { super(extensionManagementServerService, extensionGalleryService, configurationService, productService, downloadService, userDataAutoSyncEnablementService, userDataSyncResourceEnablementService, dialogService, workspaceTrustRequestService, extensionManifestPropertiesService); } - protected override async installVSIX(vsix: URI, server: IExtensionManagementServer): Promise { + protected override async installVSIX(vsix: URI, server: IExtensionManagementServer, options: InstallVSIXOptions | undefined): Promise { if (vsix.scheme === Schemas.vscodeRemote && server === this.extensionManagementServerService.localExtensionManagementServer) { const downloadedLocation = joinPath(this.environmentService.tmpDir, generateUuid()); await this.downloadService.download(vsix, downloadedLocation); @@ -47,7 +47,7 @@ export class ExtensionManagementService extends BaseExtensionManagementService { const manifest = await this.getManifest(vsix); if (manifest) { await this.checkForWorkspaceTrust(manifest); - return server.extensionManagementService.install(vsix); + return server.extensionManagementService.install(vsix, options); } return Promise.reject('Unable to get the extension manifest.'); diff --git a/lib/vscode/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionTipsService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionTipsService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionTipsService.ts rename to src/vs/workbench/services/extensionManagement/electron-sandbox/extensionTipsService.ts diff --git a/lib/vscode/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionUrlTrustService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionUrlTrustService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionUrlTrustService.ts rename to src/vs/workbench/services/extensionManagement/electron-sandbox/extensionUrlTrustService.ts diff --git a/lib/vscode/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts similarity index 97% rename from lib/vscode/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts rename to src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts index 3478bc93d96c..4f0174456c7d 100644 --- a/lib/vscode/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IExtensionGalleryService, InstallOperation, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IExtensionGalleryService, InstallOperation, InstallOptions, InstallVSIXOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { URI } from 'vs/base/common/uri'; import { ExtensionType, IExtensionManifest } from 'vs/platform/extensions/common/extensions'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; @@ -41,8 +41,8 @@ export class NativeRemoteExtensionManagementService extends WebRemoteExtensionMa this.localExtensionManagementService = localExtensionManagementServer.extensionManagementService; } - override async install(vsix: URI): Promise { - const local = await super.install(vsix); + override async install(vsix: URI, options?: InstallVSIXOptions): Promise { + const local = await super.install(vsix, options); await this.installUIDependenciesAndPackedExtensions(local); return local; } diff --git a/lib/vscode/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts b/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts similarity index 99% rename from lib/vscode/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts rename to src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts index 49e0126904f9..1318c3f2d1aa 100644 --- a/lib/vscode/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts +++ b/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts @@ -55,6 +55,7 @@ export class TestExtensionEnablementService extends ExtensionEnablementService { const storageService = createStorageService(instantiationService); const extensionManagementService = instantiationService.get(IExtensionManagementService) || instantiationService.stub(IExtensionManagementService, { onDidInstallExtension: new Emitter().event, onDidUninstallExtension: new Emitter().event } as IExtensionManagementService); const extensionManagementServerService = instantiationService.get(IExtensionManagementServerService) || instantiationService.stub(IExtensionManagementServerService, { localExtensionManagementServer: { extensionManagementService } }); + const workspaceTrustManagementService = instantiationService.get(IWorkspaceTrustManagementService) || instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService()); super( storageService, new GlobalExtensionEnablementService(storageService), @@ -69,9 +70,9 @@ export class TestExtensionEnablementService extends ExtensionEnablementService { instantiationService.get(INotificationService) || instantiationService.stub(INotificationService, new TestNotificationService()), instantiationService.get(IHostService), new class extends mock() { override isDisabledByBisect() { return false; } }, - instantiationService.get(IWorkspaceTrustManagementService) || instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService()), + workspaceTrustManagementService, new class extends mock() { override requestWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Promise { return Promise.resolve(true); } }, - instantiationService.get(IExtensionManifestPropertiesService) || instantiationService.stub(IExtensionManifestPropertiesService, new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService())) + instantiationService.get(IExtensionManifestPropertiesService) || instantiationService.stub(IExtensionManifestPropertiesService, new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService(), workspaceTrustManagementService)) ); } diff --git a/lib/vscode/src/vs/workbench/services/extensionRecommendations/common/extensionIgnoredRecommendationsService.ts b/src/vs/workbench/services/extensionRecommendations/common/extensionIgnoredRecommendationsService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensionRecommendations/common/extensionIgnoredRecommendationsService.ts rename to src/vs/workbench/services/extensionRecommendations/common/extensionIgnoredRecommendationsService.ts diff --git a/lib/vscode/src/vs/workbench/services/extensionRecommendations/common/extensionRecommendations.ts b/src/vs/workbench/services/extensionRecommendations/common/extensionRecommendations.ts similarity index 98% rename from lib/vscode/src/vs/workbench/services/extensionRecommendations/common/extensionRecommendations.ts rename to src/vs/workbench/services/extensionRecommendations/common/extensionRecommendations.ts index 0d76094d021d..3d993c896ca2 100644 --- a/lib/vscode/src/vs/workbench/services/extensionRecommendations/common/extensionRecommendations.ts +++ b/src/vs/workbench/services/extensionRecommendations/common/extensionRecommendations.ts @@ -44,6 +44,7 @@ export interface IExtensionRecommendationsService { getConfigBasedRecommendations(): Promise<{ important: string[], others: string[] }>; getWorkspaceRecommendations(): Promise; getKeymapRecommendations(): string[]; + getLanguageRecommendations(): string[]; } export type IgnoredRecommendationChangeNotification = { diff --git a/lib/vscode/src/vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig.ts b/src/vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig.ts rename to src/vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig.ts diff --git a/lib/vscode/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts b/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts rename to src/vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService.ts diff --git a/lib/vscode/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts b/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts rename to src/vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader.ts diff --git a/lib/vscode/src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts b/src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts rename to src/vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/browser/extensionService.ts b/src/vs/workbench/services/extensions/browser/extensionService.ts similarity index 98% rename from lib/vscode/src/vs/workbench/services/extensions/browser/extensionService.ts rename to src/vs/workbench/services/extensions/browser/extensionService.ts index c0722aff9916..1ab766411c38 100644 --- a/lib/vscode/src/vs/workbench/services/extensions/browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/browser/extensionService.ts @@ -185,8 +185,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten this._remoteAgentService.getEnvironment(), this._remoteAgentService.scanExtensions() ]); - localExtensions = this._checkEnabledAndProposedAPI(localExtensions); - remoteExtensions = this._checkEnabledAndProposedAPI(remoteExtensions); + localExtensions = this._checkEnabledAndProposedAPI(localExtensions, false); + remoteExtensions = this._checkEnabledAndProposedAPI(remoteExtensions, false); const remoteAgentConnection = this._remoteAgentService.getConnection(); this._runningLocation = this._runningLocationClassifier.determineRunningLocation(localExtensions, remoteExtensions); @@ -196,7 +196,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten const result = this._registry.deltaExtensions(remoteExtensions.concat(localExtensions), []); if (result.removedDueToLooping.length > 0) { - this._logOrShowMessage(Severity.Error, nls.localize('looping', 'The following extensions contain dependency loops and have been disabled: {0}', result.removedDueToLooping.map(e => `'${e.identifier.value}'`).join(', '))); + this._logOrShowMessage(Severity.Error, nls.localize('looping', "The following extensions contain dependency loops and have been disabled: {0}", result.removedDueToLooping.map(e => `'${e.identifier.value}'`).join(', '))); } if (remoteEnv && remoteAgentConnection) { diff --git a/lib/vscode/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts similarity index 97% rename from lib/vscode/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts rename to src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts index 129ab322e21e..6c46aa161132 100644 --- a/lib/vscode/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts @@ -8,7 +8,7 @@ import { IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/li import { URI } from 'vs/base/common/uri'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementService, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IWorkbenchExtensionEnablementService, EnablementState } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; @@ -255,7 +255,13 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { // Extension is not installed else { - const galleryExtension = await this.galleryService.getCompatibleExtension(extensionIdentifier); + let galleryExtension: IGalleryExtension | undefined; + + try { + galleryExtension = await this.galleryService.getCompatibleExtension(extensionIdentifier) ?? undefined; + } catch (err) { + return; + } if (!galleryExtension) { return; @@ -277,7 +283,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { await this.progressService.withProgress({ location: ProgressLocation.Notification, title: localize('Installing', "Installing Extension '{0}'...", galleryExtension.displayName || galleryExtension.name) - }, () => this.extensionManagementService.installFromGallery(galleryExtension)); + }, () => this.extensionManagementService.installFromGallery(galleryExtension!)); this.notificationService.prompt( Severity.Info, diff --git a/lib/vscode/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts similarity index 99% rename from lib/vscode/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts rename to src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts index fee40e289d8e..bf44e6b8d705 100644 --- a/lib/vscode/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts +++ b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts @@ -360,8 +360,6 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI, globalStorageHome: this._environmentService.globalStorageHome, workspaceStorageHome: this._environmentService.workspaceStorageHome, - webviewResourceRoot: this._environmentService.webviewResourceRoot, - webviewCspSource: this._environmentService.webviewCspSource, }, workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? undefined : { configuration: workspace.configuration || undefined, diff --git a/lib/vscode/src/vs/workbench/services/extensions/browser/webWorkerFileSystemProvider.ts b/src/vs/workbench/services/extensions/browser/webWorkerFileSystemProvider.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/browser/webWorkerFileSystemProvider.ts rename to src/vs/workbench/services/extensions/browser/webWorkerFileSystemProvider.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/common/abstractExtensionService.ts b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts similarity index 90% rename from lib/vscode/src/vs/workbench/services/extensions/common/abstractExtensionService.ts rename to src/vs/workbench/services/extensions/common/abstractExtensionService.ts index 8fe00fa65dad..8b1903e969bf 100644 --- a/lib/vscode/src/vs/workbench/services/extensions/common/abstractExtensionService.ts +++ b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { isNonEmptyArray } from 'vs/base/common/arrays'; import { Barrier } from 'vs/base/common/async'; import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import * as perf from 'vs/base/common/performance'; import { isEqualOrParent } from 'vs/base/common/resources'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -51,7 +51,7 @@ export function parseScannedExtension(extension: ITranslatedScannedExtension): I class DeltaExtensionsQueueItem { constructor( public readonly toAdd: IExtension[], - public readonly toRemove: string[] + public readonly toRemove: string[] | IExtension[] ) { } } @@ -68,6 +68,69 @@ export const enum ExtensionRunningPreference { Remote } +class LockCustomer { + public readonly promise: Promise; + private _resolve!: (value: IDisposable) => void; + + constructor( + public readonly name: string + ) { + this.promise = new Promise((resolve, reject) => { + this._resolve = resolve; + }); + } + + resolve(value: IDisposable): void { + this._resolve(value); + } +} + +class Lock { + private readonly _pendingCustomers: LockCustomer[] = []; + private _isLocked = false; + + public async acquire(customerName: string): Promise { + const customer = new LockCustomer(customerName); + this._pendingCustomers.push(customer); + this._advance(); + return customer.promise; + } + + private _advance(): void { + if (this._isLocked) { + // cannot advance yet + return; + } + if (this._pendingCustomers.length === 0) { + // no more waiting customers + return; + } + + const customer = this._pendingCustomers.shift()!; + + this._isLocked = true; + let customerHoldsLock = true; + + let logLongRunningCustomerTimeout = setTimeout(() => { + if (customerHoldsLock) { + console.warn(`The customer named ${customer.name} has been holding on to the lock for 30s. This might be a problem.`); + } + }, 30 * 1000 /* 30 seconds */); + + const releaseLock = () => { + if (!customerHoldsLock) { + return; + } + clearTimeout(logLongRunningCustomerTimeout); + customerHoldsLock = false; + this._isLocked = false; + this._advance(); + }; + + customer.resolve(toDisposable(releaseLock)); + } +} + export abstract class AbstractExtensionService extends Disposable implements IExtensionService { public _serviceBrand: undefined; @@ -88,6 +151,8 @@ export abstract class AbstractExtensionService extends Disposable implements IEx public readonly onDidChangeResponsiveChange: Event = this._onDidChangeResponsiveChange.event; protected readonly _registry: ExtensionDescriptionRegistry; + private readonly _registryLock: Lock; + private readonly _installedExtensionsReady: Barrier; protected readonly _isDev: boolean; private readonly _extensionsMessages: Map; @@ -98,7 +163,6 @@ export abstract class AbstractExtensionService extends Disposable implements IEx private _deltaExtensionsQueue: DeltaExtensionsQueueItem[]; private _inHandleDeltaExtensions: boolean; - private readonly _onDidFinishHandleDeltaExtensions = this._register(new Emitter()); protected _runningLocation: Map; @@ -130,6 +194,8 @@ export abstract class AbstractExtensionService extends Disposable implements IEx })); this._registry = new ExtensionDescriptionRegistry([]); + this._registryLock = new Lock(); + this._installedExtensionsReady = new Barrier(); this._isDev = !this._environmentService.isBuilt || this._environmentService.isExtensionDevelopment; this._extensionsMessages = new Map(); @@ -151,14 +217,14 @@ export abstract class AbstractExtensionService extends Disposable implements IEx this._register(this._extensionEnablementService.onEnablementChanged((extensions) => { let toAdd: IExtension[] = []; - let toRemove: string[] = []; + let toRemove: IExtension[] = []; for (const extension of extensions) { if (this._safeInvokeIsEnabled(extension)) { // an extension has been enabled toAdd.push(extension); } else { // an extension has been disabled - toRemove.push(extension.identifier.id); + toRemove.push(extension); } } this._handleDeltaExtensions(new DeltaExtensionsQueueItem(toAdd, toRemove)); @@ -207,20 +273,23 @@ export abstract class AbstractExtensionService extends Disposable implements IEx return; } - while (this._deltaExtensionsQueue.length > 0) { - const item = this._deltaExtensionsQueue.shift()!; - try { - this._inHandleDeltaExtensions = true; + let lock: IDisposable | null = null; + try { + this._inHandleDeltaExtensions = true; + lock = await this._registryLock.acquire('handleDeltaExtensions'); + while (this._deltaExtensionsQueue.length > 0) { + const item = this._deltaExtensionsQueue.shift()!; await this._deltaExtensions(item.toAdd, item.toRemove); - } finally { - this._inHandleDeltaExtensions = false; + } + } finally { + this._inHandleDeltaExtensions = false; + if (lock) { + lock.dispose(); } } - - this._onDidFinishHandleDeltaExtensions.fire(); } - private async _deltaExtensions(_toAdd: IExtension[], _toRemove: string[]): Promise { + private async _deltaExtensions(_toAdd: IExtension[], _toRemove: string[] | IExtension[]): Promise { let toAdd: IExtensionDescription[] = []; for (let i = 0, len = _toAdd.length; i < len; i++) { const extension = _toAdd[i]; @@ -240,13 +309,20 @@ export abstract class AbstractExtensionService extends Disposable implements IEx let toRemove: IExtensionDescription[] = []; for (let i = 0, len = _toRemove.length; i < len; i++) { - const extensionId = _toRemove[i]; + const extensionOrId = _toRemove[i]; + const extensionId = (typeof extensionOrId === 'string' ? extensionOrId : extensionOrId.identifier.id); + const extension = (typeof extensionOrId === 'string' ? null : extensionOrId); const extensionDescription = this._registry.getExtensionDescription(extensionId); if (!extensionDescription) { // ignore disabling/uninstalling an extension which is not running continue; } + if (extension && extensionDescription.extensionLocation.scheme !== extension.location.scheme) { + // this event is for a different extension than mine (maybe for the local extension, while I have the remote extension) + continue; + } + if (!this.canRemoveExtension(extensionDescription)) { // uses non-dynamic extension point or is activated continue; @@ -559,11 +635,17 @@ export abstract class AbstractExtensionService extends Disposable implements IEx public async startExtensionHosts(): Promise { this.stopExtensionHosts(); - if (this._inHandleDeltaExtensions) { - await Event.toPromise(this._onDidFinishHandleDeltaExtensions.event); - } + const lock = await this._registryLock.acquire('startExtensionHosts'); + try { + this._startExtensionHosts(false, Array.from(this._allRequestedActivateEvents.keys())); - this._startExtensionHosts(false, Array.from(this._allRequestedActivateEvents.keys())); + const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess); + if (localProcessExtensionHost) { + await localProcessExtensionHost.ready(); + } + } finally { + lock.dispose(); + } } public async restartExtensionHost(): Promise { @@ -680,15 +762,23 @@ export abstract class AbstractExtensionService extends Disposable implements IEx } } - protected _checkEnabledAndProposedAPI(extensions: IExtensionDescription[]): IExtensionDescription[] { + /** + * @argument extensions The extensions to be checked. + * @argument ignoreWorkspaceTrust Do not take workspace trust into account. + */ + protected _checkEnabledAndProposedAPI(extensions: IExtensionDescription[], ignoreWorkspaceTrust: boolean): IExtensionDescription[] { // enable or disable proposed API per extension this._checkEnableProposedApi(extensions); // keep only enabled extensions - return extensions.filter(extension => this._isEnabled(extension)); + return extensions.filter(extension => this._isEnabled(extension, ignoreWorkspaceTrust)); } - protected _isEnabled(extension: IExtensionDescription): boolean { + /** + * @argument extension The extension to be checked. + * @argument ignoreWorkspaceTrust Do not take workspace trust into account. + */ + protected _isEnabled(extension: IExtensionDescription, ignoreWorkspaceTrust: boolean): boolean { if (extension.isUnderDevelopment) { // Never disable extensions under development return true; @@ -699,7 +789,20 @@ export abstract class AbstractExtensionService extends Disposable implements IEx return false; } - return this._safeInvokeIsEnabled(toExtension(extension)); + const ext = toExtension(extension); + + const isEnabled = this._safeInvokeIsEnabled(ext); + if (isEnabled) { + return true; + } + + if (ignoreWorkspaceTrust && this._safeInvokeIsDisabledByWorkspaceTrust(ext)) { + // This extension is disabled, but the reason for it being disabled + // is workspace trust, so we will consider it enabled + return true; + } + + return false; } protected _safeInvokeIsEnabled(extension: IExtension): boolean { @@ -710,6 +813,14 @@ export abstract class AbstractExtensionService extends Disposable implements IEx } } + protected _safeInvokeIsDisabledByWorkspaceTrust(extension: IExtension): boolean { + try { + return this._extensionEnablementService.isDisabledByWorkspaceTrust(extension); + } catch (err) { + return false; + } + } + protected _doHandleExtensionPoints(affectedExtensions: IExtensionDescription[]): void { const affectedExtensionPoints: { [extPointName: string]: boolean; } = Object.create(null); for (let extensionDescription of affectedExtensions) { diff --git a/lib/vscode/src/vs/workbench/services/extensions/common/extensionDescriptionRegistry.ts b/src/vs/workbench/services/extensions/common/extensionDescriptionRegistry.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/common/extensionDescriptionRegistry.ts rename to src/vs/workbench/services/extensions/common/extensionDescriptionRegistry.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/common/extensionDevOptions.ts b/src/vs/workbench/services/extensions/common/extensionDevOptions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/common/extensionDevOptions.ts rename to src/vs/workbench/services/extensions/common/extensionDevOptions.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/common/extensionHostMain.ts b/src/vs/workbench/services/extensions/common/extensionHostMain.ts similarity index 92% rename from lib/vscode/src/vs/workbench/services/extensions/common/extensionHostMain.ts rename to src/vs/workbench/services/extensions/common/extensionHostMain.ts index 0cb9763625bb..0120d4dcdd92 100644 --- a/lib/vscode/src/vs/workbench/services/extensions/common/extensionHostMain.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostMain.ts @@ -36,6 +36,7 @@ export class ExtensionHostMain { private _isTerminating: boolean; private readonly _hostUtils: IHostUtils; + private readonly _rpcProtocol: RPCProtocol; private readonly _extensionService: IExtHostExtensionService; private readonly _logService: ILogService; private readonly _disposables = new DisposableStore(); @@ -48,15 +49,15 @@ export class ExtensionHostMain { ) { this._isTerminating = false; this._hostUtils = hostUtils; - const rpcProtocol = new RPCProtocol(protocol, null, uriTransformer); + this._rpcProtocol = new RPCProtocol(protocol, null, uriTransformer); // ensure URIs are transformed and revived - initData = ExtensionHostMain._transform(initData, rpcProtocol); + initData = ExtensionHostMain._transform(initData, this._rpcProtocol); // bootstrap services const services = new ServiceCollection(...getSingletonServiceDescriptors()); services.set(IExtHostInitDataService, { _serviceBrand: undefined, ...initData }); - services.set(IExtHostRpcService, new ExtHostRpcService(rpcProtocol)); + services.set(IExtHostRpcService, new ExtHostRpcService(this._rpcProtocol)); services.set(IURITransformerService, new URITransformerService(uriTransformer)); services.set(IHostUtils, hostUtils); @@ -99,8 +100,8 @@ export class ExtensionHostMain { }; }); - const mainThreadExtensions = rpcProtocol.getProxy(MainContext.MainThreadExtensionService); - const mainThreadErrors = rpcProtocol.getProxy(MainContext.MainThreadErrors); + const mainThreadExtensions = this._rpcProtocol.getProxy(MainContext.MainThreadExtensionService); + const mainThreadErrors = this._rpcProtocol.getProxy(MainContext.MainThreadErrors); errors.setUnexpectedErrorHandler(err => { const data = errors.transformErrorForSerialization(err); const extension = extensionErrors.get(err); @@ -124,9 +125,12 @@ export class ExtensionHostMain { this._disposables.dispose(); errors.setUnexpectedErrorHandler((err) => { - // TODO: write to log once we have one + this._logService.error(err); }); + // Invalidate all proxies + this._rpcProtocol.dispose(); + const extensionsDeactivated = this._extensionService.deactivateAll(); // Give extensions 1 second to wrap up any async dispose, then exit in at most 4 seconds diff --git a/lib/vscode/src/vs/workbench/services/extensions/common/extensionHostManager.ts b/src/vs/workbench/services/extensions/common/extensionHostManager.ts similarity index 97% rename from lib/vscode/src/vs/workbench/services/extensions/common/extensionHostManager.ts rename to src/vs/workbench/services/extensions/common/extensionHostManager.ts index b363ff4c1ffd..50ef4572c745 100644 --- a/lib/vscode/src/vs/workbench/services/extensions/common/extensionHostManager.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostManager.ts @@ -24,6 +24,7 @@ import { IExtensionHost, ExtensionHostKind, ActivationKind } from 'vs/workbench/ import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator'; import { CATEGORIES } from 'vs/workbench/common/actions'; import { timeout } from 'vs/base/common/async'; +import { URI } from 'vs/base/common/uri'; // Enable to see detailed message communication between window and extension host const LOG_EXTENSION_HOST_COMMUNICATION = false; @@ -132,6 +133,10 @@ export class ExtensionHostManager extends Disposable { return p.value; } + public async ready(): Promise { + await this._getProxy(); + } + private async _measureLatency(proxy: ExtHostExtensionServiceShape): Promise { const COUNT = 10; @@ -285,6 +290,15 @@ export class ExtensionHostManager extends Disposable { } } + public async getCanonicalURI(remoteAuthority: string, uri: URI): Promise { + const proxy = await this._getProxy(); + if (!proxy) { + throw new Error(`Cannot resolve canonical URI`); + } + const result = await proxy.$getCanonicalURI(remoteAuthority, uri); + return URI.revive(result); + } + public async start(enabledExtensionIds: ExtensionIdentifier[]): Promise { const proxy = await this._getProxy(); if (!proxy) { diff --git a/lib/vscode/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts b/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts rename to src/vs/workbench/services/extensions/common/extensionHostProtocol.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/common/extensionManifestPropertiesService.ts b/src/vs/workbench/services/extensions/common/extensionManifestPropertiesService.ts similarity index 92% rename from lib/vscode/src/vs/workbench/services/extensions/common/extensionManifestPropertiesService.ts rename to src/vs/workbench/services/extensions/common/extensionManifestPropertiesService.ts index 913b00826241..8afff68e3374 100644 --- a/lib/vscode/src/vs/workbench/services/extensions/common/extensionManifestPropertiesService.ts +++ b/src/vs/workbench/services/extensions/common/extensionManifestPropertiesService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IExtensionManifest, ExtensionKind, ExtensionIdentifier, ExtensionUntrustedWorkpaceSupportType } from 'vs/platform/extensions/common/extensions'; +import { IExtensionManifest, ExtensionKind, ExtensionIdentifier, ExtensionUntrustedWorkpaceSupportType, ExtensionVirtualWorkpaceSupportType } from 'vs/platform/extensions/common/extensions'; import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { isNonEmptyArray } from 'vs/base/common/arrays'; @@ -13,7 +13,9 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ExtensionUntrustedWorkspaceSupport } from 'vs/base/common/product'; import { Disposable } from 'vs/base/common/lifecycle'; -import { isWorkspaceTrustEnabled, WORKSPACE_TRUST_EXTENSION_SUPPORT } from 'vs/workbench/services/workspaces/common/workspaceTrust'; +import { WORKSPACE_TRUST_EXTENSION_SUPPORT } from 'vs/workbench/services/workspaces/common/workspaceTrust'; +import { isBoolean } from 'vs/base/common/types'; +import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; export const IExtensionManifestPropertiesService = createDecorator('extensionManifestPropertiesService'); @@ -30,7 +32,7 @@ export interface IExtensionManifestPropertiesService { getExtensionKind(manifest: IExtensionManifest): ExtensionKind[]; getExtensionUntrustedWorkspaceSupportType(manifest: IExtensionManifest): ExtensionUntrustedWorkpaceSupportType; - canSupportVirtualWorkspace(manifest: IExtensionManifest): boolean; + getExtensionVirtualWorkspaceSupportType(manifest: IExtensionManifest): ExtensionVirtualWorkpaceSupportType; } export class ExtensionManifestPropertiesService extends Disposable implements IExtensionManifestPropertiesService { @@ -50,6 +52,7 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE constructor( @IProductService private readonly productService: IProductService, @IConfigurationService private readonly configurationService: IConfigurationService, + @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService ) { super(); @@ -123,7 +126,7 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE getExtensionUntrustedWorkspaceSupportType(manifest: IExtensionManifest): ExtensionUntrustedWorkpaceSupportType { // Workspace trust feature is disabled, or extension has no entry point - if (!isWorkspaceTrustEnabled(this.configurationService) || !manifest.main) { + if (!this.workspaceTrustManagementService.workspaceTrustEnabled || !manifest.main) { return true; } @@ -156,7 +159,7 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE return false; } - canSupportVirtualWorkspace(manifest: IExtensionManifest): boolean { + getExtensionVirtualWorkspaceSupportType(manifest: IExtensionManifest): ExtensionVirtualWorkpaceSupportType { // check user configured const userConfiguredVirtualWorkspaceSupport = this.getConfiguredVirtualWorkspaceSupport(manifest); if (userConfiguredVirtualWorkspaceSupport !== undefined) { @@ -171,8 +174,14 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE } // check the manifest - if (manifest.capabilities?.virtualWorkspaces !== undefined) { - return manifest.capabilities?.virtualWorkspaces; + const virtualWorkspaces = manifest.capabilities?.virtualWorkspaces; + if (isBoolean(virtualWorkspaces)) { + return virtualWorkspaces; + } else if (virtualWorkspaces) { + const supported = virtualWorkspaces.supported; + if (isBoolean(supported) || supported === 'limited') { + return supported; + } } // check default from product diff --git a/lib/vscode/src/vs/workbench/services/extensions/common/extensionPoints.ts b/src/vs/workbench/services/extensions/common/extensionPoints.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/common/extensionPoints.ts rename to src/vs/workbench/services/extensions/common/extensionPoints.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/common/extensions.ts b/src/vs/workbench/services/extensions/common/extensions.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/common/extensions.ts rename to src/vs/workbench/services/extensions/common/extensions.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/common/extensionsRegistry.ts b/src/vs/workbench/services/extensions/common/extensionsRegistry.ts similarity index 91% rename from lib/vscode/src/vs/workbench/services/extensions/common/extensionsRegistry.ts rename to src/vs/workbench/services/extensions/common/extensionsRegistry.ts index dca05b7ca6dd..1e91d9bdff22 100644 --- a/lib/vscode/src/vs/workbench/services/extensions/common/extensionsRegistry.ts +++ b/src/vs/workbench/services/extensions/common/extensionsRegistry.ts @@ -320,6 +320,16 @@ export const schema: IJSONSchema = { body: 'onAuthenticationRequest:${11:authenticationProviderId}', description: nls.localize('vscode.extension.activationEvents.onAuthenticationRequest', 'An activation event emitted whenever sessions are requested from the specified authentication provider.') }, + { + label: 'onRenderer', + description: nls.localize('vscode.extension.activationEvents.onRenderer', 'An activation event emitted whenever a notebook output renderer is used.'), + body: 'onRenderer:${11:rendererId}' + }, + { + label: 'onTerminalProfile', + body: 'onTerminalProfile:${1:terminalType}', + description: nls.localize('vscode.extension.activationEvents.onTerminalProfile', 'An activation event emitted when a specific terminal profile is launched.'), + }, { label: '*', description: nls.localize('vscode.extension.activationEvents.star', 'An activation event emitted on VS Code startup. To ensure a great end user experience, please use this activation event in your extension only when no other activation events combination works in your use-case.'), @@ -421,8 +431,28 @@ export const schema: IJSONSchema = { properties: { virtualWorkspaces: { description: nls.localize('vscode.extension.capabilities.virtualWorkspaces', "Declares whether the extension should be enabled in virtual workspaces. A virtual workspace is a workspace which is not backed by any on-disk resources. When false, this extension will be automatically disabled in virtual workspaces. Default is true."), - type: 'boolean', - default: true + type: ['boolean', 'object'], + defaultSnippets: [ + { label: 'limited', body: { supported: '${1:limited}', description: '${2}' } }, + { label: 'false', body: { supported: false, description: '${2}' } }, + ], + default: true.valueOf, + properties: { + supported: { + markdownDescription: nls.localize('vscode.extension.capabilities.virtualWorkspaces.supported', "Declares the level of support for virtual workspaces by the extension."), + type: ['string', 'boolean'], + enum: ['limited', true, false], + enumDescriptions: [ + nls.localize('vscode.extension.capabilities.virtualWorkspaces.supported.limited', "The extension will be enabled in virtual workspaces with some functionality disabled."), + nls.localize('vscode.extension.capabilities.virtualWorkspaces.supported.true', "The extension will be enabled in virtual workspaces with all functionality enabled."), + nls.localize('vscode.extension.capabilities.virtualWorkspaces.supported.false', "The extension will not be enabled in virtual workspaces."), + ] + }, + description: { + type: 'string', + markdownDescription: nls.localize('vscode.extension.capabilities.virtualWorkspaces.description', "A description of how virtual workspaces affects the extensions behavior and why it is needed. This only applies when `supported` is not `true`."), + } + } }, untrustedWorkspaces: { description: nls.localize('vscode.extension.capabilities.untrustedWorkspaces', 'Declares how the extension should be handled in untrusted workspaces.'), diff --git a/lib/vscode/src/vs/workbench/services/extensions/common/extensionsUtil.ts b/src/vs/workbench/services/extensions/common/extensionsUtil.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/common/extensionsUtil.ts rename to src/vs/workbench/services/extensions/common/extensionsUtil.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/common/lazyPromise.ts b/src/vs/workbench/services/extensions/common/lazyPromise.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/common/lazyPromise.ts rename to src/vs/workbench/services/extensions/common/lazyPromise.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/common/polyfillNestedWorker.protocol.ts b/src/vs/workbench/services/extensions/common/polyfillNestedWorker.protocol.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/common/polyfillNestedWorker.protocol.ts rename to src/vs/workbench/services/extensions/common/polyfillNestedWorker.protocol.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/common/proxyIdentifier.ts b/src/vs/workbench/services/extensions/common/proxyIdentifier.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/common/proxyIdentifier.ts rename to src/vs/workbench/services/extensions/common/proxyIdentifier.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/common/remoteConsoleUtil.ts b/src/vs/workbench/services/extensions/common/remoteConsoleUtil.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/common/remoteConsoleUtil.ts rename to src/vs/workbench/services/extensions/common/remoteConsoleUtil.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts b/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts similarity index 98% rename from lib/vscode/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts rename to src/vs/workbench/services/extensions/common/remoteExtensionHost.ts index 4b07928a83d5..d238526f526c 100644 --- a/lib/vscode/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts +++ b/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts @@ -235,9 +235,7 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost { extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI, extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI, globalStorageHome: remoteInitData.globalStorageHome, - workspaceStorageHome: remoteInitData.workspaceStorageHome, - webviewResourceRoot: this._environmentService.webviewResourceRoot, - webviewCspSource: this._environmentService.webviewCspSource, + workspaceStorageHome: remoteInitData.workspaceStorageHome }, workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : { configuration: workspace.configuration, diff --git a/lib/vscode/src/vs/workbench/services/extensions/common/rpcProtocol.ts b/src/vs/workbench/services/extensions/common/rpcProtocol.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/common/rpcProtocol.ts rename to src/vs/workbench/services/extensions/common/rpcProtocol.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts b/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts similarity index 92% rename from lib/vscode/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts rename to src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts index 792a4cc38165..aa78078e14ea 100644 --- a/lib/vscode/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts +++ b/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as fs from 'fs'; import * as nls from 'vs/nls'; import * as path from 'vs/base/common/path'; import * as errors from 'vs/base/common/errors'; @@ -69,9 +68,10 @@ export class CachedExtensionScanner { const version = this._productService.version; const commit = this._productService.commit; + const date = this._productService.date; const devMode = !!process.env['VSCODE_DEV']; const locale = platform.language; - const input = new ExtensionScannerInput(version, commit, locale, devMode, path, isBuiltin, false, translations); + const input = new ExtensionScannerInput(version, date, commit, locale, devMode, path, isBuiltin, false, translations); return ExtensionScanner.scanSingleExtension(input, log); } @@ -151,7 +151,7 @@ export class CachedExtensionScanner { const cacheFile = path.join(cacheFolder, cacheKey); try { - const cacheRawContents = await fs.promises.readFile(cacheFile, 'utf8'); + const cacheRawContents = await pfs.Promises.readFile(cacheFile, 'utf8'); return JSON.parse(cacheRawContents); } catch (err) { // That's ok... @@ -165,7 +165,7 @@ export class CachedExtensionScanner { const cacheFile = path.join(cacheFolder, cacheKey); try { - await fs.promises.mkdir(cacheFolder, { recursive: true }); + await pfs.Promises.mkdir(cacheFolder, { recursive: true }); } catch (err) { // That's ok... } @@ -184,7 +184,7 @@ export class CachedExtensionScanner { } try { - const folderStat = await fs.promises.stat(input.absoluteFolderPath); + const folderStat = await pfs.Promises.stat(input.absoluteFolderPath); input.mtime = folderStat.mtime.getTime(); } catch (err) { // That's ok... @@ -224,7 +224,7 @@ export class CachedExtensionScanner { private static async _readTranslationConfig(): Promise { if (platform.translationsConfigFile) { try { - const content = await fs.promises.readFile(platform.translationsConfigFile, 'utf8'); + const content = await pfs.Promises.readFile(platform.translationsConfigFile, 'utf8'); return JSON.parse(content) as Translations; } catch (err) { // no problemo @@ -245,6 +245,7 @@ export class CachedExtensionScanner { const version = productService.version; const commit = productService.commit; + const date = productService.date; const devMode = !!process.env['VSCODE_DEV']; const locale = platform.language; @@ -253,7 +254,7 @@ export class CachedExtensionScanner { notificationService, environmentService, BUILTIN_MANIFEST_CACHE_FILE, - new ExtensionScannerInput(version, commit, locale, devMode, getSystemExtensionsRoot(), true, false, translations), + new ExtensionScannerInput(version, date, commit, locale, devMode, getSystemExtensionsRoot(), true, false, translations), log ); @@ -263,10 +264,10 @@ export class CachedExtensionScanner { const builtInExtensions = Promise.resolve(productService.builtInExtensions || []); const controlFilePath = joinPath(environmentService.userHome, '.vscode-oss-dev', 'extensions', 'control.json').fsPath; - const controlFile = fs.promises.readFile(controlFilePath, 'utf8') + const controlFile = pfs.Promises.readFile(controlFilePath, 'utf8') .then(raw => JSON.parse(raw), () => ({} as any)); - const input = new ExtensionScannerInput(version, commit, locale, devMode, getExtraDevSystemExtensionsRoot(), true, false, translations); + const input = new ExtensionScannerInput(version, date, commit, locale, devMode, getExtraDevSystemExtensionsRoot(), true, false, translations); const extraBuiltinExtensions = Promise.all([builtInExtensions, controlFile]) .then(([builtInExtensions, control]) => new ExtraBuiltInExtensionResolver(builtInExtensions, control)) .then(resolver => ExtensionScanner.scanExtensions(input, log, resolver)); @@ -279,7 +280,7 @@ export class CachedExtensionScanner { notificationService, environmentService, USER_MANIFEST_CACHE_FILE, - new ExtensionScannerInput(version, commit, locale, devMode, environmentService.extensionsPath, false, false, translations), + new ExtensionScannerInput(version, date, commit, locale, devMode, environmentService.extensionsPath, false, false, translations), log )); @@ -288,7 +289,7 @@ export class CachedExtensionScanner { if (environmentService.isExtensionDevelopment && environmentService.extensionDevelopmentLocationURI) { const extDescsP = environmentService.extensionDevelopmentLocationURI.filter(extLoc => extLoc.scheme === Schemas.file).map(extLoc => { return ExtensionScanner.scanOneOrMultipleExtensions( - new ExtensionScannerInput(version, commit, locale, devMode, originalFSPath(extLoc), false, true, translations), log + new ExtensionScannerInput(version, date, commit, locale, devMode, originalFSPath(extLoc), false, true, translations), log ); }); developedExtensions = Promise.all(extDescsP).then((extDescArrays: IExtensionDescription[][]) => { diff --git a/lib/vscode/src/vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts rename to src/vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts similarity index 92% rename from lib/vscode/src/vs/workbench/services/extensions/electron-browser/extensionService.ts rename to src/vs/workbench/services/extensions/electron-browser/extensionService.ts index b3a09f4164dc..67fecffb3cef 100644 --- a/lib/vscode/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -15,7 +15,7 @@ import { IWorkbenchExtensionEnablementService, EnablementState, IWebExtensionsSc import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IRemoteExtensionHostDataProvider, RemoteExtensionHost, IRemoteExtensionHostInitData } from 'vs/workbench/services/extensions/common/remoteExtensionHost'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { IRemoteAuthorityResolverService, RemoteAuthorityResolverError, RemoteTrustOption, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { IRemoteAuthorityResolverService, RemoteAuthorityResolverError, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; @@ -42,12 +42,8 @@ import { Schemas } from 'vs/base/common/network'; import { ExtensionHostExitCode } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; import { updateProxyConfigurationsScope } from 'vs/platform/request/common/request'; import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; -import { Codicon } from 'vs/base/common/codicons'; -import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; - -const MACHINE_PROMPT = false; +import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; export class ExtensionService extends AbstractExtensionService implements IExtensionService { @@ -75,7 +71,6 @@ export class ExtensionService extends AbstractExtensionService implements IExten @IRemoteExplorerService private readonly _remoteExplorerService: IRemoteExplorerService, @IExtensionGalleryService private readonly _extensionGalleryService: IExtensionGalleryService, @ILogService private readonly _logService: ILogService, - @IDialogService private readonly _dialogService: IDialogService, @IWorkspaceTrustManagementService private readonly _workspaceTrustManagementService: IWorkspaceTrustManagementService, @IExtensionManifestPropertiesService extensionManifestPropertiesService: IExtensionManifestPropertiesService, ) { @@ -144,7 +139,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten return { getInitData: async () => { if (isInitialStart) { - const localExtensions = this._checkEnabledAndProposedAPI(await this._scanAllLocalExtensions()); + // Here we load even extensions that would be disabled by workspace trust + const localExtensions = this._checkEnabledAndProposedAPI(await this._scanAllLocalExtensions(), /* ignore workspace trust */true); const runningLocation = this._runningLocationClassifier.determineRunningLocation(localExtensions, []); const localProcessExtensions = filterByRunningLocation(localExtensions, runningLocation, desiredRunningLocation); return { @@ -343,11 +339,24 @@ export class ExtensionService extends AbstractExtensionService implements IExten const remoteAuthority = this._environmentService.remoteAuthority; const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess)!; - const localExtensions = this._checkEnabledAndProposedAPI(await this._scanAllLocalExtensions()); let remoteEnv: IRemoteAgentEnvironment | null = null; let remoteExtensions: IExtensionDescription[] = []; if (remoteAuthority) { + + this._remoteAuthorityResolverService._setCanonicalURIProvider(async (uri) => { + if (uri.scheme !== Schemas.vscodeRemote || uri.authority !== remoteAuthority) { + // The current remote authority resolver cannot give the canonical URI for this URI + return uri; + } + const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess)!; + return localProcessExtensionHost.getCanonicalURI(remoteAuthority, uri); + }); + + // Now that the canonical URI provider has been registered, we need to wait for the trust state to be + // calculated. The trust state will be used while resolving the authority, however the resolver can + // override the trust state through the resolver result. + await this._workspaceTrustManagementService.workspaceResolved; let resolverResult: ResolverResult; try { @@ -364,42 +373,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten this._remoteAuthorityResolverService._setResolvedAuthorityError(remoteAuthority, err); // Proceed with the local extension host - await this._startLocalExtensionHost(localExtensions); + await this._startLocalExtensionHost(); return; } - let promptForMachineTrust = MACHINE_PROMPT; - - if (resolverResult.options?.trust === RemoteTrustOption.DisableTrust) { - promptForMachineTrust = false; - this._workspaceTrustManagementService.setWorkspaceTrust(true); - } else if (resolverResult.options?.trust === RemoteTrustOption.MachineTrusted) { - promptForMachineTrust = false; - } - - if (promptForMachineTrust) { - const dialogResult = await this._dialogService.show( - Severity.Info, - nls.localize('machineTrustQuestion', "Do you trust the machine you're connecting to?"), - [nls.localize('yes', "Yes, connect."), nls.localize('no', "No, do not connect.")], - { - cancelId: 1, - custom: { - icon: Codicon.remoteExplorer - }, - // checkbox: { label: nls.localize('remember', "Remember my choice"), checked: true } - } - ); - - if (dialogResult.choice !== 0) { - // Did not confirm trust - this._notificationService.notify({ severity: Severity.Warning, message: nls.localize('trustFailure', "Refused to connect to untrusted machine.") }); - // Proceed with the local extension host - await this._startLocalExtensionHost(localExtensions); - return; - } - } - // set the resolved authority this._remoteAuthorityResolverService._setResolvedAuthority(resolverResult.authority, resolverResult.options); this._remoteExplorerService.setTunnelInformation(resolverResult.tunnelInformation); @@ -420,23 +397,31 @@ export class ExtensionService extends AbstractExtensionService implements IExten this._remoteAgentService.getEnvironment(), this._remoteAgentService.scanExtensions() ]); - remoteExtensions = this._checkEnabledAndProposedAPI(remoteExtensions); if (!remoteEnv) { this._notificationService.notify({ severity: Severity.Error, message: nls.localize('getEnvironmentFailure', "Could not fetch remote environment") }); // Proceed with the local extension host - await this._startLocalExtensionHost(localExtensions); + await this._startLocalExtensionHost(); return; } updateProxyConfigurationsScope(remoteEnv.useHostProxy ? ConfigurationScope.APPLICATION : ConfigurationScope.MACHINE); + } else { + + this._remoteAuthorityResolverService._setCanonicalURIProvider(async (uri) => uri); + } - await this._startLocalExtensionHost(localExtensions, remoteAuthority, remoteEnv, remoteExtensions); + await this._startLocalExtensionHost(remoteAuthority, remoteEnv, remoteExtensions); } - private async _startLocalExtensionHost(localExtensions: IExtensionDescription[], remoteAuthority: string | undefined = undefined, remoteEnv: IRemoteAgentEnvironment | null = null, remoteExtensions: IExtensionDescription[] = []): Promise { + private async _startLocalExtensionHost(remoteAuthority: string | undefined = undefined, remoteEnv: IRemoteAgentEnvironment | null = null, remoteExtensions: IExtensionDescription[] = []): Promise { + // Ensure that the workspace trust state has been fully initialized so + // that the extension host can start with the correct set of extensions. + await this._workspaceTrustManagementService.workspaceTrustInitialized; + remoteExtensions = this._checkEnabledAndProposedAPI(remoteExtensions, false); + const localExtensions = this._checkEnabledAndProposedAPI(await this._scanAllLocalExtensions(), false); this._runningLocation = this._runningLocationClassifier.determineRunningLocation(localExtensions, remoteExtensions); // remove non-UI extensions from the local extensions @@ -516,7 +501,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten const allExtensions = await this._scanAllLocalExtensions(); const extension = allExtensions.filter(e => e.identifier.value === resolverExtensionId)[0]; if (extension) { - if (!this._isEnabled(extension)) { + if (!this._isEnabled(extension, false)) { const message = nls.localize('enableResolver', "Extension '{0}' is required to open the remote window.\nOK to enable?", recommendation.friendlyName); this._notificationService.prompt(Severity.Info, message, [{ diff --git a/lib/vscode/src/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts similarity index 99% rename from lib/vscode/src/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts rename to src/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts index 72535eae5530..245da60c35b1 100644 --- a/lib/vscode/src/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts @@ -476,8 +476,6 @@ export class LocalProcessExtensionHost implements IExtensionHost { extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI, globalStorageHome: this._environmentService.globalStorageHome, workspaceStorageHome: this._environmentService.workspaceStorageHome, - webviewResourceRoot: this._environmentService.webviewResourceRoot, - webviewCspSource: this._environmentService.webviewCspSource, }, workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? undefined : { configuration: withNullAsUndefined(workspace.configuration), @@ -627,6 +625,8 @@ export class LocalProcessExtensionHost implements IExtensionHost { // (graceful termination) protocol.send(createMessageOfType(MessageType.Terminate)); + protocol.getSocket().dispose(); + protocol.dispose(); // Give the extension host 10s, after which we will diff --git a/lib/vscode/src/vs/workbench/services/extensions/node/extensionHostProcess.ts b/src/vs/workbench/services/extensions/node/extensionHostProcess.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/node/extensionHostProcess.ts rename to src/vs/workbench/services/extensions/node/extensionHostProcess.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts similarity index 95% rename from lib/vscode/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts rename to src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts index 5abd3c05236d..a0baef250340 100644 --- a/lib/vscode/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts @@ -17,12 +17,11 @@ import { IInitData } from 'vs/workbench/api/common/extHost.protocol'; import { MessageType, createMessageOfType, isMessageOfType, IExtHostSocketMessage, IExtHostReadyMessage, IExtHostReduceGraceTimeMessage, ExtensionHostExitCode } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; import { ExtensionHostMain, IExitFn } from 'vs/workbench/services/extensions/common/extensionHostMain'; import { VSBuffer } from 'vs/base/common/buffer'; -import { IURITransformer, URITransformer } from 'vs/base/common/uriIpc'; +import { IURITransformer, URITransformer, IRawURITransformer } from 'vs/base/common/uriIpc'; import { exists } from 'vs/base/node/pfs'; import { realpath } from 'vs/base/node/extpath'; import { IHostUtils } from 'vs/workbench/api/common/extHostExtensionService'; import { RunOnceScheduler } from 'vs/base/common/async'; -import * as proxyAgent from 'vs/base/node/proxy_agent'; import 'vs/workbench/api/common/extHost.common.services'; import 'vs/workbench/api/node/extHost.node.services'; @@ -138,11 +137,8 @@ function _createExtHostProtocol(): Promise { // Wait for rich client to reconnect protocol.onSocketClose(() => { - // NOTE@coder: Inform the server so we can manage offline - // connections there instead. Our goal is to persist connections - // forever (to a reasonable point) to account for things like - // hibernating overnight. - process.send!({ type: 'VSCODE_EXTHOST_DISCONNECTED' }); + // The socket has closed, let's give the renderer a certain amount of time to reconnect + disconnectRunner1.schedule(); }); } } @@ -177,6 +173,9 @@ function _createExtHostProtocol(): Promise { }); socket.once('error', reject); + socket.on('close', () => { + onTerminate('renderer closed the socket'); + }); }); } } @@ -313,8 +312,6 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise { - proxyAgent.monkeyPatch(true); - performance.mark(`code/extHost/willConnectToRenderer`); const protocol = await createExtHostProtocol(); performance.mark(`code/extHost/didConnectToRenderer`); @@ -335,9 +332,11 @@ export async function startExtensionHostProcess(): Promise { // Attempt to load uri transformer let uriTransformer: IURITransformer | null = null; - if (initData.remote.authority) { + if (initData.remote.authority && args.uriTransformerPath) { try { - uriTransformer = new URITransformer(initData.remote.authority); + const rawURITransformerFactory = require.__$__nodeRequire(args.uriTransformerPath); + const rawURITransformer = rawURITransformerFactory(initData.remote.authority); + uriTransformer = new URITransformer(rawURITransformer); } catch (e) { console.error(e); } diff --git a/lib/vscode/src/vs/workbench/services/extensions/node/extensionPoints.ts b/src/vs/workbench/services/extensions/node/extensionPoints.ts similarity index 90% rename from lib/vscode/src/vs/workbench/services/extensions/node/extensionPoints.ts rename to src/vs/workbench/services/extensions/node/extensionPoints.ts index 5506bddc81db..14106fd427a2 100644 --- a/lib/vscode/src/vs/workbench/services/extensions/node/extensionPoints.ts +++ b/src/vs/workbench/services/extensions/node/extensionPoints.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as fs from 'fs'; import * as nls from 'vs/nls'; import * as path from 'vs/base/common/path'; import * as semver from 'vs/base/common/semver/semver'; @@ -30,14 +29,16 @@ export interface NlsConfiguration { abstract class ExtensionManifestHandler { protected readonly _ourVersion: string; + protected readonly _ourProductDate: string | undefined; protected readonly _log: ILog; protected readonly _absoluteFolderPath: string; protected readonly _isBuiltin: boolean; protected readonly _isUnderDevelopment: boolean; protected readonly _absoluteManifestPath: string; - constructor(ourVersion: string, log: ILog, absoluteFolderPath: string, isBuiltin: boolean, isUnderDevelopment: boolean) { + constructor(ourVersion: string, ourProductDate: string | undefined, log: ILog, absoluteFolderPath: string, isBuiltin: boolean, isUnderDevelopment: boolean) { this._ourVersion = ourVersion; + this._ourProductDate = ourProductDate; this._log = log; this._absoluteFolderPath = absoluteFolderPath; this._isBuiltin = isBuiltin; @@ -58,7 +59,7 @@ class ExtensionManifestParser extends ExtensionManifestHandler { } public parse(): Promise { - return fs.promises.readFile(this._absoluteManifestPath).then((manifestContents) => { + return pfs.Promises.readFile(this._absoluteManifestPath).then((manifestContents) => { const errors: json.ParseError[] = []; const manifest = ExtensionManifestParser._fastParseJSON(manifestContents.toString(), errors); if (json.getNodeType(manifest) !== 'object') { @@ -91,8 +92,8 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler { private readonly _nlsConfig: NlsConfiguration; - constructor(ourVersion: string, log: ILog, absoluteFolderPath: string, isBuiltin: boolean, isUnderDevelopment: boolean, nlsConfig: NlsConfiguration) { - super(ourVersion, log, absoluteFolderPath, isBuiltin, isUnderDevelopment); + constructor(ourVersion: string, ourProductDate: string | undefined, log: ILog, absoluteFolderPath: string, isBuiltin: boolean, isUnderDevelopment: boolean, nlsConfig: NlsConfiguration) { + super(ourVersion, ourProductDate, log, absoluteFolderPath, isBuiltin, isUnderDevelopment); this._nlsConfig = nlsConfig; } @@ -128,7 +129,7 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler { let translationPath = this._nlsConfig.translations[translationId]; let localizedMessages: Promise; if (translationPath) { - localizedMessages = fs.promises.readFile(translationPath, 'utf8').then((content) => { + localizedMessages = pfs.Promises.readFile(translationPath, 'utf8').then((content) => { let errors: json.ParseError[] = []; let translationBundle: TranslationBundle = json.parse(content, errors); if (errors.length > 0) { @@ -153,7 +154,7 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler { if (!messageBundle.localized) { return { values: undefined, default: messageBundle.original }; } - return fs.promises.readFile(messageBundle.localized, 'utf8').then(messageBundleContent => { + return pfs.Promises.readFile(messageBundle.localized, 'utf8').then(messageBundleContent => { let errors: json.ParseError[] = []; let messages: MessageBag = json.parse(messageBundleContent, errors); if (errors.length > 0) { @@ -202,7 +203,7 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler { private static resolveOriginalMessageBundle(originalMessageBundle: string | null, errors: json.ParseError[]) { return new Promise<{ [key: string]: string; } | null>((c, e) => { if (originalMessageBundle) { - fs.promises.readFile(originalMessageBundle).then(originalBundleContent => { + pfs.Promises.readFile(originalMessageBundle).then(originalBundleContent => { c(json.parse(originalBundleContent.toString(), errors)); }, (err) => { c(null); @@ -318,7 +319,7 @@ class ExtensionManifestValidator extends ExtensionManifestHandler { extensionDescription.isUnderDevelopment = this._isUnderDevelopment; let notices: string[] = []; - if (!ExtensionManifestValidator.isValidExtensionDescription(this._ourVersion, this._absoluteFolderPath, extensionDescription, notices)) { + if (!ExtensionManifestValidator.isValidExtensionDescription(this._ourVersion, this._ourProductDate, this._absoluteFolderPath, extensionDescription, notices)) { notices.forEach((error) => { this._log.error(this._absoluteFolderPath, error); }); @@ -344,7 +345,7 @@ class ExtensionManifestValidator extends ExtensionManifestHandler { return extensionDescription; } - private static isValidExtensionDescription(version: string, extensionFolderPath: string, extensionDescription: IExtensionDescription, notices: string[]): boolean { + private static isValidExtensionDescription(version: string, productDate: string | undefined, extensionFolderPath: string, extensionDescription: IExtensionDescription, notices: string[]): boolean { if (!ExtensionManifestValidator.baseIsValidExtensionDescription(extensionFolderPath, extensionDescription, notices)) { return false; @@ -355,7 +356,7 @@ class ExtensionManifestValidator extends ExtensionManifestHandler { return false; } - return isValidExtensionVersion(version, extensionDescription, notices); + return isValidExtensionVersion(version, productDate, extensionDescription, notices); } private static baseIsValidExtensionDescription(extensionFolderPath: string, extensionDescription: IExtensionDescription, notices: string[]): boolean { @@ -453,6 +454,7 @@ export class ExtensionScannerInput { constructor( public readonly ourVersion: string, + public readonly ourProductDate: string | undefined, public readonly commit: string | undefined, public readonly locale: string | undefined, public readonly devMode: boolean, @@ -476,6 +478,7 @@ export class ExtensionScannerInput { public static equals(a: ExtensionScannerInput, b: ExtensionScannerInput): boolean { return ( a.ourVersion === b.ourVersion + && a.ourProductDate === b.ourProductDate && a.commit === b.commit && a.locale === b.locale && a.devMode === b.devMode @@ -512,23 +515,23 @@ export class ExtensionScanner { /** * Read the extension defined in `absoluteFolderPath` */ - private static scanExtension(version: string, log: ILog, absoluteFolderPath: string, isBuiltin: boolean, isUnderDevelopment: boolean, nlsConfig: NlsConfiguration): Promise { + private static scanExtension(version: string, productDate: string | undefined, log: ILog, absoluteFolderPath: string, isBuiltin: boolean, isUnderDevelopment: boolean, nlsConfig: NlsConfiguration): Promise { absoluteFolderPath = path.normalize(absoluteFolderPath); - let parser = new ExtensionManifestParser(version, log, absoluteFolderPath, isBuiltin, isUnderDevelopment); + let parser = new ExtensionManifestParser(version, productDate, log, absoluteFolderPath, isBuiltin, isUnderDevelopment); return parser.parse().then((extensionDescription) => { if (extensionDescription === null) { return null; } - let nlsReplacer = new ExtensionManifestNLSReplacer(version, log, absoluteFolderPath, isBuiltin, isUnderDevelopment, nlsConfig); + let nlsReplacer = new ExtensionManifestNLSReplacer(version, productDate, log, absoluteFolderPath, isBuiltin, isUnderDevelopment, nlsConfig); return nlsReplacer.replaceNLS(extensionDescription); }).then((extensionDescription) => { if (extensionDescription === null) { return null; } - let validator = new ExtensionManifestValidator(version, log, absoluteFolderPath, isBuiltin, isUnderDevelopment); + let validator = new ExtensionManifestValidator(version, productDate, log, absoluteFolderPath, isBuiltin, isUnderDevelopment); return validator.validate(extensionDescription); }); } @@ -549,7 +552,7 @@ export class ExtensionScanner { let obsolete: { [folderName: string]: boolean; } = {}; if (!isBuiltin) { try { - const obsoleteFileContents = await fs.promises.readFile(path.join(absoluteFolderPath, '.obsolete'), 'utf8'); + const obsoleteFileContents = await pfs.Promises.readFile(path.join(absoluteFolderPath, '.obsolete'), 'utf8'); obsolete = JSON.parse(obsoleteFileContents); } catch (err) { // Don't care @@ -566,7 +569,7 @@ export class ExtensionScanner { } const nlsConfig = ExtensionScannerInput.createNLSConfig(input); - let _extensionDescriptions = await Promise.all(refs.map(r => this.scanExtension(input.ourVersion, log, r.path, isBuiltin, isUnderDevelopment, nlsConfig))); + let _extensionDescriptions = await Promise.all(refs.map(r => this.scanExtension(input.ourVersion, input.ourProductDate, log, r.path, isBuiltin, isUnderDevelopment, nlsConfig))); let extensionDescriptions = arrays.coalesce(_extensionDescriptions); extensionDescriptions = extensionDescriptions.filter(item => item !== null && !obsolete[new ExtensionIdentifierWithVersion({ id: getGalleryExtensionId(item.publisher, item.name) }, item.version).key()]); @@ -601,7 +604,7 @@ export class ExtensionScanner { return pfs.SymlinkSupport.existsFile(path.join(absoluteFolderPath, MANIFEST_FILE)).then((exists) => { if (exists) { const nlsConfig = ExtensionScannerInput.createNLSConfig(input); - return this.scanExtension(input.ourVersion, log, absoluteFolderPath, isBuiltin, isUnderDevelopment, nlsConfig).then((extensionDescription) => { + return this.scanExtension(input.ourVersion, input.ourProductDate, log, absoluteFolderPath, isBuiltin, isUnderDevelopment, nlsConfig).then((extensionDescription) => { if (extensionDescription === null) { return []; } @@ -620,7 +623,7 @@ export class ExtensionScanner { const isBuiltin = input.isBuiltin; const isUnderDevelopment = input.isUnderDevelopment; const nlsConfig = ExtensionScannerInput.createNLSConfig(input); - return this.scanExtension(input.ourVersion, log, absoluteFolderPath, isBuiltin, isUnderDevelopment, nlsConfig); + return this.scanExtension(input.ourVersion, input.ourProductDate, log, absoluteFolderPath, isBuiltin, isUnderDevelopment, nlsConfig); } public static mergeBuiltinExtensions(builtinExtensions: Promise, extraBuiltinExtensions: Promise): Promise { diff --git a/lib/vscode/src/vs/workbench/services/extensions/node/proxyResolver.ts b/src/vs/workbench/services/extensions/node/proxyResolver.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/node/proxyResolver.ts rename to src/vs/workbench/services/extensions/node/proxyResolver.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/test/browser/extensionService.test.ts b/src/vs/workbench/services/extensions/test/browser/extensionService.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/test/browser/extensionService.test.ts rename to src/vs/workbench/services/extensions/test/browser/extensionService.test.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/test/common/extensionManifestPropertiesService.test.ts b/src/vs/workbench/services/extensions/test/common/extensionManifestPropertiesService.test.ts similarity index 80% rename from lib/vscode/src/vs/workbench/services/extensions/test/common/extensionManifestPropertiesService.test.ts rename to src/vs/workbench/services/extensions/test/common/extensionManifestPropertiesService.test.ts index 71ce4b823c18..82b82e59c671 100644 --- a/lib/vscode/src/vs/workbench/services/extensions/test/common/extensionManifestPropertiesService.test.ts +++ b/src/vs/workbench/services/extensions/test/common/extensionManifestPropertiesService.test.ts @@ -12,11 +12,13 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/ import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IProductService } from 'vs/platform/product/common/productService'; import { isWeb } from 'vs/base/common/platform'; +import { TestWorkspaceTrustManagementService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService'; +import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; suite('ExtensionManifestPropertiesService - ExtensionKind', () => { function check(manifest: Partial, expected: ExtensionKind[]): void { - const extensionManifestPropertiesService = new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService()); + const extensionManifestPropertiesService = new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService(), new TestWorkspaceTrustManagementService()); assert.deepStrictEqual(extensionManifestPropertiesService.deduceExtensionKind(manifest), expected); } @@ -80,6 +82,7 @@ if (!isWeb) { test('test extension workspace trust request when main entry point is missing', () => { instantiationService.stub(IProductService, >{}); + instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService()); const extensionMaifest = getExtensionManifest(); assertUntrustedWorkspaceSupport(extensionMaifest, true); @@ -87,7 +90,7 @@ if (!isWeb) { test('test extension workspace trust request when workspace trust is disabled', async () => { instantiationService.stub(IProductService, >{}); - await testConfigurationService.setUserConfiguration('security', { workspace: { trust: { enabled: false } } }); + instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService(false)); const extensionMaifest = getExtensionManifest({ main: './out/extension.js' }); assertUntrustedWorkspaceSupport(extensionMaifest, true); @@ -95,37 +98,34 @@ if (!isWeb) { test('test extension workspace trust request when override exists in settings.json', async () => { instantiationService.stub(IProductService, >{}); + instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService()); - await testConfigurationService.setUserConfiguration('security', { workspace: { trust: { extensionUntrustedSupport: { 'pub.a': { supported: true } } } } }); + await testConfigurationService.setUserConfiguration('extensions', { supportUntrustedWorkspaces: { 'pub.a': { supported: true } } }); const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: 'limited' } } }); assertUntrustedWorkspaceSupport(extensionMaifest, true); }); test('test extension workspace trust request when override for the version exists in settings.json', async () => { instantiationService.stub(IProductService, >{}); + instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService()); - await testConfigurationService.setUserConfiguration('security', { workspace: { trust: { extensionUntrustedSupport: { 'pub.a': { supported: true, version: '1.0.0' } } } } }); + await testConfigurationService.setUserConfiguration('extensions', { supportUntrustedWorkspaces: { 'pub.a': { supported: true, version: '1.0.0' } } }); const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: 'limited' } } }); assertUntrustedWorkspaceSupport(extensionMaifest, true); }); test('test extension workspace trust request when override for a different version exists in settings.json', async () => { instantiationService.stub(IProductService, >{}); + instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService()); - await testConfigurationService.setUserConfiguration('security', { - workspace: { - trust: { - enabled: true, - extensionUntrustedSupport: { 'pub.a': { supported: true, version: '2.0.0' } } - } - } - }); + await testConfigurationService.setUserConfiguration('extensions', { supportUntrustedWorkspaces: { 'pub.a': { supported: true, version: '2.0.0' } } }); const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: 'limited' } } }); assertUntrustedWorkspaceSupport(extensionMaifest, 'limited'); }); test('test extension workspace trust request when default exists in product.json', () => { instantiationService.stub(IProductService, >{ extensionUntrustedWorkspaceSupport: { 'pub.a': { default: true } } }); + instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService()); const extensionMaifest = getExtensionManifest({ main: './out/extension.js' }); assertUntrustedWorkspaceSupport(extensionMaifest, true); @@ -133,6 +133,7 @@ if (!isWeb) { test('test extension workspace trust request when override exists in product.json', () => { instantiationService.stub(IProductService, >{ extensionUntrustedWorkspaceSupport: { 'pub.a': { override: 'limited' } } }); + instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService()); const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: true } } }); assertUntrustedWorkspaceSupport(extensionMaifest, 'limited'); @@ -140,6 +141,7 @@ if (!isWeb) { test('test extension workspace trust request when value exists in package.json', () => { instantiationService.stub(IProductService, >{}); + instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService()); const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: 'limited' } } }); assertUntrustedWorkspaceSupport(extensionMaifest, 'limited'); @@ -147,6 +149,7 @@ if (!isWeb) { test('test extension workspace trust request when no value exists in package.json', () => { instantiationService.stub(IProductService, >{}); + instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService()); const extensionMaifest = getExtensionManifest({ main: './out/extension.js' }); assertUntrustedWorkspaceSupport(extensionMaifest, false); diff --git a/lib/vscode/src/vs/workbench/services/extensions/test/common/rpcProtocol.test.ts b/src/vs/workbench/services/extensions/test/common/rpcProtocol.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/test/common/rpcProtocol.test.ts rename to src/vs/workbench/services/extensions/test/common/rpcProtocol.test.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/worker/extensionHostWorker.ts b/src/vs/workbench/services/extensions/worker/extensionHostWorker.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/worker/extensionHostWorker.ts rename to src/vs/workbench/services/extensions/worker/extensionHostWorker.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts b/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts rename to src/vs/workbench/services/extensions/worker/extensionHostWorkerMain.ts diff --git a/lib/vscode/src/vs/workbench/services/extensions/worker/httpWebWorkerExtensionHostIframe.html b/src/vs/workbench/services/extensions/worker/httpWebWorkerExtensionHostIframe.html similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/worker/httpWebWorkerExtensionHostIframe.html rename to src/vs/workbench/services/extensions/worker/httpWebWorkerExtensionHostIframe.html diff --git a/lib/vscode/src/vs/workbench/services/extensions/worker/httpsWebWorkerExtensionHostIframe.html b/src/vs/workbench/services/extensions/worker/httpsWebWorkerExtensionHostIframe.html similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/worker/httpsWebWorkerExtensionHostIframe.html rename to src/vs/workbench/services/extensions/worker/httpsWebWorkerExtensionHostIframe.html diff --git a/lib/vscode/src/vs/workbench/services/extensions/worker/polyfillNestedWorker.ts b/src/vs/workbench/services/extensions/worker/polyfillNestedWorker.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/extensions/worker/polyfillNestedWorker.ts rename to src/vs/workbench/services/extensions/worker/polyfillNestedWorker.ts diff --git a/lib/vscode/src/vs/workbench/services/files/browser/elevatedFileService.ts b/src/vs/workbench/services/files/browser/elevatedFileService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/files/browser/elevatedFileService.ts rename to src/vs/workbench/services/files/browser/elevatedFileService.ts diff --git a/lib/vscode/src/vs/workbench/services/files/common/elevatedFileService.ts b/src/vs/workbench/services/files/common/elevatedFileService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/files/common/elevatedFileService.ts rename to src/vs/workbench/services/files/common/elevatedFileService.ts diff --git a/lib/vscode/src/vs/workbench/services/files/electron-sandbox/elevatedFileService.ts b/src/vs/workbench/services/files/electron-sandbox/elevatedFileService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/files/electron-sandbox/elevatedFileService.ts rename to src/vs/workbench/services/files/electron-sandbox/elevatedFileService.ts diff --git a/lib/vscode/src/vs/workbench/services/filesConfiguration/common/filesConfigurationService.ts b/src/vs/workbench/services/filesConfiguration/common/filesConfigurationService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/filesConfiguration/common/filesConfigurationService.ts rename to src/vs/workbench/services/filesConfiguration/common/filesConfigurationService.ts diff --git a/lib/vscode/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts similarity index 99% rename from lib/vscode/src/vs/workbench/services/history/browser/history.ts rename to src/vs/workbench/services/history/browser/history.ts index 4ce401e8a18d..43e9ed6563c7 100644 --- a/lib/vscode/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -7,7 +7,8 @@ import { localize } from 'vs/nls'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IEditor } from 'vs/editor/common/editorCommon'; import { ITextEditorOptions, IResourceEditorInput, TextEditorSelectionRevealType, IEditorOptions } from 'vs/platform/editor/common/editor'; -import { IEditorInput, IEditorPane, EditorExtensions, EditorInput, IEditorCloseEvent, IEditorInputFactoryRegistry, EditorResourceAccessor, IEditorIdentifier, GroupIdentifier, EditorsOrder, SideBySideEditor } from 'vs/workbench/common/editor'; +import { IEditorInput, IEditorPane, EditorExtensions, IEditorCloseEvent, IEditorInputFactoryRegistry, EditorResourceAccessor, IEditorIdentifier, GroupIdentifier, EditorsOrder, SideBySideEditor } from 'vs/workbench/common/editor'; +import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { FileChangesEvent, IFileService, FileChangeType, FILES_EXCLUDE_CONFIG, FileOperationEvent, FileOperation } from 'vs/platform/files/common/files'; @@ -398,7 +399,7 @@ export class HistoryService extends Disposable implements IHistoryService { return this.editorService.openEditor(location.input, options); } - return this.editorService.openEditor({ resource: (location.input as IResourceEditorInput).resource, options }); + return this.editorService.openEditor({ resource: location.input.resource, options }); } private handleEditorEventInNavigationStack(control: IEditorPane | undefined, event?: ICursorPositionChangedEvent): void { @@ -1011,7 +1012,7 @@ export class HistoryService extends Disposable implements IHistoryService { const editorSerializer = this.editorInputFactory.getEditorInputSerializer(editorInputJSON.typeId); if (editorSerializer) { const input = editorSerializer.deserialize(this.instantiationService, editorInputJSON.deserialized); - if (input) { + if (input instanceof EditorInput) { this.onEditorDispose(input, () => this.removeFromHistory(input), this.editorHistoryListeners); } diff --git a/lib/vscode/src/vs/workbench/services/history/common/history.ts b/src/vs/workbench/services/history/common/history.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/history/common/history.ts rename to src/vs/workbench/services/history/common/history.ts diff --git a/lib/vscode/src/vs/workbench/services/history/test/browser/history.test.ts b/src/vs/workbench/services/history/test/browser/history.test.ts similarity index 86% rename from lib/vscode/src/vs/workbench/services/history/test/browser/history.test.ts rename to src/vs/workbench/services/history/test/browser/history.test.ts index da0879a53ec8..9927273df89f 100644 --- a/lib/vscode/src/vs/workbench/services/history/test/browser/history.test.ts +++ b/src/vs/workbench/services/history/test/browser/history.test.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { EditorOptions } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; import { workbenchInstantiationService, TestFileEditorInput, registerTestEditor, createEditorPart } from 'vs/workbench/test/browser/workbenchTestServices'; import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart'; @@ -53,11 +52,11 @@ suite('HistoryService', function () { const [part, historyService, editorService] = await createServices(); const input1 = new TestFileEditorInput(URI.parse('foo://bar1'), TEST_EDITOR_INPUT_ID); - await part.activeGroup.openEditor(input1, EditorOptions.create({ pinned: true })); + await part.activeGroup.openEditor(input1, { pinned: true }); assert.strictEqual(part.activeGroup.activeEditor, input1); const input2 = new TestFileEditorInput(URI.parse('foo://bar2'), TEST_EDITOR_INPUT_ID); - await part.activeGroup.openEditor(input2, EditorOptions.create({ pinned: true })); + await part.activeGroup.openEditor(input2, { pinned: true }); assert.strictEqual(part.activeGroup.activeEditor, input2); let editorChangePromise = Event.toPromise(editorService.onDidActiveEditorChange); @@ -78,10 +77,10 @@ suite('HistoryService', function () { assert.strictEqual(history.length, 0); const input1 = new TestFileEditorInput(URI.parse('foo://bar1'), TEST_EDITOR_INPUT_ID); - await part.activeGroup.openEditor(input1, EditorOptions.create({ pinned: true })); + await part.activeGroup.openEditor(input1, { pinned: true }); const input2 = new TestFileEditorInput(URI.parse('foo://bar2'), TEST_EDITOR_INPUT_ID); - await part.activeGroup.openEditor(input2, EditorOptions.create({ pinned: true })); + await part.activeGroup.openEditor(input2, { pinned: true }); history = historyService.getHistory(); assert.strictEqual(history.length, 2); @@ -98,7 +97,7 @@ suite('HistoryService', function () { assert.ok(!historyService.getLastActiveFile('foo')); const input1 = new TestFileEditorInput(URI.parse('foo://bar1'), TEST_EDITOR_INPUT_ID); - await part.activeGroup.openEditor(input1, EditorOptions.create({ pinned: true })); + await part.activeGroup.openEditor(input1, { pinned: true }); assert.strictEqual(historyService.getLastActiveFile('foo')?.toString(), input1.resource.toString()); }); @@ -109,10 +108,10 @@ suite('HistoryService', function () { const input1 = new TestFileEditorInput(URI.parse('foo://bar1'), TEST_EDITOR_INPUT_ID); const input2 = new TestFileEditorInput(URI.parse('foo://bar2'), TEST_EDITOR_INPUT_ID); - await part.activeGroup.openEditor(input1, EditorOptions.create({ pinned: true })); + await part.activeGroup.openEditor(input1, { pinned: true }); assert.strictEqual(part.activeGroup.activeEditor, input1); - await part.activeGroup.openEditor(input2, EditorOptions.create({ pinned: true })); + await part.activeGroup.openEditor(input2, { pinned: true }); assert.strictEqual(part.activeGroup.activeEditor, input2); let editorChangePromise = Event.toPromise(editorService.onDidActiveEditorChange); @@ -145,8 +144,8 @@ suite('HistoryService', function () { const sideGroup = part.addGroup(rootGroup, GroupDirection.RIGHT); - await rootGroup.openEditor(input1, EditorOptions.create({ pinned: true })); - await sideGroup.openEditor(input2, EditorOptions.create({ pinned: true })); + await rootGroup.openEditor(input1, { pinned: true }); + await sideGroup.openEditor(input2, { pinned: true }); let editorChangePromise = Event.toPromise(editorService.onDidActiveEditorChange); historyService.openPreviouslyUsedEditor(); @@ -169,9 +168,9 @@ suite('HistoryService', function () { const input3 = new TestFileEditorInput(URI.parse('foo://bar3'), TEST_EDITOR_INPUT_ID); const input4 = new TestFileEditorInput(URI.parse('foo://bar4'), TEST_EDITOR_INPUT_ID); - await part.activeGroup.openEditor(input1, EditorOptions.create({ pinned: true })); - await part.activeGroup.openEditor(input2, EditorOptions.create({ pinned: true })); - await part.activeGroup.openEditor(input3, EditorOptions.create({ pinned: true })); + await part.activeGroup.openEditor(input1, { pinned: true }); + await part.activeGroup.openEditor(input2, { pinned: true }); + await part.activeGroup.openEditor(input3, { pinned: true }); let editorChangePromise = Event.toPromise(editorService.onDidActiveEditorChange); historyService.openPreviouslyUsedEditor(); @@ -179,7 +178,7 @@ suite('HistoryService', function () { assert.strictEqual(part.activeGroup.activeEditor, input2); await timeout(0); - await part.activeGroup.openEditor(input4, EditorOptions.create({ pinned: true })); + await part.activeGroup.openEditor(input4, { pinned: true }); editorChangePromise = Event.toPromise(editorService.onDidActiveEditorChange); historyService.openPreviouslyUsedEditor(); diff --git a/lib/vscode/src/vs/workbench/services/host/browser/browserHostService.ts b/src/vs/workbench/services/host/browser/browserHostService.ts similarity index 98% rename from lib/vscode/src/vs/workbench/services/host/browser/browserHostService.ts rename to src/vs/workbench/services/host/browser/browserHostService.ts index 8506a81b3575..7c5c8b61da83 100644 --- a/lib/vscode/src/vs/workbench/services/host/browser/browserHostService.ts +++ b/src/vs/workbench/services/host/browser/browserHostService.ts @@ -256,8 +256,8 @@ export class BrowserHostService extends Disposable implements IHostService { // Same Window: open via editor service in current window if (this.shouldReuse(options, true /* file */)) { editorService.openEditor({ - leftResource: editors[0].resource, - rightResource: editors[1].resource, + originalInput: { resource: editors[0].resource }, + modifiedInput: { resource: editors[1].resource }, options: { pinned: true } }); } @@ -292,7 +292,7 @@ export class BrowserHostService extends Disposable implements IHostService { openables = [openable]; } - editorService.openEditors(await pathsToEditors(openables, this.fileService)); + editorService.openEditors(await pathsToEditors(openables, this.fileService), undefined, { validateTrust: true }); } // New Window: open into empty window diff --git a/lib/vscode/src/vs/workbench/services/host/browser/host.ts b/src/vs/workbench/services/host/browser/host.ts similarity index 97% rename from lib/vscode/src/vs/workbench/services/host/browser/host.ts rename to src/vs/workbench/services/host/browser/host.ts index 9e6a97e9c9c4..106c41c05d32 100644 --- a/lib/vscode/src/vs/workbench/services/host/browser/host.ts +++ b/src/vs/workbench/services/host/browser/host.ts @@ -12,7 +12,7 @@ export const IHostService = createDecorator('hostService'); /** * A set of methods supported in both web and native environments. * - * @see `INativeHostService` for methods that are specific to native + * @see {@link INativeHostService} for methods that are specific to native * environments. */ export interface IHostService { diff --git a/lib/vscode/src/vs/workbench/services/host/electron-sandbox/nativeHostService.ts b/src/vs/workbench/services/host/electron-sandbox/nativeHostService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/host/electron-sandbox/nativeHostService.ts rename to src/vs/workbench/services/host/electron-sandbox/nativeHostService.ts diff --git a/lib/vscode/src/vs/workbench/services/hover/browser/hover.ts b/src/vs/workbench/services/hover/browser/hover.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/hover/browser/hover.ts rename to src/vs/workbench/services/hover/browser/hover.ts diff --git a/lib/vscode/src/vs/workbench/services/hover/browser/hoverService.ts b/src/vs/workbench/services/hover/browser/hoverService.ts similarity index 84% rename from lib/vscode/src/vs/workbench/services/hover/browser/hoverService.ts rename to src/vs/workbench/services/hover/browser/hoverService.ts index 0e1b809311c1..f89f70cd98e9 100644 --- a/lib/vscode/src/vs/workbench/services/hover/browser/hoverService.ts +++ b/src/vs/workbench/services/hover/browser/hoverService.ts @@ -8,11 +8,12 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { editorHoverBackground, editorHoverBorder, textLinkForeground, editorHoverForeground, editorHoverStatusBarBackground, textCodeBlockBackground, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; import { IHoverService, IHoverOptions } from 'vs/workbench/services/hover/browser/hover'; -import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; +import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { HoverWidget } from 'vs/workbench/services/hover/browser/hoverWidget'; import { IContextViewProvider, IDelegate } from 'vs/base/browser/ui/contextview/contextview'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { addDisposableListener, EventType } from 'vs/base/browser/dom'; export class HoverService implements IHoverService { declare readonly _serviceBrand: undefined; @@ -21,8 +22,10 @@ export class HoverService implements IHoverService { constructor( @IInstantiationService private readonly _instantiationService: IInstantiationService, - @IContextViewService private readonly _contextViewService: IContextViewService + @IContextViewService private readonly _contextViewService: IContextViewService, + @IContextMenuService contextMenuService: IContextMenuService ) { + contextMenuService.onDidShowContextMenu(() => this.hideHover()); } showHover(options: IHoverOptions, focus?: boolean): IDisposable | undefined { @@ -31,17 +34,28 @@ export class HoverService implements IHoverService { } this._currentHoverOptions = options; + const hoverDisposables = new DisposableStore(); const hover = this._instantiationService.createInstance(HoverWidget, options); - hover.onDispose(() => this._currentHoverOptions = undefined); + hover.onDispose(() => { + this._currentHoverOptions = undefined; + hoverDisposables.dispose(); + }); const provider = this._contextViewService as IContextViewProvider; provider.showContextView(new HoverContextViewDelegate(hover, focus)); hover.onRequestLayout(() => provider.layout()); + if ('targetElements' in options.target) { + for (const element of options.target.targetElements) { + hoverDisposables.add(addDisposableListener(element, EventType.CLICK, () => this.hideHover())); + } + } else { + hoverDisposables.add(addDisposableListener(options.target, EventType.CLICK, () => this.hideHover())); + } if ('IntersectionObserver' in window) { const observer = new IntersectionObserver(e => this._intersectionChange(e, hover), { threshold: 0 }); const firstTargetElement = 'targetElements' in options.target ? options.target.targetElements[0] : options.target; observer.observe(firstTargetElement); - hover.onDispose(() => observer.disconnect()); + hoverDisposables.add(toDisposable(() => observer.disconnect())); } return hover; diff --git a/lib/vscode/src/vs/workbench/services/hover/browser/hoverWidget.ts b/src/vs/workbench/services/hover/browser/hoverWidget.ts similarity index 98% rename from lib/vscode/src/vs/workbench/services/hover/browser/hoverWidget.ts rename to src/vs/workbench/services/hover/browser/hoverWidget.ts index e1312fe85e52..bf357e33278c 100644 --- a/lib/vscode/src/vs/workbench/services/hover/browser/hoverWidget.ts +++ b/src/vs/workbench/services/hover/browser/hoverWidget.ts @@ -18,6 +18,7 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { MarkdownRenderer } from 'vs/editor/browser/core/markdownRenderer'; +import { isString } from 'vs/base/common/types'; const $ = dom.$; type TargetRect = { @@ -66,7 +67,7 @@ export class HoverWidget extends Widget { ) { super(); - this._linkHandler = options.linkHandler || this._openerService.open; + this._linkHandler = options.linkHandler || (url => this._openerService.open(url, { allowCommands: (!isString(options.text) && options.text.isTrusted) })); this._target = 'targetElements' in options.target ? options.target : new ElementHoverTarget(options.target); diff --git a/lib/vscode/src/vs/workbench/services/hover/browser/media/hover.css b/src/vs/workbench/services/hover/browser/media/hover.css similarity index 100% rename from lib/vscode/src/vs/workbench/services/hover/browser/media/hover.css rename to src/vs/workbench/services/hover/browser/media/hover.css diff --git a/lib/vscode/src/vs/workbench/services/integrity/browser/integrityService.ts b/src/vs/workbench/services/integrity/browser/integrityService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/integrity/browser/integrityService.ts rename to src/vs/workbench/services/integrity/browser/integrityService.ts diff --git a/lib/vscode/src/vs/workbench/services/integrity/common/integrity.ts b/src/vs/workbench/services/integrity/common/integrity.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/integrity/common/integrity.ts rename to src/vs/workbench/services/integrity/common/integrity.ts diff --git a/lib/vscode/src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts b/src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts rename to src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts diff --git a/lib/vscode/src/vs/workbench/services/ipc/electron-sandbox/sharedProcessService.ts b/src/vs/workbench/services/ipc/electron-sandbox/sharedProcessService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/ipc/electron-sandbox/sharedProcessService.ts rename to src/vs/workbench/services/ipc/electron-sandbox/sharedProcessService.ts diff --git a/lib/vscode/src/vs/workbench/services/issue/common/issue.ts b/src/vs/workbench/services/issue/common/issue.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/issue/common/issue.ts rename to src/vs/workbench/services/issue/common/issue.ts diff --git a/lib/vscode/src/vs/workbench/services/issue/electron-sandbox/issueService.ts b/src/vs/workbench/services/issue/electron-sandbox/issueService.ts similarity index 83% rename from lib/vscode/src/vs/workbench/services/issue/electron-sandbox/issueService.ts rename to src/vs/workbench/services/issue/electron-sandbox/issueService.ts index 2f630ed449b7..684aae6847a7 100644 --- a/lib/vscode/src/vs/workbench/services/issue/electron-sandbox/issueService.ts +++ b/src/vs/workbench/services/issue/electron-sandbox/issueService.ts @@ -6,7 +6,7 @@ import { IssueReporterStyles, IssueReporterData, ProcessExplorerData, IssueReporterExtensionData } from 'vs/platform/issue/common/issue'; import { IIssueService } from 'vs/platform/issue/electron-sandbox/issue'; import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService'; -import { textLinkForeground, inputBackground, inputBorder, inputForeground, buttonBackground, buttonHoverBackground, buttonForeground, inputValidationErrorBorder, foreground, inputActiveOptionBorder, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, editorBackground, editorForeground, listHoverBackground, listHoverForeground, textLinkActiveForeground, inputValidationErrorBackground, inputValidationErrorForeground } from 'vs/platform/theme/common/colorRegistry'; +import { textLinkForeground, inputBackground, inputBorder, inputForeground, buttonBackground, buttonHoverBackground, buttonForeground, inputValidationErrorBorder, foreground, inputActiveOptionBorder, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, editorBackground, editorForeground, listHoverBackground, listHoverForeground, textLinkActiveForeground, inputValidationErrorBackground, inputValidationErrorForeground, listActiveSelectionBackground, listActiveSelectionForeground, listFocusOutline, listFocusBackground, listFocusForeground, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; @@ -19,6 +19,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { ITASExperimentService } from 'vs/workbench/services/experiment/common/experimentService'; import { IAuthenticationService } from 'vs/workbench/services/authentication/browser/authenticationService'; import { registerMainProcessRemoteService } from 'vs/platform/ipc/electron-sandbox/services'; +import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; export class WorkbenchIssueService implements IWorkbenchIssueService { declare readonly _serviceBrand: undefined; @@ -29,6 +30,7 @@ export class WorkbenchIssueService implements IWorkbenchIssueService { @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, @IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService, @INativeWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService, + @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService, @IProductService private readonly productService: IProductService, @ITASExperimentService private readonly experimentService: ITASExperimentService, @IAuthenticationService private readonly authenticationService: IAuthenticationService @@ -70,15 +72,24 @@ export class WorkbenchIssueService implements IWorkbenchIssueService { }); } const experiments = await this.experimentService.getCurrentExperiments(); - const githubSessions = await this.authenticationService.getSessions('github'); - const potentialSessions = githubSessions.filter(session => session.scopes.includes('repo')); + + let githubAccessToken = ''; + try { + const githubSessions = await this.authenticationService.getSessions('github'); + const potentialSessions = githubSessions.filter(session => session.scopes.includes('repo')); + githubAccessToken = potentialSessions[0]?.accessToken; + } catch (e) { + // Ignore + } + const theme = this.themeService.getColorTheme(); const issueReporterData: IssueReporterData = Object.assign({ styles: getIssueReporterStyles(theme), zoomLevel: getZoomLevel(), enabledExtensions: extensionData, experiments: experiments?.join('\n'), - githubAccessToken: potentialSessions[0]?.accessToken + restrictedMode: !this.workspaceTrustManagementService.isWorkpaceTrusted(), + githubAccessToken, }, dataOverrides); return this.issueService.openReporter(issueReporterData); } @@ -91,8 +102,14 @@ export class WorkbenchIssueService implements IWorkbenchIssueService { styles: { backgroundColor: getColor(theme, editorBackground), color: getColor(theme, editorForeground), - hoverBackground: getColor(theme, listHoverBackground), - hoverForeground: getColor(theme, listHoverForeground) + listHoverBackground: getColor(theme, listHoverBackground), + listHoverForeground: getColor(theme, listHoverForeground), + listFocusBackground: getColor(theme, listFocusBackground), + listFocusForeground: getColor(theme, listFocusForeground), + listFocusOutline: getColor(theme, listFocusOutline), + listActiveSelectionBackground: getColor(theme, listActiveSelectionBackground), + listActiveSelectionForeground: getColor(theme, listActiveSelectionForeground), + listHoverOutline: getColor(theme, activeContrastBorder), }, platform: platform, applicationName: this.productService.applicationName diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keybindingService.ts b/src/vs/workbench/services/keybinding/browser/keybindingService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keybindingService.ts rename to src/vs/workbench/services/keybinding/browser/keybindingService.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/cz.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/cz.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/cz.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/cz.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de-swiss.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de-swiss.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de-swiss.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/de-swiss.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.linux.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.linux.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.linux.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.linux.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/dk.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/dk.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/dk.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/dk.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/dvorak.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/dvorak.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/dvorak.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/dvorak.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-belgian.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-belgian.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-belgian.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-belgian.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-ext.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-ext.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-ext.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-ext.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-in.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-in.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-in.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-in.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.linux.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.linux.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.linux.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.linux.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es-latin.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es-latin.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es-latin.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/es-latin.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.linux.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.linux.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.linux.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.linux.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.linux.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.linux.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.linux.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.linux.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/hu.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/hu.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/hu.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/hu.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/it.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/it.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/it.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/it.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/it.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/it.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/it.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/it.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/jp-roman.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/jp-roman.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/jp-roman.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/jp-roman.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/jp.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/jp.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/jp.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/jp.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ko.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ko.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ko.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/ko.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.linux.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.linux.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.linux.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.linux.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/no.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/no.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/no.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/no.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pl.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pl.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pl.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/pl.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pl.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pl.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pl.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/pl.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt-br.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt-br.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt-br.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt-br.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.linux.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.linux.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.linux.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.linux.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/sv.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/sv.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/sv.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/sv.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/sv.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/sv.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/sv.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/sv.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/thai.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/thai.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/thai.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/thai.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/tr.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/tr.win.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/tr.win.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/tr.win.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/zh-hans.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/zh-hans.darwin.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/keyboardLayouts/zh-hans.darwin.ts rename to src/vs/workbench/services/keybinding/browser/keyboardLayouts/zh-hans.darwin.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/navigatorKeyboard.ts b/src/vs/workbench/services/keybinding/browser/navigatorKeyboard.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/navigatorKeyboard.ts rename to src/vs/workbench/services/keybinding/browser/navigatorKeyboard.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/browser/unboundCommands.ts b/src/vs/workbench/services/keybinding/browser/unboundCommands.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/browser/unboundCommands.ts rename to src/vs/workbench/services/keybinding/browser/unboundCommands.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/common/keybindingEditing.ts b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/common/keybindingEditing.ts rename to src/vs/workbench/services/keybinding/common/keybindingEditing.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/common/keybindingIO.ts b/src/vs/workbench/services/keybinding/common/keybindingIO.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/common/keybindingIO.ts rename to src/vs/workbench/services/keybinding/common/keybindingIO.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/common/keymapInfo.ts b/src/vs/workbench/services/keybinding/common/keymapInfo.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/common/keymapInfo.ts rename to src/vs/workbench/services/keybinding/common/keymapInfo.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper.ts b/src/vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper.ts rename to src/vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts b/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts similarity index 99% rename from lib/vscode/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts rename to src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts index b4062798117f..cdc7586ccf14 100644 --- a/lib/vscode/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts +++ b/src/vs/workbench/services/keybinding/common/macLinuxKeyboardMapper.ts @@ -993,6 +993,7 @@ export class MacLinuxKeyboardMapper implements IKeyboardMapper { || (keyCode === KeyCode.End) || (keyCode === KeyCode.PageDown) || (keyCode === KeyCode.PageUp) + || (keyCode === KeyCode.Backspace) ) { // "Dispatch" on keyCode for these key codes to workaround issues with remote desktoping software // where the scan codes appear to be incorrect (see https://github.com/microsoft/vscode/issues/24107) diff --git a/lib/vscode/src/vs/workbench/services/keybinding/common/windowsKeyboardMapper.ts b/src/vs/workbench/services/keybinding/common/windowsKeyboardMapper.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/common/windowsKeyboardMapper.ts rename to src/vs/workbench/services/keybinding/common/windowsKeyboardMapper.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/electron-sandbox/nativeKeyboardLayout.ts b/src/vs/workbench/services/keybinding/electron-sandbox/nativeKeyboardLayout.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/electron-sandbox/nativeKeyboardLayout.ts rename to src/vs/workbench/services/keybinding/electron-sandbox/nativeKeyboardLayout.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/browser/browserKeyboardMapper.test.ts b/src/vs/workbench/services/keybinding/test/browser/browserKeyboardMapper.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/browser/browserKeyboardMapper.test.ts rename to src/vs/workbench/services/keybinding/test/browser/browserKeyboardMapper.test.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/browser/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/browser/keybindingEditing.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/browser/keybindingEditing.test.ts rename to src/vs/workbench/services/keybinding/test/browser/keybindingEditing.test.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/browser/keybindingIO.test.ts b/src/vs/workbench/services/keybinding/test/browser/keybindingIO.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/browser/keybindingIO.test.ts rename to src/vs/workbench/services/keybinding/test/browser/keybindingIO.test.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/keyboardMapperTestUtils.ts b/src/vs/workbench/services/keybinding/test/electron-browser/keyboardMapperTestUtils.ts similarity index 94% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/keyboardMapperTestUtils.ts rename to src/vs/workbench/services/keybinding/test/electron-browser/keyboardMapperTestUtils.ts index 64967e8838c0..d17478838fe1 100644 --- a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/keyboardMapperTestUtils.ts +++ b/src/vs/workbench/services/keybinding/test/electron-browser/keyboardMapperTestUtils.ts @@ -5,11 +5,10 @@ import * as assert from 'assert'; import * as path from 'vs/base/common/path'; -import { promises } from 'fs'; import { getPathFromAmdModule } from 'vs/base/test/node/testUtils'; import { Keybinding, ResolvedKeybinding, SimpleKeybinding } from 'vs/base/common/keyCodes'; import { ScanCodeBinding } from 'vs/base/common/scanCode'; -import { writeFile } from 'vs/base/node/pfs'; +import { Promises, writeFile } from 'vs/base/node/pfs'; import { IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; import { IKeyboardMapper } from 'vs/platform/keyboardLayout/common/keyboardMapper'; @@ -53,7 +52,7 @@ export function assertResolveUserBinding(mapper: IKeyboardMapper, parts: (Simple } export function readRawMapping(file: string): Promise { - return promises.readFile(getPathFromAmdModule(require, `vs/workbench/services/keybinding/test/electron-browser/${file}.js`)).then((buff) => { + return Promises.readFile(getPathFromAmdModule(require, `vs/workbench/services/keybinding/test/electron-browser/${file}.js`)).then((buff) => { let contents = buff.toString(); let func = new Function('define', contents); let rawMappings: T | null = null; @@ -67,7 +66,7 @@ export function readRawMapping(file: string): Promise { export function assertMapping(writeFileIfDifferent: boolean, mapper: IKeyboardMapper, file: string): Promise { const filePath = path.normalize(getPathFromAmdModule(require, `vs/workbench/services/keybinding/test/electron-browser/${file}`)); - return promises.readFile(filePath).then((buff) => { + return Promises.readFile(filePath).then((buff) => { const expected = buff.toString().replace(/\r\n/g, '\n'); const actual = mapper.dumpDebugInfo().replace(/\r\n/g, '\n'); if (actual !== expected && writeFileIfDifferent) { diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/linux_de_ch.js b/src/vs/workbench/services/keybinding/test/electron-browser/linux_de_ch.js similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/linux_de_ch.js rename to src/vs/workbench/services/keybinding/test/electron-browser/linux_de_ch.js diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/linux_de_ch.txt b/src/vs/workbench/services/keybinding/test/electron-browser/linux_de_ch.txt similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/linux_de_ch.txt rename to src/vs/workbench/services/keybinding/test/electron-browser/linux_de_ch.txt diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/linux_en_uk.js b/src/vs/workbench/services/keybinding/test/electron-browser/linux_en_uk.js similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/linux_en_uk.js rename to src/vs/workbench/services/keybinding/test/electron-browser/linux_en_uk.js diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/linux_en_uk.txt b/src/vs/workbench/services/keybinding/test/electron-browser/linux_en_uk.txt similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/linux_en_uk.txt rename to src/vs/workbench/services/keybinding/test/electron-browser/linux_en_uk.txt diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/linux_en_us.js b/src/vs/workbench/services/keybinding/test/electron-browser/linux_en_us.js similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/linux_en_us.js rename to src/vs/workbench/services/keybinding/test/electron-browser/linux_en_us.js diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/linux_en_us.txt b/src/vs/workbench/services/keybinding/test/electron-browser/linux_en_us.txt similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/linux_en_us.txt rename to src/vs/workbench/services/keybinding/test/electron-browser/linux_en_us.txt diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/linux_ru.js b/src/vs/workbench/services/keybinding/test/electron-browser/linux_ru.js similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/linux_ru.js rename to src/vs/workbench/services/keybinding/test/electron-browser/linux_ru.js diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/linux_ru.txt b/src/vs/workbench/services/keybinding/test/electron-browser/linux_ru.txt similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/linux_ru.txt rename to src/vs/workbench/services/keybinding/test/electron-browser/linux_ru.txt diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/macLinuxFallbackKeyboardMapper.test.ts b/src/vs/workbench/services/keybinding/test/electron-browser/macLinuxFallbackKeyboardMapper.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/macLinuxFallbackKeyboardMapper.test.ts rename to src/vs/workbench/services/keybinding/test/electron-browser/macLinuxFallbackKeyboardMapper.test.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/macLinuxKeyboardMapper.test.ts b/src/vs/workbench/services/keybinding/test/electron-browser/macLinuxKeyboardMapper.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/macLinuxKeyboardMapper.test.ts rename to src/vs/workbench/services/keybinding/test/electron-browser/macLinuxKeyboardMapper.test.ts diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/mac_de_ch.js b/src/vs/workbench/services/keybinding/test/electron-browser/mac_de_ch.js similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/mac_de_ch.js rename to src/vs/workbench/services/keybinding/test/electron-browser/mac_de_ch.js diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/mac_de_ch.txt b/src/vs/workbench/services/keybinding/test/electron-browser/mac_de_ch.txt similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/mac_de_ch.txt rename to src/vs/workbench/services/keybinding/test/electron-browser/mac_de_ch.txt diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/mac_en_us.js b/src/vs/workbench/services/keybinding/test/electron-browser/mac_en_us.js similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/mac_en_us.js rename to src/vs/workbench/services/keybinding/test/electron-browser/mac_en_us.js diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/mac_en_us.txt b/src/vs/workbench/services/keybinding/test/electron-browser/mac_en_us.txt similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/mac_en_us.txt rename to src/vs/workbench/services/keybinding/test/electron-browser/mac_en_us.txt diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/mac_zh_hant.js b/src/vs/workbench/services/keybinding/test/electron-browser/mac_zh_hant.js similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/mac_zh_hant.js rename to src/vs/workbench/services/keybinding/test/electron-browser/mac_zh_hant.js diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/mac_zh_hant.txt b/src/vs/workbench/services/keybinding/test/electron-browser/mac_zh_hant.txt similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/mac_zh_hant.txt rename to src/vs/workbench/services/keybinding/test/electron-browser/mac_zh_hant.txt diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/win_de_ch.js b/src/vs/workbench/services/keybinding/test/electron-browser/win_de_ch.js similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/win_de_ch.js rename to src/vs/workbench/services/keybinding/test/electron-browser/win_de_ch.js diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/win_de_ch.txt b/src/vs/workbench/services/keybinding/test/electron-browser/win_de_ch.txt similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/win_de_ch.txt rename to src/vs/workbench/services/keybinding/test/electron-browser/win_de_ch.txt diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/win_en_us.js b/src/vs/workbench/services/keybinding/test/electron-browser/win_en_us.js similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/win_en_us.js rename to src/vs/workbench/services/keybinding/test/electron-browser/win_en_us.js diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/win_en_us.txt b/src/vs/workbench/services/keybinding/test/electron-browser/win_en_us.txt similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/win_en_us.txt rename to src/vs/workbench/services/keybinding/test/electron-browser/win_en_us.txt diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/win_por_ptb.js b/src/vs/workbench/services/keybinding/test/electron-browser/win_por_ptb.js similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/win_por_ptb.js rename to src/vs/workbench/services/keybinding/test/electron-browser/win_por_ptb.js diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/win_por_ptb.txt b/src/vs/workbench/services/keybinding/test/electron-browser/win_por_ptb.txt similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/win_por_ptb.txt rename to src/vs/workbench/services/keybinding/test/electron-browser/win_por_ptb.txt diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/win_ru.js b/src/vs/workbench/services/keybinding/test/electron-browser/win_ru.js similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/win_ru.js rename to src/vs/workbench/services/keybinding/test/electron-browser/win_ru.js diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/win_ru.txt b/src/vs/workbench/services/keybinding/test/electron-browser/win_ru.txt similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/win_ru.txt rename to src/vs/workbench/services/keybinding/test/electron-browser/win_ru.txt diff --git a/lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/windowsKeyboardMapper.test.ts b/src/vs/workbench/services/keybinding/test/electron-browser/windowsKeyboardMapper.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/keybinding/test/electron-browser/windowsKeyboardMapper.test.ts rename to src/vs/workbench/services/keybinding/test/electron-browser/windowsKeyboardMapper.test.ts diff --git a/lib/vscode/src/vs/workbench/services/label/common/labelService.ts b/src/vs/workbench/services/label/common/labelService.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/label/common/labelService.ts rename to src/vs/workbench/services/label/common/labelService.ts diff --git a/lib/vscode/src/vs/workbench/services/label/test/browser/label.test.ts b/src/vs/workbench/services/label/test/browser/label.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/label/test/browser/label.test.ts rename to src/vs/workbench/services/label/test/browser/label.test.ts diff --git a/lib/vscode/src/vs/workbench/services/label/test/electron-browser/label.test.ts b/src/vs/workbench/services/label/test/electron-browser/label.test.ts similarity index 100% rename from lib/vscode/src/vs/workbench/services/label/test/electron-browser/label.test.ts rename to src/vs/workbench/services/label/test/electron-browser/label.test.ts diff --git a/lib/vscode/src/vs/workbench/services/layout/browser/layoutService.ts b/src/vs/workbench/services/layout/browser/layoutService.ts similarity index 98% rename from lib/vscode/src/vs/workbench/services/layout/browser/layoutService.ts rename to src/vs/workbench/services/layout/browser/layoutService.ts index 1c385ecb0345..83d72d6341e8 100644 --- a/lib/vscode/src/vs/workbench/services/layout/browser/layoutService.ts +++ b/src/vs/workbench/services/layout/browser/layoutService.ts @@ -15,6 +15,7 @@ export const IWorkbenchLayoutService = refineServiceDecorator

    ;_H-3eTFZxQzTS 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%0AOJ?~S#lb5rD5;z^0+LoDm^K5Lm*RbBYk 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